Merge branch 'master' of https://github.com/Regalis11/Barotrauma.git
This commit is contained in:
@@ -65,9 +65,9 @@ namespace Barotrauma
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.UpdateMoney });
|
||||
}
|
||||
|
||||
partial void OnTalentGiven(string talentIdentifier)
|
||||
partial void OnTalentGiven(TalentPrefab talentPrefab)
|
||||
{
|
||||
GameServer.Log($"{GameServer.CharacterLogName(this)} has gained the talent '{talentIdentifier}'", ServerLog.MessageType.Talent);
|
||||
GameServer.Log($"{GameServer.CharacterLogName(this)} has gained the talent '{talentPrefab.DisplayName}'", ServerLog.MessageType.Talent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,15 +288,18 @@ namespace Barotrauma
|
||||
{
|
||||
UInt32 talentIdentifier = msg.ReadUInt32();
|
||||
var prefab = TalentPrefab.TalentPrefabs.Find(p => p.UIntIdentifier == talentIdentifier);
|
||||
if (prefab != null) { talentSelection.Add(prefab.Identifier); }
|
||||
if (prefab == null) { continue; }
|
||||
|
||||
if (TalentTree.IsViableTalentForCharacter(this, prefab.Identifier, talentSelection))
|
||||
{
|
||||
GiveTalent(prefab.Identifier);
|
||||
talentSelection.Add(prefab.Identifier);
|
||||
}
|
||||
}
|
||||
talentSelection = TalentTree.CheckTalentSelection(this, talentSelection);
|
||||
|
||||
foreach (string talent in talentSelection)
|
||||
if (talentSelection.Count != talentCount)
|
||||
{
|
||||
GiveTalent(talent);
|
||||
DebugConsole.AddWarning($"Failed to unlock talents: the amount of unlocked talents doesn't match (client: {talentCount}, server: {talentSelection.Count})");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -28,11 +28,11 @@ namespace Barotrauma
|
||||
if (!CheatsEnabled && IsCheat)
|
||||
{
|
||||
NewMessage("Client \"" + client.Name + "\" attempted to use the command \"" + names[0] + "\". Cheats must be enabled using \"enablecheats\" before the command can be used.", Color.Red);
|
||||
GameMain.Server.SendConsoleMessage("You need to enable cheats using the command \"enablecheats\" before you can use the command \"" + names[0] + "\".", client);
|
||||
GameMain.Server.SendConsoleMessage("You need to enable cheats using the command \"enablecheats\" before you can use the command \"" + names[0] + "\".", client, Color.Red);
|
||||
|
||||
#if USE_STEAM
|
||||
NewMessage("Enabling cheats will disable Steam achievements during this play session.", Color.Red);
|
||||
GameMain.Server.SendConsoleMessage("Enabling cheats will disable Steam achievements during this play session.", client);
|
||||
GameMain.Server.SendConsoleMessage("Enabling cheats will disable Steam achievements during this play session.", client, Color.Red);
|
||||
#endif
|
||||
|
||||
return;
|
||||
@@ -367,7 +367,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[0] + "\" is not a valid bot spawn mode. (Valid modes are Fill and Normal)", client);
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[0] + "\" is not a valid bot spawn mode. (Valid modes are Fill and Normal)", client, Color.Red);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1046,12 +1046,12 @@ namespace Barotrauma
|
||||
}));
|
||||
AssignOnClientRequestExecute("clientlist", (Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("***************", client);
|
||||
GameMain.Server.SendConsoleMessage("***************", client, Color.Cyan);
|
||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("- " + c.ID.ToString() + ": " + c.Name + ", " + c.Connection.EndPointString + $", ping {c.Ping} ms", client);
|
||||
GameMain.Server.SendConsoleMessage("- " + c.ID.ToString() + ": " + c.Name + ", " + c.Connection.EndPointString + $", ping {c.Ping} ms", client, Color.Cyan);
|
||||
}
|
||||
GameMain.Server.SendConsoleMessage("***************", client);
|
||||
GameMain.Server.SendConsoleMessage("***************", client, Color.Cyan);
|
||||
});
|
||||
|
||||
commands.Add(new Command("enablecheats", "enablecheats: Enables cheat commands and disables Steam achievements during this play session.", (string[] args) =>
|
||||
@@ -1164,13 +1164,13 @@ namespace Barotrauma
|
||||
if (GameMain.Server == null || args.Length == 0) return;
|
||||
if (!int.TryParse(args[0], out int maxPlayers))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage(args[0] + " is not a valid player count.", client);
|
||||
GameMain.Server.SendConsoleMessage(args[0] + " is not a valid player count.", client, Color.Red);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (maxPlayers > NetConfig.MaxPlayers)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"Setting the maximum amount of players to {maxPlayers} failed due to exceeding the limit of {NetConfig.MaxPlayers} players per server. Using the maximum of {NetConfig.MaxPlayers} instead.", client);
|
||||
GameMain.Server.SendConsoleMessage($"Setting the maximum amount of players to {maxPlayers} failed due to exceeding the limit of {NetConfig.MaxPlayers} players per server. Using the maximum of {NetConfig.MaxPlayers} instead.", client, Color.Red);
|
||||
maxPlayers = NetConfig.MaxPlayers;
|
||||
}
|
||||
|
||||
@@ -1471,7 +1471,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[1] + "\" is not a valid ban duration.", client);
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[1] + "\" is not a valid ban duration.", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1591,7 +1591,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[0] + "\" is not a valid bot spawn mode. (Valid modes are Fill and Normal)", client);
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[0] + "\" is not a valid bot spawn mode. (Valid modes are Fill and Normal)", client, Color.Red);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -1615,7 +1615,7 @@ namespace Barotrauma
|
||||
if (Submarine.MainSub == null || Level.Loaded == null) return;
|
||||
if (Level.Loaded.Type == LevelData.LevelType.Outpost)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("The teleportsub command is unavailable in outpost levels!", client);
|
||||
GameMain.Server.SendConsoleMessage("The teleportsub command is unavailable in outpost levels!", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1639,7 +1639,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!(GameMain.GameSession?.Campaign is MultiPlayerCampaign mpCampaign))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("No campaign active.", client);
|
||||
GameMain.Server.SendConsoleMessage("No campaign active.", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
mpCampaign.LastUpdateID++;
|
||||
@@ -1687,13 +1687,13 @@ namespace Barotrauma
|
||||
a.Identifier.Equals(args[0], StringComparison.OrdinalIgnoreCase));
|
||||
if (afflictionPrefab == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Affliction \"" + args[0] + "\" not found.", client);
|
||||
GameMain.Server.SendConsoleMessage("Affliction \"" + args[0] + "\" not found.", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!float.TryParse(args[1], out float afflictionStrength))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[1] + "\" is not a valid affliction strength.", client);
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[1] + "\" is not a valid affliction strength.", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1776,7 +1776,7 @@ namespace Barotrauma
|
||||
c.DisplayName.Equals(args[0], StringComparison.OrdinalIgnoreCase));
|
||||
if (talentPrefab == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Couldn't find the talent \"" + args[0] + "\".", client);
|
||||
GameMain.Server.SendConsoleMessage("Couldn't find the talent \"" + args[0] + "\".", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
targetCharacter.GiveTalent(talentPrefab);
|
||||
@@ -1802,12 +1802,12 @@ namespace Barotrauma
|
||||
var job = JobPrefab.Prefabs.Find(jp => jp.Name != null && jp.Name.Equals(args[0], StringComparison.OrdinalIgnoreCase));
|
||||
if (job == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"Failed to find the job \"{args[0]}\".", client);
|
||||
GameMain.Server.SendConsoleMessage($"Failed to find the job \"{args[0]}\".", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
if (!TalentTree.JobTalentTrees.TryGetValue(job.Identifier, out TalentTree talentTree))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"No talents configured for the job \"{args[0]}\".", client);
|
||||
GameMain.Server.SendConsoleMessage($"No talents configured for the job \"{args[0]}\".", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
talentTrees.Add(talentTree);
|
||||
@@ -1857,7 +1857,7 @@ namespace Barotrauma
|
||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
Vector2 explosionPos = cursorWorldPos;
|
||||
float range = 500, force = 10, damage = 50, structureDamage = 10, itemDamage = 100, empStrength = 0.0f, ballastFloraStrength = 50f;
|
||||
float range = 500, force = 10, damage = 50, structureDamage = 20, itemDamage = 100, empStrength = 0.0f, ballastFloraStrength = 50f;
|
||||
if (args.Length > 0) float.TryParse(args[0], out range);
|
||||
if (args.Length > 1) float.TryParse(args[1], out force);
|
||||
if (args.Length > 2) float.TryParse(args[2], out damage);
|
||||
@@ -1874,6 +1874,10 @@ namespace Barotrauma
|
||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
Character killedCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args);
|
||||
if (killedCharacter == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Could not find the specified character.", client, Color.Red);
|
||||
}
|
||||
killedCharacter?.SetAllDamage(200.0f, 0.0f, 0.0f);
|
||||
}
|
||||
);
|
||||
@@ -1889,6 +1893,10 @@ namespace Barotrauma
|
||||
GameMain.Server.SetClientCharacter(client, character);
|
||||
client.SpectateOnly = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Could not find the specified character.", client, Color.Red);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1915,7 +1923,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage(args[0] + " is not a valid difficulty setting (enter a value between 0-100)", client);
|
||||
GameMain.Server.SendConsoleMessage(args[0] + " is not a valid difficulty setting (enter a value between 0-100)", client, Color.Red);
|
||||
NewMessage(args[0] + " is not a valid difficulty setting (enter a value between 0-100)", Color.Red);
|
||||
}
|
||||
}
|
||||
@@ -1939,7 +1947,7 @@ namespace Barotrauma
|
||||
ClientPermissions permission = ClientPermissions.None;
|
||||
if (!Enum.TryParse(perm, true, out permission))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage(perm + " is not a valid permission!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage(perm + " is not a valid permission!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1971,7 +1979,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (client.Connection == GameMain.Server.OwnerConnection)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Cannot revoke permissions from the server owner!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Cannot revoke permissions from the server owner!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1980,7 +1988,7 @@ namespace Barotrauma
|
||||
ClientPermissions permission = ClientPermissions.None;
|
||||
if (!Enum.TryParse(perm, true, out permission))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage(perm + " is not a valid permission!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage(perm + " is not a valid permission!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
client.RemovePermission(permission);
|
||||
@@ -2004,7 +2012,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (client.Connection == GameMain.Server.OwnerConnection)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Cannot modify the rank of the server owner!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Cannot modify the rank of the server owner!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2012,7 +2020,7 @@ namespace Barotrauma
|
||||
PermissionPreset preset = PermissionPreset.List.Find(p => p.Name.Equals(rank, StringComparison.OrdinalIgnoreCase));
|
||||
if (preset == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Rank \"" + rank + "\" not found.", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Rank \"" + rank + "\" not found.", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2032,12 +2040,12 @@ namespace Barotrauma
|
||||
var client = FindClient(args[0]);
|
||||
if (client == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Client \"" + args[0] + "\" not found.", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Client \"" + args[0] + "\" not found.", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
if (client.Connection == GameMain.Server.OwnerConnection)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Cannot modify the command permissions of the server owner!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Cannot modify the command permissions of the server owner!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2056,7 +2064,7 @@ namespace Barotrauma
|
||||
Command matchingCommand = commands.Find(c => c.names.Contains(splitCommands[i]));
|
||||
if (matchingCommand == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Could not find the command \"" + splitCommands[i] + "\"!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Could not find the command \"" + splitCommands[i] + "\"!", senderClient, Color.Red);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2094,7 +2102,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (client.Connection == GameMain.Server.OwnerConnection)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Cannot revoke command permissions from the server owner!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Cannot revoke command permissions from the server owner!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
List<Command> revokedCommands = new List<Command>();
|
||||
@@ -2112,7 +2120,7 @@ namespace Barotrauma
|
||||
Command matchingCommand = commands.Find(c => c.names.Contains(splitCommands[i]));
|
||||
if (matchingCommand == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Could not find the command \"" + splitCommands[i] + "\"!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Could not find the command \"" + splitCommands[i] + "\"!", senderClient, Color.Red);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2192,7 +2200,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (args.Length < 2)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Invalid parameters. The command should be formatted as \"setclientcharacter [client] [character]\". If the names consist of multiple words, you should surround them with quotation marks.", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Invalid parameters. The command should be formatted as \"setclientcharacter [client] [character]\". If the names consist of multiple words, you should surround them with quotation marks.", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2205,7 +2213,7 @@ namespace Barotrauma
|
||||
var client = GameMain.Server.ConnectedClients.Find(c => c.Name == args[0]);
|
||||
if (client == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Client \"" + args[0] + "\" not found.", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Client \"" + args[0] + "\" not found.", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2222,17 +2230,18 @@ namespace Barotrauma
|
||||
if (args.Length == 0) { return; }
|
||||
if (!(GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("No campaign active!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("No campaign active!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
if (int.TryParse(args[0], out int money))
|
||||
{
|
||||
campaign.Money += money;
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(money, GameAnalyticsManager.MoneySource.Cheat, "console");
|
||||
campaign.LastUpdateID++;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"\"{args[0]}\" is not a valid numeric value.", senderClient);
|
||||
GameMain.Server.SendConsoleMessage($"\"{args[0]}\" is not a valid numeric value.", senderClient, Color.Red);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -2242,7 +2251,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!(GameMain.GameSession?.GameMode is CampaignMode campaign))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("No campaign active!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("No campaign active!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2250,7 +2259,7 @@ namespace Barotrauma
|
||||
if (args.Length < 1 || !int.TryParse(args[0], out destinationIndex)) return;
|
||||
if (destinationIndex < 0 || destinationIndex >= campaign.Map.CurrentLocation.Connections.Count)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Index out of bounds!", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Index out of bounds!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
Location location = campaign.Map.CurrentLocation.Connections[destinationIndex].OtherLocation(campaign.Map.CurrentLocation);
|
||||
@@ -2267,14 +2276,41 @@ namespace Barotrauma
|
||||
NewMessage(tag, Color.Yellow);
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
commands.Add(new Command("sendchatmessage", "Sends a chat message with specified type and color.", (string[] args) =>
|
||||
{
|
||||
if (args.Length < 2) { return; }
|
||||
|
||||
ChatMessageType chatMessageType = ChatMessageType.Default;
|
||||
Color? chatMessageColor = null;
|
||||
|
||||
if (args.Length >= 3 && int.TryParse(args[2], out int result))
|
||||
{
|
||||
chatMessageType = (ChatMessageType)result;
|
||||
}
|
||||
|
||||
if (args.Length >= 7 &&
|
||||
int.TryParse(args[3], out int r) &&
|
||||
int.TryParse(args[4], out int g) &&
|
||||
int.TryParse(args[5], out int b) &&
|
||||
int.TryParse(args[6], out int a))
|
||||
{
|
||||
chatMessageColor = new Color(r, g, b, a);
|
||||
}
|
||||
|
||||
foreach (var client in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
GameMain.Server.SendDirectChatMessage(ChatMessage.Create(args[0], args[1], chatMessageType, null, null, textColor: chatMessageColor), client);
|
||||
}
|
||||
}));
|
||||
|
||||
AssignOnClientRequestExecute(
|
||||
"setskill",
|
||||
(senderClient, cursorWorldPos, args) =>
|
||||
{
|
||||
if (args.Length < 2)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"Missing arguments. Expected at least 2 but got {args.Length} (skill, level, name)", senderClient);
|
||||
GameMain.Server.SendConsoleMessage($"Missing arguments. Expected at least 2 but got {args.Length} (skill, level, name)", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2284,7 +2320,7 @@ namespace Barotrauma
|
||||
|
||||
if (character?.Info?.Job == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Character is not valid.", senderClient);
|
||||
GameMain.Server.SendConsoleMessage("Character is not valid.", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2311,7 +2347,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"{levelString} is not a valid level. Expected number or \"max\".", senderClient);
|
||||
GameMain.Server.SendConsoleMessage($"{levelString} is not a valid level. Expected number or \"max\".", senderClient, Color.Red);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -2405,7 +2441,7 @@ namespace Barotrauma
|
||||
if (string.IsNullOrWhiteSpace(command)) return;
|
||||
if (!client.HasPermission(ClientPermissions.ConsoleCommands) && client.Connection != GameMain.Server.OwnerConnection)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("You are not permitted to use console commands!", client);
|
||||
GameMain.Server.SendConsoleMessage("You are not permitted to use console commands!", client, Color.Red);
|
||||
GameServer.Log(GameServer.ClientLogName(client) + " attempted to execute the console command \"" + command + "\" without a permission to use console commands.", ServerLog.MessageType.ConsoleUsage);
|
||||
return;
|
||||
}
|
||||
@@ -2414,19 +2450,19 @@ namespace Barotrauma
|
||||
Command matchingCommand = commands.Find(c => c.names.Contains(splitCommand[0].ToLowerInvariant()));
|
||||
if (matchingCommand != null && !client.PermittedConsoleCommands.Contains(matchingCommand) && client.Connection != GameMain.Server.OwnerConnection)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("You are not permitted to use the command\"" + matchingCommand.names[0] + "\"!", client);
|
||||
GameMain.Server.SendConsoleMessage("You are not permitted to use the command\"" + matchingCommand.names[0] + "\"!", client, Color.Red);
|
||||
GameServer.Log(GameServer.ClientLogName(client) + " attempted to execute the console command \"" + command + "\" without a permission to use the command.", ServerLog.MessageType.ConsoleUsage);
|
||||
return;
|
||||
}
|
||||
else if (matchingCommand == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Command \"" + splitCommand[0] + "\" not found.", client);
|
||||
GameMain.Server.SendConsoleMessage("Command \"" + splitCommand[0] + "\" not found.", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MathUtils.IsValid(cursorWorldPos))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Could not execute command \"" + command + "\" - invalid cursor position.", client);
|
||||
GameMain.Server.SendConsoleMessage("Could not execute command \"" + command + "\" - invalid cursor position.", client, Color.Red);
|
||||
NewMessage(GameServer.ClientLogName(client) + " attempted to execute the console command \"" + command + "\" with invalid cursor position.", Color.White);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace Barotrauma
|
||||
{
|
||||
public static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
|
||||
|
||||
public static bool IsSingleplayer => NetworkMember == null;
|
||||
public static bool IsMultiplayer => NetworkMember != null;
|
||||
|
||||
|
||||
private static World world;
|
||||
public static World World
|
||||
@@ -36,7 +39,7 @@ namespace Barotrauma
|
||||
public static GameServer Server;
|
||||
public static NetworkMember NetworkMember
|
||||
{
|
||||
get { return Server as NetworkMember; }
|
||||
get { return Server; }
|
||||
}
|
||||
|
||||
public static GameSession GameSession;
|
||||
@@ -64,6 +67,9 @@ namespace Barotrauma
|
||||
|
||||
private static Stopwatch stopwatch;
|
||||
|
||||
private static Queue<int> prevUpdateRates = new Queue<int>();
|
||||
private static int updateCount = 0;
|
||||
|
||||
private static ContentPackage vanillaContent;
|
||||
public static ContentPackage VanillaContent
|
||||
{
|
||||
@@ -373,7 +379,9 @@ namespace Barotrauma
|
||||
{
|
||||
DebugConsole.NewMessage("WARNING: Stopwatch frequency under 1500 ticks per second. Expect significant syncing accuracy issues.", Color.Yellow);
|
||||
}
|
||||
Stopwatch performanceMeasurement = new Stopwatch();
|
||||
|
||||
Stopwatch performanceCounterTimer = Stopwatch.StartNew();
|
||||
|
||||
stopwatch = Stopwatch.StartNew();
|
||||
long prevTicks = stopwatch.ElapsedTicks;
|
||||
while (ShouldRun)
|
||||
@@ -381,9 +389,11 @@ namespace Barotrauma
|
||||
long currTicks = stopwatch.ElapsedTicks;
|
||||
double elapsedTime = Math.Max(currTicks - prevTicks, 0) / frequency;
|
||||
Timing.Accumulator += elapsedTime;
|
||||
if (Timing.Accumulator > 1.0)
|
||||
if (Timing.Accumulator > Timing.AccumulatorMax)
|
||||
{
|
||||
//prevent spiral of death
|
||||
//prevent spiral of death:
|
||||
//if the game's running too slowly then we have no choice but to skip a bunch of steps
|
||||
//otherwise it snowballs and becomes unplayable
|
||||
Timing.Accumulator = Timing.Step;
|
||||
}
|
||||
prevTicks = currTicks;
|
||||
@@ -410,6 +420,7 @@ namespace Barotrauma
|
||||
performanceMeasurement.Reset();
|
||||
|
||||
Timing.Accumulator -= Timing.Step;
|
||||
updateCount++;
|
||||
}
|
||||
|
||||
#if !DEBUG
|
||||
@@ -425,10 +436,37 @@ namespace Barotrauma
|
||||
DebugConsole.UpdateCommandLine((int)(Timing.Accumulator * 800));
|
||||
#endif
|
||||
|
||||
int frameTime = (int)(((double)(stopwatch.ElapsedTicks - prevTicks) / frequency) * 1000.0);
|
||||
int frameTime = (int)((stopwatch.ElapsedTicks - prevTicks) / frequency * 1000.0);
|
||||
frameTime = Math.Max(0, frameTime);
|
||||
|
||||
Thread.Sleep(Math.Max(((int)(Timing.Step * 1000.0) - frameTime) / 2, 0));
|
||||
|
||||
if (performanceCounterTimer.ElapsedMilliseconds > 1000)
|
||||
{
|
||||
int updateRate = (int)Math.Round(updateCount / (double)(performanceCounterTimer.ElapsedMilliseconds / 1000.0));
|
||||
prevUpdateRates.Enqueue(updateRate);
|
||||
if (prevUpdateRates.Count >= 10)
|
||||
{
|
||||
int avgUpdateRate = (int)prevUpdateRates.Average();
|
||||
if (avgUpdateRate < Timing.FixedUpdateRate * 0.98 && GameSession != null && Timing.TotalTime > GameSession.RoundStartTime + 1.0)
|
||||
{
|
||||
DebugConsole.AddWarning($"Running slowly ({avgUpdateRate} updates/s)!");
|
||||
if (Server != null)
|
||||
{
|
||||
foreach (Client c in Server.ConnectedClients)
|
||||
{
|
||||
if (c.Connection == Server.OwnerConnection || c.Permissions != ClientPermissions.None)
|
||||
{
|
||||
Server.SendConsoleMessage($"Server running slowly ({avgUpdateRate} updates/s)!", c, Color.Orange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
prevUpdateRates.Clear();
|
||||
}
|
||||
performanceCounterTimer.Restart();
|
||||
updateCount = 0;
|
||||
}
|
||||
}
|
||||
stopwatch.Stop();
|
||||
|
||||
@@ -447,8 +485,9 @@ namespace Barotrauma
|
||||
public static void ResetFrameTime()
|
||||
{
|
||||
Timing.Accumulator = 0.0f;
|
||||
stopwatch?.Reset();
|
||||
stopwatch?.Start();
|
||||
stopwatch?.Restart();
|
||||
prevUpdateRates.Clear();
|
||||
updateCount = 0;
|
||||
}
|
||||
|
||||
public CoroutineHandle ShowLoading(IEnumerable<CoroutineStatus> loader, bool waitKeyHit = true)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.Extensions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -23,10 +24,10 @@ namespace Barotrauma
|
||||
{
|
||||
// Check all the prices before starting the transaction
|
||||
// to make sure the modifiers stay the same for the whole transaction
|
||||
Dictionary<ItemPrefab, int> sellValues = GetSellValuesAtCurrentLocation(itemsToBuy.Select(i => i.ItemPrefab));
|
||||
foreach (SoldItem item in itemsToBuy)
|
||||
var sellValues = GetSellValuesAtCurrentLocation(itemsToBuy.Select(i => i.ItemPrefab));
|
||||
foreach (var item in itemsToBuy)
|
||||
{
|
||||
var itemValue = sellValues[item.ItemPrefab];
|
||||
int itemValue = sellValues[item.ItemPrefab];
|
||||
if (Location.StoreCurrentBalance < itemValue || item.Removed) { continue; }
|
||||
Location.StoreCurrentBalance += itemValue;
|
||||
campaign.Money -= itemValue;
|
||||
@@ -36,17 +37,29 @@ namespace Barotrauma
|
||||
|
||||
public void SellItems(List<SoldItem> itemsToSell)
|
||||
{
|
||||
bool canAddToRemoveQueue = (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) && Entity.Spawner != null;
|
||||
IEnumerable<Item> sellableItemsInSub = Enumerable.Empty<Item>();
|
||||
if (canAddToRemoveQueue && itemsToSell.Any(i => i.Origin == SoldItem.SellOrigin.Submarine && i.ID == Entity.NullEntityID && !i.Removed))
|
||||
{
|
||||
sellableItemsInSub = GetSellableItemsFromSub();
|
||||
}
|
||||
// Check all the prices before starting the transaction
|
||||
// to make sure the modifiers stay the same for the whole transaction
|
||||
Dictionary<ItemPrefab, int> sellValues = GetSellValuesAtCurrentLocation(itemsToSell.Select(i => i.ItemPrefab));
|
||||
var canAddToRemoveQueue = (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) && Entity.Spawner != null;
|
||||
foreach (SoldItem item in itemsToSell)
|
||||
var sellValues = GetSellValuesAtCurrentLocation(itemsToSell.Select(i => i.ItemPrefab));
|
||||
foreach (var item in itemsToSell)
|
||||
{
|
||||
var itemValue = sellValues[item.ItemPrefab];
|
||||
|
||||
int itemValue = sellValues[item.ItemPrefab];
|
||||
// check if the store can afford the item and if the item hasn't been removed already
|
||||
if (Location.StoreCurrentBalance < itemValue || item.Removed) { continue; }
|
||||
|
||||
// Server determines the items that are sold from the sub in multiplayer
|
||||
if (item.Origin == SoldItem.SellOrigin.Submarine && item.ID == Entity.NullEntityID && !item.Removed)
|
||||
{
|
||||
var matchingItem = sellableItemsInSub.FirstOrDefault(i => !i.Removed && i.Prefab == item.ItemPrefab &&
|
||||
itemsToSell.None(itemToSell => itemToSell.ItemPrefab == i.Prefab && itemToSell.ID == i.ID));
|
||||
// This is a failsafe for scenarios where a client is trying to sell more items than there's available on the sub
|
||||
if (matchingItem == null) { continue; }
|
||||
item.SetItemId(matchingItem.ID);
|
||||
}
|
||||
if (!item.Removed && canAddToRemoveQueue && Entity.FindEntityByID(item.ID) is Item entity)
|
||||
{
|
||||
item.Removed = true;
|
||||
@@ -55,6 +68,7 @@ namespace Barotrauma
|
||||
SoldItems.Add(item);
|
||||
Location.StoreCurrentBalance -= itemValue;
|
||||
campaign.Money += itemValue;
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(itemValue, GameAnalyticsManager.MoneySource.Store, item.ItemPrefab.Identifier);
|
||||
}
|
||||
OnSoldItemsChanged?.Invoke();
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Barotrauma
|
||||
foreach (var activeOrder in ActiveOrders)
|
||||
{
|
||||
if (!(activeOrder?.First is Order order) || activeOrder.Second.HasValue) { continue; }
|
||||
OrderChatMessage.WriteOrder(msg, order, null, order.TargetSpatialEntity, null, 0, order.WallSectionIndex);
|
||||
OrderChatMessage.WriteOrder(msg, order, targetCharacter: null, order.TargetSpatialEntity, orderOption: null, orderPriority: 0, order.WallSectionIndex, isNewOrder: true);
|
||||
bool hasOrderGiver = order.OrderGiver != null;
|
||||
msg.Write(hasOrderGiver);
|
||||
if (hasOrderGiver)
|
||||
|
||||
+149
-128
@@ -166,16 +166,15 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// There is a client-side implementation of the method in <see cref="CampaignMode"/>
|
||||
/// </summary>
|
||||
public bool AllowedToManageCampaign(Client client)
|
||||
public bool AllowedToManageCampaign(Client client, ClientPermissions permissions = ClientPermissions.ManageCampaign)
|
||||
{
|
||||
//allow ending the round if the client has permissions, is the owner, or the only client in the server,
|
||||
//allow managing the campaign if the client has permissions, is the owner, or the only client in the server,
|
||||
//or if no-one has management permissions
|
||||
return
|
||||
client.HasPermission(ClientPermissions.ManageCampaign) ||
|
||||
client.HasPermission(permissions) ||
|
||||
GameMain.Server.ConnectedClients.Count == 1 ||
|
||||
IsOwner(client) ||
|
||||
GameMain.Server.ConnectedClients.None(c =>
|
||||
c.InGame && (IsOwner(c) || c.HasPermission(ClientPermissions.ManageCampaign)));
|
||||
GameMain.Server.ConnectedClients.None(c => c.InGame && (IsOwner(c) || c.HasPermission(permissions)));
|
||||
}
|
||||
|
||||
public void SaveExperiencePoints(Client client)
|
||||
@@ -213,7 +212,14 @@ namespace Barotrauma
|
||||
}
|
||||
//use the info of the character the client is currently controlling
|
||||
// or the previously saved info if not (e.g. if the client has been spectating or died)
|
||||
var characterInfo = c.Character?.Info ?? characterData.Find(d => d.MatchesClient(c))?.CharacterInfo;
|
||||
var characterInfo = c.Character?.Info;
|
||||
var matchingCharacterData = characterData.Find(d => d.MatchesClient(c));
|
||||
if (matchingCharacterData != null)
|
||||
{
|
||||
//hasn't spawned this round -> don't touch the data
|
||||
if (!matchingCharacterData.HasSpawned) { continue; }
|
||||
characterInfo ??= matchingCharacterData.CharacterInfo;
|
||||
}
|
||||
if (characterInfo == null) { continue; }
|
||||
//reduce skills if the character has died
|
||||
if (characterInfo.CauseOfDeath != null && characterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected)
|
||||
@@ -285,11 +291,15 @@ namespace Barotrauma
|
||||
break;
|
||||
case TransitionType.ProgressToNextLocation:
|
||||
Map.MoveToNextLocation();
|
||||
TotalPassedLevels++;
|
||||
break;
|
||||
case TransitionType.End:
|
||||
EndCampaign();
|
||||
IsFirstRound = true;
|
||||
break;
|
||||
case TransitionType.ProgressToNextEmptyLocation:
|
||||
TotalPassedLevels++;
|
||||
break;
|
||||
}
|
||||
|
||||
Map.ProgressWorld(transitionType, (float)(Timing.TotalTime - GameMain.GameSession.RoundStartTime));
|
||||
@@ -348,7 +358,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateCampaignSubs();
|
||||
|
||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||
PendingSubmarineSwitch = null;
|
||||
@@ -399,44 +408,12 @@ namespace Barotrauma
|
||||
Map.OnMissionsSelected += (loc, mission) => { LastUpdateID++; };
|
||||
Reputation.OnAnyReputationValueChanged += () => { LastUpdateID++; };
|
||||
|
||||
UpdateCampaignSubs();
|
||||
|
||||
//increment save ID so clients know they're lacking the most up-to-date save file
|
||||
LastSaveID++;
|
||||
}
|
||||
|
||||
public static void UpdateCampaignSubs()
|
||||
{
|
||||
bool isSubmarineVisible(SubmarineInfo s)
|
||||
=> !GameMain.Server.ServerSettings.HiddenSubs.Any(h
|
||||
=> s.Name.Equals(h, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
List<SubmarineInfo> availableSubs =
|
||||
SubmarineInfo.SavedSubmarines
|
||||
.Where(s =>
|
||||
s.IsCampaignCompatible
|
||||
&& isSubmarineVisible(s))
|
||||
.ToList();
|
||||
|
||||
if (!availableSubs.Any())
|
||||
{
|
||||
//None of the available subs were marked as campaign-compatible, just include all visible subs
|
||||
availableSubs.AddRange(
|
||||
SubmarineInfo.SavedSubmarines
|
||||
.Where(isSubmarineVisible));
|
||||
}
|
||||
|
||||
if (!availableSubs.Any())
|
||||
{
|
||||
//No subs are visible at all! Just make the selected one available
|
||||
availableSubs.Add(GameMain.NetLobbyScreen.SelectedSub);
|
||||
}
|
||||
|
||||
GameMain.NetLobbyScreen.CampaignSubmarines = availableSubs;
|
||||
}
|
||||
|
||||
public bool CanPurchaseSub(SubmarineInfo info)
|
||||
=> info.Price <= Money && GameMain.NetLobbyScreen.CampaignSubmarines.Contains(info);
|
||||
=> info.Price <= Money && GetCampaignSubs().Contains(info);
|
||||
|
||||
public void DiscardClientCharacterData(Client client)
|
||||
{
|
||||
@@ -591,14 +568,21 @@ namespace Barotrauma
|
||||
foreach (PurchasedItem pi in CargoManager.ItemsInBuyCrate)
|
||||
{
|
||||
msg.Write(pi.ItemPrefab.Identifier);
|
||||
msg.WriteRangedInteger(pi.Quantity, 0, 100);
|
||||
msg.WriteRangedInteger(pi.Quantity, 0, CargoManager.MaxQuantity);
|
||||
}
|
||||
|
||||
msg.Write((UInt16)CargoManager.ItemsInSellFromSubCrate.Count);
|
||||
foreach (PurchasedItem pi in CargoManager.ItemsInSellFromSubCrate)
|
||||
{
|
||||
msg.Write(pi.ItemPrefab.Identifier);
|
||||
msg.WriteRangedInteger(pi.Quantity, 0, CargoManager.MaxQuantity);
|
||||
}
|
||||
|
||||
msg.Write((UInt16)CargoManager.PurchasedItems.Count);
|
||||
foreach (PurchasedItem pi in CargoManager.PurchasedItems)
|
||||
{
|
||||
msg.Write(pi.ItemPrefab.Identifier);
|
||||
msg.WriteRangedInteger(pi.Quantity, 0, 100);
|
||||
msg.WriteRangedInteger(pi.Quantity, 0, CargoManager.MaxQuantity);
|
||||
}
|
||||
|
||||
msg.Write((UInt16)CargoManager.SoldItems.Count);
|
||||
@@ -608,6 +592,7 @@ namespace Barotrauma
|
||||
msg.Write((UInt16)si.ID);
|
||||
msg.Write(si.Removed);
|
||||
msg.Write(si.SellerID);
|
||||
msg.Write((byte)si.Origin);
|
||||
}
|
||||
|
||||
msg.Write((ushort)UpgradeManager.PendingUpgrades.Count);
|
||||
@@ -662,6 +647,15 @@ namespace Barotrauma
|
||||
buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
|
||||
}
|
||||
|
||||
UInt16 subSellCrateItemCount = msg.ReadUInt16();
|
||||
List<PurchasedItem> subSellCrateItems = new List<PurchasedItem>();
|
||||
for (int i = 0; i < subSellCrateItemCount; i++)
|
||||
{
|
||||
string itemPrefabIdentifier = msg.ReadString();
|
||||
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
|
||||
subSellCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
|
||||
}
|
||||
|
||||
UInt16 purchasedItemCount = msg.ReadUInt16();
|
||||
List<PurchasedItem> purchasedItems = new List<PurchasedItem>();
|
||||
for (int i = 0; i < purchasedItemCount; i++)
|
||||
@@ -679,7 +673,8 @@ namespace Barotrauma
|
||||
UInt16 id = msg.ReadUInt16();
|
||||
bool removed = msg.ReadBoolean();
|
||||
byte sellerId = msg.ReadByte();
|
||||
soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId));
|
||||
byte origin = msg.ReadByte();
|
||||
soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId, (SoldItem.SellOrigin)origin));
|
||||
}
|
||||
|
||||
ushort purchasedUpgradeCount = msg.ReadUInt16();
|
||||
@@ -703,122 +698,146 @@ namespace Barotrauma
|
||||
for (int i = 0; i < purchasedItemSwapCount; i++)
|
||||
{
|
||||
UInt16 itemToRemoveID = msg.ReadUInt16();
|
||||
Item itemToRemove = Entity.FindEntityByID(itemToRemoveID) as Item;
|
||||
|
||||
string itemToInstallIdentifier = msg.ReadString();
|
||||
ItemPrefab itemToInstall = string.IsNullOrEmpty(itemToInstallIdentifier) ? null : ItemPrefab.Find(string.Empty, itemToInstallIdentifier);
|
||||
|
||||
if (itemToRemove == null) { continue; }
|
||||
|
||||
if (!(Entity.FindEntityByID(itemToRemoveID) is Item itemToRemove)) { continue; }
|
||||
purchasedItemSwaps.Add(new PurchasedItemSwap(itemToRemove, itemToInstall));
|
||||
}
|
||||
|
||||
if (!AllowedToManageCampaign(sender))
|
||||
bool allowedToManageCampaign = AllowedToManageCampaign(sender);
|
||||
if (AllowedToManageCampaign(sender))
|
||||
{
|
||||
DebugConsole.ThrowError("Client \"" + sender.Name + "\" does not have a permission to manage the campaign");
|
||||
return;
|
||||
}
|
||||
|
||||
Location location = Map.CurrentLocation;
|
||||
int hullRepairCost = location?.GetAdjustedMechanicalCost(HullRepairCost) ?? HullRepairCost;
|
||||
int itemRepairCost = location?.GetAdjustedMechanicalCost(ItemRepairCost) ?? ItemRepairCost;
|
||||
int shuttleRetrieveCost = location?.GetAdjustedMechanicalCost(ShuttleReplaceCost) ?? ShuttleReplaceCost;
|
||||
|
||||
if (purchasedHullRepairs != this.PurchasedHullRepairs)
|
||||
{
|
||||
if (purchasedHullRepairs && Money >= hullRepairCost)
|
||||
Location location = Map.CurrentLocation;
|
||||
int hullRepairCost = location?.GetAdjustedMechanicalCost(HullRepairCost) ?? HullRepairCost;
|
||||
int itemRepairCost = location?.GetAdjustedMechanicalCost(ItemRepairCost) ?? ItemRepairCost;
|
||||
int shuttleRetrieveCost = location?.GetAdjustedMechanicalCost(ShuttleReplaceCost) ?? ShuttleReplaceCost;
|
||||
if (purchasedHullRepairs != this.PurchasedHullRepairs)
|
||||
{
|
||||
this.PurchasedHullRepairs = true;
|
||||
Money -= hullRepairCost;
|
||||
if (purchasedHullRepairs && Money >= hullRepairCost)
|
||||
{
|
||||
this.PurchasedHullRepairs = true;
|
||||
Money -= hullRepairCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(hullRepairCost, GameAnalyticsManager.MoneySink.Service, "hullrepairs");
|
||||
}
|
||||
else if (!purchasedHullRepairs)
|
||||
{
|
||||
this.PurchasedHullRepairs = false;
|
||||
Money += hullRepairCost;
|
||||
}
|
||||
}
|
||||
else if (!purchasedHullRepairs)
|
||||
if (purchasedItemRepairs != this.PurchasedItemRepairs)
|
||||
{
|
||||
this.PurchasedHullRepairs = false;
|
||||
Money += hullRepairCost;
|
||||
if (purchasedItemRepairs && Money >= itemRepairCost)
|
||||
{
|
||||
this.PurchasedItemRepairs = true;
|
||||
Money -= itemRepairCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(itemRepairCost, GameAnalyticsManager.MoneySink.Service, "devicerepairs");
|
||||
}
|
||||
else if (!purchasedItemRepairs)
|
||||
{
|
||||
this.PurchasedItemRepairs = false;
|
||||
Money += itemRepairCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (purchasedItemRepairs != this.PurchasedItemRepairs)
|
||||
{
|
||||
if (purchasedItemRepairs && Money >= itemRepairCost)
|
||||
if (purchasedLostShuttles != this.PurchasedLostShuttles)
|
||||
{
|
||||
this.PurchasedItemRepairs = true;
|
||||
Money -= itemRepairCost;
|
||||
if (GameMain.GameSession?.SubmarineInfo != null &&
|
||||
GameMain.GameSession.SubmarineInfo.LeftBehindSubDockingPortOccupied)
|
||||
{
|
||||
GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("ReplaceShuttleDockingPortOccupied"), sender, ChatMessageType.MessageBox);
|
||||
}
|
||||
else if (purchasedLostShuttles && Money >= shuttleRetrieveCost)
|
||||
{
|
||||
this.PurchasedLostShuttles = true;
|
||||
Money -= shuttleRetrieveCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(shuttleRetrieveCost, GameAnalyticsManager.MoneySink.Service, "retrieveshuttle");
|
||||
}
|
||||
else if (!purchasedItemRepairs)
|
||||
{
|
||||
this.PurchasedLostShuttles = false;
|
||||
Money += shuttleRetrieveCost;
|
||||
}
|
||||
}
|
||||
else if (!purchasedItemRepairs)
|
||||
if (currentLocIndex < Map.Locations.Count && Map.AllowDebugTeleport)
|
||||
{
|
||||
this.PurchasedItemRepairs = false;
|
||||
Money += itemRepairCost;
|
||||
}
|
||||
}
|
||||
if (purchasedLostShuttles != this.PurchasedLostShuttles)
|
||||
{
|
||||
if (GameMain.GameSession?.SubmarineInfo != null &&
|
||||
GameMain.GameSession.SubmarineInfo.LeftBehindSubDockingPortOccupied)
|
||||
{
|
||||
GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("ReplaceShuttleDockingPortOccupied"), sender, ChatMessageType.MessageBox);
|
||||
}
|
||||
else if (purchasedLostShuttles && Money >= shuttleRetrieveCost)
|
||||
{
|
||||
this.PurchasedLostShuttles = true;
|
||||
Money -= shuttleRetrieveCost;
|
||||
}
|
||||
else if (!purchasedItemRepairs)
|
||||
{
|
||||
this.PurchasedLostShuttles = false;
|
||||
Money += shuttleRetrieveCost;
|
||||
Map.SetLocation(currentLocIndex);
|
||||
}
|
||||
Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
|
||||
if (Map.SelectedLocation == null) { Map.SelectRandomLocation(preferUndiscovered: true); }
|
||||
if (Map.SelectedConnection != null) { Map.SelectMission(selectedMissionIndices); }
|
||||
CheckTooManyMissions(Map.CurrentLocation, sender);
|
||||
}
|
||||
|
||||
if (currentLocIndex < Map.Locations.Count && Map.AllowDebugTeleport)
|
||||
bool allowedToUseStore = AllowedToManageCampaign(sender, ClientPermissions.CampaignStore);
|
||||
if (allowedToManageCampaign || allowedToUseStore || AllowedToManageCampaign(sender, ClientPermissions.BuyItems))
|
||||
{
|
||||
Map.SetLocation(currentLocIndex);
|
||||
var currentBuyCrateItems = new List<PurchasedItem>(CargoManager.ItemsInBuyCrate);
|
||||
currentBuyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, -i.Quantity));
|
||||
buyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, i.Quantity));
|
||||
CargoManager.SellBackPurchasedItems(new List<PurchasedItem>(CargoManager.PurchasedItems));
|
||||
CargoManager.PurchaseItems(purchasedItems, false);
|
||||
}
|
||||
|
||||
Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
|
||||
if (Map.SelectedLocation == null) { Map.SelectRandomLocation(preferUndiscovered: true); }
|
||||
if (Map.SelectedConnection != null) { Map.SelectMission(selectedMissionIndices); }
|
||||
|
||||
CheckTooManyMissions(Map.CurrentLocation, sender);
|
||||
|
||||
List<PurchasedItem> currentBuyCrateItems = new List<PurchasedItem>(CargoManager.ItemsInBuyCrate);
|
||||
currentBuyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, -i.Quantity));
|
||||
buyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, i.Quantity));
|
||||
|
||||
CargoManager.SellBackPurchasedItems(new List<PurchasedItem>(CargoManager.PurchasedItems));
|
||||
CargoManager.PurchaseItems(purchasedItems, false);
|
||||
|
||||
// for some reason CargoManager.SoldItem is never cleared by the server, I've added a check to SellItems that ignores all
|
||||
// sold items that are removed so they should be discarded on the next message
|
||||
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems));
|
||||
CargoManager.SellItems(soldItems);
|
||||
|
||||
foreach (var (prefab, category, _) in purchasedUpgrades)
|
||||
bool allowedToSellSubItems = AllowedToManageCampaign(sender, ClientPermissions.SellSubItems);
|
||||
if (allowedToManageCampaign || allowedToUseStore || allowedToSellSubItems)
|
||||
{
|
||||
UpgradeManager.PurchaseUpgrade(prefab, category);
|
||||
|
||||
// unstable logging
|
||||
int price = prefab.Price.GetBuyprice(UpgradeManager.GetUpgradeLevel(prefab, category), Map?.CurrentLocation);
|
||||
int level = UpgradeManager.GetUpgradeLevel(prefab, category);
|
||||
GameServer.Log($"SERVER: Purchased level {level} {category.Identifier}.{prefab.Identifier} for {price}", ServerLog.MessageType.ServerMessage);
|
||||
var currentSubSellCrateItems = new List<PurchasedItem>(CargoManager.ItemsInSellFromSubCrate);
|
||||
currentSubSellCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInSubSellCrate(i.ItemPrefab, -i.Quantity));
|
||||
subSellCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInSubSellCrate(i.ItemPrefab, i.Quantity));
|
||||
}
|
||||
|
||||
foreach (var purchasedItemSwap in purchasedItemSwaps)
|
||||
bool allowedToSellInventoryItems = AllowedToManageCampaign(sender, ClientPermissions.SellInventoryItems);
|
||||
if (allowedToManageCampaign || allowedToUseStore || (allowedToSellInventoryItems && allowedToSellSubItems))
|
||||
{
|
||||
if (purchasedItemSwap.ItemToInstall == null)
|
||||
// for some reason CargoManager.SoldItem is never cleared by the server, I've added a check to SellItems that ignores all
|
||||
// sold items that are removed so they should be discarded on the next message
|
||||
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems));
|
||||
CargoManager.SellItems(soldItems);
|
||||
}
|
||||
else if (allowedToSellInventoryItems || allowedToSellSubItems)
|
||||
{
|
||||
if (allowedToSellInventoryItems)
|
||||
{
|
||||
UpgradeManager.CancelItemSwap(purchasedItemSwap.ItemToRemove);
|
||||
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Character)));
|
||||
soldItems.RemoveAll(i => i.Origin != SoldItem.SellOrigin.Character);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall);
|
||||
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Submarine)));
|
||||
soldItems.RemoveAll(i => i.Origin != SoldItem.SellOrigin.Submarine);
|
||||
}
|
||||
CargoManager.SellItems(soldItems);
|
||||
}
|
||||
foreach (Item item in Item.ItemList)
|
||||
|
||||
if (allowedToManageCampaign)
|
||||
{
|
||||
if (item.PendingItemSwap != null && !purchasedItemSwaps.Any(it => it.ItemToRemove == item))
|
||||
foreach (var (prefab, category, _) in purchasedUpgrades)
|
||||
{
|
||||
UpgradeManager.CancelItemSwap(item);
|
||||
item.PendingItemSwap = null;
|
||||
UpgradeManager.PurchaseUpgrade(prefab, category);
|
||||
|
||||
// unstable logging
|
||||
int price = prefab.Price.GetBuyprice(UpgradeManager.GetUpgradeLevel(prefab, category), Map?.CurrentLocation);
|
||||
int level = UpgradeManager.GetUpgradeLevel(prefab, category);
|
||||
GameServer.Log($"SERVER: Purchased level {level} {category.Identifier}.{prefab.Identifier} for {price}", ServerLog.MessageType.ServerMessage);
|
||||
}
|
||||
foreach (var purchasedItemSwap in purchasedItemSwaps)
|
||||
{
|
||||
if (purchasedItemSwap.ItemToInstall == null)
|
||||
{
|
||||
UpgradeManager.CancelItemSwap(purchasedItemSwap.ItemToRemove);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall);
|
||||
}
|
||||
}
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.PendingItemSwap != null && !purchasedItemSwaps.Any(it => it.ItemToRemove == item))
|
||||
{
|
||||
UpgradeManager.CancelItemSwap(item);
|
||||
item.PendingItemSwap = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1031,7 +1050,9 @@ namespace Barotrauma
|
||||
new XAttribute("purchasedhullrepairs", PurchasedHullRepairs),
|
||||
new XAttribute("purchaseditemrepairs", PurchasedItemRepairs),
|
||||
new XAttribute("cheatsenabled", CheatsEnabled));
|
||||
|
||||
modeElement.Add(Settings.Save());
|
||||
modeElement.Add(SaveStats());
|
||||
CampaignMetadata?.Save(modeElement);
|
||||
Map.Save(modeElement);
|
||||
CargoManager?.SavePurchasedItems(modeElement);
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
internal partial class MedicalClinic
|
||||
{
|
||||
private enum RateLimitResult
|
||||
{
|
||||
OK,
|
||||
LimitReached
|
||||
}
|
||||
|
||||
private struct RateLimitInfo
|
||||
{
|
||||
public int Requests;
|
||||
public const int MaxRequests = 5;
|
||||
public DateTimeOffset Expiry;
|
||||
}
|
||||
|
||||
private readonly Dictionary<Client, RateLimitInfo> rateLimits = new Dictionary<Client, RateLimitInfo>();
|
||||
|
||||
public void ServerRead(IReadMessage inc, Client sender)
|
||||
{
|
||||
NetworkHeader header = (NetworkHeader)inc.ReadByte();
|
||||
|
||||
switch (header)
|
||||
{
|
||||
case NetworkHeader.REQUEST_AFFLICTIONS:
|
||||
ProcessRequestedAfflictions(inc, sender);
|
||||
break;
|
||||
case NetworkHeader.REQUEST_PENDING:
|
||||
ProcessRequestedPending(sender);
|
||||
break;
|
||||
case NetworkHeader.ADD_PENDING:
|
||||
ProcessNewAddition(inc, sender);
|
||||
break;
|
||||
case NetworkHeader.REMOVE_PENDING:
|
||||
ProcessNewRemoval(inc, sender);
|
||||
break;
|
||||
case NetworkHeader.HEAL_PENDING:
|
||||
ProcessHealing(sender);
|
||||
break;
|
||||
case NetworkHeader.CLEAR_PENDING:
|
||||
ProcessClearing(sender);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessNewAddition(IReadMessage inc, Client client)
|
||||
{
|
||||
if (CheckRateLimit(client) == RateLimitResult.LimitReached) { return; }
|
||||
|
||||
NetCrewMember newCrewMember = INetSerializableStruct.Read<NetCrewMember>(inc);
|
||||
InsertPendingCrewMember(newCrewMember);
|
||||
ServerSend(newCrewMember, NetworkHeader.ADD_PENDING, DeliveryMethod.Reliable, reponseClient: client);
|
||||
}
|
||||
|
||||
private void ProcessNewRemoval(IReadMessage inc, Client client)
|
||||
{
|
||||
if (CheckRateLimit(client) == RateLimitResult.LimitReached) { return; }
|
||||
|
||||
NetRemovedAffliction removed = INetSerializableStruct.Read<NetRemovedAffliction>(inc);
|
||||
RemovePendingAffliction(removed.CrewMember, removed.Affliction);
|
||||
ServerSend(removed, NetworkHeader.REMOVE_PENDING, DeliveryMethod.Reliable, reponseClient: client);
|
||||
}
|
||||
|
||||
private void ProcessRequestedPending(Client client)
|
||||
{
|
||||
if (CheckRateLimit(client) == RateLimitResult.LimitReached) { return; }
|
||||
|
||||
INetSerializableStruct writeCrewMember = new NetPendingCrew
|
||||
{
|
||||
CrewMembers = PendingHeals.ToArray()
|
||||
};
|
||||
|
||||
ServerSend(writeCrewMember, NetworkHeader.REQUEST_PENDING, DeliveryMethod.Reliable, targetClient: client);
|
||||
}
|
||||
|
||||
private void ProcessHealing(Client client)
|
||||
{
|
||||
if (CheckRateLimit(client) == RateLimitResult.LimitReached) { return; }
|
||||
|
||||
HealRequestResult result = HealAllPending();
|
||||
ServerSend(new NetHealRequest { Result = result }, NetworkHeader.HEAL_PENDING, DeliveryMethod.Reliable, reponseClient: client);
|
||||
}
|
||||
|
||||
private void ProcessClearing(Client client)
|
||||
{
|
||||
if (CheckRateLimit(client) == RateLimitResult.LimitReached) { return; }
|
||||
|
||||
if (!PendingHeals.Any()) { return; }
|
||||
|
||||
ClearPendingHeals();
|
||||
ServerSend(null, NetworkHeader.CLEAR_PENDING, DeliveryMethod.Reliable, reponseClient: client);
|
||||
}
|
||||
|
||||
private void ProcessRequestedAfflictions(IReadMessage inc, Client client)
|
||||
{
|
||||
if (CheckRateLimit(client) == RateLimitResult.LimitReached) { return; }
|
||||
|
||||
NetCrewMember crewMember = INetSerializableStruct.Read<NetCrewMember>(inc);
|
||||
|
||||
CharacterInfo? foundInfo = crewMember.FindCharacterInfo(GetCrewCharacters());
|
||||
|
||||
NetAffliction[] pendingAfflictions = Array.Empty<NetAffliction>();
|
||||
int infoId = 0;
|
||||
|
||||
if (foundInfo is { Character: { CharacterHealth: { } health } })
|
||||
{
|
||||
pendingAfflictions = GetAllAfflictions(health);
|
||||
infoId = foundInfo.GetIdentifierUsingOriginalName();
|
||||
}
|
||||
|
||||
INetSerializableStruct writeCrewMember = new NetCrewMember
|
||||
{
|
||||
CharacterInfoID = infoId,
|
||||
Afflictions = pendingAfflictions
|
||||
};
|
||||
|
||||
ServerSend(writeCrewMember, NetworkHeader.REQUEST_AFFLICTIONS, DeliveryMethod.Unreliable, client);
|
||||
}
|
||||
|
||||
private RateLimitResult CheckRateLimit(Client client)
|
||||
{
|
||||
if (rateLimits.TryGetValue(client, out RateLimitInfo rateLimitInfo))
|
||||
{
|
||||
if (rateLimitInfo.Expiry < DateTimeOffset.Now)
|
||||
{
|
||||
rateLimitInfo.Expiry = DateTimeOffset.Now.AddSeconds(5);
|
||||
rateLimitInfo.Requests = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rateLimitInfo.Requests > RateLimitInfo.MaxRequests) { return RateLimitResult.LimitReached; }
|
||||
|
||||
rateLimitInfo.Requests++;
|
||||
}
|
||||
|
||||
rateLimits[client] = rateLimitInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
rateLimits.Add(client, new RateLimitInfo { Requests = 1, Expiry = DateTimeOffset.Now.AddSeconds(5) });
|
||||
}
|
||||
|
||||
return RateLimitResult.OK;
|
||||
}
|
||||
|
||||
private IWriteMessage StartSending()
|
||||
{
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte)ServerPacketHeader.MEDICAL);
|
||||
return msg;
|
||||
}
|
||||
|
||||
private void ServerSend(INetSerializableStruct? netStruct, NetworkHeader header, DeliveryMethod deliveryMethod, Client? targetClient = null, Client? reponseClient = null)
|
||||
{
|
||||
if (targetClient is null)
|
||||
{
|
||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
SendToClient(c);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SendToClient(targetClient);
|
||||
|
||||
void SendToClient(Client c)
|
||||
{
|
||||
MessageFlag flag = MessageFlag.Announce;
|
||||
if (reponseClient != null && reponseClient == c)
|
||||
{
|
||||
flag = MessageFlag.Response;
|
||||
}
|
||||
|
||||
IWriteMessage msg = StartSending();
|
||||
msg.Write((byte)header);
|
||||
msg.Write((byte)flag);
|
||||
netStruct?.Write(msg);
|
||||
GameMain.Server.ServerPeer.Send(msg, c.Connection, deliveryMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
internal partial class Growable
|
||||
{
|
||||
private const int serverHealthUpdateDelay = 10;
|
||||
private int serverHealthUpdateTimer;
|
||||
|
||||
partial void LoadVines(XElement element)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
|
||||
@@ -50,14 +50,14 @@ namespace Barotrauma.Items.Components
|
||||
newSteeringInput = new Vector2(msg.ReadSingle(), msg.ReadSingle());
|
||||
}
|
||||
|
||||
if (!item.CanClientAccess(c)) return;
|
||||
if (!item.CanClientAccess(c)) { return; }
|
||||
|
||||
user = c.Character;
|
||||
AutoPilot = autoPilot;
|
||||
|
||||
if (dockingButtonClicked)
|
||||
{
|
||||
item.SendSignal("1", "toggle_docking");
|
||||
item.SendSignal(new Signal("1", sender: c.Character), "toggle_docking");
|
||||
GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, item.GetComponentIndex(this), true });
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace Barotrauma.Items.Components
|
||||
msg.Write(DeteriorateAlways);
|
||||
msg.Write(tinkeringDuration);
|
||||
msg.Write(tinkeringStrength);
|
||||
msg.Write(tinkeringPowersDevices);
|
||||
msg.Write(CurrentFixer == null ? (ushort)0 : CurrentFixer.ID);
|
||||
msg.WriteRangedInteger((int)currentFixerAction, 0, 2);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,26 @@ namespace Barotrauma.Items.Components
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.Write(Snapped);
|
||||
|
||||
if (!Snapped)
|
||||
{
|
||||
msg.Write(target?.ID ?? Entity.NullEntityID);
|
||||
if (source is Entity entity && !entity.Removed)
|
||||
{
|
||||
msg.Write(entity?.ID ?? Entity.NullEntityID);
|
||||
msg.Write((byte)0);
|
||||
}
|
||||
else if (source is Limb limb && limb.character != null && !limb.character.Removed)
|
||||
{
|
||||
msg.Write(limb.character?.ID ?? Entity.NullEntityID);
|
||||
msg.Write((byte)limb.character.AnimController.Limbs.IndexOf(limb));
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write(Entity.NullEntityID);
|
||||
msg.Write((byte)0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
int signalIndex = msg.ReadRangedInteger(0, Signals.Length - 1);
|
||||
if (!item.CanClientAccess(c)) { return; }
|
||||
if (!SendSignal(signalIndex)) { return; }
|
||||
if (!SendSignal(signalIndex, c.Character)) { return; }
|
||||
GameServer.Log($"{GameServer.CharacterLogName(c.Character)} sent a signal \"{Signals[signalIndex]}\" from {item.Name}", ServerLog.MessageType.ItemInteraction);
|
||||
item.CreateServerEvent(this, new object[] { signalIndex });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class WifiComponent
|
||||
{
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.WriteRangedInteger(Channel, MinChannel, MaxChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,22 +98,6 @@ namespace Barotrauma
|
||||
case NetEntityEvent.Type.AssignCampaignInteraction:
|
||||
msg.Write((byte)CampaignInteractionType);
|
||||
break;
|
||||
case NetEntityEvent.Type.Treatment:
|
||||
{
|
||||
ItemComponent targetComponent = (ItemComponent)extraData[1];
|
||||
ActionType actionType = (ActionType)extraData[2];
|
||||
ushort targetID = (ushort)extraData[3];
|
||||
Limb targetLimb = (Limb)extraData[4];
|
||||
|
||||
Character targetCharacter = FindEntityByID(targetID) as Character;
|
||||
byte targetLimbIndex = targetLimb != null && targetCharacter != null ? (byte)Array.IndexOf(targetCharacter.AnimController.Limbs, targetLimb) : (byte)255;
|
||||
|
||||
msg.Write((byte)components.IndexOf(targetComponent));
|
||||
msg.WriteRangedInteger((int)actionType, 0, Enum.GetValues(typeof(ActionType)).Length - 1);
|
||||
msg.Write(targetID);
|
||||
msg.Write(targetLimbIndex);
|
||||
}
|
||||
break;
|
||||
case NetEntityEvent.Type.ApplyStatusEffect:
|
||||
{
|
||||
ActionType actionType = (ActionType)extraData[1];
|
||||
@@ -268,6 +252,7 @@ namespace Barotrauma
|
||||
|
||||
msg.Write(Position.X);
|
||||
msg.Write(Position.Y);
|
||||
msg.WriteRangedSingle(body == null ? 0.0f : MathUtils.WrapAngleTwoPi(body.Rotation), 0.0f, MathHelper.TwoPi, 8);
|
||||
msg.Write(Submarine != null ? Submarine.ID : (ushort)0);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -27,8 +27,8 @@ namespace Barotrauma
|
||||
//don't create updates if all clients are very far from the hull
|
||||
float hullUpdateDistanceSqr = NetConfig.HullUpdateDistance * NetConfig.HullUpdateDistance;
|
||||
if (!GameMain.Server.ConnectedClients.Any(c =>
|
||||
c.Character != null &&
|
||||
Vector2.DistanceSquared(c.Character.WorldPosition, WorldPosition) < hullUpdateDistanceSqr))
|
||||
c.Character != null &&
|
||||
Vector2.DistanceSquared(c.Character.WorldPosition, WorldPosition) < hullUpdateDistanceSqr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Barotrauma.Networking
|
||||
string orderOption = orderMessageInfo.OrderOption ??
|
||||
(orderMessageInfo.OrderOptionIndex == null || orderMessageInfo.OrderOptionIndex < 0 || orderMessageInfo.OrderOptionIndex >= orderPrefab.Options.Length ?
|
||||
"" : orderPrefab.Options[orderMessageInfo.OrderOptionIndex.Value]);
|
||||
orderMsg = new OrderChatMessage(orderPrefab, orderOption, orderMessageInfo.Priority, orderTargetPosition ?? orderTargetEntity as ISpatialEntity, orderTargetCharacter, c.Character)
|
||||
orderMsg = new OrderChatMessage(orderPrefab, orderOption, orderMessageInfo.Priority, orderTargetPosition ?? orderTargetEntity as ISpatialEntity, orderTargetCharacter, c.Character, isNewOrder: orderMessageInfo.IsNewOrder)
|
||||
{
|
||||
WallSectionIndex = wallSectionIndex
|
||||
};
|
||||
@@ -223,6 +223,11 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
msg.Write(Sender.ID);
|
||||
}
|
||||
msg.Write(customTextColor != null);
|
||||
if (customTextColor != null)
|
||||
{
|
||||
msg.WriteColorR8G8B8A8(customTextColor.Value);
|
||||
}
|
||||
msg.WritePadBits();
|
||||
if (Type == ChatMessageType.ServerMessageBoxInGame)
|
||||
{
|
||||
|
||||
@@ -117,8 +117,14 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
GameMain.Server.VoipServer.UnregisterQueue(VoipQueue);
|
||||
VoipQueue.Dispose();
|
||||
characterInfo?.Remove();
|
||||
characterInfo = null;
|
||||
if (characterInfo != null)
|
||||
{
|
||||
if (characterInfo.Character == null || characterInfo.Character.Removed)
|
||||
{
|
||||
characterInfo?.Remove();
|
||||
characterInfo = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void InitClientSync()
|
||||
|
||||
@@ -222,33 +222,6 @@ namespace Barotrauma.Networking
|
||||
if (shuttle != null) { GameMain.NetLobbyScreen.SelectedShuttle = shuttle; }
|
||||
}
|
||||
|
||||
List<SubmarineInfo> campaignSubs = new List<SubmarineInfo>();
|
||||
if (serverSettings.CampaignSubmarines != null && serverSettings.CampaignSubmarines.Length > 0)
|
||||
{
|
||||
string[] submarines = serverSettings.CampaignSubmarines.Split(ServerSettings.SubmarineSeparatorChar);
|
||||
for (int i = 0; i < submarines.Length; i++)
|
||||
{
|
||||
SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == submarines[i]);
|
||||
if (subInfo != null && subInfo.IsCampaignCompatible)
|
||||
{
|
||||
campaignSubs.Add(subInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add vanilla submarines by default
|
||||
for (int i = 0; i < SubmarineInfo.SavedSubmarines.Count(); i++)
|
||||
{
|
||||
SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.ElementAt(i);
|
||||
if (subInfo.IsVanillaSubmarine() && subInfo.IsCampaignCompatible)
|
||||
{
|
||||
campaignSubs.Add(SubmarineInfo.SavedSubmarines.ElementAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
GameMain.NetLobbyScreen.CampaignSubmarines = campaignSubs;
|
||||
|
||||
started = true;
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent("GameServer:Start");
|
||||
@@ -763,7 +736,15 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
break;
|
||||
case ClientPacketHeader.REQUEST_STARTGAMEFINALIZE:
|
||||
if (gameStarted && connectedClient != null)
|
||||
if (connectedClient == null)
|
||||
{
|
||||
DebugConsole.AddWarning("Received a REQUEST_STARTGAMEFINALIZE message. Client not connected, ignoring the message.");
|
||||
}
|
||||
else if (!gameStarted)
|
||||
{
|
||||
DebugConsole.AddWarning("Received a REQUEST_STARTGAMEFINALIZE message. Game not started, ignoring the message.");
|
||||
}
|
||||
else
|
||||
{
|
||||
SendRoundStartFinalize(connectedClient);
|
||||
}
|
||||
@@ -783,7 +764,7 @@ namespace Barotrauma.Networking
|
||||
string seed = inc.ReadString();
|
||||
string subName = inc.ReadString();
|
||||
string subHash = inc.ReadString();
|
||||
CampaignSettings settings = new CampaignSettings(inc);
|
||||
CampaignSettings settings = new CampaignSettings(inc);
|
||||
|
||||
var matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash);
|
||||
|
||||
@@ -806,6 +787,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
ServerSettings.RadiationEnabled = settings.RadiationEnabled;
|
||||
ServerSettings.MaxMissionCount = settings.MaxMissionCount;
|
||||
ServerSettings.SaveSettings();
|
||||
MultiPlayerCampaign.StartNewCampaign(localSavePath, matchingSub.FilePath, seed, settings);
|
||||
}
|
||||
}
|
||||
@@ -845,6 +827,9 @@ namespace Barotrauma.Networking
|
||||
case ClientPacketHeader.CREW:
|
||||
ReadCrewMessage(inc, connectedClient);
|
||||
break;
|
||||
case ClientPacketHeader.MEDICAL:
|
||||
ReadMedicalMessage(inc, connectedClient);
|
||||
break;
|
||||
case ClientPacketHeader.READY_CHECK:
|
||||
ReadyCheck.ServerRead(inc, connectedClient);
|
||||
break;
|
||||
@@ -885,6 +870,12 @@ namespace Barotrauma.Networking
|
||||
case ClientNetError.MISSING_ENTITY:
|
||||
UInt16 eventID = inc.ReadUInt16();
|
||||
UInt16 entityID = inc.ReadUInt16();
|
||||
byte subCount = inc.ReadByte();
|
||||
List<string> subNames = new List<string>();
|
||||
for (int i = 0; i < subCount; i++)
|
||||
{
|
||||
subNames.Add(inc.ReadString());
|
||||
}
|
||||
Entity entity = Entity.FindEntityByID(entityID);
|
||||
if (entity == null)
|
||||
{
|
||||
@@ -892,16 +883,23 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else if (entity is Character character)
|
||||
{
|
||||
errorStr = "Missing character " + character.Name + " (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
|
||||
errorStrNoName = "Missing character " + character.SpeciesName + "(event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
|
||||
errorStr = $"Missing character {character.Name} (event id {eventID}, entity id {entityID}).";
|
||||
errorStrNoName = $"Missing character {character.SpeciesName} (event id {eventID}, entity id {entityID}).";
|
||||
}
|
||||
else if (entity is Item item)
|
||||
{
|
||||
errorStr = errorStrNoName = "Missing item " + item.Name + " (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
|
||||
errorStr = errorStrNoName = $"Missing item {item.Name}, sub: {item.Submarine?.Info?.Name ?? "none"} (event id {eventID}, entity id {entityID}).";
|
||||
}
|
||||
else
|
||||
{
|
||||
errorStr = errorStrNoName = "Missing entity " + entity.ToString() + " (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
|
||||
errorStr = errorStrNoName = $"Missing entity {entity}, sub: {entity.Submarine?.Info?.Name ?? "none"} (event id {eventID}, entity id {entityID}).";
|
||||
}
|
||||
var serverSubNames = Submarine.Loaded.Select(s => s.Info.Name);
|
||||
if (subCount != Submarine.Loaded.Count || !subNames.SequenceEqual(serverSubNames))
|
||||
{
|
||||
string subErrorStr = $" Loaded submarines don't match (client: {string.Join(", ", subNames)}, server: {string.Join(", ", serverSubNames)}).";
|
||||
errorStr += subErrorStr;
|
||||
errorStrNoName += subErrorStr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1247,6 +1245,14 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadMedicalMessage(IReadMessage inc, Client sender)
|
||||
{
|
||||
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign mpCampaign)
|
||||
{
|
||||
mpCampaign.MedicalClinic.ServerRead(inc, sender);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadReadyToSpawnMessage(IReadMessage inc, Client sender)
|
||||
{
|
||||
sender.SpectateOnly = inc.ReadBoolean() && (serverSettings.AllowSpectating || sender.Connection == OwnerConnection);
|
||||
@@ -1873,27 +1879,10 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
outmsg.Write(GameMain.NetLobbyScreen.SelectedSub.Name);
|
||||
outmsg.Write(GameMain.NetLobbyScreen.SelectedSub.MD5Hash.ToString());
|
||||
outmsg.Write(serverSettings.UseRespawnShuttle);
|
||||
outmsg.Write(GameMain.NetLobbyScreen.SelectedShuttle.Name);
|
||||
outmsg.Write(GameMain.NetLobbyScreen.SelectedShuttle.MD5Hash.ToString());
|
||||
|
||||
List<int> campaignSubIndices = new List<int>();
|
||||
if (GameMain.NetLobbyScreen.SelectedMode == GameModePreset.MultiPlayerCampaign)
|
||||
{
|
||||
IReadOnlyList<SubmarineInfo> subList = GameMain.NetLobbyScreen.GetSubList();
|
||||
for (int i = 0; i < subList.Count; i++)
|
||||
{
|
||||
if (GameMain.NetLobbyScreen.CampaignSubmarines.Contains(subList[i]))
|
||||
{
|
||||
campaignSubIndices.Add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
outmsg.Write((UInt16)campaignSubIndices.Count);
|
||||
foreach (int campaignSubIndex in campaignSubIndices)
|
||||
{
|
||||
outmsg.Write((UInt16)campaignSubIndex);
|
||||
}
|
||||
outmsg.Write(serverSettings.UseRespawnShuttle || (gameStarted && respawnManager.UsingShuttle));
|
||||
var selectedShuttle = gameStarted && respawnManager.UsingShuttle ? respawnManager.RespawnShuttle.Info : GameMain.NetLobbyScreen.SelectedShuttle;
|
||||
outmsg.Write(selectedShuttle.Name);
|
||||
outmsg.Write(selectedShuttle.MD5Hash.ToString());
|
||||
|
||||
outmsg.Write(serverSettings.Voting.AllowSubVoting);
|
||||
outmsg.Write(serverSettings.Voting.AllowModeVoting);
|
||||
@@ -1954,7 +1943,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
int chatMessageBytes = outmsg.LengthBytes;
|
||||
WriteChatMessages(outmsg, c);
|
||||
chatMessageBytes = outmsg.LengthBytes - outmsg.LengthBytes;
|
||||
chatMessageBytes = outmsg.LengthBytes - chatMessageBytes;
|
||||
|
||||
outmsg.Write((byte)ServerNetObject.END_OF_MESSAGE);
|
||||
|
||||
@@ -1977,7 +1966,11 @@ namespace Barotrauma.Networking
|
||||
warningMsg +=
|
||||
" Settings buffer size: " + settingsBuf.LengthBytes + " bytes\n";
|
||||
}
|
||||
if (GameSettings.VerboseLogging) { DebugConsole.AddWarning(warningMsg); }
|
||||
#if DEBUG || UNSTABLE
|
||||
DebugConsole.ThrowError(warningMsg);
|
||||
#else
|
||||
if (GameSettings.VerboseLogging) { DebugConsole.AddWarning(warningMsg); }
|
||||
#endif
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame1:ClientWriteLobby" + outmsg.LengthBytes, GameAnalyticsManager.ErrorSeverity.Warning, warningMsg);
|
||||
}
|
||||
|
||||
@@ -1993,12 +1986,16 @@ namespace Barotrauma.Networking
|
||||
//these large initial messages until the client acknowledges receiving them
|
||||
c.LastRecvLobbyUpdate++;
|
||||
|
||||
SendVoteStatus(new List<Client>() { c });
|
||||
}
|
||||
else
|
||||
{
|
||||
serverPeer.Send(outmsg, c.Connection, DeliveryMethod.Unreliable);
|
||||
}
|
||||
|
||||
if (isInitialUpdate)
|
||||
{
|
||||
SendVoteStatus(new List<Client>() { c });
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteChatMessages(IWriteMessage outmsg, Client c)
|
||||
@@ -2064,7 +2061,7 @@ namespace Barotrauma.Networking
|
||||
msg.Write(selectedSub.Name);
|
||||
msg.Write(selectedSub.MD5Hash.Hash);
|
||||
|
||||
msg.Write(serverSettings.UseRespawnShuttle);
|
||||
msg.Write(serverSettings.UseRespawnShuttle || (gameStarted && respawnManager.UsingShuttle));
|
||||
msg.Write(selectedShuttle.Name);
|
||||
msg.Write(selectedShuttle.MD5Hash.Hash);
|
||||
|
||||
@@ -2182,7 +2179,6 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
{
|
||||
SendStartMessage(roundStartSeed, GameMain.NetLobbyScreen.LevelSeed, GameMain.GameSession, connectedClients, false);
|
||||
|
||||
GameMain.GameSession.StartRound(GameMain.NetLobbyScreen.LevelSeed, serverSettings.SelectedLevelDifficulty);
|
||||
Log("Game mode: " + selectedMode.Name, ServerLog.MessageType.ServerMessage);
|
||||
Log("Submarine: " + selectedSub.Name, ServerLog.MessageType.ServerMessage);
|
||||
@@ -2202,8 +2198,7 @@ namespace Barotrauma.Networking
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
|
||||
MissionMode missionMode = GameMain.GameSession.GameMode as MissionMode;
|
||||
bool missionAllowRespawn = missionMode == null || !missionMode.Missions.Any(m => !m.AllowRespawn);
|
||||
bool missionAllowRespawn = !(GameMain.GameSession.GameMode is MissionMode missionMode) || !missionMode.Missions.Any(m => !m.AllowRespawn);
|
||||
bool isOutpost = campaign != null && campaign.NextLevel?.Type == LevelData.LevelType.Outpost;
|
||||
|
||||
if (serverSettings.AllowRespawn && missionAllowRespawn)
|
||||
@@ -2281,7 +2276,7 @@ namespace Barotrauma.Networking
|
||||
characterInfos.Add(client.CharacterInfo);
|
||||
if (client.CharacterInfo.Job == null || client.CharacterInfo.Job.Prefab != client.AssignedJob.First)
|
||||
{
|
||||
client.CharacterInfo.Job = new Job(client.AssignedJob.First, client.AssignedJob.Second);
|
||||
client.CharacterInfo.Job = new Job(client.AssignedJob.First, Rand.RandSync.Unsynced, client.AssignedJob.Second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2498,7 +2493,7 @@ namespace Barotrauma.Networking
|
||||
msg.Write(serverSettings.LockAllDefaultWires);
|
||||
msg.Write(serverSettings.AllowRagdollButton);
|
||||
msg.Write(serverSettings.AllowLinkingWifiToChat);
|
||||
msg.Write(serverSettings.UseRespawnShuttle);
|
||||
msg.Write(serverSettings.UseRespawnShuttle || (gameStarted && respawnManager.UsingShuttle));
|
||||
msg.Write((byte)serverSettings.LosMode);
|
||||
msg.Write(includesFinalize); msg.WritePadBits();
|
||||
|
||||
@@ -2510,8 +2505,9 @@ namespace Barotrauma.Networking
|
||||
msg.Write(serverSettings.SelectedLevelDifficulty);
|
||||
msg.Write(gameSession.SubmarineInfo.Name);
|
||||
msg.Write(gameSession.SubmarineInfo.MD5Hash.Hash);
|
||||
msg.Write(GameMain.NetLobbyScreen.SelectedShuttle.Name);
|
||||
msg.Write(GameMain.NetLobbyScreen.SelectedShuttle.MD5Hash.Hash);
|
||||
var selectedShuttle = gameStarted && respawnManager.UsingShuttle ? respawnManager.RespawnShuttle.Info : GameMain.NetLobbyScreen.SelectedShuttle;
|
||||
msg.Write(selectedShuttle.Name);
|
||||
msg.Write(selectedShuttle.MD5Hash.Hash);
|
||||
msg.Write((byte)GameMain.GameSession.GameMode.Missions.Count());
|
||||
foreach (Mission mission in GameMain.GameSession.GameMode.Missions)
|
||||
{
|
||||
@@ -2966,9 +2962,9 @@ namespace Barotrauma.Networking
|
||||
SendDirectChatMessage(msg, recipient);
|
||||
}
|
||||
|
||||
public void SendConsoleMessage(string txt, Client recipient)
|
||||
public void SendConsoleMessage(string txt, Client recipient, Color? color = null)
|
||||
{
|
||||
ChatMessage msg = ChatMessage.Create("", txt, ChatMessageType.Console, null);
|
||||
ChatMessage msg = ChatMessage.Create("", txt, ChatMessageType.Console, sender: null, textColor: color);
|
||||
SendDirectChatMessage(msg, recipient);
|
||||
}
|
||||
|
||||
@@ -3219,11 +3215,11 @@ namespace Barotrauma.Networking
|
||||
//too far to hear the msg -> don't send
|
||||
if (!client.Character.CanHearCharacter(message.Sender)) { continue; }
|
||||
}
|
||||
SendDirectChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.OrderPriority, message.TargetEntity, message.TargetCharacter, message.Sender), client);
|
||||
SendDirectChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.OrderPriority, message.TargetEntity, message.TargetCharacter, message.Sender, isNewOrder: message.IsNewOrder), client);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(message.Text))
|
||||
{
|
||||
AddChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.OrderPriority, message.Text, message.TargetEntity, message.TargetCharacter, message.Sender));
|
||||
AddChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.OrderPriority, message.Text, message.TargetEntity, message.TargetCharacter, message.Sender, isNewOrder: message.IsNewOrder));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3418,14 +3414,40 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void IncrementStat(Character character, string achievementIdentifier, int amount)
|
||||
{
|
||||
achievementIdentifier = achievementIdentifier.ToLowerInvariant();
|
||||
foreach (Client client in connectedClients)
|
||||
{
|
||||
if (client.Character == character)
|
||||
{
|
||||
IncrementStat(client, achievementIdentifier, amount);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void GiveAchievement(Client client, string achievementIdentifier)
|
||||
{
|
||||
if (client.GivenAchievements.Contains(achievementIdentifier)) return;
|
||||
if (client.GivenAchievements.Contains(achievementIdentifier)) { return; }
|
||||
client.GivenAchievements.Add(achievementIdentifier);
|
||||
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte)ServerPacketHeader.ACHIEVEMENT);
|
||||
msg.Write(achievementIdentifier);
|
||||
msg.Write(0);
|
||||
|
||||
serverPeer.Send(msg, client.Connection, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
public void IncrementStat(Client client, string achievementIdentifier, int amount)
|
||||
{
|
||||
if (client.GivenAchievements.Contains(achievementIdentifier)) { return; }
|
||||
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte)ServerPacketHeader.ACHIEVEMENT);
|
||||
msg.Write(achievementIdentifier);
|
||||
msg.Write(amount);
|
||||
|
||||
serverPeer.Send(msg, client.Connection, DeliveryMethod.Reliable);
|
||||
}
|
||||
@@ -3779,7 +3801,7 @@ namespace Barotrauma.Networking
|
||||
if (assignedPlayerCount[jobPrefab] >= jobPrefab.MaxNumber) { continue; }
|
||||
|
||||
var variant = Rand.Range(0, jobPrefab.Variants, Rand.RandSync.Server);
|
||||
unassignedBots[0].Job = new Job(jobPrefab, variant);
|
||||
unassignedBots[0].Job = new Job(jobPrefab, Rand.RandSync.Server, variant);
|
||||
assignedPlayerCount[jobPrefab]++;
|
||||
unassignedBots.Remove(unassignedBots[0]);
|
||||
canAssign = true;
|
||||
@@ -3802,7 +3824,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
var job = remainingJobs.GetRandom();
|
||||
var variant = Rand.Range(0, job.Variants);
|
||||
c.Job = new Job(job, variant);
|
||||
c.Job = new Job(job, Rand.RandSync.Unsynced, variant);
|
||||
assignedPlayerCount[c.Job.Prefab]++;
|
||||
}
|
||||
}
|
||||
@@ -3891,16 +3913,6 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (GameMain.NetLobbyScreen.SelectedSub != null) { serverSettings.SelectedSubmarine = GameMain.NetLobbyScreen.SelectedSub.Name; }
|
||||
if (GameMain.NetLobbyScreen.SelectedShuttle != null) { serverSettings.SelectedShuttle = GameMain.NetLobbyScreen.SelectedShuttle.Name; }
|
||||
if (GameMain.NetLobbyScreen.CampaignSubmarines != null)
|
||||
{
|
||||
string submarinesString = string.Empty;
|
||||
for (int i = 0; i < GameMain.NetLobbyScreen.CampaignSubmarines.Count; i++)
|
||||
{
|
||||
submarinesString += GameMain.NetLobbyScreen.CampaignSubmarines[i].Name + ServerSettings.SubmarineSeparatorChar;
|
||||
}
|
||||
submarinesString.Trim(ServerSettings.SubmarineSeparatorChar);
|
||||
serverSettings.CampaignSubmarines = submarinesString;
|
||||
}
|
||||
|
||||
serverSettings.SaveSettings();
|
||||
|
||||
|
||||
@@ -118,14 +118,18 @@ namespace Barotrauma.Networking
|
||||
return ShouldStartRespawnCountdown(characterToRespawnCount);
|
||||
}
|
||||
|
||||
private int GetMinCharactersToRespawn()
|
||||
{
|
||||
return Math.Max((int)(GameMain.Server.ConnectedClients.Count * GameMain.Server.ServerSettings.MinRespawnRatio), 1);
|
||||
}
|
||||
|
||||
private bool ShouldStartRespawnCountdown(int characterToRespawnCount)
|
||||
{
|
||||
if (GameMain.Lua.game.overrideRespawnSub)
|
||||
{
|
||||
characterToRespawnCount = 0;
|
||||
}
|
||||
int totalCharacterCount = GameMain.Server.ConnectedClients.Count;
|
||||
return (float)characterToRespawnCount >= Math.Max((float)totalCharacterCount * GameMain.Server.ServerSettings.MinRespawnRatio, 1.0f);
|
||||
return characterToRespawnCount >= GetMinCharactersToRespawn();
|
||||
}
|
||||
|
||||
partial void UpdateWaiting(float deltaTime)
|
||||
@@ -139,7 +143,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
pendingRespawnCount = GetClientsToRespawn().Count();
|
||||
requiredRespawnCount = (int)Math.Max((float)GameMain.Server.ConnectedClients.Count * GameMain.Server.ServerSettings.MinRespawnRatio, 1.0f);
|
||||
requiredRespawnCount = GetMinCharactersToRespawn();
|
||||
if (pendingRespawnCount != prevPendingRespawnCount ||
|
||||
requiredRespawnCount != prevRequiredRespawnCount)
|
||||
{
|
||||
@@ -372,7 +376,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (campaign?.GetClientCharacterData(c) == null || c.CharacterInfo.Job == null)
|
||||
{
|
||||
c.CharacterInfo.Job = new Job(c.AssignedJob.First, c.AssignedJob.Second);
|
||||
c.CharacterInfo.Job = new Job(c.AssignedJob.First, Rand.RandSync.Unsynced, c.AssignedJob.Second);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,21 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
partial class ServerSettings
|
||||
{
|
||||
partial class NetPropertyData
|
||||
{
|
||||
private object lastSyncedValue;
|
||||
public UInt16 LastUpdateID { get; private set; }
|
||||
|
||||
public void SyncValue()
|
||||
{
|
||||
if (!PropEquals(lastSyncedValue, Value))
|
||||
{
|
||||
LastUpdateID = (UInt16)(GameMain.NetLobbyScreen.LastUpdateID);
|
||||
lastSyncedValue = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly string ClientPermissionsFile = "Data" + Path.DirectorySeparatorChar + "clientpermissions.xml";
|
||||
public static readonly char SubmarineSeparatorChar = '|';
|
||||
|
||||
@@ -35,20 +50,25 @@ namespace Barotrauma.Networking
|
||||
LoadClientPermissions();
|
||||
}
|
||||
|
||||
private void WriteNetProperties(IWriteMessage outMsg)
|
||||
private void WriteNetProperties(IWriteMessage outMsg, Client c)
|
||||
{
|
||||
outMsg.Write((UInt16)netProperties.Keys.Count);
|
||||
foreach (UInt32 key in netProperties.Keys)
|
||||
{
|
||||
outMsg.Write(key);
|
||||
netProperties[key].Write(outMsg);
|
||||
var property = netProperties[key];
|
||||
property.SyncValue();
|
||||
if (property.LastUpdateID > c.LastRecvLobbyUpdate)
|
||||
{
|
||||
outMsg.Write(key);
|
||||
netProperties[key].Write(outMsg);
|
||||
}
|
||||
}
|
||||
outMsg.Write((UInt32)0);
|
||||
}
|
||||
|
||||
public void ServerAdminWrite(IWriteMessage outMsg, Client c)
|
||||
{
|
||||
c.LastSentServerSettingsUpdate = LastPropertyUpdateId;
|
||||
WriteNetProperties(outMsg);
|
||||
WriteNetProperties(outMsg, c);
|
||||
WriteMonsterEnabled(outMsg);
|
||||
BanList.ServerAdminWrite(outMsg, c);
|
||||
Whitelist.ServerAdminWrite(outMsg, c);
|
||||
@@ -79,8 +99,11 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
WriteExtraCargo(outMsg);
|
||||
}
|
||||
|
||||
WriteHiddenSubs(outMsg);
|
||||
|
||||
if (requiredFlags.HasFlag(NetFlags.HiddenSubs))
|
||||
{
|
||||
WriteHiddenSubs(outMsg);
|
||||
}
|
||||
|
||||
if (c.HasPermission(Networking.ClientPermissions.ManageSettings)
|
||||
&& !NetIdUtils.IdMoreRecentOrMatches(c.LastRecvServerSettingsUpdate, LastPropertyUpdateId))
|
||||
@@ -164,6 +187,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
ReadHiddenSubs(incMsg);
|
||||
changed |= true;
|
||||
UpdateFlag(NetFlags.HiddenSubs);
|
||||
}
|
||||
|
||||
if (flags.HasFlag(NetFlags.Misc))
|
||||
@@ -199,11 +223,6 @@ namespace Barotrauma.Networking
|
||||
AutoRestart = autoRestart;
|
||||
}
|
||||
|
||||
RadiationEnabled = incMsg.ReadBoolean();
|
||||
|
||||
int maxMissionCount = MaxMissionCount + incMsg.ReadByte() - 1;
|
||||
MaxMissionCount = MathHelper.Clamp(maxMissionCount, CampaignSettings.MinMissionCountLimit, CampaignSettings.MaxMissionCountLimit);
|
||||
|
||||
changed |= true;
|
||||
UpdateFlag(NetFlags.Misc);
|
||||
}
|
||||
|
||||
@@ -32,26 +32,6 @@ namespace Barotrauma
|
||||
set { selectedShuttle = value; lastUpdateID++; }
|
||||
}
|
||||
|
||||
[Obsolete("TODO: this list shouldn't exist, the client should just use the visible subs list instead")]
|
||||
public List<SubmarineInfo> CampaignSubmarines
|
||||
{
|
||||
get
|
||||
{
|
||||
return campaignSubmarines;
|
||||
}
|
||||
set
|
||||
{
|
||||
campaignSubmarines = value;
|
||||
lastUpdateID++;
|
||||
if (GameMain.NetworkMember?.ServerSettings != null)
|
||||
{
|
||||
GameMain.NetworkMember.ServerSettings.ServerDetailsChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<SubmarineInfo> campaignSubmarines;
|
||||
|
||||
public GameModePreset[] GameModes { get; }
|
||||
|
||||
private int selectedModeIndex;
|
||||
|
||||
Reference in New Issue
Block a user