(f0d812055) v0.9.9.0

This commit is contained in:
Joonas Rikkonen
2020-04-23 19:19:37 +03:00
parent b647059b93
commit ac37a3b0e4
391 changed files with 15054 additions and 5420 deletions
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.9.8.0</Version>
<Version>0.9.9.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>
+1 -1
View File
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.9.8.0</Version>
<Version>0.9.9.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>
@@ -9,20 +9,23 @@ namespace Barotrauma
partial void InitProjSpecific(XElement mainElement) { }
partial void OnAttackedProjSpecific(Character attacker, AttackResult attackResult)
partial void OnAttackedProjSpecific(Character attacker, AttackResult attackResult, float stun)
{
GameMain.Server.KarmaManager.OnCharacterHealthChanged(this, attacker, attackResult.Damage, attackResult.Afflictions);
GameMain.Server.KarmaManager.OnCharacterHealthChanged(this, attacker, attackResult.Damage, stun, attackResult.Afflictions);
}
partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction)
partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction, bool log)
{
if (causeOfDeath == CauseOfDeathType.Affliction)
if (log)
{
GameServer.Log(LogName + " has died (Cause of death: " + causeOfDeathAffliction.Prefab.Name + ")", ServerLog.MessageType.Attack);
}
else
{
GameServer.Log(LogName + " has died (Cause of death: " + causeOfDeath + ")", ServerLog.MessageType.Attack);
if (causeOfDeath == CauseOfDeathType.Affliction)
{
GameServer.Log(GameServer.CharacterLogName(this) + " has died (Cause of death: " + causeOfDeathAffliction.Prefab.Name + ")", ServerLog.MessageType.Attack);
}
else
{
GameServer.Log(GameServer.CharacterLogName(this) + " has died (Cause of death: " + causeOfDeath + ")", ServerLog.MessageType.Attack);
}
}
healthUpdateTimer = 0.0f;
@@ -243,7 +243,7 @@ namespace Barotrauma
return;
}
if (IsUnconscious)
if (IsIncapacitated)
{
var causeOfDeath = CharacterHealth.GetCauseOfDeath();
Kill(causeOfDeath.First, causeOfDeath.Second);
@@ -264,21 +264,21 @@ namespace Barotrauma
switch ((NetEntityEvent.Type)extraData[0])
{
case NetEntityEvent.Type.InventoryState:
msg.WriteRangedInteger(0, 0, 3);
msg.WriteRangedInteger(0, 0, 4);
msg.Write(GameMain.Server.EntityEventManager.Events.Last()?.ID ?? (ushort)0);
Inventory.ServerWrite(msg, c);
break;
case NetEntityEvent.Type.Control:
msg.WriteRangedInteger(1, 0, 3);
msg.WriteRangedInteger(1, 0, 4);
Client owner = (Client)extraData[1];
msg.Write(owner != null && owner.Character == this && GameMain.Server.ConnectedClients.Contains(owner) ? owner.ID : (byte)0);
break;
case NetEntityEvent.Type.Status:
msg.WriteRangedInteger(2, 0, 3);
msg.WriteRangedInteger(2, 0, 4);
WriteStatus(msg);
break;
case NetEntityEvent.Type.UpdateSkills:
msg.WriteRangedInteger(3, 0, 3);
msg.WriteRangedInteger(3, 0, 4);
if (Info?.Job == null)
{
msg.Write((byte)0);
@@ -293,6 +293,15 @@ namespace Barotrauma
}
}
break;
case NetEntityEvent.Type.ExecuteAttack:
Limb attackLimb = extraData[1] as Limb;
UInt16 targetEntityID = (UInt16)extraData[2];
int targetLimbIndex = extraData.Length > 3 ? (int)extraData[3] : 0;
msg.WriteRangedInteger(4, 0, 4);
msg.Write((byte)(Removed ? 0 : Array.IndexOf(AnimController.Limbs, attackLimb)));
msg.Write(targetEntityID);
msg.Write((byte)targetLimbIndex);
break;
default:
DebugConsole.ThrowError("Invalid NetworkEvent type for entity " + ToString() + " (" + (NetEntityEvent.Type)extraData[0] + ")");
break;
@@ -354,7 +363,7 @@ namespace Barotrauma
Vector2 relativeCursorPos = cursorPosition - AimRefPosition;
tempBuffer.Write((UInt16)(65535.0 * Math.Atan2(relativeCursorPos.Y, relativeCursorPos.X) / (2.0 * Math.PI)));
tempBuffer.Write(IsRagdolled || IsUnconscious || Stun > 0.0f || IsDead);
tempBuffer.Write(IsRagdolled || Stun > 0.0f || IsDead || IsIncapacitated);
tempBuffer.Write(AnimController.Dir > 0.0f);
}
@@ -497,6 +506,31 @@ namespace Barotrauma
msg.Write(this is AICharacter);
msg.Write(info.SpeciesName);
info.ServerWrite(msg);
// Current order
if (info.CurrentOrder != null)
{
msg.Write(true);
msg.Write((byte)Order.PrefabList.IndexOf(info.CurrentOrder.Prefab));
msg.Write(info.CurrentOrder.TargetEntity == null ? (UInt16)0 :
info.CurrentOrder.TargetEntity.ID);
if (info.CurrentOrder.OrderGiver != null)
{
msg.Write(true);
msg.Write(info.CurrentOrder.OrderGiver.ID);
}
else
{
msg.Write(false);
}
msg.Write((byte)(string.IsNullOrWhiteSpace(info.CurrentOrderOption) ? 0 :
Array.IndexOf(info.CurrentOrder.Prefab.Options, info.CurrentOrderOption)));
}
else
{
msg.Write(false);
}
TryWriteStatus(msg);
void TryWriteStatus(IWriteMessage msg)
@@ -82,10 +82,6 @@ namespace Barotrauma
{
if (queuedMessages.Count > 0)
{
int inputLines = Math.Max((int)Math.Ceiling(input.Length / (float)Console.WindowWidth), 1);
Console.CursorLeft = 0;
Console.Write(new string(' ', consoleWidth));
Console.CursorTop = Math.Max(Console.CursorTop - inputLines, 0);
Console.CursorLeft = 0;
while (queuedMessages.Count > 0)
{
@@ -192,32 +188,64 @@ namespace Barotrauma
sw.Stop();
}
private static void WriteAndResetLine(string txt)
{
int consoleWidth = Console.BufferWidth;
int linesWritten = 0;
while (true)
{
if (txt.Length > consoleWidth)
{
linesWritten++;
Console.Write(txt.Substring(0, consoleWidth));
txt = txt.Substring(consoleWidth);
}
else
{
Console.Write(txt);
if (txt.Length == consoleWidth)
{
Console.Write(' '); Console.CursorLeft--;
linesWritten++;
}
break;
}
}
Console.CursorTop -= linesWritten;
}
private static void RewriteInputToCommandLine(string input)
{
if (Console.WindowWidth == 0 || Console.WindowHeight == 0) { return; }
int consoleWidth = Math.Max(Console.WindowWidth, 5);
int inputLines = Math.Max((int)Math.Ceiling(input.Length / (float)consoleWidth), 1);
int cursorLine = Math.Max((int)Math.Ceiling((input.Length + 1) / (float)consoleWidth), 1);
int consoleWidth = Math.Max(Console.BufferWidth, 5);
//int inputLines = Math.Max((int)Math.Ceiling(input.Length / (float)consoleWidth), 1);
//int cursorLine = Math.Max((int)Math.Ceiling((input.Length + 1) / (float)consoleWidth), 1);
try
{
Console.WriteLine(""); Console.CursorTop -= inputLines;
string tmpInput = input;
while (tmpInput.Length >= consoleWidth)
{
tmpInput = tmpInput.Substring(consoleWidth);
}
string ln = input.Length > 0 ? AutoComplete(input, 0) : "";
while (ln.Length >= consoleWidth)
{
ln = ln.Substring(consoleWidth);
}
ln += new string(' ', consoleWidth - (ln.Length % consoleWidth));
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.CursorLeft = 0;
Console.Write(ln);
WriteAndResetLine(ln);
Console.ForegroundColor = ConsoleColor.White;
Console.CursorLeft = 0;
Console.CursorTop -= cursorLine;
Console.Write(input);
WriteAndResetLine(tmpInput);
Console.CursorLeft = input.Length % consoleWidth;
}
catch (Exception e)
{
string errorMsg = "Failed to write input to command line (window width: " + Console.WindowWidth + ", window height: " + Console.WindowHeight + ", inputLines:" + inputLines + ")\n"
string errorMsg = "Failed to write input to command line (window width: " + Console.WindowWidth + ", window height: " + Console.WindowHeight + ")\n"
+ e.Message + "\n" + e.StackTrace;
GameAnalyticsManager.AddErrorEventOnce("DebugConsole.RewriteInputToCommandLine", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
}
@@ -558,7 +586,7 @@ namespace Barotrauma
ShowQuestionPrompt("Rank to grant to \"" + client.Name + "\"?", (rank) =>
{
PermissionPreset preset = PermissionPreset.List.Find(p => p.Name.ToLowerInvariant() == rank.ToLowerInvariant());
PermissionPreset preset = PermissionPreset.List.Find(p => p.Name.Equals(rank, StringComparison.OrdinalIgnoreCase));
if (preset == null)
{
ThrowError("Rank \"" + rank + "\" not found.");
@@ -948,7 +976,7 @@ namespace Barotrauma
NewMessage("***************", Color.Cyan);
foreach (Client c in GameMain.Server.ConnectedClients)
{
NewMessage("- " + c.ID.ToString() + ": " + c.Name + (c.Character != null ? " playing " + c.Character.LogName : "") + ", " + c.Connection.EndPointString, Color.Cyan);
NewMessage("- " + c.ID.ToString() + ": " + c.Name + (c.Character != null ? " playing " + c.Character.LogName : "") + ", " + c.Connection.EndPointString + $", ping {c.Ping} ms", Color.Cyan);
}
NewMessage("***************", Color.Cyan);
}));
@@ -957,7 +985,7 @@ namespace Barotrauma
GameMain.Server.SendConsoleMessage("***************", client);
foreach (Client c in GameMain.Server.ConnectedClients)
{
GameMain.Server.SendConsoleMessage("- " + c.ID.ToString() + ": " + c.Name + ", " + c.Connection.EndPointString, client);
GameMain.Server.SendConsoleMessage("- " + c.ID.ToString() + ": " + c.Name + ", " + c.Connection.EndPointString + $", ping {c.Ping} ms", client);
}
GameMain.Server.SendConsoleMessage("***************", client);
});
@@ -1165,7 +1193,7 @@ namespace Barotrauma
else
{
string modeName = string.Join(" ", args);
if (modeName.ToLowerInvariant() == "campaign")
if (modeName.Equals("campaign", StringComparison.OrdinalIgnoreCase))
{
MultiPlayerCampaign.StartCampaignSetup();
}
@@ -1210,7 +1238,7 @@ namespace Barotrauma
commands.Add(new Command("sub|submarine", "submarine [name]: Select the submarine for the next round.", (string[] args) =>
{
Submarine sub = GameMain.NetLobbyScreen.GetSubList().Find(s => s.Name.ToLower() == string.Join(" ", args).ToLower());
SubmarineInfo sub = GameMain.NetLobbyScreen.GetSubList().Find(s => s.Name.ToLower() == string.Join(" ", args).ToLower());
if (sub != null)
{
@@ -1223,13 +1251,13 @@ namespace Barotrauma
{
return new string[][]
{
Submarine.SavedSubmarines.Select(s => s.Name).ToArray()
SubmarineInfo.SavedSubmarines.Select(s => s.Name).ToArray()
};
}));
commands.Add(new Command("shuttle", "shuttle [name]: Select the specified submarine as the respawn shuttle for the next round.", (string[] args) =>
{
Submarine shuttle = GameMain.NetLobbyScreen.GetSubList().Find(s => s.Name.ToLower() == string.Join(" ", args).ToLower());
SubmarineInfo shuttle = GameMain.NetLobbyScreen.GetSubList().Find(s => s.Name.ToLower() == string.Join(" ", args).ToLower());
if (shuttle != null)
{
@@ -1242,7 +1270,7 @@ namespace Barotrauma
{
return new string[][]
{
Submarine.SavedSubmarines.Select(s => s.Name).ToArray()
SubmarineInfo.SavedSubmarines.Select(s => s.Name).ToArray()
};
}));
@@ -1475,6 +1503,27 @@ namespace Barotrauma
}
);
AssignOnClientRequestExecute(
"teleportsub",
(Client client, Vector2 cursorWorldPos, string[] args) =>
{
if (Submarine.MainSub == null || Level.Loaded == null) return;
if (args.Length == 0 || args[0].Equals("cursor", StringComparison.OrdinalIgnoreCase))
{
Submarine.MainSub.SetPosition(cursorWorldPos);
}
else if (args[0].Equals("start", StringComparison.OrdinalIgnoreCase))
{
Submarine.MainSub.SetPosition(Level.Loaded.StartPosition - Vector2.UnitY * Submarine.MainSub.Borders.Height);
}
else
{
Submarine.MainSub.SetPosition(Level.Loaded.EndPosition - Vector2.UnitY * Submarine.MainSub.Borders.Height);
}
}
);
AssignOnClientRequestExecute(
"godmode",
(Client client, Vector2 cursorWorldPos, string[] args) =>
@@ -1493,7 +1542,7 @@ namespace Barotrauma
{
if (args.Length < 2) return;
AfflictionPrefab afflictionPrefab = AfflictionPrefab.List.FirstOrDefault(a => a.Name.ToLowerInvariant() == args[0].ToLowerInvariant());
AfflictionPrefab afflictionPrefab = AfflictionPrefab.List.FirstOrDefault(a => a.Name.Equals(args[0], StringComparison.OrdinalIgnoreCase));
if (afflictionPrefab == null)
{
GameMain.Server.SendConsoleMessage("Affliction \"" + args[0] + "\" not found.", client);
@@ -1576,13 +1625,14 @@ namespace Barotrauma
(Client client, Vector2 cursorWorldPos, string[] args) =>
{
Vector2 explosionPos = cursorWorldPos;
float range = 500, force = 10, damage = 50, structureDamage = 10, empStrength = 0.0f; ;
float range = 500, force = 10, damage = 50, structureDamage = 10, itemDamage = 100, empStrength = 0.0f; ;
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);
if (args.Length > 3) float.TryParse(args[3], out structureDamage);
if (args.Length > 4) float.TryParse(args[4], out empStrength);
new Explosion(range, force, damage, structureDamage, empStrength).Explode(explosionPos, null);
if (args.Length > 4) float.TryParse(args[4], out itemDamage);
if (args.Length > 5) float.TryParse(args[5], out empStrength);
new Explosion(range, force, damage, structureDamage, itemDamage, empStrength).Explode(explosionPos, null);
}
);
@@ -1718,7 +1768,7 @@ namespace Barotrauma
}
string rank = string.Join("", args.Skip(1));
PermissionPreset preset = PermissionPreset.List.Find(p => p.Name.ToLowerInvariant() == rank.ToLowerInvariant());
PermissionPreset preset = PermissionPreset.List.Find(p => p.Name.Equals(rank, StringComparison.OrdinalIgnoreCase));
if (preset == null)
{
GameMain.Server.SendConsoleMessage("Rank \"" + rank + "\" not found.", senderClient);
@@ -1966,7 +2016,7 @@ namespace Barotrauma
if (!client.HasPermission(ClientPermissions.ConsoleCommands) && client.Connection != GameMain.Server.OwnerConnection)
{
GameMain.Server.SendConsoleMessage("You are not permitted to use console commands!", client);
GameServer.Log(client.Name + " attempted to execute the console command \"" + command + "\" without a permission to use console commands.", ServerLog.MessageType.ConsoleUsage);
GameServer.Log(GameServer.ClientLogName(client) + " attempted to execute the console command \"" + command + "\" without a permission to use console commands.", ServerLog.MessageType.ConsoleUsage);
return;
}
@@ -1975,7 +2025,7 @@ namespace Barotrauma
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);
GameServer.Log(client.Name + " attempted to execute the console command \"" + command + "\" without a permission to use the command.", ServerLog.MessageType.ConsoleUsage);
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)
@@ -1987,18 +2037,18 @@ namespace Barotrauma
if (!MathUtils.IsValid(cursorWorldPos))
{
GameMain.Server.SendConsoleMessage("Could not execute command \"" + command + "\" - invalid cursor position.", client);
NewMessage(client.Name + " attempted to execute the console command \"" + command + "\" with invalid cursor position.", Color.White);
NewMessage(GameServer.ClientLogName(client) + " attempted to execute the console command \"" + command + "\" with invalid cursor position.", Color.White);
return;
}
try
{
matchingCommand.ServerExecuteOnClientRequest(client, cursorWorldPos, splitCommand.Skip(1).ToArray());
GameServer.Log("Console command \"" + command + "\" executed by " + client.Name + ".", ServerLog.MessageType.ConsoleUsage);
GameServer.Log("Console command \"" + command + "\" executed by " + GameServer.ClientLogName(client) + ".", ServerLog.MessageType.ConsoleUsage);
}
catch (Exception e)
{
ThrowError("Executing the command \"" + matchingCommand.names[0] + "\" by request from \"" + client.Name + "\" failed.", e);
ThrowError("Executing the command \"" + matchingCommand.names[0] + "\" by request from \"" + GameServer.ClientLogName(client) + "\" failed.", e);
}
}
@@ -9,7 +9,7 @@ namespace Barotrauma
msg.Write((ushort)items.Count);
foreach (Item item in items)
{
item.WriteSpawnData(msg, item.ID);
item.WriteSpawnData(msg, item.ID, item.ParentInventory?.Owner?.ID ?? 0);
}
}
}
@@ -75,8 +75,8 @@ namespace Barotrauma
}
else
{
teamDead[0] = crews[0].All(c => c.IsDead || c.IsUnconscious);
teamDead[1] = crews[1].All(c => c.IsDead || c.IsUnconscious);
teamDead[0] = crews[0].All(c => c.IsDead || c.IsIncapacitated);
teamDead[1] = crews[1].All(c => c.IsDead || c.IsIncapacitated);
}
if (state == 0)
@@ -1,12 +1,32 @@
using Barotrauma.Networking;
using System.Collections.Generic;
namespace Barotrauma
{
partial class SalvageMission : Mission
partial class SalvageMission : Mission
{
private bool usedExistingItem;
private readonly List<Pair<int, int>> executedEffectIndices = new List<Pair<int, int>>();
public override void ServerWriteInitial(IWriteMessage msg, Client c)
{
item.WriteSpawnData(msg, item.ID);
msg.Write(usedExistingItem);
if (usedExistingItem)
{
msg.Write(item.ID);
}
else
{
item.WriteSpawnData(msg, item.ID, item.ParentInventory?.Owner?.ID ?? 0);
}
msg.Write((byte)executedEffectIndices.Count);
foreach (Pair<int, int> effectIndex in executedEffectIndices)
{
msg.Write((byte)effectIndex.First);
msg.Write((byte)effectIndex.Second);
}
}
}
}
@@ -61,7 +61,7 @@ namespace Barotrauma
if (vanillaContent == null)
{
// TODO: Dynamic method for defining and finding the vanilla content package.
vanillaContent = ContentPackage.List.SingleOrDefault(cp => Path.GetFileName(cp.Path).ToLowerInvariant() == "vanilla 0.9.xml");
vanillaContent = ContentPackage.List.SingleOrDefault(cp => Path.GetFileName(cp.Path).Equals("vanilla 0.9.xml", StringComparison.OrdinalIgnoreCase));
}
return vanillaContent;
}
@@ -111,6 +111,7 @@ namespace Barotrauma
StructurePrefab.LoadAll(GetFilesOfType(ContentType.Structure));
ItemPrefab.LoadAll(GetFilesOfType(ContentType.Item));
JobPrefab.LoadAll(GetFilesOfType(ContentType.Jobs));
CorpsePrefab.LoadAll(GetFilesOfType(ContentType.Corpses));
NPCConversation.LoadAll(GetFilesOfType(ContentType.NPCConversations));
ItemAssemblyPrefab.LoadAll();
LevelObjectPrefab.LoadAll();
@@ -118,7 +119,7 @@ namespace Barotrauma
GameModePreset.Init();
LocationType.Init();
Submarine.RefreshSavedSubs();
SubmarineInfo.RefreshSavedSubs();
Screen.SelectNull();
@@ -15,7 +15,7 @@ namespace Barotrauma
{
if (string.IsNullOrWhiteSpace(savePath)) return;
GameMain.GameSession = new GameSession(new Submarine(subPath, ""), savePath,
GameMain.GameSession = new GameSession(new SubmarineInfo(subPath, ""), savePath,
GameModePreset.List.Find(g => g.Identifier == "multiplayercampaign"));
var campaign = ((MultiPlayerCampaign)GameMain.GameSession.GameMode);
campaign.GenerateMap(seed);
@@ -46,7 +46,7 @@ namespace Barotrauma
DebugConsole.NewMessage("********* CAMPAIGN SETUP *********", Color.White);
DebugConsole.ShowQuestionPrompt("Do you want to start a new campaign? Y/N", (string arg) =>
{
if (arg.ToLowerInvariant() == "y" || arg.ToLowerInvariant() == "yes")
if (arg.Equals("y", StringComparison.OrdinalIgnoreCase) || arg.Equals("yes", StringComparison.OrdinalIgnoreCase))
{
DebugConsole.ShowQuestionPrompt("Enter a save name for the campaign:", (string saveName) =>
{
@@ -189,7 +189,7 @@ namespace Barotrauma
foreach (PurchasedItem pi in CargoManager.PurchasedItems)
{
msg.Write(pi.ItemPrefab.Identifier);
msg.Write((UInt16)pi.Quantity);
msg.WriteRangedInteger(pi.Quantity, 0, 100);
}
var characterData = GetClientCharacterData(c);
@@ -217,7 +217,7 @@ namespace Barotrauma
for (int i = 0; i < purchasedItemCount; i++)
{
string itemPrefabIdentifier = msg.ReadString();
UInt16 itemQuantity = msg.ReadUInt16();
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
}
@@ -255,8 +255,8 @@ namespace Barotrauma
}
if (purchasedLostShuttles != this.PurchasedLostShuttles)
{
if (GameMain.GameSession?.Submarine != null &&
GameMain.GameSession.Submarine.LeftBehindSubDockingPortOccupied)
if (GameMain.GameSession?.SubmarineInfo != null &&
GameMain.GameSession.SubmarineInfo.LeftBehindSubDockingPortOccupied)
{
GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("ReplaceShuttleDockingPortOccupied"), sender, ChatMessageType.MessageBox);
}
@@ -30,7 +30,7 @@ namespace Barotrauma.Items.Components
AttachToWall();
item.CreateServerEvent(this);
GameServer.Log(c.Character.LogName + " attached " + item.Name + " to a wall", ServerLog.MessageType.ItemInteraction);
GameServer.Log(GameServer.CharacterLogName(c.Character) + " attached " + item.Name + " to a wall", ServerLog.MessageType.ItemInteraction);
}
}
}
@@ -0,0 +1,45 @@
using Barotrauma.Networking;
using System.Collections.Generic;
namespace Barotrauma.Items.Components
{
partial class LightComponent : Powered, IServerSerializable
{
private CoroutineHandle sendStateCoroutine;
private bool lastSentState;
private float sendStateTimer;
partial void OnStateChanged()
{
sendStateTimer = 0.5f;
if (sendStateCoroutine == null)
{
sendStateCoroutine = CoroutineManager.StartCoroutine(SendStateAfterDelay());
}
}
private IEnumerable<object> SendStateAfterDelay()
{
while (sendStateTimer > 0.0f)
{
sendStateTimer -= CoroutineManager.DeltaTime;
yield return CoroutineStatus.Running;
}
if (item.Removed || GameMain.NetworkMember == null)
{
yield return CoroutineStatus.Success;
}
sendStateCoroutine = null;
if (lastSentState != IsActive) { item.CreateServerEvent(this); }
yield return CoroutineStatus.Success;
}
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
msg.Write(IsActive);
lastSentState = IsActive;
}
}
}
@@ -19,7 +19,7 @@ namespace Barotrauma.Items.Components
{
if (Math.Abs(newTargetForce - targetForce) > 0.01f)
{
GameServer.Log(c.Character.LogName + " set the force of " + item.Name + " to " + (int)(newTargetForce) + " %", ServerLog.MessageType.ItemInteraction);
GameServer.Log(GameServer.CharacterLogName(c.Character) + " set the force of " + item.Name + " to " + (int)(newTargetForce) + " %", ServerLog.MessageType.ItemInteraction);
}
targetForce = newTargetForce;
@@ -17,11 +17,11 @@ namespace Barotrauma.Items.Components
{
if (newFlowPercentage != FlowPercentage)
{
GameServer.Log(c.Character.LogName + " set the pumping speed of " + item.Name + " to " + (int)(newFlowPercentage) + " %", ServerLog.MessageType.ItemInteraction);
GameServer.Log(GameServer.CharacterLogName(c.Character) + " set the pumping speed of " + item.Name + " to " + (int)(newFlowPercentage) + " %", ServerLog.MessageType.ItemInteraction);
}
if (newIsActive != IsActive)
{
GameServer.Log(c.Character.LogName + (newIsActive ? " turned on " : " turned off ") + item.Name, ServerLog.MessageType.ItemInteraction);
GameServer.Log(GameServer.CharacterLogName(c.Character) + (newIsActive ? " turned on " : " turned off ") + item.Name, ServerLog.MessageType.ItemInteraction);
}
FlowPercentage = newFlowPercentage;
@@ -14,7 +14,7 @@ namespace Barotrauma.Items.Components
if (item.CanClientAccess(c))
{
RechargeSpeed = newRechargeSpeed;
GameServer.Log(c.Character.LogName + " set the recharge speed of " + item.Name + " to " + (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", ServerLog.MessageType.ItemInteraction);
GameServer.Log(GameServer.CharacterLogName(c.Character) + " set the recharge speed of " + item.Name + " to " + (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", ServerLog.MessageType.ItemInteraction);
}
item.CreateServerEvent(this);
@@ -0,0 +1,42 @@
using Barotrauma.Networking;
using System;
namespace Barotrauma.Items.Components
{
partial class Projectile : ItemComponent
{
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
bool stuck = StickTarget != null && !item.Removed && !StickTargetRemoved();
msg.Write(stuck);
if (stuck)
{
msg.Write(item.Submarine?.ID ?? Entity.NullEntityID);
msg.Write(item.CurrentHull?.ID ?? Entity.NullEntityID);
msg.Write(item.SimPosition.X);
msg.Write(item.SimPosition.Y);
msg.Write(stickJoint.Axis.X);
msg.Write(stickJoint.Axis.Y);
if (StickTarget.UserData is Structure structure)
{
msg.Write(structure.ID);
int bodyIndex = structure.Bodies.IndexOf(StickTarget);
msg.Write((byte)(bodyIndex == -1 ? 0 : bodyIndex));
}
else if (StickTarget.UserData is Entity entity)
{
msg.Write(entity.ID);
}
else if (StickTarget.UserData is Limb limb)
{
msg.Write(limb.character.ID);
msg.Write((byte)Array.IndexOf(limb.character.AnimController.Limbs, limb));
}
else
{
throw new NotImplementedException(StickTarget.UserData?.ToString() ?? "null" + " is not a valid projectile stick target.");
}
}
}
}
}
@@ -12,7 +12,7 @@ namespace Barotrauma.Items.Components
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
{
if (c.Character == null) return;
if (c.Character == null) { return; }
var requestedFixAction = (FixActions)msg.ReadRangedInteger(0, 2);
if (requestedFixAction != FixActions.None)
{
@@ -0,0 +1,12 @@
using Barotrauma.Networking;
namespace Barotrauma.Items.Components
{
partial class Rope : ItemComponent
{
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
msg.Write(Snapped);
}
}
}
@@ -66,6 +66,9 @@ namespace Barotrauma.Items.Components
if (!CheckCharacterSuccess(c.Character))
{
item.CreateServerEvent(this);
c.Character.SelectedItems[0]?.GetComponent<Wire>()?.CreateNetworkEvent();
c.Character.SelectedItems[1]?.GetComponent<Wire>()?.CreateNetworkEvent();
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFailure, this, c.Character.ID });
return;
}
@@ -85,7 +88,7 @@ namespace Barotrauma.Items.Components
if (existingWire.Locked)
{
//this should not be possible unless the client is running a modified version of the game
GameServer.Log(c.Character.LogName + " attempted to disconnect a locked wire from " +
GameServer.Log(GameServer.CharacterLogName(c.Character) + " attempted to disconnect a locked wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ")", ServerLog.MessageType.Error);
continue;
}
@@ -103,7 +106,7 @@ namespace Barotrauma.Items.Components
if (existingWire.Connections[0] == null && existingWire.Connections[1] == null)
{
GameServer.Log(c.Character.LogName + " disconnected a wire from " +
GameServer.Log(GameServer.CharacterLogName(c.Character) + " disconnected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ")", ServerLog.MessageType.Wiring);
if (existingWire.Item.ParentInventory != null)
@@ -119,7 +122,7 @@ namespace Barotrauma.Items.Components
}
else if (existingWire.Connections[0] != null)
{
GameServer.Log(c.Character.LogName + " disconnected a wire from " +
GameServer.Log(GameServer.CharacterLogName(c.Character) + " disconnected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + existingWire.Connections[0].Item.Name + " (" + existingWire.Connections[0].Name + ")", ServerLog.MessageType.Wiring);
//wires that are not in anyone's inventory (i.e. not currently being rewired)
@@ -134,7 +137,7 @@ namespace Barotrauma.Items.Components
}
else if (existingWire.Connections[1] != null)
{
GameServer.Log(c.Character.LogName + " disconnected a wire from " +
GameServer.Log(GameServer.CharacterLogName(c.Character) + " disconnected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + existingWire.Connections[1].Item.Name + " (" + existingWire.Connections[1].Name + ")", ServerLog.MessageType.Wiring);
/*if (existingWire.Item.ParentInventory == null && !wires.Any(w => w.Contains(existingWire)))
@@ -158,7 +161,7 @@ namespace Barotrauma.Items.Components
disconnectedWire.Item.ParentInventory == null)
{
disconnectedWire.Item.Drop(c.Character);
GameServer.Log(c.Character.LogName + " dropped " + disconnectedWire.Name, ServerLog.MessageType.Inventory);
GameServer.Log(GameServer.CharacterLogName(c.Character) + " dropped " + disconnectedWire.Name, ServerLog.MessageType.Inventory);
}
}
@@ -177,13 +180,13 @@ namespace Barotrauma.Items.Components
if (otherConnection == null)
{
GameServer.Log(c.Character.LogName + " connected a wire to " +
GameServer.Log(GameServer.CharacterLogName(c.Character) + " connected a wire to " +
Connections[i].Item.Name + " (" + Connections[i].Name + ")",
ServerLog.MessageType.Wiring);
}
else
{
GameServer.Log(c.Character.LogName + " connected a wire from " +
GameServer.Log(GameServer.CharacterLogName(c.Character) + " connected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ") to " +
(otherConnection == null ? "none" : otherConnection.Item.Name + " (" + (otherConnection.Name) + ")"),
ServerLog.MessageType.Wiring);
@@ -10,9 +10,17 @@ namespace Barotrauma.Items.Components
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
{
bool[] elementStates = new bool[customInterfaceElementList.Count];
string[] elementValues = new string[customInterfaceElementList.Count];
for (int i = 0; i < customInterfaceElementList.Count; i++)
{
elementStates[i] = msg.ReadBoolean();
if (!string.IsNullOrEmpty(customInterfaceElementList[i].PropertyName))
{
elementValues[i] = msg.ReadString();
}
else
{
elementStates[i] = msg.ReadBoolean();
}
}
CustomInterfaceElement clickedButton = null;
@@ -20,7 +28,11 @@ namespace Barotrauma.Items.Components
{
for (int i = 0; i < customInterfaceElementList.Count; i++)
{
if (customInterfaceElementList[i].ContinuousSignal)
if (!string.IsNullOrEmpty(customInterfaceElementList[i].PropertyName))
{
TextChanged(customInterfaceElementList[i], elementValues[i]);
}
else if (customInterfaceElementList[i].ContinuousSignal)
{
TickBoxToggled(customInterfaceElementList[i], elementStates[i]);
}
@@ -48,7 +60,11 @@ namespace Barotrauma.Items.Components
//extradata contains an array of buttons clicked by a client (or nothing if nothing was clicked)
for (int i = 0; i < customInterfaceElementList.Count; i++)
{
if (customInterfaceElementList[i].ContinuousSignal)
if (!string.IsNullOrEmpty(customInterfaceElementList[i].PropertyName))
{
msg.Write(customInterfaceElementList[i].Signal);
}
else if(customInterfaceElementList[i].ContinuousSignal)
{
msg.Write(customInterfaceElementList[i].State);
}
@@ -14,7 +14,7 @@ namespace Barotrauma.Items.Components
{
newOutputValue = newOutputValue.Substring(0, MaxMessageLength);
}
GameServer.Log(c.Character.LogName + " entered \"" + newOutputValue + "\" on " + item.Name,
GameServer.Log(GameServer.CharacterLogName(c.Character) + " entered \"" + newOutputValue + "\" on " + item.Name,
ServerLog.MessageType.ItemInteraction);
OutputValue = newOutputValue;
item.SendSignal(0, newOutputValue, "signal_out", null);
@@ -6,7 +6,7 @@ namespace Barotrauma.Items.Components
{
partial class Wire : ItemComponent, IDrawableComponent, IServerSerializable
{
private void CreateNetworkEvent()
public void CreateNetworkEvent()
{
if (GameMain.Server == null) return;
//split into multiple events because one might not be enough to fit all the nodes
@@ -66,6 +66,19 @@ namespace Barotrauma
Item droppedItem = Items[i];
Entity prevOwner = Owner;
droppedItem.Drop(null);
var previousInventory = prevOwner switch
{
Item itemInventory => (itemInventory.FindParentInventory(inventory => inventory is CharacterInventory) as CharacterInventory),
Character character => character.Inventory,
_ => null
};
if (previousInventory != null && previousInventory != c.Character?.Inventory)
{
GameMain.Server?.KarmaManager.OnItemTakenFromPlayer(previousInventory, c, droppedItem);
}
if (droppedItem.body != null && prevOwner != null)
{
droppedItem.body.SetTransform(prevOwner.SimPosition, 0.0f);
@@ -88,6 +101,10 @@ namespace Barotrauma
if (!prevItems.Contains(item) && !item.CanClientAccess(c))
{
if (item.body != null && !c.PendingPositionUpdates.Contains(item))
{
c.PendingPositionUpdates.Enqueue(item);
}
item.PositionUpdateInterval = 0.0f;
continue;
}
@@ -106,7 +123,7 @@ namespace Barotrauma
CreateNetworkEvent();
foreach (Inventory prevInventory in prevItemInventories.Distinct())
{
if (prevInventory != this) prevInventory?.CreateNetworkEvent();
if (prevInventory != this) { prevInventory?.CreateNetworkEvent(); }
}
foreach (Item item in Items.Distinct())
@@ -116,11 +133,11 @@ namespace Barotrauma
{
if (Owner == c.Character)
{
GameServer.Log(c.Character.LogName+ " picked up " + item.Name, ServerLog.MessageType.Inventory);
GameServer.Log(GameServer.CharacterLogName(c.Character) + " picked up " + item.Name, ServerLog.MessageType.Inventory);
}
else
{
GameServer.Log(c.Character.LogName + " placed " + item.Name + " in " + Owner, ServerLog.MessageType.Inventory);
GameServer.Log(GameServer.CharacterLogName(c.Character) + " placed " + item.Name + " in " + Owner, ServerLog.MessageType.Inventory);
}
}
}
@@ -131,11 +148,11 @@ namespace Barotrauma
{
if (Owner == c.Character)
{
GameServer.Log(c.Character.LogName + " dropped " + item.Name, ServerLog.MessageType.Inventory);
GameServer.Log(GameServer.CharacterLogName(c.Character) + " dropped " + item.Name, ServerLog.MessageType.Inventory);
}
else
{
GameServer.Log(c.Character.LogName + " removed " + item.Name + " from " + Owner, ServerLog.MessageType.Inventory);
GameServer.Log(GameServer.CharacterLogName(c.Character) + " removed " + item.Name + " from " + Owner, ServerLog.MessageType.Inventory);
}
}
}
@@ -186,12 +186,12 @@ namespace Barotrauma
if (ContainedItems == null || ContainedItems.All(i => i == null))
{
GameServer.Log(c.Character.LogName + " used item " + Name, ServerLog.MessageType.ItemInteraction);
GameServer.Log(GameServer.CharacterLogName(c.Character) + " used item " + Name, ServerLog.MessageType.ItemInteraction);
}
else
{
GameServer.Log(
c.Character.LogName + " used item " + Name + " (contained items: " + string.Join(", ", ContainedItems.Select(i => i.Name)) + ")",
GameServer.CharacterLogName(c.Character) + " used item " + Name + " (contained items: " + string.Join(", ", ContainedItems.Select(i => i.Name)) + ")",
ServerLog.MessageType.ItemInteraction);
}
@@ -213,7 +213,7 @@ namespace Barotrauma
}
}
public void WriteSpawnData(IWriteMessage msg, UInt16 entityID)
public void WriteSpawnData(IWriteMessage msg, UInt16 entityID, UInt16 originalInventoryID)
{
if (GameMain.Server == null) return;
@@ -227,7 +227,7 @@ namespace Barotrauma
msg.Write(entityID);
if (ParentInventory == null || ParentInventory.Owner == null)
if (ParentInventory == null || ParentInventory.Owner == null || originalInventoryID == 0)
{
msg.Write((ushort)0);
@@ -237,7 +237,7 @@ namespace Barotrauma
}
else
{
msg.Write(ParentInventory.Owner.ID);
msg.Write(originalInventoryID);
//find the index of the ItemContainer this item is inside to get the item to
//spawn in the correct inventory in multi-inventory items like fabricators
@@ -260,6 +260,8 @@ namespace Barotrauma
msg.Write(slotIndex < 0 ? (byte)255 : (byte)slotIndex);
}
msg.Write(body == null ? (byte)0 : (byte)body.BodyType);
byte teamID = 0;
foreach (WifiComponent wifiComponent in GetComponents<WifiComponent>())
{
@@ -347,7 +347,7 @@ namespace Barotrauma.Networking
BannedPlayer bannedPlayer = bannedPlayers.Find(p => p.UniqueIdentifier == id);
if (bannedPlayer != null)
{
GameServer.Log(c.Name + " unbanned " + bannedPlayer.Name + " (" + bannedPlayer.IP + ")", ServerLog.MessageType.ConsoleUsage);
GameServer.Log(GameServer.ClientLogName(c) + " unbanned " + bannedPlayer.Name + " (" + bannedPlayer.IP + ")", ServerLog.MessageType.ConsoleUsage);
RemoveBan(bannedPlayer);
}
}
@@ -358,7 +358,7 @@ namespace Barotrauma.Networking
BannedPlayer bannedPlayer = bannedPlayers.Find(p => p.UniqueIdentifier == id);
if (bannedPlayer != null)
{
GameServer.Log(c.Name + " rangebanned " + bannedPlayer.Name + " (" + bannedPlayer.IP + ")", ServerLog.MessageType.ConsoleUsage);
GameServer.Log(GameServer.ClientLogName(c) + " rangebanned " + bannedPlayer.Name + " (" + bannedPlayer.IP + ")", ServerLog.MessageType.ConsoleUsage);
RangeBan(bannedPlayer);
}
}
@@ -159,6 +159,7 @@ namespace Barotrauma.Networking
msg.Write((byte)ServerNetObject.CHAT_MESSAGE);
msg.Write(NetStateID);
msg.Write((byte)Type);
msg.Write((byte)ChangeType);
msg.Write(Text);
msg.Write(SenderName);
@@ -75,7 +75,8 @@ namespace Barotrauma.Networking
public bool SpectateOnly;
public int KarmaKickCount;
private float syncedKarma = 100.0f;
private float karma = 100.0f;
public float Karma
{
@@ -89,6 +90,11 @@ namespace Barotrauma.Networking
{
if (GameMain.Server == null || !GameMain.Server.ServerSettings.KarmaEnabled) { return; }
karma = Math.Min(Math.Max(value, 0.0f), 100.0f);
if (!MathUtils.NearlyEqual(karma, syncedKarma, 10.0f))
{
syncedKarma = karma;
GameMain.NetworkMember.LastClientListUpdateID++;
}
}
}
@@ -35,7 +35,7 @@ namespace Barotrauma
{
message.Write((byte)SpawnableType.Item);
DebugConsole.Log("Writing item spawn data " + entities.Entity.ToString() + " (original ID: " + entities.OriginalID + ", current ID: " + entities.Entity.ID + ")");
((Item)entities.Entity).WriteSpawnData(message, entities.OriginalID);
((Item)entities.Entity).WriteSpawnData(message, entities.OriginalID, entities.OriginalInventoryID);
}
else if (entities.Entity is Character)
{
@@ -332,7 +332,7 @@ namespace Barotrauma.Networking
case (byte)FileTransferType.Submarine:
string fileName = inc.ReadString();
string fileHash = inc.ReadString();
var requestedSubmarine = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == fileName && s.MD5Hash.Hash == fileHash);
var requestedSubmarine = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == fileName && s.MD5Hash.Hash == fileHash);
if (requestedSubmarine != null)
{
@@ -205,12 +205,12 @@ namespace Barotrauma.Networking
GameMain.NetLobbyScreen.RandomizeSettings();
if (!string.IsNullOrEmpty(serverSettings.SelectedSubmarine))
{
Submarine sub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == serverSettings.SelectedSubmarine);
SubmarineInfo sub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == serverSettings.SelectedSubmarine);
if (sub != null) { GameMain.NetLobbyScreen.SelectedSub = sub; }
}
if (!string.IsNullOrEmpty(serverSettings.SelectedShuttle))
{
Submarine shuttle = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == serverSettings.SelectedShuttle);
SubmarineInfo shuttle = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == serverSettings.SelectedShuttle);
if (shuttle != null) { GameMain.NetLobbyScreen.SelectedShuttle = shuttle; }
}
started = true;
@@ -279,7 +279,7 @@ namespace Barotrauma.Networking
SendConsoleMessage("Granted all permissions to " + newClient.Name + ".", newClient);
}
SendChatMessage($"ServerMessage.JoinedServer~[client]={clName}", ChatMessageType.Server, null);
SendChatMessage($"ServerMessage.JoinedServer~[client]={clName}", ChatMessageType.Server, null, changeType: PlayerConnectionChangeType.Joined);
serverSettings.ServerDetailsChanged = true;
if (previousPlayer != null && previousPlayer.Name != newClient.Name)
@@ -338,6 +338,8 @@ namespace Barotrauma.Networking
fileSender.Update(deltaTime);
KarmaManager.UpdateClients(ConnectedClients, deltaTime);
UpdatePing();
if (serverSettings.VoiceChatEnabled)
{
VoipServer.SendToClients(connectedClients);
@@ -382,7 +384,7 @@ namespace Barotrauma.Networking
}
bool isCrewDead =
connectedClients.All(c => c.Character == null || c.Character.IsDead || c.Character.IsUnconscious);
connectedClients.All(c => c.Character == null || c.Character.IsDead || c.Character.IsIncapacitated);
bool subAtLevelEnd = false;
if (Submarine.MainSub != null && Submarine.MainSubs[1] == null)
@@ -529,7 +531,7 @@ namespace Barotrauma.Networking
c.ChatSpamSpeed = Math.Max(0.0f, c.ChatSpamSpeed - deltaTime);
//constantly increase AFK timer if the client is controlling a character (gets reset to zero every time an input is received)
if (gameStarted && c.Character != null && !c.Character.IsDead && !c.Character.IsUnconscious)
if (gameStarted && c.Character != null && !c.Character.IsDead && !c.Character.IsIncapacitated)
{
if (c.Connection != OwnerConnection) c.KickAFKTimer += deltaTime;
}
@@ -611,6 +613,41 @@ namespace Barotrauma.Networking
}
}
private double lastPingTime;
private byte[] lastPingData;
private void UpdatePing()
{
if (Timing.TotalTime > lastPingTime + 1.0)
{
lastPingData ??= new byte[64];
for (int i=0;i<lastPingData.Length;i++)
{
lastPingData[i] = (byte)Rand.Range(33, 126);
}
lastPingTime = Timing.TotalTime;
ConnectedClients.ForEach(c =>
{
IWriteMessage pingReq = new WriteOnlyMessage();
pingReq.Write((byte)ServerPacketHeader.PING_REQUEST);
pingReq.Write((byte)lastPingData.Length);
pingReq.Write(lastPingData, 0, lastPingData.Length);
serverPeer.Send(pingReq, c.Connection, DeliveryMethod.Unreliable);
IWriteMessage pingInf = new WriteOnlyMessage();
pingInf.Write((byte)ServerPacketHeader.CLIENT_PINGS);
pingInf.Write((byte)ConnectedClients.Count);
ConnectedClients.ForEach(c2 =>
{
pingInf.Write(c2.ID);
pingInf.Write(c2.Ping);
});
serverPeer.Send(pingInf, c.Connection, DeliveryMethod.Unreliable);
});
}
}
private void ReadDataMessage(NetworkConnection sender, IReadMessage inc)
{
var connectedClient = connectedClients.Find(c => c.Connection == sender);
@@ -618,6 +655,16 @@ namespace Barotrauma.Networking
ClientPacketHeader header = (ClientPacketHeader)inc.ReadByte();
switch (header)
{
case ClientPacketHeader.PING_RESPONSE:
byte responseLen = inc.ReadByte();
if (responseLen != lastPingData.Length) { return; }
for (int i=0;i<responseLen;i++)
{
byte b = inc.ReadByte();
if (b != lastPingData[i]) { return; }
}
connectedClient.Ping = (UInt16)((Timing.TotalTime - lastPingTime) * 1000);
break;
case ClientPacketHeader.RESPONSE_STARTGAME:
if (connectedClient != null)
{
@@ -653,7 +700,7 @@ namespace Barotrauma.Networking
string subName = inc.ReadString();
string subHash = inc.ReadString();
var matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash);
var matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash);
if (matchingSub == null)
{
@@ -748,11 +795,11 @@ namespace Barotrauma.Networking
if (Level.Loaded != null && levelEqualityCheckVal != Level.Loaded.EqualityCheckVal)
{
errorStr += " Level equality check failed. The level generated at your end doesn't match the level generated by the server(seed: " + Level.Loaded.Seed +
", sub: " + Submarine.MainSub.Name + " (" + Submarine.MainSub.MD5Hash.ShortHash + ")" +
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortHash + ")" +
", mirrored: " + Level.Loaded.Mirrored + ").";
}
Log(c.Name + " has reported an error: " + errorStr, ServerLog.MessageType.Error);
Log(GameServer.ClientLogName(c) + " has reported an error: " + errorStr, ServerLog.MessageType.Error);
GameAnalyticsManager.AddErrorEventOnce("GameServer.HandleClientError:" + errorStr, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorStr);
try
@@ -783,8 +830,8 @@ namespace Barotrauma.Networking
Directory.CreateDirectory(ServerLog.SavePath);
}
string filePath = "event_error_log_server_" + client.Name + "_" + ToolBox.RemoveInvalidFileNameChars(DateTime.UtcNow.ToShortTimeString() + ".log");
filePath = Path.Combine(ServerLog.SavePath, filePath);
string filePath = "event_error_log_server_" + client.Name + "_" + DateTime.UtcNow.ToShortTimeString() + ".log";
filePath = Path.Combine(ServerLog.SavePath, ToolBox.RemoveInvalidFileNameChars(filePath));
if (File.Exists(filePath)) { return; }
List<string> errorLines = new List<string>
@@ -798,7 +845,7 @@ namespace Barotrauma.Networking
}
if (GameMain.GameSession?.Submarine != null)
{
errorLines.Add("Submarine: " + GameMain.GameSession.Submarine.Name);
errorLines.Add("Submarine: " + GameMain.GameSession.Submarine.Info.Name);
}
if (Level.Loaded != null)
{
@@ -1068,7 +1115,7 @@ namespace Barotrauma.Networking
}
else if (!sender.HasPermission(command))
{
Log("Client \"" + sender.Name + "\" sent a server command \"" + command + "\". Permission denied.", ServerLog.MessageType.ServerMessage);
Log("Client \"" + GameServer.ClientLogName(sender) + "\" sent a server command \"" + command + "\". Permission denied.", ServerLog.MessageType.ServerMessage);
return;
}
@@ -1077,10 +1124,10 @@ namespace Barotrauma.Networking
case ClientPermissions.Kick:
string kickedName = inc.ReadString().ToLowerInvariant();
string kickReason = inc.ReadString();
var kickedClient = connectedClients.Find(cl => cl != sender && cl.Name.ToLowerInvariant() == kickedName && cl.Connection != OwnerConnection);
var kickedClient = connectedClients.Find(cl => cl != sender && cl.Name.Equals(kickedName, StringComparison.OrdinalIgnoreCase) && cl.Connection != OwnerConnection);
if (kickedClient != null)
{
Log("Client \"" + sender.Name + "\" kicked \"" + kickedClient.Name + "\".", ServerLog.MessageType.ServerMessage);
Log("Client \"" + GameServer.ClientLogName(sender) + "\" kicked \"" + GameServer.ClientLogName(kickedClient) + "\".", ServerLog.MessageType.ServerMessage);
KickClient(kickedClient, string.IsNullOrEmpty(kickReason) ? $"ServerMessage.KickedBy~[initiator]={sender.Name}" : kickReason);
}
else
@@ -1094,10 +1141,10 @@ namespace Barotrauma.Networking
bool range = inc.ReadBoolean();
double durationSeconds = inc.ReadDouble();
var bannedClient = connectedClients.Find(cl => cl != sender && cl.Name.ToLowerInvariant() == bannedName && cl.Connection != OwnerConnection);
var bannedClient = connectedClients.Find(cl => cl != sender && cl.Name.Equals(bannedName, StringComparison.OrdinalIgnoreCase) && cl.Connection != OwnerConnection);
if (bannedClient != null)
{
Log("Client \"" + sender.Name + "\" banned \"" + bannedClient.Name + "\".", ServerLog.MessageType.ServerMessage);
Log("Client \"" + GameServer.ClientLogName(sender) + "\" banned \"" + GameServer.ClientLogName(bannedClient) + "\".", ServerLog.MessageType.ServerMessage);
if (durationSeconds > 0)
{
BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? $"ServerMessage.BannedBy~[initiator]={sender.Name}" : banReason, range, TimeSpan.FromSeconds(durationSeconds));
@@ -1121,12 +1168,12 @@ namespace Barotrauma.Networking
bool end = inc.ReadBoolean();
if (gameStarted && end)
{
Log("Client \"" + sender.Name + "\" ended the round.", ServerLog.MessageType.ServerMessage);
Log("Client \"" + GameServer.ClientLogName(sender) + "\" ended the round.", ServerLog.MessageType.ServerMessage);
EndGame();
}
else if (!gameStarted && !end && !initiatedStartGame)
{
Log("Client \"" + sender.Name + "\" started the round.", ServerLog.MessageType.ServerMessage);
Log("Client \"" + GameServer.ClientLogName(sender) + "\" started the round.", ServerLog.MessageType.ServerMessage);
StartGame();
}
break;
@@ -1137,7 +1184,7 @@ namespace Barotrauma.Networking
var subList = GameMain.NetLobbyScreen.GetSubList();
if (subIndex >= subList.Count)
{
DebugConsole.NewMessage("Client \"" + sender.Name + "\" attempted to select a sub, index out of bounds (" + subIndex + ")", Color.Red);
DebugConsole.NewMessage("Client \"" + GameServer.ClientLogName(sender) + "\" attempted to select a sub, index out of bounds (" + subIndex + ")", Color.Red);
}
else
{
@@ -1153,7 +1200,7 @@ namespace Barotrauma.Networking
break;
case ClientPermissions.SelectMode:
UInt16 modeIndex = inc.ReadUInt16();
if (GameMain.NetLobbyScreen.GameModes[modeIndex].Identifier.ToLowerInvariant() == "multiplayercampaign")
if (GameMain.NetLobbyScreen.GameModes[modeIndex].Identifier.Equals("multiplayercampaign", StringComparison.OrdinalIgnoreCase))
{
string[] saveFiles = SaveUtil.GetSaveFiles(SaveUtil.SaveType.Multiplayer).ToArray();
for (int i = 0; i < saveFiles.Length; i++)
@@ -1220,12 +1267,12 @@ namespace Barotrauma.Networking
string logMsg;
if (permissionNames.Any())
{
logMsg = "Client \"" + sender.Name + "\" set the permissions of the client \"" + targetClient.Name + "\" to "
logMsg = "Client \"" + GameServer.ClientLogName(sender) + "\" set the permissions of the client \"" + GameServer.ClientLogName(targetClient) + "\" to "
+ string.Join(", ", permissionNames);
}
else
{
logMsg = "Client \"" + sender.Name + "\" removed all permissions from the client \"" + targetClient.Name + ".";
logMsg = "Client \"" + GameServer.ClientLogName(sender) + "\" removed all permissions from the client \"" + GameServer.ClientLogName(targetClient) + ".";
}
Log(logMsg, ServerLog.MessageType.ServerMessage);
@@ -1342,7 +1389,7 @@ namespace Barotrauma.Networking
{
//if docked to a sub with a smaller ID, don't send an update
// (= update is only sent for the docked sub that has the smallest ID, doesn't matter if it's the main sub or a shuttle)
if (sub.IsOutpost || sub.DockedTo.Any(s => s.ID < sub.ID)) continue;
if (sub.Info.IsOutpost || sub.DockedTo.Any(s => s.ID < sub.ID)) continue;
if (!c.PendingPositionUpdates.Contains(sub)) c.PendingPositionUpdates.Enqueue(sub);
}
@@ -1484,9 +1531,21 @@ namespace Barotrauma.Networking
outmsg.Write(client.Name);
outmsg.Write(client.Character == null || !gameStarted ? (client.PreferredJob ?? "") : "");
outmsg.Write(client.Character == null || !gameStarted ? (ushort)0 : client.Character.ID);
if (c.HasPermission(ClientPermissions.ServerLog))
{
outmsg.Write(client.Karma);
}
else
{
outmsg.Write(100.0f);
}
outmsg.Write(client.Muted);
outmsg.Write(client.InGame);
outmsg.Write(client.Connection != OwnerConnection); //is kicking the player allowed
outmsg.Write(client.Permissions != ClientPermissions.None);
outmsg.Write(client.Connection != OwnerConnection &&
!client.HasPermission(ClientPermissions.Ban) &&
!client.HasPermission(ClientPermissions.Kick) &&
!client.HasPermission(ClientPermissions.Unban)); //is kicking the player allowed
outmsg.WritePadBits();
}
}
@@ -1655,12 +1714,12 @@ namespace Barotrauma.Networking
Log("Starting a new round...", ServerLog.MessageType.ServerMessage);
Submarine selectedSub = null;
Submarine selectedShuttle = GameMain.NetLobbyScreen.SelectedShuttle;
SubmarineInfo selectedSub = null;
SubmarineInfo selectedShuttle = GameMain.NetLobbyScreen.SelectedShuttle;
if (serverSettings.Voting.AllowSubVoting)
{
selectedSub = serverSettings.Voting.HighestVoted<Submarine>(VoteType.Sub, connectedClients);
selectedSub = serverSettings.Voting.HighestVoted<SubmarineInfo>(VoteType.Sub, connectedClients);
if (selectedSub == null) selectedSub = GameMain.NetLobbyScreen.SelectedSub;
}
else
@@ -1692,7 +1751,7 @@ namespace Barotrauma.Networking
return true;
}
private IEnumerable<object> InitiateStartGame(Submarine selectedSub, Submarine selectedShuttle, bool usingShuttle, GameModePreset selectedMode)
private IEnumerable<object> InitiateStartGame(SubmarineInfo selectedSub, SubmarineInfo selectedShuttle, bool usingShuttle, GameModePreset selectedMode)
{
initiatedStartGame = true;
@@ -1740,7 +1799,7 @@ namespace Barotrauma.Networking
yield return CoroutineStatus.Success;
}
private IEnumerable<object> StartGame(Submarine selectedSub, Submarine selectedShuttle, bool usingShuttle, GameModePreset selectedMode)
private IEnumerable<object> StartGame(SubmarineInfo selectedSub, SubmarineInfo selectedShuttle, bool usingShuttle, GameModePreset selectedMode)
{
entityEventManager.Clear();
@@ -1805,12 +1864,11 @@ namespace Barotrauma.Networking
SendStartMessage(roundStartSeed, campaign.Map.SelectedConnection.Level.Seed, GameMain.GameSession, connectedClients, false);
GameMain.GameSession.StartRound(campaign.Map.SelectedConnection.Level,
reloadSub: true,
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
campaign.AssignClientCharacterInfos(connectedClients);
Log("Game mode: " + selectedMode.Name, ServerLog.MessageType.ServerMessage);
Log("Submarine: " + GameMain.GameSession.Submarine.Name, ServerLog.MessageType.ServerMessage);
Log("Submarine: " + GameMain.GameSession.SubmarineInfo.Name, ServerLog.MessageType.ServerMessage);
Log("Level seed: " + campaign.Map.SelectedConnection.Level.Seed, ServerLog.MessageType.ServerMessage);
}
else
@@ -1823,11 +1881,11 @@ namespace Barotrauma.Networking
Log("Level seed: " + GameMain.NetLobbyScreen.LevelSeed, ServerLog.MessageType.ServerMessage);
}
if (GameMain.GameSession.Submarine.IsFileCorrupted)
if (GameMain.GameSession.SubmarineInfo.IsFileCorrupted)
{
CoroutineManager.StopCoroutines(startGameCoroutine);
initiatedStartGame = false;
SendChatMessage(TextManager.FormatServerMessage($"SubLoadError~[subname]={GameMain.GameSession.Submarine.Name}"), ChatMessageType.Error);
SendChatMessage(TextManager.FormatServerMessage($"SubLoadError~[subname]={GameMain.GameSession.SubmarineInfo.Name}"), ChatMessageType.Error);
yield return CoroutineStatus.Failure;
}
@@ -1836,6 +1894,7 @@ namespace Barotrauma.Networking
if (serverSettings.AllowRespawn && missionAllowRespawn) { respawnManager = new RespawnManager(this, usingShuttle ? selectedShuttle : null); }
Level.Loaded?.SpawnCorpses();
AutoItemPlacer.PlaceIfNeeded(GameMain.GameSession.GameMode);
entityEventManager.RefreshEntityIDs();
@@ -1993,8 +2052,8 @@ namespace Barotrauma.Networking
msg.Write((byte)GameMain.NetLobbyScreen.MissionType);
msg.Write(gameSession.Submarine.Name);
msg.Write(gameSession.Submarine.MD5Hash.Hash);
msg.Write(gameSession.SubmarineInfo.Name);
msg.Write(gameSession.SubmarineInfo.MD5Hash.Hash);
msg.Write(serverSettings.UseRespawnShuttle);
msg.Write(GameMain.NetLobbyScreen.SelectedShuttle.Name);
msg.Write(GameMain.NetLobbyScreen.SelectedShuttle.MD5Hash.Hash);
@@ -2139,7 +2198,16 @@ namespace Barotrauma.Networking
public override void AddChatMessage(ChatMessage message)
{
if (string.IsNullOrEmpty(message.Text)) { return; }
Log(message.TextWithSender, ServerLog.MessageType.Chat);
string logMsg;
if (message.SenderClient != null)
{
logMsg = GameServer.ClientLogName(message.SenderClient) + ": " + message.TranslatedText;
}
else
{
logMsg = message.TextWithSender;
}
Log(logMsg, ServerLog.MessageType.Chat);
base.AddChatMessage(message);
}
@@ -2192,11 +2260,9 @@ namespace Barotrauma.Networking
public override void KickPlayer(string playerName, string reason)
{
playerName = playerName.ToLowerInvariant();
Client client = connectedClients.Find(c =>
c.Name.ToLowerInvariant() == playerName ||
(c.Character != null && c.Character.Name.ToLowerInvariant() == playerName));
c.Name.Equals(playerName, StringComparison.OrdinalIgnoreCase) ||
(c.Character != null && c.Character.Name.Equals(playerName, StringComparison.OrdinalIgnoreCase)));
KickClient(client, reason);
}
@@ -2225,16 +2291,14 @@ namespace Barotrauma.Networking
string msg = DisconnectReason.Kicked.ToString();
string logMsg = $"ServerMessage.KickedFromServer~[client]={client.Name}";
DisconnectClient(client, logMsg, msg, reason);
DisconnectClient(client, logMsg, msg, reason, PlayerConnectionChangeType.Kicked);
}
public override void BanPlayer(string playerName, string reason, bool range = false, TimeSpan? duration = null)
{
playerName = playerName.ToLowerInvariant();
Client client = connectedClients.Find(c =>
c.Name.ToLowerInvariant() == playerName ||
(c.Character != null && c.Character.Name.ToLowerInvariant() == playerName));
c.Name.Equals(playerName, StringComparison.OrdinalIgnoreCase) ||
(c.Character != null && c.Character.Name.Equals(playerName, StringComparison.OrdinalIgnoreCase)));
if (client == null)
{
@@ -2258,7 +2322,7 @@ namespace Barotrauma.Networking
client.Karma = Math.Max(client.Karma, 50.0f);
string targetMsg = DisconnectReason.Banned.ToString();
DisconnectClient(client, $"ServerMessage.BannedFromServer~[client]={client.Name}", targetMsg, reason);
DisconnectClient(client, $"ServerMessage.BannedFromServer~[client]={client.Name}", targetMsg, reason, PlayerConnectionChangeType.Banned);
if (client.SteamID == 0 || range)
{
@@ -2302,10 +2366,10 @@ namespace Barotrauma.Networking
Client client = connectedClients.Find(x => x.Connection == senderConnection);
if (client == null) return;
DisconnectClient(client, msg, targetmsg, string.Empty);
DisconnectClient(client, msg, targetmsg, string.Empty, PlayerConnectionChangeType.Disconnected);
}
public void DisconnectClient(Client client, string msg = "", string targetmsg = "", string reason = "")
public void DisconnectClient(Client client, string msg = "", string targetmsg = "", string reason = "", PlayerConnectionChangeType changeType = PlayerConnectionChangeType.Disconnected)
{
if (client == null) return;
@@ -2352,7 +2416,7 @@ namespace Barotrauma.Networking
UpdateVoteStatus();
SendChatMessage(msg, ChatMessageType.Server);
SendChatMessage(msg, ChatMessageType.Server, changeType: changeType);
UpdateCrewFrame();
@@ -2401,7 +2465,7 @@ namespace Barotrauma.Networking
/// <summary>
/// Add the message to the chatbox and pass it to all clients who can receive it
/// </summary>
public void SendChatMessage(string message, ChatMessageType? type = null, Client senderClient = null, Character senderCharacter = null)
public void SendChatMessage(string message, ChatMessageType? type = null, Client senderClient = null, Character senderCharacter = null, PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None)
{
string senderName = "";
@@ -2486,17 +2550,20 @@ namespace Barotrauma.Networking
senderCharacter = senderClient.Character;
senderName = senderCharacter == null ? senderClient.Name : senderCharacter.Name;
if (type == ChatMessageType.Private)
{
if (senderCharacter != null && !senderCharacter.IsDead || targetClient.Character != null && !targetClient.Character.IsDead)
{
//sender or target has an alive character, sending private messages not allowed
SendDirectChatMessage(ChatMessage.Create("", $"ServerMessage.PrivateMessagesNotAllowed", ChatMessageType.Error, null), senderClient);
return;
}
}
//sender doesn't have a character or the character can't speak -> only ChatMessageType.Dead allowed
if (senderCharacter == null || senderCharacter.IsDead || senderCharacter.SpeechImpediment >= 100.0f)
else if (senderCharacter == null || senderCharacter.IsDead || senderCharacter.SpeechImpediment >= 100.0f)
{
type = ChatMessageType.Dead;
}
else if (type == ChatMessageType.Private)
{
//sender has an alive character, sending private messages not allowed
return;
}
}
}
else
@@ -2592,7 +2659,9 @@ namespace Barotrauma.Networking
senderName,
modifiedMessage,
(ChatMessageType)type,
senderCharacter);
senderCharacter,
senderClient,
changeType);
SendDirectChatMessage(chatMsg, client);
}
@@ -2663,6 +2732,9 @@ namespace Barotrauma.Networking
var clientsToKick = connectedClients.FindAll(c =>
c.Connection != OwnerConnection &&
!c.HasPermission(ClientPermissions.Kick) &&
!c.HasPermission(ClientPermissions.Ban) &&
!c.HasPermission(ClientPermissions.Unban) &&
c.KickVoteCount >= connectedClients.Count * serverSettings.KickVoteRequiredRatio);
foreach (Client c in clientsToKick)
{
@@ -2673,7 +2745,7 @@ namespace Barotrauma.Networking
previousPlayer.KickVoters.Clear();
}
SendChatMessage($"ServerMessage.KickedFromServer~[client]={c.Name}", ChatMessageType.Server, null);
SendChatMessage($"ServerMessage.KickedFromServer~[client]={c.Name}", ChatMessageType.Server, null, changeType: PlayerConnectionChangeType.Kicked);
KickClient(c, "ServerMessage.KickedByVote");
BanClient(c, "ServerMessage.KickedByVoteAutoBan", duration: TimeSpan.FromSeconds(serverSettings.AutoBanTime));
}
@@ -2857,6 +2929,11 @@ namespace Barotrauma.Networking
{
newCharacter.LastNetworkUpdateID = client.Character.LastNetworkUpdateID;
}
if (newCharacter.Info != null && newCharacter.Info.Character == null)
{
newCharacter.Info.Character = newCharacter;
}
newCharacter.OwnerClientEndPoint = client.Connection.EndPointString;
newCharacter.OwnerClientName = client.Name;
@@ -3203,6 +3280,25 @@ namespace Barotrauma.Networking
}
}
public static string ClientLogName(Client client, string name = null)
{
if (client == null) { return name; }
string retVal = "‖";
if (client.Karma < 40.0f)
{
retVal += "color:#ff9900;";
}
retVal += "metadata:" + (client.SteamID!=0 ? client.SteamID.ToString() : client.ID.ToString()) + "‖" + (name ?? client.Name) + "‖end‖";
return retVal;
}
public static string CharacterLogName(Character character)
{
if (character == null) { return "[NULL]"; }
Client client = GameMain.Server.ConnectedClients.Find(c => c.Character == character);
return ClientLogName(client, character.LogName);
}
public static void Log(string line, ServerLog.MessageType messageType)
{
if (GameMain.Server == null || !GameMain.Server.ServerSettings.SaveServerLogs) return;
@@ -3,6 +3,7 @@ using Barotrauma.Networking;
using System;
using System.Collections.Generic;
using System.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
{
@@ -12,8 +13,18 @@ namespace Barotrauma
{
public List<Pair<Wire, float>> WireDisconnectTime = new List<Pair<Wire, float>>();
public struct TimeAmount
{
public double Time;
public float Amount;
}
public List<TimeAmount> KarmaDecreasesInPastMinute = new List<TimeAmount>();
public float PreviousNotifiedKarma;
public double PreviousKarmaNotificationTime;
public float StructureDamageAccumulator;
private float structureDamagePerSecond;
@@ -23,6 +34,9 @@ namespace Barotrauma
set { structureDamagePerSecond = value; }
}
public List<TimeAmount> StunsInPastMinute = new List<TimeAmount>();
public float StunKarmaDecreaseMultiplier;
//when did a given character last attack this one
public Dictionary<Character, double> LastAttackTime
{
@@ -53,6 +67,13 @@ namespace Barotrauma
clientMemory.StructureDamagePerSecond = clientMemory.StructureDamageAccumulator;
clientMemory.StructureDamageAccumulator = 0.0f;
clientMemory.StunsInPastMinute.RemoveAll(s => s.Time + 60.0f < Timing.TotalTime);
if (!clientMemory.StunsInPastMinute.Any())
{
clientMemory.StunKarmaDecreaseMultiplier = 1.0f;
}
var toRemove = clientMemory.LastAttackTime.Where(pair => pair.Value < Timing.TotalTime - AllowedRetaliationTime).Select(pair => pair.Key).ToList();
foreach (var lastAttacker in toRemove)
{
@@ -89,28 +110,26 @@ namespace Barotrauma
var clientMemory = GetClientMemory(client);
float karmaChange = client.Karma - clientMemory.PreviousNotifiedKarma;
if (Math.Abs(karmaChange) > 1.0f &&
(TestMode || Math.Abs(karmaChange) / clientMemory.PreviousNotifiedKarma > KarmaNotificationInterval / 100.0f))
if (Math.Abs(karmaChange) > 1.0f && TestMode)
{
if (TestMode)
string msg =
karmaChange < 0 ? $"Your karma has decreased to {client.Karma}" : $"Your karma has increased to {client.Karma}";
if (!string.IsNullOrEmpty(debugKarmaChangeReason))
{
string msg =
karmaChange < 0 ? $"Your karma has decreased to {client.Karma}" : $"Your karma has increased to {client.Karma}";
if (!string.IsNullOrEmpty(debugKarmaChangeReason))
{
msg += $". Reason: {debugKarmaChangeReason}";
}
GameMain.Server.SendDirectChatMessage(msg, client);
msg += $". Reason: {debugKarmaChangeReason}";
}
else if (Math.Abs(KickBanThreshold - client.Karma) < KarmaNotificationInterval)
{
GameMain.Server.SendDirectChatMessage(TextManager.Get("KarmaBanWarning"), client);
}
else
{
GameMain.Server.SendDirectChatMessage(TextManager.Get(karmaChange < 0 ? "KarmaDecreasedUnknownAmount" : "KarmaIncreasedUnknownAmount"), client);
}
clientMemory.PreviousNotifiedKarma = client.Karma;
GameMain.Server.SendDirectChatMessage(msg, client);
clientMemory.PreviousNotifiedKarma = client.Karma;
clientMemory.PreviousKarmaNotificationTime = Timing.TotalTime;
}
else if (Timing.TotalTime >= clientMemory.PreviousKarmaNotificationTime + 5.0f &&
clientMemory.PreviousNotifiedKarma >= KickBanThreshold + KarmaNotificationInterval &&
client.Karma < KickBanThreshold + KarmaNotificationInterval)
{
GameMain.Server.SendDirectChatMessage(TextManager.Get("KarmaBanWarning"), client);
GameServer.Log(GameServer.ClientLogName(client) + " has been warned for having dangerously low karma.", ServerLog.MessageType.Karma);
clientMemory.PreviousNotifiedKarma = client.Karma;
clientMemory.PreviousKarmaNotificationTime = Timing.TotalTime;
}
}
@@ -130,10 +149,10 @@ namespace Barotrauma
//increase the strength of the herpes affliction in steps instead of linearly
//otherwise clients could determine their exact karma value from the strength
float herpesStrength = 0.0f;
if (client.Karma < 20)
herpesStrength = 100.0f;
else if (client.Karma < 30)
herpesStrength = 60.0f;
if (client.Karma < 20)
herpesStrength = 100.0f;
else if (client.Karma < 30)
herpesStrength = 60.0f;
else if (client.Karma < 40.0f)
herpesStrength = 30.0f;
@@ -141,6 +160,8 @@ namespace Barotrauma
if (existingAffliction == null && herpesStrength > 0.0f)
{
client.Character.CharacterHealth.ApplyAffliction(null, new Affliction(herpesAffliction, herpesStrength));
GameServer.Log($"{GameServer.ClientLogName(client)} has contracted space herpes due to low karma.", ServerLog.MessageType.Karma);
GameMain.NetworkMember.LastClientListUpdateID++;
}
else if (existingAffliction != null)
{
@@ -205,7 +226,84 @@ namespace Barotrauma
clientMemories.Remove(client);
}
public void OnCharacterHealthChanged(Character target, Character attacker, float damage, IEnumerable<Affliction> appliedAfflictions = null)
// ReSharper disable once UseNegatedPatternMatching, LoopCanBeConvertedToQuery
public void OnItemTakenFromPlayer(CharacterInventory inventory, Client yoinker, Item item)
{
Client targetClient = GameMain.Server.ConnectedClients.Find(c => c.Character == inventory.Owner);
Character yoinkerCharacter = yoinker?.Character;
Character targetCharacter = inventory.Owner as Character;
if (yoinker == null || item == null || yoinkerCharacter == null || targetCharacter == null || yoinkerCharacter == targetCharacter) { return; }
if (targetClient == null && (!DangerousItemStealBots || targetCharacter.AIController == null)) { return; }
// Only if the target is alive and they are stunned, unconscious or handcuffed
if (targetCharacter.IsDead || targetCharacter.Removed || !(targetCharacter.Stun > 0) && !targetCharacter.IsUnconscious && !targetCharacter.LockHands) { return; }
if (GameMain.Server.TraitorManager?.Traitors != null)
{
if (GameMain.Server.TraitorManager.Traitors.Any(t => t.Character == targetCharacter || t.Character == yoinkerCharacter))
{
// Don't penalize traitors
return;
}
}
var foundItem = Inventory.FindItemRecursive(item, it => it.Prefab.Identifier == "idcard" || it.GetComponent<RangedWeapon>() != null || it.GetComponent<MeleeWeapon>() != null);
if (foundItem == null) { return; }
bool isIdCard = foundItem.prefab.Identifier == "idcard";
bool isWeapon = foundItem.GetComponent<RangedWeapon>() != null || foundItem.GetComponent<MeleeWeapon>() != null;
if (isIdCard)
{
string name = string.Empty;
foreach (var tag in foundItem.Tags.Split(','))
{
string[] split = tag.Split(':');
string key = split.Length > 0 ? split[0] : string.Empty;
string value = split.Length > 1 ? split[1] : string.Empty;
if (key == "name") { name = value; }
}
// Name tag doesn't belong to anyone in particular or we own the ID card
if (name == null || name == yoinkerCharacter.Name) { return; }
}
if (MathUtils.NearlyEqual(DangerousItemStealKarmaDecrease, 0)) { return; }
const float calcUpper = 1, calcLower = -1;
float upper = DangerousItemStealKarmaDecrease + 10.0f;
float lower = DangerousItemStealKarmaDecrease - 10.0f;
if (lower < 0)
{
upper += Math.Abs(lower);
lower = 0;
}
// If we're stealing from a bot assume the bot has 50 karma
var targetKarma = targetClient?.Karma ?? 50;
float karmaDifference = Math.Clamp((targetKarma - yoinker.Karma) / 50.0f, calcLower, calcUpper);
float karmaDecrease = lower + (karmaDifference - calcLower) * (upper - lower) / (calcUpper - calcLower);
JobPrefab clientJob = yoinker.CharacterInfo?.Job?.Prefab;
// security officers receive less karma penalty
if (clientJob != null && clientJob.Identifier == "securityofficer" && isWeapon)
{
karmaDecrease *= 0.5f;
}
AdjustKarma(yoinkerCharacter, -karmaDecrease, "Stolen dangerous item");
}
public void OnCharacterHealthChanged(Character target, Character attacker, float damage, float stun, IEnumerable<Affliction> appliedAfflictions = null)
{
if (target == null || attacker == null) { return; }
if (target == attacker) { return; }
@@ -238,11 +336,11 @@ namespace Barotrauma
if (appliedAfflictions != null)
{
foreach (Affliction affliction in appliedAfflictions)
{
if (MathUtils.NearlyEqual(affliction.Prefab.KarmaChangeOnApplied, 0.0f)) { continue; }
damage -= affliction.Prefab.KarmaChangeOnApplied * affliction.Strength;
}
foreach (Affliction affliction in appliedAfflictions)
{
if (MathUtils.NearlyEqual(affliction.Prefab.KarmaChangeOnApplied, 0.0f)) { continue; }
damage -= affliction.Prefab.KarmaChangeOnApplied * affliction.Strength;
}
}
Client targetClient = GameMain.Server.ConnectedClients.Find(c => c.Character == target);
@@ -253,15 +351,16 @@ namespace Barotrauma
}
Client attackerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == attacker);
if (attackerClient != null)
ClientMemory attackerMemory = GetClientMemory(attackerClient);
if (attackerMemory != null)
{
//if the attacker has been attacked by the target within the last x seconds, ignore the damage
//(= no karma penalty from retaliating against someone who attacked you)
var attackerMemory = GetClientMemory(attackerClient);
if (attackerMemory.LastAttackTime.ContainsKey(target) &&
attackerMemory.LastAttackTime[target] > Timing.TotalTime - AllowedRetaliationTime)
{
damage = Math.Min(damage, 0);
stun = 0.0f;
}
}
@@ -270,6 +369,7 @@ namespace Barotrauma
target.HasEquippedItem("clowncostume"))
{
damage *= 0.5f;
stun *= 0.5f;
}
//smaller karma penalty for attacking someone who's aiming with a weapon
@@ -278,6 +378,7 @@ namespace Barotrauma
target.SelectedItems.Any(it => it != null && (it.GetComponent<MeleeWeapon>() != null || it.GetComponent<RangedWeapon>() != null)))
{
damage *= 0.5f;
stun *= 0.5f;
}
//damage scales according to the karma of the target
@@ -298,6 +399,30 @@ namespace Barotrauma
}
else
{
if (stun > 0 && attackerMemory != null)
{
//GameServer.Log(GameServer.CharacterLogName(attacker) + " stunned " + GameServer.CharacterLogName(target) + $" ({stun})", ServerLog.MessageType.Karma);
attackerMemory.StunsInPastMinute.Add(new ClientMemory.TimeAmount() { Time = Timing.TotalTime, Amount = stun });
if (attackerMemory.StunsInPastMinute.Count > 1)
{
float avgStunsInflicted = attackerMemory.StunsInPastMinute[0].Amount / (float)(attackerMemory.StunsInPastMinute[1].Time - attackerMemory.StunsInPastMinute[0].Time);
for (int i = 1; i < attackerMemory.StunsInPastMinute.Count; i++)
{
avgStunsInflicted += attackerMemory.StunsInPastMinute[i].Amount / (float)(attackerMemory.StunsInPastMinute[i].Time - attackerMemory.StunsInPastMinute[i - 1].Time);
}
//GameServer.Log(avgStunsInflicted.ToString(), ServerLog.MessageType.Karma);
if (avgStunsInflicted > StunFriendlyKarmaDecreaseThreshold ||
attackerMemory.StunKarmaDecreaseMultiplier > 1.0f)
{
AdjustKarma(attacker, -StunFriendlyKarmaDecrease * attackerMemory.StunKarmaDecreaseMultiplier, "Stunned friendly");
attackerMemory.StunKarmaDecreaseMultiplier *= 2.0f;
}
}
}
if (damage > 0)
{
AdjustKarma(attacker, -damage * DamageFriendlyKarmaDecrease, "Damaged friendly");
@@ -395,6 +520,7 @@ namespace Barotrauma
private ClientMemory GetClientMemory(Client client)
{
if (client == null) { return null; }
if (!clientMemories.ContainsKey(client))
{
clientMemories[client] = new ClientMemory()
@@ -429,6 +555,21 @@ namespace Barotrauma
}
client.Karma += amount;
if (amount < 0.0f)
{
float? herpesStrength = client.Character?.CharacterHealth.GetAfflictionStrength("spaceherpes");
var clientMemory = GetClientMemory(client);
clientMemory.KarmaDecreasesInPastMinute.RemoveAll(ta => ta.Time + 60.0f < Timing.TotalTime);
float aggregate = clientMemory.KarmaDecreasesInPastMinute.Select(ta => ta.Amount).DefaultIfEmpty().Aggregate((a, b) => a + b);
clientMemory.KarmaDecreasesInPastMinute.Add(new ClientMemory.TimeAmount() { Time = Timing.TotalTime, Amount = -amount });
if (herpesStrength.HasValue && herpesStrength <= 0.0f && aggregate - amount > 25.0f && aggregate <= 25.0f)
{
GameServer.Log($"{GameServer.ClientLogName(client)} has lost more than 25 karma in the past minute.", ServerLog.MessageType.Karma);
}
}
if (TestMode)
{
SendKarmaNotifications(client, debugKarmaChangeReason);
@@ -138,7 +138,12 @@ namespace Barotrauma.Networking
//remove old events that have been sent to all clients, they are redundant now
// keep at least one event in the list (lastSentToAll == e.ID) so we can use it to keep track of the latest ID
// and events less than 15 seconds old to give disconnected clients a bit of time to reconnect without getting desynced
events.RemoveAll(e => (NetIdUtils.IdMoreRecent(lastSentToAll, e.ID) || !inGameClientsPresent) && e.CreateTime < Timing.TotalTime - 15.0f);
if (Timing.TotalTime > GameMain.GameSession.RoundStartTime + NetConfig.RoundStartSyncDuration)
{
events.RemoveAll(e =>
(NetIdUtils.IdMoreRecent(lastSentToAll, e.ID) || !inGameClientsPresent) &&
e.CreateTime < Timing.TotalTime - NetConfig.EventRemovalTime);
}
for (int i = events.Count - 1; i >= 0; i--)
{
@@ -175,7 +180,7 @@ namespace Barotrauma.Networking
//UNLESS the character is unconscious, in which case we'll read the messages immediately (because further inputs will be ignored)
//atm the "give in" command is the only thing unconscious characters can do, other types of events are ignored
if (!bufferedEvent.Character.IsUnconscious &&
if (!bufferedEvent.Character.IsIncapacitated &&
NetIdUtils.IdMoreRecent(bufferedEvent.CharacterStateID, bufferedEvent.Character.LastProcessedID))
{
continue;
@@ -224,7 +229,9 @@ namespace Barotrauma.Networking
});
lastSentToAnyoneTime = events.Find(e => e.ID == lastSentToAnyone)?.CreateTime ?? Timing.TotalTime;
if ((Timing.TotalTime - lastSentToAnyoneTime) > 10.0 && (Timing.TotalTime - lastWarningTime) > 5.0)
if (Timing.TotalTime - lastWarningTime > 5.0 &&
Timing.TotalTime - lastSentToAnyoneTime > 10.0 &&
Timing.TotalTime > GameMain.GameSession.RoundStartTime + NetConfig.RoundStartSyncDuration)
{
lastWarningTime = Timing.TotalTime;
GameServer.Log("WARNING: ServerEntityEventManager is lagging behind! Last sent id: " + lastSentToAnyone.ToString() + ", latest create id: " + ID.ToString(), ServerLog.MessageType.ServerMessage);
@@ -235,19 +242,21 @@ namespace Barotrauma.Networking
clients.Where(c => c.NeedsMidRoundSync).ForEach(c => { if (NetIdUtils.IdMoreRecent(lastSentToAll, c.FirstNewEventID)) lastSentToAll = (ushort)(c.FirstNewEventID - 1); });
ServerEntityEvent firstEventToResend = events.Find(e => e.ID == (ushort)(lastSentToAll + 1));
if (firstEventToResend != null && ((lastSentToAnyoneTime - firstEventToResend.CreateTime) > 10.0 || (Timing.TotalTime - firstEventToResend.CreateTime) > 30.0))
if (firstEventToResend != null &&
Timing.TotalTime > GameMain.GameSession.RoundStartTime + NetConfig.RoundStartSyncDuration &&
((lastSentToAnyoneTime - firstEventToResend.CreateTime) > NetConfig.OldReceivedEventKickTime || (Timing.TotalTime - firstEventToResend.CreateTime) > NetConfig.OldEventKickTime))
{
// This event is 10 seconds older than the last one we've successfully sent,
// kick everyone that hasn't received it yet, this is way too old
// UNLESS the event was created when the client was still midround syncing,
// in which case we'll wait until the timeout runs out before kicking the client
List<Client> toKick = inGameClients.FindAll(c =>
NetIdUtils.IdMoreRecent((UInt16)(lastSentToAll + 1), c.LastRecvEntityEventID) &&
NetIdUtils.IdMoreRecent((UInt16)(lastSentToAll + 1), c.LastRecvEntityEventID) &&
(firstEventToResend.CreateTime > c.MidRoundSyncTimeOut || lastSentToAnyoneTime > c.MidRoundSyncTimeOut || Timing.TotalTime > c.MidRoundSyncTimeOut + 10.0));
toKick.ForEach(c =>
{
DebugConsole.NewMessage(c.Name + " was kicked due to excessive desync (expected old event " + (c.LastRecvEntityEventID + 1).ToString() + ")", Color.Red);
GameServer.Log("Disconnecting client " + c.Name + " due to excessive desync (expected old event "
GameServer.Log("Disconnecting client " + GameServer.ClientLogName(c) + " due to excessive desync (expected old event "
+ (c.LastRecvEntityEventID + 1).ToString() +
" (created " + (Timing.TotalTime - firstEventToResend.CreateTime).ToString("0.##") + " s ago, " +
(lastSentToAnyoneTime - firstEventToResend.CreateTime).ToString("0.##") + " s older than last event sent to anyone)" +
@@ -265,7 +274,7 @@ namespace Barotrauma.Networking
toKick.ForEach(c =>
{
DebugConsole.NewMessage(c.Name + " was kicked due to excessive desync (expected removed event " + (c.LastRecvEntityEventID + 1).ToString() + ", last available is " + events[0].ID.ToString() + ")", Color.Red);
GameServer.Log("Disconnecting client " + c.Name + " due to excessive desync (expected removed event " + (c.LastRecvEntityEventID + 1).ToString() + ", last available is " + events[0].ID.ToString() + ")", ServerLog.MessageType.Error);
GameServer.Log("Disconnecting client " + GameServer.ClientLogName(c) + " due to excessive desync (expected removed event " + (c.LastRecvEntityEventID + 1).ToString() + ", last available is " + events[0].ID.ToString() + ")", ServerLog.MessageType.Error);
server.DisconnectClient(c, "", DisconnectReason.ExcessiveDesyncRemovedEvent + "/ServerMessage.ExcessiveDesyncRemovedEvent");
});
}
@@ -274,7 +283,7 @@ namespace Barotrauma.Networking
var timedOutClients = clients.FindAll(c => c.Connection != GameMain.Server.OwnerConnection && c.InGame && c.NeedsMidRoundSync && Timing.TotalTime > c.MidRoundSyncTimeOut);
foreach (Client timedOutClient in timedOutClients)
{
GameServer.Log("Disconnecting client " + timedOutClient.Name + ". Syncing the client with the server took too long.", ServerLog.MessageType.Error);
GameServer.Log("Disconnecting client " + GameServer.ClientLogName(timedOutClient) + ". Syncing the client with the server took too long.", ServerLog.MessageType.Error);
GameMain.Server.DisconnectClient(timedOutClient, "", DisconnectReason.SyncTimeout + "/ServerMessage.SyncTimeout");
}
@@ -419,12 +419,12 @@ namespace Barotrauma.Networking
//steam auth cannot be done (SteamManager not initialized or no ticket given),
//but it's not required either -> let the client join without auth
if ((!Steam.SteamManager.IsInitialized || (ticket?.Length??0) == 0) &&
if ((!Steam.SteamManager.IsInitialized || (ticket?.Length ?? 0) == 0) &&
!requireSteamAuth)
{
pendingClient.Name = name;
pendingClient.OwnerKey = ownKey;
pendingClient.InitializationStep = ConnectionInitialization.ContentPackageOrder;
pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.ContentPackageOrder;
}
else
{
@@ -258,6 +258,9 @@ namespace Barotrauma.Networking
{
bool bot = i >= clients.Count;
characterInfos[i].CurrentOrder = null;
characterInfos[i].CurrentOrderOption = null;
var character = Character.Create(characterInfos[i], shuttleSpawnPoints[i].WorldPosition, characterInfos[i].Name, !bot, bot);
character.TeamID = Character.TeamType.Team1;
@@ -279,7 +282,7 @@ namespace Barotrauma.Networking
clients[i].Character = character;
character.OwnerClientEndPoint = clients[i].Connection.EndPointString;
character.OwnerClientName = clients[i].Name;
GameServer.Log(string.Format("Respawning {0} ({1}) as {2}", clients[i].Name, clients[i].Connection?.EndPointString, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning);
GameServer.Log(string.Format("Respawning {0} ({1}) as {2}", GameServer.ClientLogName(clients[i]), clients[i].Connection?.EndPointString, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning);
}
if (divingSuitPrefab != null && oxyPrefab != null && RespawnShuttle != null)
@@ -108,7 +108,7 @@ namespace Barotrauma.Networking
netProperties[key].Read(incMsg);
if (!netProperties[key].PropEquals(prevValue, netProperties[key]))
{
GameServer.Log(c.Name + " changed " + netProperties[key].Name + " to " + netProperties[key].Value.ToString(), ServerLog.MessageType.ServerMessage);
GameServer.Log(GameServer.ClientLogName(c) + " changed " + netProperties[key].Name + " to " + netProperties[key].Value.ToString(), ServerLog.MessageType.ServerMessage);
}
changed = true;
}
@@ -367,7 +367,7 @@ namespace Barotrauma.Networking
if (clientElement.Attribute("preset") == null)
{
string permissionsStr = clientElement.GetAttributeString("permissions", "");
if (permissionsStr.ToLowerInvariant() == "all")
if (permissionsStr.Equals("all", StringComparison.OrdinalIgnoreCase))
{
foreach (ClientPermissions permission in Enum.GetValues(typeof(ClientPermissions)))
{
@@ -384,7 +384,7 @@ namespace Barotrauma.Networking
{
foreach (XElement commandElement in clientElement.Elements())
{
if (commandElement.Name.ToString().ToLowerInvariant() != "command") continue;
if (!commandElement.Name.ToString().Equals("command", StringComparison.OrdinalIgnoreCase)) { continue; }
string commandName = commandElement.GetAttributeString("name", "");
DebugConsole.Command command = DebugConsole.FindCommand(commandName);
@@ -89,7 +89,8 @@ namespace Barotrauma.Networking
if (sender.Character != null && sender.Character.SpeechImpediment >= 100.0f) { return false; }
//check if the message can be sent via radio
if (ChatMessage.CanUseRadio(sender.Character, out WifiComponent senderRadio) &&
if (!sender.VoipQueue.ForceLocal &&
ChatMessage.CanUseRadio(sender.Character, out WifiComponent senderRadio) &&
ChatMessage.CanUseRadio(recipient.Character, out WifiComponent recipientRadio))
{
if (recipientRadio.CanReceive(senderRadio)) { return true; }
@@ -38,7 +38,7 @@ namespace Barotrauma
{
case VoteType.Sub:
string subName = inc.ReadString();
Submarine sub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == subName);
SubmarineInfo sub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName);
sender.SetVote(voteType, sub);
break;
@@ -74,7 +74,7 @@ namespace Barotrauma
if (ready != sender.GetVote<bool>(VoteType.StartRound))
{
sender.SetVote(VoteType.StartRound, ready);
GameServer.Log(sender.Name + (ready ? " is ready to start the game." : " is not ready to start the game."), ServerLog.MessageType.ServerMessage);
GameServer.Log(GameServer.ClientLogName(sender) + (ready ? " is ready to start the game." : " is not ready to start the game."), ServerLog.MessageType.ServerMessage);
}
break;
@@ -97,7 +97,7 @@ namespace Barotrauma
foreach (Pair<object, int> vote in voteList)
{
msg.Write((byte)vote.Second);
msg.Write(((Submarine)vote.First).Name);
msg.Write(((SubmarineInfo)vote.First).Name);
}
}
msg.Write(AllowModeVoting);
@@ -181,7 +181,7 @@ namespace Barotrauma.Networking
WhiteListedPlayer whitelistedPlayer = whitelistedPlayers.Find(p => p.UniqueIdentifier == id);
if (whitelistedPlayer != null)
{
GameServer.Log(c.Name + " removed " + whitelistedPlayer.Name + " from whitelist (" + whitelistedPlayer.IP + ")", ServerLog.MessageType.ConsoleUsage);
GameServer.Log(GameServer.ClientLogName(c) + " removed " + whitelistedPlayer.Name + " from whitelist (" + whitelistedPlayer.IP + ")", ServerLog.MessageType.ConsoleUsage);
RemoveFromWhiteList(whitelistedPlayer);
}
}
@@ -192,7 +192,7 @@ namespace Barotrauma.Networking
string name = incMsg.ReadString();
string ip = incMsg.ReadString();
GameServer.Log(c.Name + " added " + name + " to whitelist (" + ip + ")", ServerLog.MessageType.ConsoleUsage);
GameServer.Log(GameServer.ClientLogName(c) + " added " + name + " to whitelist (" + ip + ")", ServerLog.MessageType.ConsoleUsage);
AddToWhiteList(name, ip);
}
@@ -36,6 +36,7 @@ namespace Barotrauma
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(CrashHandler);
#endif
#if LINUX
setLinuxEnv();
#endif
@@ -97,7 +98,7 @@ namespace Barotrauma
sb.AppendLine("Selected content packages: " + (!GameMain.SelectedPackages.Any() ? "None" : string.Join(", ", GameMain.SelectedPackages.Select(c => c.Name))));
}
sb.AppendLine("Level seed: " + ((Level.Loaded == null) ? "no level loaded" : Level.Loaded.Seed));
sb.AppendLine("Loaded submarine: " + ((Submarine.MainSub == null) ? "None" : Submarine.MainSub.Name + " (" + Submarine.MainSub.MD5Hash + ")"));
sb.AppendLine("Loaded submarine: " + ((Submarine.MainSub == null) ? "None" : Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash + ")"));
sb.AppendLine("Selected screen: " + (Screen.Selected == null ? "None" : Screen.Selected.ToString()));
if (GameMain.Server != null)
@@ -8,10 +8,10 @@ namespace Barotrauma
{
partial class NetLobbyScreen : Screen
{
private Submarine selectedSub;
private Submarine selectedShuttle;
private SubmarineInfo selectedSub;
private SubmarineInfo selectedShuttle;
public Submarine SelectedSub
public SubmarineInfo SelectedSub
{
get { return selectedSub; }
set
@@ -24,7 +24,7 @@ namespace Barotrauma
}
}
}
public Submarine SelectedShuttle
public SubmarineInfo SelectedShuttle
{
get { return selectedShuttle; }
set { selectedShuttle = value; lastUpdateID++; }
@@ -121,7 +121,7 @@ namespace Barotrauma
{
LevelSeed = ToolBox.RandomSeed(8);
subs = Submarine.SavedSubmarines.Where(s => !s.HasTag(SubmarineTag.HideInMenus)).ToList();
subs = SubmarineInfo.SavedSubmarines.Where(s => !s.HasTag(SubmarineTag.HideInMenus)).ToList();
if (subs == null || subs.Count() == 0)
{
@@ -150,8 +150,8 @@ namespace Barotrauma
GameModes = GameModePreset.List.ToArray();
}
private List<Submarine> subs;
public List<Submarine> GetSubList()
private List<SubmarineInfo> subs;
public List<SubmarineInfo> GetSubList()
{
return subs;
}
@@ -198,7 +198,7 @@ namespace Barotrauma
if (GameMain.Server.ServerSettings.SubSelectionMode == SelectionMode.Random)
{
var nonShuttles = Submarine.SavedSubmarines.Where(c => !c.HasTag(SubmarineTag.Shuttle) && !c.HasTag(SubmarineTag.HideInMenus)).ToList();
var nonShuttles = SubmarineInfo.SavedSubmarines.Where(c => !c.HasTag(SubmarineTag.Shuttle) && !c.HasTag(SubmarineTag.HideInMenus)).ToList();
SelectedSub = nonShuttles[Rand.Range(0, nonShuttles.Count)];
}
if (GameMain.Server.ServerSettings.ModeSelectionMode == SelectionMode.Random)
@@ -67,7 +67,7 @@ namespace Barotrauma
{
continue;
}
if (character.SpeciesName.ToLowerInvariant() == entities[activeEntityIndex] && Vector2.Distance(activeEntitySavedPosition, character.WorldPosition) < graceDistance)
if (character.SpeciesName.Equals(entities[activeEntityIndex], StringComparison.OrdinalIgnoreCase) && Vector2.Distance(activeEntitySavedPosition, character.WorldPosition) < graceDistance)
{
activeEntity = character;
transformationTime = 0.0;
@@ -117,7 +117,7 @@ namespace Barotrauma
{
continue;
}
if (character.SpeciesName.ToLowerInvariant() == entities[activeEntityIndex].ToLowerInvariant())
if (character.SpeciesName.Equals(entities[activeEntityIndex], StringComparison.OrdinalIgnoreCase))
{
activeEntity = character;
break;
@@ -131,7 +131,7 @@ namespace Barotrauma
{
continue;
}
if (item.prefab.Identifier.ToLowerInvariant() == entities[0].ToLowerInvariant())
if (item.prefab.Identifier.Equals(entities[0], StringComparison.OrdinalIgnoreCase))
{
activeEntity = item;
break;
@@ -23,7 +23,7 @@ namespace Barotrauma
var floodingAmount = 0.0f;
foreach (Hull hull in Hull.hullList)
{
if (hull.Submarine == null || hull.Submarine.IsOutpost || Traitors.All(traitor => hull.Submarine.TeamID != traitor.Character.TeamID)) { continue; }
if (hull.Submarine == null || hull.Submarine.Info.IsOutpost || Traitors.All(traitor => hull.Submarine.TeamID != traitor.Character.TeamID)) { continue; }
if (hull.Submarine == GameMain.Server?.RespawnManager?.RespawnShuttle) { continue; }
++validHullsCount;
floodingAmount += hull.WaterVolume / hull.Volume;
@@ -52,7 +52,7 @@ namespace Barotrauma
{
continue;
}
if (character.SpeciesName.ToLowerInvariant() == speciesId)
if (character.SpeciesName.Equals(speciesId, StringComparison.OrdinalIgnoreCase))
{
targetCharacter = character;
break;
@@ -235,7 +235,7 @@ namespace Barotrauma
#if SERVER
foreach (var traitor in Traitors.Values)
{
GameServer.Log($"{traitor.Character.Name} is a traitor and the current goals are:\n{(traitor.CurrentObjective?.GoalInfos != null ? TextManager.GetServerMessage(traitor.CurrentObjective?.GoalInfos) : "(empty)")}", ServerLog.MessageType.ServerMessage);
GameServer.Log($"{GameServer.CharacterLogName(traitor.Character)} is a traitor and the current goals are:\n{(traitor.CurrentObjective?.GoalInfos != null ? TextManager.GetServerMessage(traitor.CurrentObjective?.GoalInfos) : "(empty)")}", ServerLog.MessageType.ServerMessage);
}
#endif
return true;
@@ -287,10 +287,7 @@ namespace Barotrauma
{
pendingObjectives.Remove(objective);
completedObjectives.Add(objective);
if (pendingObjectives.Count > 0)
{
objective.EndMessage();
}
objective.EndMessage();
continue;
}
if (objective.IsStarted && !objective.CanBeCompleted)
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.9.8.0</Version>
<Version>0.9.9.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>