forked from SoDOff-Project/sodoff-mmo
Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
46229183e6 | ||
![]() |
bfea453118 | ||
eb4fc7df40 |
@ -1,6 +1,4 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using sodoffmmo.Attributes;
|
||||
using sodoffmmo.Attributes;
|
||||
using sodoffmmo.Core;
|
||||
using sodoffmmo.Data;
|
||||
using sodoffmmo.Management;
|
||||
@ -39,13 +37,6 @@ class ChatMessageHandler : CommandHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
// send an http request to api to check for 'IndefiniteOpenChatBan' or 'TemporaryOpenChatBan'
|
||||
ApiWebService apiWebService = new();
|
||||
var banType = apiWebService.CheckForUserBan(client);
|
||||
|
||||
if (banType != null && (banType == UserBanType.IndefiniteOpenChatBan || banType == UserBanType.TemporaryOpenChatBan))
|
||||
{ client.Send(Utils.ArrNetworkPacket(new string[] { "SMF", "-1", "CB", "1", "Sorry, You've Been Banned From Using Type Chat", "1" }, "SMF")); return; }
|
||||
|
||||
client.Room.Send(Utils.BuildChatMessage(client.PlayerData.Uid, message, client.PlayerData.DiplayName), client);
|
||||
|
||||
NetworkObject cmd = new();
|
||||
|
@ -1,27 +0,0 @@
|
||||
using sodoffmmo.Attributes;
|
||||
using sodoffmmo.Core;
|
||||
using sodoffmmo.Data;
|
||||
|
||||
namespace sodoffmmo.CommandHandlers;
|
||||
|
||||
[ExtensionCommandHandler("SCE")]
|
||||
class CounterEventHandler : CommandHandler {
|
||||
public override Task Handle(Client client, NetworkObject receivedObject) { // {"a":13,"c":1,"p":{"c":"SCE","p":{"NAME":"COUNT"},"r":-1}}
|
||||
if (client.Room is SpecialRoom room) {
|
||||
string name = receivedObject.Get<NetworkObject>("p").Get<string>("NAME");
|
||||
if (name == "COUNT" || name == "COUNT2" || name == "COUNT3") {
|
||||
int index = name switch {
|
||||
"COUNT" => 0,
|
||||
"COUNT2" => 1,
|
||||
"COUNT3" => 2
|
||||
};
|
||||
room.ambassadorGauges[index] = Math.Min(100, room.ambassadorGauges[index]+(1/Configuration.ServerConfiguration.AmbassadorGaugePlayers));
|
||||
room.Send(Utils.VlNetworkPacket(room.GetRoomVars(), client.Room.Id));
|
||||
} else {
|
||||
Console.WriteLine($"Invalid attempt to increment room var {name} in {room.Name}.");
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
using System.Globalization;
|
||||
using sodoffmmo.Attributes;
|
||||
using sodoffmmo.Core;
|
||||
using sodoffmmo.Data;
|
||||
|
||||
namespace sodoffmmo.CommandHandlers;
|
||||
|
||||
// TODO: This is currently stubbed. Supposed to do something.
|
||||
// Should probably be done by someone who actually played the game.
|
||||
[ExtensionCommandHandler("SU")]
|
||||
public class EMDZombiesUpdateHandler : CommandHandler {
|
||||
public override Task Handle(Client client, NetworkObject receivedObject) {
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
[ExtensionCommandHandler("EN")]
|
||||
public class EMDZombiesEnterHandler : CommandHandler {
|
||||
public override Task Handle(Client client, NetworkObject receivedObject) {
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
[ExtensionCommandHandler("EX")]
|
||||
public class EMDZombiesExitHandler : CommandHandler {
|
||||
public override Task Handle(Client client, NetworkObject receivedObject) {
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
@ -90,7 +90,6 @@ class LoginHandler : CommandHandler
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Console.WriteLine($"Authentication exception IID: {client.ClientID} - {ex}");
|
||||
Console.WriteLine("This Can Be Ignored If API Is The One Logging In.");
|
||||
}
|
||||
return Configuration.ServerConfiguration.Authentication != AuthenticationMode.Required; // return true on auth err if not Required mode
|
||||
}
|
||||
|
@ -14,13 +14,9 @@ class RacingPMHandler : CommandHandler
|
||||
NetworkObject p = new();
|
||||
NetworkArray arr = new();
|
||||
NetworkObject data = new();
|
||||
string M = receivedObject.Get<NetworkObject>("p").Get<string>("M");
|
||||
if (M.StartsWith("WF:") || M.StartsWith("WFWD:")) {
|
||||
// When firing weapon in EMD, recieving clients expect userid, but the sending client sends its token instead.
|
||||
string token = M.Split(':')[1];
|
||||
M = M.Replace(token, client.PlayerData.Uid);
|
||||
}
|
||||
data.Add("M", new string[] {M});
|
||||
data.Add("M", new string[] {
|
||||
receivedObject.Get<NetworkObject>("p").Get<string>("M")
|
||||
});
|
||||
data.Add("MID", client.ClientID);
|
||||
arr.Add(data);
|
||||
p.Add("arr", arr);
|
||||
@ -28,8 +24,7 @@ class RacingPMHandler : CommandHandler
|
||||
cmd.Add("p", p);
|
||||
NetworkPacket packet = NetworkObject.WrapObject(1, 13, cmd).Serialize();
|
||||
|
||||
if (client.Room != null) // Throws an exception in Eat my Dust when the player fires their weapon before fully in the room.
|
||||
client.Room.Send(packet);
|
||||
client.Room.Send(packet);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +0,0 @@
|
||||
using System;
|
||||
using sodoffmmo.Attributes;
|
||||
using sodoffmmo.Core;
|
||||
using sodoffmmo.Data;
|
||||
|
||||
namespace sodoffmmo.CommandHandlers;
|
||||
|
||||
[ExtensionCommandHandler("SMB")]
|
||||
class SendMessageBoardHandler : CommandHandler
|
||||
{
|
||||
public override Task Handle(Client client, NetworkObject receivedObject)
|
||||
{
|
||||
NetworkObject args = receivedObject.Get<NetworkObject>("p");
|
||||
|
||||
string toUserId = args.Get<string>("tgt");
|
||||
string content = args.Get<string>("cnt");
|
||||
string level = args.Get<string>("lvl");
|
||||
|
||||
if (toUserId == string.Empty) toUserId = client.PlayerData.Uid; // send to self
|
||||
|
||||
ApiWebService apiWebService = new();
|
||||
|
||||
// first check for any kind of ban
|
||||
var banType = apiWebService.CheckForUserBan(client);
|
||||
|
||||
if (banType != null && banType >= UserBanType.TemporaryOpenChatBan) { client.Send(Utils.ArrNetworkPacket(new string[] { "SMF" }, "SMF")); return Task.CompletedTask; }
|
||||
|
||||
// send message
|
||||
var result = apiWebService.SendMessageBoard(client, toUserId, content, level, "0");
|
||||
|
||||
if (result)
|
||||
client.Send(Utils.ArrNetworkPacket(new string[] { "SMA", "-1", "SUCCESS", "1", DateTime.UtcNow.ToString() }, "SMA"));
|
||||
else client.Send(Utils.ArrNetworkPacket(new string[] { "SMF" }, "SMF"));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
using System;
|
||||
using sodoffmmo.Attributes;
|
||||
using sodoffmmo.Core;
|
||||
using sodoffmmo.Data;
|
||||
|
||||
namespace sodoffmmo.CommandHandlers;
|
||||
|
||||
[ExtensionCommandHandler("SMR")]
|
||||
class SendMessageReplyHandler : CommandHandler
|
||||
{
|
||||
public override Task Handle(Client client, NetworkObject receivedObject)
|
||||
{
|
||||
NetworkObject args = receivedObject.Get<NetworkObject>("p");
|
||||
|
||||
string toUserId = args.Get<string>("tgt");
|
||||
string content = args.Get<string>("cnt");
|
||||
string level = args.Get<string>("lvl");
|
||||
string msgId = args.Get<string>("rtm");
|
||||
|
||||
if (toUserId == string.Empty) toUserId = client.PlayerData.Uid; // send to self
|
||||
|
||||
ApiWebService apiWebService = new();
|
||||
|
||||
// first check for any kind of ban
|
||||
var banType = apiWebService.CheckForUserBan(client);
|
||||
|
||||
if (banType != null && banType >= UserBanType.TemporaryOpenChatBan) { client.Send(Utils.ArrNetworkPacket(new string[] { "SMF" }, "SMF")); return Task.CompletedTask; }
|
||||
|
||||
// send message
|
||||
var result = apiWebService.SendMessageBoard(client, toUserId, content, level, msgId);
|
||||
|
||||
if (result)
|
||||
client.Send(Utils.ArrNetworkPacket(new string[] { "SMA", "-1", "SUCCESS", "1", DateTime.UtcNow.ToString() }, "SMA"));
|
||||
else client.Send(Utils.ArrNetworkPacket(new string[] { "SMF" }, "SMF"));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using sodoffmmo.Attributes;
|
||||
using sodoffmmo.Core;
|
||||
using sodoffmmo.Data;
|
||||
|
||||
namespace sodoffmmo.CommandHandlers
|
||||
{
|
||||
[ExtensionCommandHandler("SUE")]
|
||||
public class SendUserEventHandler : CommandHandler
|
||||
{
|
||||
public override Task Handle(Client client, NetworkObject receivedObject)
|
||||
{
|
||||
NetworkObject p = receivedObject.Get<NetworkObject>("p");
|
||||
|
||||
string userId = p.Get<string>("UID");
|
||||
string cmd = p.Get<string>("CMD");
|
||||
string[] arr = p.Get<string[]>("ARR");
|
||||
|
||||
// find client in all clients list
|
||||
Client? client1 = Server.AllClients.FirstOrDefault(e => e.PlayerData.Uid == userId);
|
||||
|
||||
// send command
|
||||
if (client1 != null) client1.Send(Utils.ArrNetworkPacket(arr, cmd));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@ -50,13 +50,8 @@ class SetPositionVariablesHandler : CommandHandler {
|
||||
|
||||
// user event
|
||||
string? ue = spvData.Get<string>("UE");
|
||||
if (ue != null) {
|
||||
long time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
if ((time - client.PlayerData.last_ue_time) > 499 || Configuration.ServerConfiguration.AllowChaos) {
|
||||
vars.Add("UE", ue);
|
||||
client.PlayerData.last_ue_time = time;
|
||||
}
|
||||
}
|
||||
if (ue != null)
|
||||
vars.Add("UE", ue);
|
||||
// pitch
|
||||
float? cup = spvData.Get<float?>("CUP");
|
||||
if (cup != null)
|
||||
|
@ -27,7 +27,7 @@ class SetUserVariablesHandler : CommandHandler {
|
||||
client.PlayerData.InitFromNetworkData(suvData);
|
||||
UpdatePlayersInRoom();
|
||||
SendSUVToPlayerInRoom();
|
||||
if (client.Room is SpecialRoom room) room.SendAllAlerts(client);
|
||||
client.Room.SendAllAlerts(client);
|
||||
} else {
|
||||
UpdateVars();
|
||||
}
|
||||
@ -43,7 +43,7 @@ class SetUserVariablesHandler : CommandHandler {
|
||||
foreach (string varName in PlayerData.SupportedVariables) {
|
||||
string? value = suvData.Get<string>(varName);
|
||||
if (value != null) {
|
||||
value = client.PlayerData.SetVariable(varName, value);
|
||||
client.PlayerData.SetVariable(varName, value);
|
||||
updated = true;
|
||||
data.Add(varName, value);
|
||||
vl.Add(NetworkArray.Param(varName, value));
|
||||
|
@ -10,7 +10,7 @@ class WorldEventStatusHandler : CommandHandler {
|
||||
public override Task Handle(Client client, NetworkObject receivedObject) {
|
||||
client.Send(Utils.ArrNetworkPacket( new string[] {
|
||||
"WESR",
|
||||
"WE_" + Configuration.ServerConfiguration.EventName + "|" + WorldEvent.Get().EventInfo(),
|
||||
"WE_ScoutAttack|" + WorldEvent.Get().EventInfo(),
|
||||
"EvEnd|" + WorldEvent.Get().GetLastResults()
|
||||
}));
|
||||
return Task.CompletedTask;
|
||||
|
@ -1,102 +0,0 @@
|
||||
using System;
|
||||
using System.Net.Http.Json;
|
||||
using sodoffmmo.CommandHandlers;
|
||||
|
||||
namespace sodoffmmo.Core;
|
||||
|
||||
public class ApiWebService
|
||||
{
|
||||
public UserBanType? CheckForUserBan(Client client)
|
||||
{
|
||||
HttpClient httpClient = new();
|
||||
var content = new FormUrlEncodedContent(
|
||||
new Dictionary<string, string> {
|
||||
{ "token", client.PlayerData.UNToken }
|
||||
}
|
||||
);
|
||||
httpClient.Timeout = new TimeSpan(0, 0, 3);
|
||||
|
||||
try
|
||||
{
|
||||
var response = httpClient.PostAsync($"{Configuration.ServerConfiguration.ApiUrl}/Moderation/CheckForVikingBan", content).Result;
|
||||
Log("Moderation/CheckForVikingBan");
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.OK && response.Content != null) return response.Content.ReadFromJsonAsync<UserBanType>().Result;
|
||||
else return null;
|
||||
} catch (Exception e) { LogError(e.Message); return null; }
|
||||
}
|
||||
|
||||
public string? BanUser(Client client, string userId, string banType, string days)
|
||||
{
|
||||
HttpClient httpClient = new();
|
||||
var content = new FormUrlEncodedContent(
|
||||
new Dictionary<string, string> {
|
||||
{ "token", client.PlayerData.UNToken },
|
||||
{ "userId", userId },
|
||||
{ "banType", banType },
|
||||
{ "days", days }
|
||||
}
|
||||
);
|
||||
httpClient.Timeout = new TimeSpan(0, 0, 3);
|
||||
|
||||
try
|
||||
{
|
||||
var response = httpClient.PostAsync($"{Configuration.ServerConfiguration.ApiUrl}/Moderation/AddBanToVikingByGuid", content).Result;
|
||||
Log("Moderation/AddBanToVikingByGuid");
|
||||
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.OK && response.Content != null) return response.Content.ReadAsStringAsync().Result;
|
||||
else return null;
|
||||
} catch (Exception e) { LogError(e.Message); return null; }
|
||||
}
|
||||
|
||||
public bool SendMessageBoard(Client client, string userId, string data, string level, string replyMessageId)
|
||||
{
|
||||
HttpClient httpClient = new();
|
||||
var content = new FormUrlEncodedContent
|
||||
(
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
{ "token", client.PlayerData.UNToken },
|
||||
{ "userId", userId },
|
||||
{ "data", data },
|
||||
{ "messageLevel", level },
|
||||
{ "replyMessageId", replyMessageId }
|
||||
}
|
||||
);
|
||||
httpClient.Timeout = new TimeSpan(0, 0, 3);
|
||||
|
||||
try
|
||||
{
|
||||
var response = httpClient.PostAsync($"{Configuration.ServerConfiguration.ApiUrl}/Messaging/PostTextMessage", content).Result;
|
||||
Log("Messaging/PostTextMessage");
|
||||
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.OK && response.Content != null) return response.Content.ReadFromJsonAsync<bool>().Result;
|
||||
else return false;
|
||||
} catch (Exception e) { LogError(e.Message); return false; }
|
||||
}
|
||||
|
||||
public bool SetOnline(Client client, bool online)
|
||||
{
|
||||
HttpClient httpClient = new();
|
||||
var content = new FormUrlEncodedContent
|
||||
(
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
{ "token", client.PlayerData.UNToken },
|
||||
{ "online", online.ToString() }
|
||||
}
|
||||
);
|
||||
|
||||
try
|
||||
{
|
||||
var response = httpClient.PostAsync($"{Configuration.ServerConfiguration.ApiUrl}/Precense/SetVikingOnline", content).Result;
|
||||
Log("Precense/SetVikingOnline");
|
||||
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.OK && response.Content != null) return response.Content.ReadFromJsonAsync<bool>().Result;
|
||||
else return false;
|
||||
} catch (Exception e) { LogError(e.Message); return false; }
|
||||
}
|
||||
|
||||
private void Log(string endpoint) => Console.WriteLine($"Sent API Request To {Configuration.ServerConfiguration.ApiUrl}/{endpoint}");
|
||||
|
||||
private void LogError(string message) => Console.WriteLine($"An Error Has Occured When Sending An API Request - {message}");
|
||||
}
|
@ -47,9 +47,6 @@ public class Client {
|
||||
}
|
||||
|
||||
public void SetRoom(Room? room) {
|
||||
// api web service for setting precense
|
||||
ApiWebService apiWebService = new();
|
||||
|
||||
lock(clientLock) {
|
||||
// set variable player data as not valid, but do not reset all player data
|
||||
PlayerData.IsValid = false;
|
||||
@ -62,8 +59,6 @@ public class Client {
|
||||
data.Add("r", Room.Id);
|
||||
data.Add("u", ClientID);
|
||||
Room.Send(NetworkObject.WrapObject(0, 1004, data).Serialize());
|
||||
|
||||
apiWebService.SetOnline(this, false);
|
||||
}
|
||||
|
||||
// set new room (null when SetRoom is used as LeaveRoom)
|
||||
@ -75,8 +70,6 @@ public class Client {
|
||||
|
||||
Send(Room.SubscribeRoom());
|
||||
if (Room.Name != "LIMBO") UpdatePlayerUserVariables(); // do not update user vars if room is limbo
|
||||
|
||||
apiWebService.SetOnline(this, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -105,13 +98,11 @@ public class Client {
|
||||
}
|
||||
|
||||
public void ScheduleDisconnect() {
|
||||
ApiWebService apiWebService = new();
|
||||
if (Room != null) {
|
||||
// quiet remove from room (to avoid issues in Room.Send)
|
||||
// - do not change Room value here
|
||||
// - full remove will be will take place Server.HandleClient (before real disconnected)
|
||||
Room.RemoveClient(this);
|
||||
apiWebService.SetOnline(this, false);
|
||||
}
|
||||
scheduledDisconnect = true;
|
||||
}
|
||||
|
@ -33,11 +33,6 @@ internal sealed class ServerConfiguration {
|
||||
public int EventTimer { get; set; } = 30;
|
||||
public int FirstEventTimer { get; set; } = 10;
|
||||
public Dictionary<string, string[][]> RoomAlerts { get; set; } = new();
|
||||
public string[] AmbassadorRooms { get; set; } = Array.Empty<string>();
|
||||
public int AmbassadorGaugeStart { get; set; } = 75;
|
||||
public float AmbassadorGaugeDecayRate { get; set; } = 60;
|
||||
public bool AmbassadorGaugeDecayOnlyWhenInRoom { get; set; } = true;
|
||||
public float AmbassadorGaugePlayers { get; set; } = 0.5f;
|
||||
public int RacingMaxPlayers { get; set; } = 6;
|
||||
public int RacingMinPlayers { get; set; } = 2;
|
||||
public int RacingMainLobbyTimer { get; set; } = 15;
|
||||
|
144
src/Core/Room.cs
144
src/Core/Room.cs
@ -82,7 +82,7 @@ public class Room {
|
||||
|
||||
public static Room GetOrAdd(string name, bool autoRemove = false) {
|
||||
lock(RoomsListLock) {
|
||||
if (!Room.Exists(name))
|
||||
if (!Room.Exists(name))
|
||||
return new Room(name, autoRemove: autoRemove);
|
||||
return rooms[name];
|
||||
}
|
||||
@ -111,7 +111,7 @@ public class Room {
|
||||
roomInfo.Add(false); // is password protected
|
||||
roomInfo.Add((short)clients.Count); // player count
|
||||
roomInfo.Add((short)4096); // max player count
|
||||
roomInfo.Add(GetRoomVars()); // variables (plus added data)
|
||||
roomInfo.Add(RoomVariables); // variables
|
||||
roomInfo.Add((short)0); // spectator count
|
||||
roomInfo.Add((short)0); // max spectator count
|
||||
|
||||
@ -143,7 +143,7 @@ public class Room {
|
||||
r1.Add(false);
|
||||
r1.Add((short)clients.Count); // player count
|
||||
r1.Add((short)4096); // max player count
|
||||
r1.Add(GetRoomVars());
|
||||
r1.Add(new NetworkArray());
|
||||
r1.Add((short)0);
|
||||
r1.Add((short)0);
|
||||
|
||||
@ -154,5 +154,141 @@ public class Room {
|
||||
return NetworkObject.WrapObject(0, 15, obj).Serialize();
|
||||
}
|
||||
|
||||
internal virtual NetworkArray GetRoomVars() { return RoomVariables; }
|
||||
|
||||
private int alertId = -1;
|
||||
private Random random = new Random();
|
||||
|
||||
List<AlertInfo> alerts = new();
|
||||
|
||||
public void AddAlert(AlertInfo alert) {
|
||||
alerts.Add(alert);
|
||||
ResetAlertTimer(alert);
|
||||
}
|
||||
|
||||
public void SendAllAlerts(Client client) {
|
||||
foreach (AlertInfo alert in alerts) {
|
||||
if (alert.IsRunning()) StartAlert(alert, client);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void StartAlert(AlertInfo alert, Client? specificClient = null) {
|
||||
if (specificClient != null) return; // Disables joining ongoing alerts.
|
||||
|
||||
NetworkArray NewRoomVariables = new();
|
||||
NewRoomVariables.Add(NetworkArray.VlElement(REDALERT_START, alertId++, isPersistent: true));
|
||||
NewRoomVariables.Add(NetworkArray.VlElement(REDALERT_TYPE, alert.type, isPersistent: true));
|
||||
double duration = (alert.endTime - DateTime.Now).TotalSeconds;
|
||||
NewRoomVariables.Add(NetworkArray.VlElement(REDALERT_LENGTH, alert.type == "1" ? alert.redAlertDuration : duration, isPersistent: true));
|
||||
if (alert.type == "1") {
|
||||
NewRoomVariables.Add(NetworkArray.VlElement(REDALERT_TIMEOUT, duration, isPersistent: true));
|
||||
} else if (alert.type == "3") {
|
||||
alert.songId = random.Next(0, alert.songs);
|
||||
NewRoomVariables.Add(NetworkArray.VlElement(REDALERT_SONG, (double)alert.songId, isPersistent: true));
|
||||
}
|
||||
NetworkPacket packet = Utils.VlNetworkPacket(NewRoomVariables, Id);
|
||||
if (specificClient is null) {
|
||||
RoomVariables = NewRoomVariables;
|
||||
Send(packet);
|
||||
Console.WriteLine("Started event " +alert + " in room " + Name);
|
||||
} else {
|
||||
specificClient.Send(packet);
|
||||
Console.WriteLine("Added " + specificClient.PlayerData.DiplayName + " to event " + alert + " with " + duration + " seconds remaining");
|
||||
}
|
||||
}
|
||||
|
||||
void ResetAlertTimer(AlertInfo alert) {
|
||||
System.Timers.Timer? timer = alert.timer;
|
||||
if (timer != null) {
|
||||
timer.Stop();
|
||||
timer.Close();
|
||||
}
|
||||
DateTime startTime = DateTime.Now.AddMilliseconds(random.Next(alert.minTime * 1000, alert.maxTime * 1000));
|
||||
DateTime endTime = startTime.AddSeconds(alert.duration);
|
||||
for (int i = 0; i < alerts.IndexOf(alert); i++) {
|
||||
// Prevent overlap between two events.
|
||||
if (alerts[i].Overlaps(endTime)) {
|
||||
startTime = alerts[i].endTime.AddSeconds(5);
|
||||
endTime = startTime.AddSeconds(alert.duration);
|
||||
}
|
||||
}
|
||||
timer = new System.Timers.Timer((startTime - DateTime.Now).TotalMilliseconds);
|
||||
timer.AutoReset = false;
|
||||
timer.Enabled = true;
|
||||
timer.Elapsed += (sender, e) => StartAlert(alert);
|
||||
timer.Elapsed += (sender, e) => ResetAlertTimer(alert);
|
||||
alert.timer = timer;
|
||||
Console.WriteLine("Event " + alert + " in " + Name + " scheduled for " + startTime.ToString("MM/dd/yyyy HH:mm:ss tt") + " (in " + (startTime - DateTime.Now).TotalSeconds + " seconds)");
|
||||
alert.startTime = startTime;
|
||||
alert.endTime = endTime;
|
||||
}
|
||||
|
||||
private const string REDALERT_START = "RA_S";
|
||||
private const string REDALERT_TYPE = "RA_A";
|
||||
private const string REDALERT_LENGTH = "RA_L";
|
||||
private const string REDALERT_TIMEOUT = "RA_T";
|
||||
private const string REDALERT_SONG = "RA_SO";
|
||||
|
||||
public class AlertInfo {
|
||||
public readonly string type;
|
||||
public readonly double duration;
|
||||
public readonly int minTime;
|
||||
public readonly int maxTime;
|
||||
public readonly int redAlertDuration;
|
||||
public readonly int songs;
|
||||
public int songId;
|
||||
|
||||
public DateTime startTime {
|
||||
get {
|
||||
return newStartTime;
|
||||
}
|
||||
set {
|
||||
oldStartTime = newStartTime;
|
||||
newStartTime = value;
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime endTime {
|
||||
get {
|
||||
return newEndTime;
|
||||
}
|
||||
set {
|
||||
oldEndTime = newEndTime;
|
||||
newEndTime = value;
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime newStartTime;
|
||||
private DateTime newEndTime;
|
||||
private DateTime oldStartTime;
|
||||
private DateTime oldEndTime;
|
||||
|
||||
public System.Timers.Timer? timer = null;
|
||||
|
||||
public AlertInfo(string type, double duration = 20.0, int minTime = 30, int maxTime = 240, int redAlertDuration = 60, int songs = 16) {
|
||||
this.type = type;
|
||||
this.duration = duration;
|
||||
this.minTime = minTime;
|
||||
this.maxTime = maxTime;
|
||||
this.redAlertDuration = redAlertDuration;
|
||||
this.songs = songs;
|
||||
}
|
||||
|
||||
public bool Overlaps(DateTime time) {
|
||||
return (time >= oldStartTime && time <= oldEndTime);
|
||||
}
|
||||
|
||||
public bool IsRunning() {
|
||||
return Overlaps(DateTime.Now);
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return type switch {
|
||||
"1" => "RedAlert",
|
||||
"2" => "DiscoAlert",
|
||||
"3" => "DanceOff",
|
||||
_ => type
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,191 +0,0 @@
|
||||
using sodoffmmo.Data;
|
||||
|
||||
namespace sodoffmmo.Core;
|
||||
|
||||
public class SpecialRoom : Room {
|
||||
public double[] ambassadorGauges = new double[3]; // There is always a maximum of 3.
|
||||
System.Timers.Timer? ambassadorTimer;
|
||||
|
||||
public static void CreateRooms() {
|
||||
foreach (var room in Configuration.ServerConfiguration.RoomAlerts) {
|
||||
foreach (var alert in room.Value) {
|
||||
AlertInfo alertInfo = new AlertInfo(
|
||||
alert[0], // type
|
||||
float.Parse(alert[1], System.Globalization.CultureInfo.InvariantCulture.NumberFormat), // duration
|
||||
Int32.Parse(alert[2]), Int32.Parse(alert[3]), // start min - max for random start time
|
||||
Int32.Parse(alert[4]), Int32.Parse(alert[5]) // extra parameters for specific alarm types
|
||||
);
|
||||
Console.WriteLine($"Setup alert {alertInfo} for {room.Key}");
|
||||
(rooms.GetValueOrDefault(room.Key) as SpecialRoom ?? new SpecialRoom(room.Key)).AddAlert(alertInfo);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var room in Configuration.ServerConfiguration.AmbassadorRooms) {
|
||||
Console.WriteLine($"Setup Ambassador for {room}");
|
||||
(rooms.GetValueOrDefault(room) as SpecialRoom ?? new SpecialRoom(room)).InitAmbassador();
|
||||
}
|
||||
}
|
||||
|
||||
public SpecialRoom(string name) : base(name) {}
|
||||
|
||||
public void InitAmbassador() {
|
||||
for (int i=0;i<3;i++) ambassadorGauges[i] = Configuration.ServerConfiguration.AmbassadorGaugeStart;
|
||||
ambassadorTimer = new(Configuration.ServerConfiguration.AmbassadorGaugeDecayRate * 1000) {
|
||||
AutoReset = true,
|
||||
Enabled = true
|
||||
};
|
||||
ambassadorTimer.Elapsed += (sender, e) => {
|
||||
if (!Configuration.ServerConfiguration.AmbassadorGaugeDecayOnlyWhenInRoom || ClientsCount > 0) {
|
||||
for (int i=0;i<3;i++) ambassadorGauges[i] = Math.Max(0, ambassadorGauges[i]-1);
|
||||
Send(Utils.VlNetworkPacket(GetRoomVars(), Id));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
internal override NetworkArray GetRoomVars() {
|
||||
NetworkArray vars = new();
|
||||
vars.Add(NetworkArray.VlElement("COUNT", (int)Math.Round(ambassadorGauges[0]), isPersistent: true));
|
||||
vars.Add(NetworkArray.VlElement("COUNT2", (int)Math.Round(ambassadorGauges[1]), isPersistent: true));
|
||||
vars.Add(NetworkArray.VlElement("COUNT3", (int)Math.Round(ambassadorGauges[2]), isPersistent: true));
|
||||
for (int i=0;i<RoomVariables.Length;i++) vars.Add(RoomVariables[i]);
|
||||
return vars;
|
||||
}
|
||||
|
||||
private int alertId = -1;
|
||||
private Random random = new();
|
||||
|
||||
List<AlertInfo> alerts = new();
|
||||
|
||||
public void AddAlert(AlertInfo alert) {
|
||||
alerts.Add(alert);
|
||||
ResetAlertTimer(alert);
|
||||
}
|
||||
|
||||
public void SendAllAlerts(Client client) {
|
||||
return; // Disables joining ongoing alerts (since it doesn't work properly).
|
||||
|
||||
foreach (AlertInfo alert in alerts) {
|
||||
if (alert.IsRunning()) StartAlert(alert, client);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void StartAlert(AlertInfo alert, Client? specificClient = null) {
|
||||
NetworkArray NewRoomVariables = new();
|
||||
NewRoomVariables.Add(NetworkArray.VlElement(REDALERT_START, alertId++, isPersistent: true));
|
||||
NewRoomVariables.Add(NetworkArray.VlElement(REDALERT_TYPE, alert.type, isPersistent: true));
|
||||
double duration = (alert.endTime - DateTime.Now).TotalSeconds;
|
||||
NewRoomVariables.Add(NetworkArray.VlElement(REDALERT_LENGTH, alert.type == "1" ? alert.redAlertDuration : duration, isPersistent: true));
|
||||
if (alert.type == "1") {
|
||||
NewRoomVariables.Add(NetworkArray.VlElement(REDALERT_TIMEOUT, duration, isPersistent: true));
|
||||
} else if (alert.type == "3") {
|
||||
alert.songId = random.Next(0, alert.songs);
|
||||
NewRoomVariables.Add(NetworkArray.VlElement(REDALERT_SONG, (double)alert.songId, isPersistent: true));
|
||||
}
|
||||
NetworkPacket packet = Utils.VlNetworkPacket(NewRoomVariables, Id);
|
||||
if (specificClient is null) {
|
||||
RoomVariables = NewRoomVariables;
|
||||
Send(packet);
|
||||
RoomVariables = new();
|
||||
Console.WriteLine("Started event " +alert + " in room " + Name);
|
||||
} else {
|
||||
specificClient.Send(packet);
|
||||
Console.WriteLine("Added " + specificClient.PlayerData.DiplayName + " to event " + alert + " with " + duration + " seconds remaining");
|
||||
}
|
||||
}
|
||||
|
||||
void ResetAlertTimer(AlertInfo alert) {
|
||||
System.Timers.Timer? timer = alert.timer;
|
||||
if (timer != null) {
|
||||
timer.Stop();
|
||||
timer.Close();
|
||||
}
|
||||
DateTime startTime = DateTime.Now.AddMilliseconds(random.Next(alert.minTime * 1000, alert.maxTime * 1000));
|
||||
DateTime endTime = startTime.AddSeconds(alert.duration);
|
||||
for (int i = 0; i < alerts.IndexOf(alert); i++) {
|
||||
// Prevent overlap between two events.
|
||||
if (alerts[i].Overlaps(endTime)) {
|
||||
startTime = alerts[i].endTime.AddSeconds(5);
|
||||
endTime = startTime.AddSeconds(alert.duration);
|
||||
}
|
||||
}
|
||||
timer = new System.Timers.Timer((startTime - DateTime.Now).TotalMilliseconds);
|
||||
timer.AutoReset = false;
|
||||
timer.Enabled = true;
|
||||
timer.Elapsed += (sender, e) => StartAlert(alert);
|
||||
timer.Elapsed += (sender, e) => ResetAlertTimer(alert);
|
||||
alert.timer = timer;
|
||||
Console.WriteLine("Event " + alert + " in " + Name + " scheduled for " + startTime.ToString("MM/dd/yyyy HH:mm:ss tt") + " (in " + (startTime - DateTime.Now).TotalSeconds + " seconds)");
|
||||
alert.startTime = startTime;
|
||||
alert.endTime = endTime;
|
||||
}
|
||||
|
||||
private const string REDALERT_START = "RA_S";
|
||||
private const string REDALERT_TYPE = "RA_A";
|
||||
private const string REDALERT_LENGTH = "RA_L";
|
||||
private const string REDALERT_TIMEOUT = "RA_T";
|
||||
private const string REDALERT_SONG = "RA_SO";
|
||||
|
||||
public class AlertInfo {
|
||||
public readonly string type;
|
||||
public readonly double duration;
|
||||
public readonly int minTime;
|
||||
public readonly int maxTime;
|
||||
public readonly int redAlertDuration;
|
||||
public readonly int songs;
|
||||
public int songId;
|
||||
|
||||
public DateTime startTime {
|
||||
get {
|
||||
return newStartTime;
|
||||
}
|
||||
set {
|
||||
oldStartTime = newStartTime;
|
||||
newStartTime = value;
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime endTime {
|
||||
get {
|
||||
return newEndTime;
|
||||
}
|
||||
set {
|
||||
oldEndTime = newEndTime;
|
||||
newEndTime = value;
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime newStartTime;
|
||||
private DateTime newEndTime;
|
||||
private DateTime oldStartTime;
|
||||
private DateTime oldEndTime;
|
||||
|
||||
public System.Timers.Timer? timer = null;
|
||||
|
||||
public AlertInfo(string type, double duration = 20.0, int minTime = 30, int maxTime = 240, int redAlertDuration = 60, int songs = 16) {
|
||||
this.type = type;
|
||||
this.duration = duration;
|
||||
this.minTime = minTime;
|
||||
this.maxTime = maxTime;
|
||||
this.redAlertDuration = redAlertDuration;
|
||||
this.songs = songs;
|
||||
}
|
||||
|
||||
public bool Overlaps(DateTime time) {
|
||||
return (time >= oldStartTime && time <= oldEndTime);
|
||||
}
|
||||
|
||||
public bool IsRunning() {
|
||||
return Overlaps(DateTime.Now);
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return type switch {
|
||||
"1" => "RedAlert",
|
||||
"2" => "DiscoAlert",
|
||||
"3" => "DanceOff",
|
||||
_ => type
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
namespace sodoffmmo.Core;
|
||||
|
||||
public enum UserBanType
|
||||
{
|
||||
NotBanned = 0,
|
||||
IndefiniteOpenChatBan = 1,
|
||||
TemporaryOpenChatBan = 2,
|
||||
IndefiniteAccountBan = 3,
|
||||
TemporaryAccountBan = 4
|
||||
}
|
@ -38,8 +38,6 @@ public class PlayerData {
|
||||
public string DiplayName { get; set; } = "placeholder";
|
||||
public Role Role { get; set; } = Role.User;
|
||||
|
||||
public long last_ue_time { get; set; } = 0;
|
||||
|
||||
public static readonly string[] SupportedVariables = {
|
||||
"A", // avatar data
|
||||
"FP", // raised pet data
|
||||
@ -59,9 +57,6 @@ public class PlayerData {
|
||||
"P", // position vector (older games)
|
||||
"R", // rotation (older games - updated via SUV, not SPV)
|
||||
"F", // flags (older games - updated via SUV, not SPV)
|
||||
"UTI", // group/clan
|
||||
"SPM", // drive mode (Eat My Dust)
|
||||
"H", // health
|
||||
};
|
||||
|
||||
// other variables (set and updated via SUV command)
|
||||
@ -71,18 +66,18 @@ public class PlayerData {
|
||||
return variables[varName];
|
||||
}
|
||||
|
||||
public string SetVariable(string varName, string value) {
|
||||
public void SetVariable(string varName, string value) {
|
||||
// do not store in variables directory
|
||||
if (varName == "UID") {
|
||||
return value;
|
||||
return;
|
||||
}
|
||||
if (varName == "R") {
|
||||
R = float.Parse(value, CultureInfo.InvariantCulture);
|
||||
return value;
|
||||
return;
|
||||
}
|
||||
if (varName == "F") {
|
||||
F = unchecked((int)Convert.ToUInt32(value, 16));
|
||||
return value;
|
||||
return;
|
||||
}
|
||||
|
||||
// fix variable value before store
|
||||
@ -92,13 +87,11 @@ public class PlayerData {
|
||||
|
||||
// store in directory
|
||||
variables[varName] = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
public void InitFromNetworkData(NetworkObject suvData) {
|
||||
// set initial state for SPV data
|
||||
string? r = suvData.Get<string>("R"); // in Eat My Dust, rotation is sent in R1, R2, R3
|
||||
if (r != null) R = float.Parse(r, CultureInfo.InvariantCulture);
|
||||
R = float.Parse(suvData.Get<string>("R"), CultureInfo.InvariantCulture);
|
||||
string? p1 = suvData.Get<string>("P1");
|
||||
if (p1 != null) {
|
||||
P1 = float.Parse(p1, CultureInfo.InvariantCulture);
|
||||
|
@ -1,26 +0,0 @@
|
||||
using System;
|
||||
using System.Net.Http.Json;
|
||||
using sodoffmmo.Attributes;
|
||||
using sodoffmmo.Core;
|
||||
|
||||
namespace sodoffmmo.Management.Commands;
|
||||
|
||||
[ManagementCommand("ban", Role.Moderator)]
|
||||
class BanCommand : IManagementCommand
|
||||
{
|
||||
public void Handle(Client client, string[] arguments)
|
||||
{
|
||||
if(arguments.Length < 2) { client.Send(Utils.BuildServerSideMessage($"Expected 3 Args, Got {arguments.Length + 1}", "Server")); return; }
|
||||
|
||||
if (arguments[0] == "help") client.Send(Utils.BuildServerSideMessage($"::ban - This bans a user who is in-room. First argument is the id of the user in-room. Room user lists start at 0.", "Server"));
|
||||
var clientToBan = client.Room!.Clients.ToArray()[int.Parse(arguments[0])].PlayerData.Uid;
|
||||
if (clientToBan == null) { client.Send(Utils.BuildServerSideMessage($"User Could Not Be Found", "Server")); return; }
|
||||
|
||||
// send an http request to the api set in appsettings
|
||||
ApiWebService apiWebService = new();
|
||||
var response = apiWebService.BanUser(client, clientToBan, arguments[1], arguments[2]);
|
||||
|
||||
if (response != null) { client.Send(Utils.BuildServerSideMessage("User Banned Successfully", "Server")); return; }
|
||||
else { client.Send(Utils.BuildServerSideMessage("Empty Response", "Server")); }
|
||||
}
|
||||
}
|
@ -12,14 +12,11 @@ public class Server {
|
||||
readonly IPAddress ipAddress;
|
||||
readonly bool IPv6AndIPv4;
|
||||
ModuleManager moduleManager = new();
|
||||
public static List<Client> AllClients { get; private set; }
|
||||
|
||||
public Server(IPAddress ipAdress, int port, bool IPv6AndIPv4) {
|
||||
this.ipAddress = ipAdress;
|
||||
this.port = port;
|
||||
this.IPv6AndIPv4 = IPv6AndIPv4;
|
||||
|
||||
AllClients = new List<Client>();
|
||||
}
|
||||
|
||||
public async Task Run() {
|
||||
@ -32,7 +29,17 @@ public class Server {
|
||||
listener.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
|
||||
listener.Bind(new IPEndPoint(ipAddress, port));
|
||||
|
||||
SpecialRoom.CreateRooms();
|
||||
foreach (var room in Configuration.ServerConfiguration.RoomAlerts) {
|
||||
foreach (var alert in room.Value) {
|
||||
Console.WriteLine($"Setup alert \"{alert[0]}\" for {room.Key}");
|
||||
Room.GetOrAdd(room.Key).AddAlert(new Room.AlertInfo(
|
||||
alert[0], // type
|
||||
float.Parse(alert[1], System.Globalization.CultureInfo.InvariantCulture.NumberFormat), // duration
|
||||
Int32.Parse(alert[2]), Int32.Parse(alert[3]), // start min - max for random start time
|
||||
Int32.Parse(alert[4]), Int32.Parse(alert[5]) // extra parameters for specific alarm types
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
await Listen(listener);
|
||||
}
|
||||
@ -50,7 +57,6 @@ public class Server {
|
||||
|
||||
private async Task HandleClient(Socket handler) {
|
||||
Client client = new(handler);
|
||||
AllClients.Add(client);
|
||||
try {
|
||||
while (client.Connected) {
|
||||
await client.Receive();
|
||||
@ -63,7 +69,6 @@ public class Server {
|
||||
} finally {
|
||||
try {
|
||||
client.SetRoom(null);
|
||||
AllClients.Remove(client);
|
||||
} catch (Exception) { }
|
||||
client.Disconnect();
|
||||
Console.WriteLine("Socket disconnected IID: " + client.ClientID);
|
||||
|
@ -1,75 +1,55 @@
|
||||
{
|
||||
"MMOServer": {
|
||||
"// ListenIP": "Listening IP address for the MMO server, default is '*' which represents all IPv4 and IPv6 addresses",
|
||||
"ListenIP": "*",
|
||||
"MMOServer": {
|
||||
"// ListenIP": "Listening IP address for the MMO server, default is '*' which represents all IPv4 and IPv6 addresses",
|
||||
"ListenIP": "*",
|
||||
|
||||
"// Port": "Listening port number for the MMO server",
|
||||
"Port": 9933,
|
||||
"// Port": "Listening port number for the MMO server",
|
||||
"Port": 9933,
|
||||
|
||||
"// PingDelay": "delay (in milliseconds) for PNG response",
|
||||
"PingDelay": 17,
|
||||
"// PingDelay": "delay (in milliseconds) for PNG response",
|
||||
"PingDelay": 17,
|
||||
|
||||
"// EnableChat": "When true, in-game chat will be enabled",
|
||||
"EnableChat": true,
|
||||
"// EnableChat": "When true, in-game chat will be enabled",
|
||||
"EnableChat": true,
|
||||
|
||||
"// EventName": "World event name send to client (can be used to select ship type after modding WorldEventScoutAttack in client)",
|
||||
"EventName": "ScoutAttack",
|
||||
"// EventName": "World event name send to client (can be used to select ship type after modding WorldEventScoutAttack in client)",
|
||||
"EventName": "ScoutAttack",
|
||||
|
||||
"// FirstEventTimer": "time to start of first world event (battle ship event) after start MMO server",
|
||||
"FirstEventTimer": 3,
|
||||
"// FirstEventTimer": "time to start of first world event (battle ship event) after start MMO server",
|
||||
"FirstEventTimer": 3,
|
||||
|
||||
"// EventTimer": "time between start of world events (battle ship events), set both timer values (EventTimer and FirstEventTimer) to 0 to disable events",
|
||||
"EventTimer": 30,
|
||||
"// EventTimer": "time between start of world events (battle ship events), set both timer values (EventTimer and FirstEventTimer) to 0 to disable events",
|
||||
"EventTimer": 30,
|
||||
|
||||
"// RoomAlerts": "List of MMO rooms with alert function. Default empty (not used by SoD), bellow sample config for WoJS, MB and SS.",
|
||||
"// alert parameters": "alert type, duration [s], minimum time to start [s], maximum time to start [s], redAlertDuration (used for type '1'), number of songs (used for type '3')",
|
||||
"// alert types": "1 - Red Alert, 2 - Disco Alert, 3 - Dance Off",
|
||||
"RoomAlerts": {
|
||||
"LoungeInt": [ [ "3", 20.0, 30, 240, 0, 16 ] ],
|
||||
"Spaceport": [
|
||||
[ "1", 20.0, 300, 300, 60, 0 ],
|
||||
[ "2", 120.0, 1800, 3600, 60, 0 ]
|
||||
],
|
||||
"Academy": [ [ "1", 20.0, 300, 300, 60, 0 ] ],
|
||||
"ClubSSInt": [ [ "3", 20.0, 30, 240, 0, 16 ] ],
|
||||
"JunkYardEMD": [ [ "1", 20.0, 240, 300, 60, 0 ] ]
|
||||
},
|
||||
"// RoomAlerts": "List of MMO rooms with alert function. Default empty (not used by SoD), bellow sample config for WoJS, MB and SS.",
|
||||
"// alert parameters": "alert type, duration [s], minimum time to start [s], maximum time to start [s], redAlertDuration (used for type '1'), number of songs (used for type '3')",
|
||||
"RoomAlerts": {
|
||||
"LoungeInt" : [ ["3", 20.0, 30, 240, 0, 16] ],
|
||||
"Spaceport": [ ["1", 20.0, 300, 300, 60, 0], ["2", 120.0, 1800, 3600, 60, 0] ],
|
||||
"Academy": [ ["1", 20.0, 300, 300, 60, 0] ],
|
||||
"ClubSSInt" : [ ["3", 20.0, 30, 240, 0, 16] ],
|
||||
},
|
||||
|
||||
"// AmbassadorRooms": "Rooms with ambassadors (MB funzones).",
|
||||
"AmbassadorRooms": [ "Spaceport" ],
|
||||
"// RacingMaxPlayers": "maximum players allowed in Thunder Run Racing (no more than 6)",
|
||||
"RacingMaxPlayers": 6,
|
||||
|
||||
"// AmbassadorGaugeStart": "The starting value for all ambassador gauges (MB funzones).",
|
||||
"AmbassadorGaugeStart": 75,
|
||||
"// RacingMinPlayers": "minimum players to start Thunder Run Racing",
|
||||
"RacingMinPlayers": 2,
|
||||
|
||||
"// AmbassadorGaugeDecayRate": "Time in seconds before ambassador gauges decrease (MB funzones).",
|
||||
"AmbassadorGaugeDecayRate": 60,
|
||||
"// AllowChaos": "disable server side exploit protection",
|
||||
"AllowChaos": false,
|
||||
|
||||
"// AmbassadorGaugeDecayOnlyWhenInRoom": "Only decrease ambassador gauges when there is at least one player in the room (MB funzones).",
|
||||
"AmbassadorGaugeDecayOnlyWhenInRoom": true,
|
||||
"// Authentication": "Player authentication mode: Disabled, Optional, RequiredForChat, Required",
|
||||
"// Authentication Disabled": "authentication is disabled, anyone can connect to mmo",
|
||||
"// Authentication Optional": "authentication is required only for moderation activities",
|
||||
"// Authentication RequiredForChat": "authentication is required only for moderation activities and using chat (if chat is enabled)",
|
||||
"// Authentication Required": "authentication is required to connect to mmo",
|
||||
"Authentication": "Disabled",
|
||||
|
||||
"// AmbassadorGaugePlayers": "Denominator for filling the ambassador gauges (MB funzones).",
|
||||
"AmbassadorGaugePlayers": 0.5,
|
||||
"// ApiUrl": "SoDOff API server URL for authentication calls",
|
||||
"ApiUrl": "http://localhost:5000",
|
||||
|
||||
"// RacingMaxPlayers": "maximum players allowed in Thunder Run Racing (no more than 6)",
|
||||
"RacingMaxPlayers": 6,
|
||||
|
||||
"// RacingMinPlayers": "minimum players to start Thunder Run Racing",
|
||||
"RacingMinPlayers": 2,
|
||||
|
||||
"// AllowChaos": "disable server side exploit protection",
|
||||
"AllowChaos": false,
|
||||
|
||||
"// Authentication": "Player authentication mode: Disabled, Optional, RequiredForChat, Required",
|
||||
"// Authentication Disabled": "authentication is disabled, anyone can connect to mmo",
|
||||
"// Authentication Optional": "authentication is required only for moderation activities",
|
||||
"// Authentication RequiredForChat": "authentication is required only for moderation activities and using chat (if chat is enabled)",
|
||||
"// Authentication Required": "authentication is required to connect to mmo",
|
||||
"Authentication": "RequiredForChat",
|
||||
|
||||
"// ApiUrl": "SoDOff API server URL for authentication calls and other calls",
|
||||
"ApiUrl": "http://localhost:5000",
|
||||
|
||||
"// BypassToken": "Token allowed to connect without authentication",
|
||||
"BypassToken": ""
|
||||
}
|
||||
"// BypassToken": "Token allowed to connect without authentication",
|
||||
"BypassToken": ""
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user