v0.13.0.11
This commit is contained in:
@@ -26,6 +26,7 @@ namespace Barotrauma
|
||||
{
|
||||
msg.Write(ID);
|
||||
msg.Write(Name);
|
||||
msg.Write(OriginalName);
|
||||
msg.Write((byte)Gender);
|
||||
msg.Write((byte)Race);
|
||||
msg.Write((byte)HeadSpriteId);
|
||||
|
||||
@@ -105,6 +105,14 @@ namespace Barotrauma
|
||||
focusedItem = item;
|
||||
FocusedCharacter = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
//failed to interact with the item
|
||||
// -> correct the position and the state of the Holdable component (in case the item was deattached client-side)
|
||||
item.PositionUpdateInterval = 0.0f;
|
||||
var holdable = item.GetComponent<Items.Components.Holdable>();
|
||||
holdable?.Item?.CreateServerEvent(holdable);
|
||||
}
|
||||
}
|
||||
else if (closestEntity is Character character)
|
||||
{
|
||||
@@ -278,21 +286,21 @@ namespace Barotrauma
|
||||
switch ((NetEntityEvent.Type)extraData[0])
|
||||
{
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
msg.WriteRangedInteger(0, 0, 5);
|
||||
msg.WriteRangedInteger(0, 0, 6);
|
||||
msg.Write(GameMain.Server.EntityEventManager.Events.Last()?.ID ?? (ushort)0);
|
||||
Inventory.ServerWrite(msg, c);
|
||||
break;
|
||||
case NetEntityEvent.Type.Control:
|
||||
msg.WriteRangedInteger(1, 0, 5);
|
||||
msg.WriteRangedInteger(1, 0, 6);
|
||||
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, 5);
|
||||
msg.WriteRangedInteger(2, 0, 6);
|
||||
WriteStatus(msg);
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdateSkills:
|
||||
msg.WriteRangedInteger(3, 0, 5);
|
||||
msg.WriteRangedInteger(3, 0, 6);
|
||||
if (Info?.Job == null)
|
||||
{
|
||||
msg.Write((byte)0);
|
||||
@@ -311,15 +319,36 @@ namespace Barotrauma
|
||||
Limb attackLimb = extraData[1] as Limb;
|
||||
UInt16 targetEntityID = (UInt16)extraData[2];
|
||||
int targetLimbIndex = extraData.Length > 3 ? (int)extraData[3] : 0;
|
||||
msg.WriteRangedInteger(4, 0, 5);
|
||||
msg.WriteRangedInteger(4, 0, 6);
|
||||
msg.Write((byte)(Removed ? 255 : Array.IndexOf(AnimController.Limbs, attackLimb)));
|
||||
msg.Write(targetEntityID);
|
||||
msg.Write((byte)targetLimbIndex);
|
||||
break;
|
||||
case NetEntityEvent.Type.AssignCampaignInteraction:
|
||||
msg.WriteRangedInteger(5, 0, 5);
|
||||
msg.WriteRangedInteger(5, 0, 6);
|
||||
msg.Write((byte)CampaignInteractionType);
|
||||
break;
|
||||
case NetEntityEvent.Type.ObjectiveManagerOrderState:
|
||||
msg.WriteRangedInteger(6, 0, 6);
|
||||
if (!(AIController is HumanAIController controller))
|
||||
{
|
||||
msg.Write(false);
|
||||
break;
|
||||
}
|
||||
var currentOrderInfo = controller.ObjectiveManager.GetCurrentOrderInfo();
|
||||
if (!currentOrderInfo.HasValue)
|
||||
{
|
||||
msg.Write(false);
|
||||
break;
|
||||
}
|
||||
msg.Write(true);
|
||||
var orderPrefab = currentOrderInfo.Value.Order.Prefab;
|
||||
int orderIndex = Order.PrefabList.IndexOf(orderPrefab);
|
||||
msg.WriteRangedInteger(orderIndex, 0, Order.PrefabList.Count);
|
||||
if (!orderPrefab.HasOptions) { break; }
|
||||
int optionIndex = orderPrefab.Options.IndexOf(currentOrderInfo.Value.OrderOption);
|
||||
msg.WriteRangedInteger(optionIndex, 0, orderPrefab.Options.Length);
|
||||
break;
|
||||
default:
|
||||
DebugConsole.ThrowError("Invalid NetworkEvent type for entity " + ToString() + " (" + (NetEntityEvent.Type)extraData[0] + ")");
|
||||
break;
|
||||
@@ -529,29 +558,28 @@ namespace Barotrauma
|
||||
|
||||
msg.Write((byte)CampaignInteractionType);
|
||||
|
||||
// Current order
|
||||
if (info.CurrentOrder != null)
|
||||
|
||||
// Current orders
|
||||
msg.Write((byte)info.CurrentOrders.Count(o => o.Order != null));
|
||||
foreach (var orderInfo in info.CurrentOrders)
|
||||
{
|
||||
msg.Write(true);
|
||||
msg.Write((byte)Order.PrefabList.IndexOf(info.CurrentOrder.Prefab));
|
||||
msg.Write(info.CurrentOrder.TargetEntity == null ? (UInt16)0 : info.CurrentOrder.TargetEntity.ID);
|
||||
var hasOrderGiver = info.CurrentOrder.OrderGiver != null;
|
||||
if (orderInfo.Order == null) { continue; }
|
||||
msg.Write((byte)Order.PrefabList.IndexOf(orderInfo.Order.Prefab));
|
||||
msg.Write(orderInfo.Order.TargetEntity == null ? (UInt16)0 : orderInfo.Order.TargetEntity.ID);
|
||||
var hasOrderGiver = orderInfo.Order.OrderGiver != null;
|
||||
msg.Write(hasOrderGiver);
|
||||
if (hasOrderGiver) { msg.Write(info.CurrentOrder.OrderGiver.ID); }
|
||||
msg.Write((byte)(string.IsNullOrWhiteSpace(info.CurrentOrderOption) ? 0 : Array.IndexOf(info.CurrentOrder.Prefab.Options, info.CurrentOrderOption)));
|
||||
var hasTargetPosition = info.CurrentOrder.TargetPosition != null;
|
||||
if (hasOrderGiver) { msg.Write(orderInfo.Order.OrderGiver.ID); }
|
||||
msg.Write((byte)(string.IsNullOrWhiteSpace(orderInfo.OrderOption) ? 0 : Array.IndexOf(orderInfo.Order.Prefab.Options, orderInfo.OrderOption)));
|
||||
msg.Write((byte)orderInfo.ManualPriority);
|
||||
var hasTargetPosition = orderInfo.Order.TargetPosition != null;
|
||||
msg.Write(hasTargetPosition);
|
||||
if (hasTargetPosition)
|
||||
{
|
||||
msg.Write(info.CurrentOrder.TargetPosition.Position.X);
|
||||
msg.Write(info.CurrentOrder.TargetPosition.Position.Y);
|
||||
msg.Write(info.CurrentOrder.TargetPosition.Hull == null ? (UInt16)0 : info.CurrentOrder.TargetPosition.Hull.ID);
|
||||
msg.Write(orderInfo.Order.TargetPosition.Position.X);
|
||||
msg.Write(orderInfo.Order.TargetPosition.Position.Y);
|
||||
msg.Write(orderInfo.Order.TargetPosition.Hull == null ? (UInt16)0 : orderInfo.Order.TargetPosition.Hull.ID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write(false);
|
||||
}
|
||||
|
||||
TryWriteStatus(msg);
|
||||
|
||||
|
||||
@@ -73,17 +73,27 @@ namespace Barotrauma
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
int consoleWidth = Console.WindowWidth;
|
||||
if (consoleWidth < 5) consoleWidth = 5;
|
||||
int consoleHeight = Console.WindowHeight;
|
||||
if (consoleHeight < 5) consoleHeight = 5;
|
||||
int consoleWidth = 0;
|
||||
int consoleHeight = 0;
|
||||
|
||||
if(!Console.IsOutputRedirected)
|
||||
{
|
||||
consoleWidth = Console.WindowWidth;
|
||||
if (consoleWidth < 5) consoleWidth = 5;
|
||||
consoleHeight = Console.WindowHeight;
|
||||
if (consoleHeight < 5) consoleHeight = 5;
|
||||
}
|
||||
|
||||
//dequeue messages
|
||||
lock (queuedMessages)
|
||||
{
|
||||
if (queuedMessages.Count > 0)
|
||||
{
|
||||
Console.CursorLeft = 0;
|
||||
|
||||
if (!Console.IsOutputRedirected)
|
||||
{
|
||||
Console.CursorLeft = 0;
|
||||
}
|
||||
while (queuedMessages.Count > 0)
|
||||
{
|
||||
ColoredText msg = queuedMessages.Dequeue();
|
||||
@@ -102,15 +112,21 @@ namespace Barotrauma
|
||||
|
||||
if (msg.IsCommand) commandMemory.Add(msgTxt);
|
||||
|
||||
int paddingLen = consoleWidth - (msg.Text.Length % consoleWidth)-1;
|
||||
msgTxt += new string(' ', paddingLen>0 ? paddingLen : 0);
|
||||
if(!Console.IsOutputRedirected)
|
||||
{
|
||||
int paddingLen = consoleWidth - (msg.Text.Length % consoleWidth) - 1;
|
||||
msgTxt += new string(' ', paddingLen > 0 ? paddingLen : 0);
|
||||
|
||||
Console.ForegroundColor = XnaToConsoleColor.Convert(msg.Color);
|
||||
Console.ForegroundColor = XnaToConsoleColor.Convert(msg.Color);
|
||||
}
|
||||
Console.WriteLine(msgTxt);
|
||||
|
||||
if (sw.ElapsedMilliseconds >= maxTime) { break; }
|
||||
}
|
||||
RewriteInputToCommandLine(input);
|
||||
if(!Console.IsOutputRedirected)
|
||||
{
|
||||
RewriteInputToCommandLine(input);
|
||||
}
|
||||
}
|
||||
if (Messages.Count > MaxMessages)
|
||||
{
|
||||
@@ -118,73 +134,78 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
//read player input
|
||||
bool rewriteInput = false;
|
||||
while (Console.KeyAvailable)
|
||||
// No good way to display input when console output is redirected, and can't read from redirected input using KeyAvailable.
|
||||
if(!Console.IsOutputRedirected && !Console.IsInputRedirected)
|
||||
{
|
||||
if (sw.ElapsedMilliseconds >= maxTime)
|
||||
//read player input
|
||||
bool rewriteInput = false;
|
||||
while (Console.KeyAvailable)
|
||||
{
|
||||
rewriteInput = false;
|
||||
break;
|
||||
}
|
||||
rewriteInput = true;
|
||||
ConsoleKeyInfo key = Console.ReadKey(true);
|
||||
switch (key.Key)
|
||||
{
|
||||
case ConsoleKey.Enter:
|
||||
lock (QueuedCommands)
|
||||
{
|
||||
QueuedCommands.Add(input);
|
||||
}
|
||||
input = "";
|
||||
memoryIndex = -1;
|
||||
if (sw.ElapsedMilliseconds >= maxTime)
|
||||
{
|
||||
rewriteInput = false;
|
||||
break;
|
||||
case ConsoleKey.Backspace:
|
||||
if (input.Length > 0) input = input.Substring(0, input.Length - 1);
|
||||
memoryIndex = -1;
|
||||
break;
|
||||
case ConsoleKey.LeftArrow:
|
||||
input = AutoComplete(input, -1);
|
||||
break;
|
||||
case ConsoleKey.RightArrow:
|
||||
input = AutoComplete(input, 1);
|
||||
break;
|
||||
case ConsoleKey.UpArrow:
|
||||
memoryIndex--;
|
||||
if (memoryIndex < 0) memoryIndex = commandMemory.Count - 1;
|
||||
if (memoryIndex >= commandMemory.Count) memoryIndex = commandMemory.Count - 1;
|
||||
if (memoryIndex >= 0)
|
||||
{
|
||||
input = commandMemory[memoryIndex];
|
||||
}
|
||||
break;
|
||||
case ConsoleKey.DownArrow:
|
||||
memoryIndex++;
|
||||
if (memoryIndex < 0) memoryIndex = 0;
|
||||
if (memoryIndex >= commandMemory.Count) memoryIndex = 0;
|
||||
if (commandMemory.Count>0)
|
||||
{
|
||||
input = commandMemory[memoryIndex];
|
||||
}
|
||||
break;
|
||||
case ConsoleKey.Tab:
|
||||
if (input.Length > 0)
|
||||
{
|
||||
input = AutoComplete(input, 0);
|
||||
}
|
||||
rewriteInput = true;
|
||||
ConsoleKeyInfo key = Console.ReadKey(true);
|
||||
switch (key.Key)
|
||||
{
|
||||
case ConsoleKey.Enter:
|
||||
lock (QueuedCommands)
|
||||
{
|
||||
QueuedCommands.Add(input);
|
||||
}
|
||||
input = "";
|
||||
memoryIndex = -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (key.KeyChar != 0)
|
||||
{
|
||||
input += key.KeyChar;
|
||||
break;
|
||||
case ConsoleKey.Backspace:
|
||||
if (input.Length > 0) input = input.Substring(0, input.Length - 1);
|
||||
ResetAutoComplete();
|
||||
memoryIndex = -1;
|
||||
}
|
||||
ResetAutoComplete();
|
||||
break;
|
||||
break;
|
||||
case ConsoleKey.LeftArrow:
|
||||
input = AutoComplete(input, -1);
|
||||
break;
|
||||
case ConsoleKey.RightArrow:
|
||||
input = AutoComplete(input, 1);
|
||||
break;
|
||||
case ConsoleKey.UpArrow:
|
||||
memoryIndex--;
|
||||
if (memoryIndex < 0) memoryIndex = commandMemory.Count - 1;
|
||||
if (memoryIndex >= commandMemory.Count) memoryIndex = commandMemory.Count - 1;
|
||||
if (memoryIndex >= 0)
|
||||
{
|
||||
input = commandMemory[memoryIndex];
|
||||
}
|
||||
break;
|
||||
case ConsoleKey.DownArrow:
|
||||
memoryIndex++;
|
||||
if (memoryIndex < 0) memoryIndex = 0;
|
||||
if (memoryIndex >= commandMemory.Count) memoryIndex = 0;
|
||||
if (commandMemory.Count>0)
|
||||
{
|
||||
input = commandMemory[memoryIndex];
|
||||
}
|
||||
break;
|
||||
case ConsoleKey.Tab:
|
||||
if (input.Length > 0)
|
||||
{
|
||||
input = AutoComplete(input, 0);
|
||||
memoryIndex = -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (key.KeyChar != 0)
|
||||
{
|
||||
input += key.KeyChar;
|
||||
memoryIndex = -1;
|
||||
}
|
||||
ResetAutoComplete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rewriteInput) { RewriteInputToCommandLine(input); }
|
||||
}
|
||||
if (rewriteInput) { RewriteInputToCommandLine(input); }
|
||||
|
||||
sw.Stop();
|
||||
}
|
||||
@@ -512,6 +533,13 @@ namespace Barotrauma
|
||||
NewMessage(perm + " is not a valid permission!", Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
if (permission == ClientPermissions.None)
|
||||
{
|
||||
NewMessage($"No permissions were given to {client.Name}. Did you mean \"revokeperm {client.Name} All\"?");
|
||||
return;
|
||||
}
|
||||
|
||||
client.GivePermission(permission);
|
||||
GameMain.Server.UpdateClientPermissions(client);
|
||||
NewMessage("Granted " + perm + " permissions to " + client.Name + ".", Color.White);
|
||||
@@ -539,10 +567,13 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
NewMessage("Valid permissions are:", Color.White);
|
||||
foreach (ClientPermissions permission in Enum.GetValues(typeof(ClientPermissions)))
|
||||
if (args.Length < 2)
|
||||
{
|
||||
NewMessage(" - " + permission.ToString(), Color.White);
|
||||
NewMessage("Valid permissions are:", Color.White);
|
||||
foreach (ClientPermissions permission in Enum.GetValues(typeof(ClientPermissions)))
|
||||
{
|
||||
NewMessage(" - " + permission.ToString(), Color.White);
|
||||
}
|
||||
}
|
||||
ShowQuestionPrompt("Permission to revoke from \"" + client.Name + "\"?", (perm) =>
|
||||
{
|
||||
@@ -715,7 +746,6 @@ namespace Barotrauma
|
||||
{
|
||||
NewMessage("Revoked \"" + client.Name + "\"'s permission to use the console commands " + string.Join(", ", revokedCommands.Select(c => c.names[0])) + ".", Color.White);
|
||||
}
|
||||
|
||||
}, args, 1);
|
||||
});
|
||||
|
||||
@@ -1801,6 +1831,14 @@ namespace Barotrauma
|
||||
GameMain.Server.SendConsoleMessage(perm + " is not a valid permission!", senderClient);
|
||||
return;
|
||||
}
|
||||
|
||||
if (permission == ClientPermissions.None)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"No permissions were given to {client.Name}. Did you mean \"revokeperm {client.Name} All\"?", senderClient);
|
||||
NewMessage($"No permissions were given to {client.Name}. Did you mean \"revokeperm {client.Name} All\"?");
|
||||
return;
|
||||
}
|
||||
|
||||
client.GivePermission(permission);
|
||||
GameMain.Server.UpdateClientPermissions(client);
|
||||
GameMain.Server.SendConsoleMessage("Granted " + perm + " permissions to " + client.Name + ".", senderClient);
|
||||
@@ -1954,7 +1992,6 @@ namespace Barotrauma
|
||||
if (revokeAll)
|
||||
{
|
||||
revokedCommands.AddRange(commands);
|
||||
client.RemovePermission(ClientPermissions.ConsoleCommands);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1971,10 +2008,13 @@ namespace Barotrauma
|
||||
revokedCommands.Add(matchingCommand);
|
||||
}
|
||||
}
|
||||
client.GivePermission(ClientPermissions.ConsoleCommands);
|
||||
}
|
||||
|
||||
client.SetPermissions(client.Permissions, client.PermittedConsoleCommands.Except(revokedCommands).ToList());
|
||||
if (client.PermittedConsoleCommands.Count == 0)
|
||||
{
|
||||
client.RemovePermission(ClientPermissions.ConsoleCommands);
|
||||
}
|
||||
GameMain.Server.UpdateClientPermissions(client);
|
||||
GameMain.Server.SendConsoleMessage("Revoked \"" + client.Name + "\"'s permission to use the console commands " + string.Join(", ", revokedCommands.Select(c => c.names[0])) + ".", senderClient);
|
||||
if (revokeAll)
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class AbandonedOutpostMission : Mission
|
||||
{
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
if (characters.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Server attempted to write AbandonedOutpostMission data when no characters had been spawned.");
|
||||
}
|
||||
|
||||
msg.Write((byte)characters.Count);
|
||||
foreach (Character character in characters)
|
||||
{
|
||||
character.WriteSpawnData(msg, character.ID, restrictMessageSize: false);
|
||||
msg.Write(requireKill.Contains(character));
|
||||
msg.Write(requireRescue.Contains(character));
|
||||
msg.Write((ushort)characterItems[character].Count());
|
||||
foreach (Item item in characterItems[character])
|
||||
{
|
||||
item.WriteSpawnData(msg, item.ID, item.ParentInventory.Owner?.ID ?? Entity.NullEntityID, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Barotrauma.Networking;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class OutpostDestroyMission : AbandonedOutpostMission
|
||||
{
|
||||
private readonly List<Item> spawnedItems = new List<Item>();
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
base.ServerWriteInitial(msg, c);
|
||||
msg.Write((ushort)spawnedItems.Count);
|
||||
foreach (Item item in spawnedItems)
|
||||
{
|
||||
item.WriteSpawnData(msg, item.ID, Entity.NullEntityID, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -361,7 +361,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
#if !DEBUG
|
||||
if (Server?.OwnerConnection == null && !Console.IsOutputRedirected)
|
||||
if (Server?.OwnerConnection == null)
|
||||
{
|
||||
DebugConsole.UpdateCommandLine((int)(Timing.Accumulator * 800));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -13,10 +12,11 @@ namespace Barotrauma
|
||||
|
||||
public override void ShowStartMessage()
|
||||
{
|
||||
if (Mission == null) return;
|
||||
|
||||
GameServer.Log(TextManager.Get("Mission") + ": " + Mission.Name, Networking.ServerLog.MessageType.ServerMessage);
|
||||
GameServer.Log(Mission.Description, Networking.ServerLog.MessageType.ServerMessage);
|
||||
foreach (Mission mission in Missions)
|
||||
{
|
||||
GameServer.Log(TextManager.Get("Mission") + ": " + mission.Name, ServerLog.MessageType.ServerMessage);
|
||||
GameServer.Log(mission.Description, ServerLog.MessageType.ServerMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
{
|
||||
public override void ShowStartMessage()
|
||||
{
|
||||
if (mission == null) return;
|
||||
|
||||
Networking.GameServer.Log(TextManager.Get("Mission") + ": " + mission.Name, Networking.ServerLog.MessageType.ServerMessage);
|
||||
Networking.GameServer.Log(mission.Description, Networking.ServerLog.MessageType.ServerMessage);
|
||||
foreach (Mission mission in missions)
|
||||
{
|
||||
Networking.GameServer.Log(TextManager.Get("Mission") + ": " + mission.Name, Networking.ServerLog.MessageType.ServerMessage);
|
||||
Networking.GameServer.Log(mission.Description, Networking.ServerLog.MessageType.ServerMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+102
-19
@@ -32,11 +32,11 @@ namespace Barotrauma
|
||||
get { return ForceMapUI || CoroutineManager.IsCoroutineRunning("LevelTransition"); }
|
||||
}
|
||||
|
||||
public static void StartNewCampaign(string savePath, string subPath, string seed)
|
||||
public static void StartNewCampaign(string savePath, string subPath, string seed, CampaignSettings settings)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(savePath)) { return; }
|
||||
|
||||
GameMain.GameSession = new GameSession(new SubmarineInfo(subPath), savePath, GameModePreset.MultiPlayerCampaign, seed);
|
||||
GameMain.GameSession = new GameSession(new SubmarineInfo(subPath), savePath, GameModePreset.MultiPlayerCampaign, settings, seed);
|
||||
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
|
||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace Barotrauma
|
||||
DebugConsole.ShowQuestionPrompt("Enter a save name for the campaign:", (string saveName) =>
|
||||
{
|
||||
string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer, saveName);
|
||||
StartNewCampaign(savePath, GameMain.NetLobbyScreen.SelectedSub.FilePath, GameMain.NetLobbyScreen.LevelSeed);
|
||||
StartNewCampaign(savePath, GameMain.NetLobbyScreen.SelectedSub.FilePath, GameMain.NetLobbyScreen.LevelSeed, CampaignSettings.Empty);
|
||||
});
|
||||
}
|
||||
else
|
||||
@@ -367,6 +367,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (CoroutineManager.IsCoroutineRunning("LevelTransition")) { return; }
|
||||
|
||||
Map?.Radiation?.UpdateRadiation(deltaTime);
|
||||
|
||||
base.Update(deltaTime);
|
||||
if (Level.Loaded != null)
|
||||
{
|
||||
@@ -441,9 +443,16 @@ namespace Barotrauma
|
||||
foreach (Mission mission in map.CurrentLocation.AvailableMissions)
|
||||
{
|
||||
msg.Write(mission.Prefab.Identifier);
|
||||
Location missionDestination = mission.Locations[0] == map.CurrentLocation ? mission.Locations[1] : mission.Locations[0];
|
||||
LocationConnection connection = map.CurrentLocation.Connections.Find(c => c.OtherLocation(map.CurrentLocation) == missionDestination);
|
||||
msg.Write((byte)map.CurrentLocation.Connections.IndexOf(connection));
|
||||
if (mission.Locations[0] == mission.Locations[1])
|
||||
{
|
||||
msg.Write((byte)255);
|
||||
}
|
||||
else
|
||||
{
|
||||
Location missionDestination = mission.Locations[0] == map.CurrentLocation ? mission.Locations[1] : mission.Locations[0];
|
||||
LocationConnection connection = map.CurrentLocation.Connections.Find(c => c.OtherLocation(map.CurrentLocation) == missionDestination);
|
||||
msg.Write((byte)map.CurrentLocation.Connections.IndexOf(connection));
|
||||
}
|
||||
}
|
||||
|
||||
// Store balance
|
||||
@@ -658,13 +667,24 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
bool validateHires = msg.ReadBoolean();
|
||||
bool fireCharacter = msg.ReadBoolean();
|
||||
|
||||
bool renameCharacter = msg.ReadBoolean();
|
||||
int renamedIdentifier = -1;
|
||||
string newName = null;
|
||||
bool existingCrewMember = false;
|
||||
if (renameCharacter)
|
||||
{
|
||||
renamedIdentifier = msg.ReadInt32();
|
||||
newName = msg.ReadString();
|
||||
existingCrewMember = msg.ReadBoolean();
|
||||
}
|
||||
|
||||
bool fireCharacter = msg.ReadBoolean();
|
||||
int firedIdentifier = -1;
|
||||
if (fireCharacter) { firedIdentifier = msg.ReadInt32(); }
|
||||
|
||||
Location location = map?.CurrentLocation;
|
||||
|
||||
List<CharacterInfo> hiredCharacters = new List<CharacterInfo>();
|
||||
CharacterInfo firedCharacter = null;
|
||||
|
||||
if (location != null && AllowedToManageCampaign(sender))
|
||||
@@ -682,13 +702,45 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (renameCharacter)
|
||||
{
|
||||
CharacterInfo characterInfo = null;
|
||||
if (existingCrewMember && CrewManager != null)
|
||||
{
|
||||
characterInfo = CrewManager.CharacterInfos.FirstOrDefault(info => info.GetIdentifierUsingOriginalName() == renamedIdentifier);
|
||||
}
|
||||
else if(!existingCrewMember && location.HireManager != null)
|
||||
{
|
||||
characterInfo = location.HireManager.AvailableCharacters.FirstOrDefault(info => info.GetIdentifierUsingOriginalName() == renamedIdentifier);
|
||||
}
|
||||
|
||||
if (characterInfo != null && (characterInfo.Character?.IsBot ?? true))
|
||||
{
|
||||
if (existingCrewMember)
|
||||
{
|
||||
CrewManager.RenameCharacter(characterInfo, newName);
|
||||
}
|
||||
else
|
||||
{
|
||||
location.HireManager.RenameCharacter(characterInfo, newName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Tried to rename an invalid character ({renamedIdentifier})");
|
||||
}
|
||||
}
|
||||
|
||||
if (location.HireManager != null)
|
||||
{
|
||||
if (validateHires)
|
||||
{
|
||||
foreach (CharacterInfo hireInfo in location.HireManager.PendingHires)
|
||||
{
|
||||
TryHireCharacter(location, hireInfo);
|
||||
if (TryHireCharacter(location, hireInfo))
|
||||
{
|
||||
hiredCharacters.Add(hireInfo);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,10 +749,10 @@ namespace Barotrauma
|
||||
List<CharacterInfo> pendingHireInfos = new List<CharacterInfo>();
|
||||
foreach (int identifier in pendingHires)
|
||||
{
|
||||
CharacterInfo match = location.GetHireableCharacters().FirstOrDefault(info => info.GetIdentifier() == identifier);
|
||||
CharacterInfo match = location.GetHireableCharacters().FirstOrDefault(info => info.GetIdentifierUsingOriginalName() == identifier);
|
||||
if (match == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Tried to hire a character that doesn't exist ({identifier})");
|
||||
DebugConsole.ThrowError($"Tried to add a character that doesn't exist ({identifier}) to pending hires");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -712,25 +764,39 @@ namespace Barotrauma
|
||||
}
|
||||
location.HireManager.PendingHires = pendingHireInfos;
|
||||
}
|
||||
|
||||
location.HireManager.AvailableCharacters.ForEachMod(info =>
|
||||
{
|
||||
if(!location.HireManager.PendingHires.Contains(info))
|
||||
{
|
||||
location.HireManager.RenameCharacter(info, info.OriginalName);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// bounce back
|
||||
SendCrewState(validateHires, firedCharacter);
|
||||
if (renameCharacter && existingCrewMember)
|
||||
{
|
||||
SendCrewState(hiredCharacters, (renamedIdentifier, newName), firedCharacter);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendCrewState(hiredCharacters, default, firedCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Notifies the clients of the current bot situation like syncing pending and available hires
|
||||
/// available hires are also synced
|
||||
/// </summary>
|
||||
/// <param name="validateHires">When set to true notifies the clients that the hires have been validated.</param>
|
||||
/// <param name="firedCharacter">When not null will inform the clients that his character has been fired.</param>
|
||||
/// <param name="hiredCharacters">Inform the clients that these characters have been hired.</param>
|
||||
/// <param name="firedCharacter">Inform the clients that this character has been fired.</param>
|
||||
/// <remarks>
|
||||
/// It might be obsolete to sync available hires. I found that the available hires are always the same between
|
||||
/// the client and the server when there's only one person on the server but when a second person joins both of
|
||||
/// their available hires are different from the server.
|
||||
/// </remarks>
|
||||
public void SendCrewState(bool validateHires, CharacterInfo firedCharacter)
|
||||
public void SendCrewState(List<CharacterInfo> hiredCharacters, (int id, string newName) renamedCrewMember, CharacterInfo firedCharacter)
|
||||
{
|
||||
List<CharacterInfo> availableHires = new List<CharacterInfo>();
|
||||
List<CharacterInfo> pendingHires = new List<CharacterInfo>();
|
||||
@@ -756,10 +822,26 @@ namespace Barotrauma
|
||||
msg.Write((ushort)pendingHires.Count);
|
||||
foreach (CharacterInfo pendingHire in pendingHires)
|
||||
{
|
||||
msg.Write(pendingHire.GetIdentifier());
|
||||
msg.Write(pendingHire.GetIdentifierUsingOriginalName());
|
||||
}
|
||||
|
||||
msg.Write((ushort)(hiredCharacters?.Count ?? 0));
|
||||
if(hiredCharacters != null)
|
||||
{
|
||||
foreach (CharacterInfo info in hiredCharacters)
|
||||
{
|
||||
info.ServerWrite(msg);
|
||||
msg.Write(info.Salary);
|
||||
}
|
||||
}
|
||||
|
||||
bool validRenaming = renamedCrewMember.id > -1 && !string.IsNullOrEmpty(renamedCrewMember.newName);
|
||||
msg.Write(validRenaming);
|
||||
if (validRenaming)
|
||||
{
|
||||
msg.Write(renamedCrewMember.id);
|
||||
msg.Write(renamedCrewMember.newName);
|
||||
}
|
||||
|
||||
msg.Write(validateHires);
|
||||
|
||||
msg.Write(firedCharacter != null);
|
||||
if (firedCharacter != null) { msg.Write(firedCharacter.GetIdentifier()); }
|
||||
@@ -777,6 +859,7 @@ namespace Barotrauma
|
||||
new XAttribute("purchasedhullrepairs", PurchasedHullRepairs),
|
||||
new XAttribute("purchaseditemrepairs", PurchasedItemRepairs),
|
||||
new XAttribute("cheatsenabled", CheatsEnabled));
|
||||
modeElement.Add(Settings.Save());
|
||||
CampaignMetadata?.Save(modeElement);
|
||||
Map.Save(modeElement);
|
||||
CargoManager?.SavePurchasedItems(modeElement);
|
||||
|
||||
@@ -5,15 +5,13 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class DockingPort : ItemComponent, IDrawableComponent, IServerSerializable
|
||||
{
|
||||
private UInt16 originalDockingTargetID;
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.Write(docked);
|
||||
|
||||
if (docked)
|
||||
{
|
||||
msg.Write(originalDockingTargetID);
|
||||
msg.Write(DockingTarget.item.ID);
|
||||
msg.Write(IsLocked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,10 @@ namespace Barotrauma.Items.Components
|
||||
public override void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
base.ServerWrite(msg, c, extraData);
|
||||
if (!attachable || body == null) { return; }
|
||||
|
||||
bool writeAttachData = attachable && body != null;
|
||||
msg.Write(writeAttachData);
|
||||
if (!writeAttachData) { return; }
|
||||
|
||||
msg.Write(Attached);
|
||||
msg.Write(body.SimPosition.X);
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (dockingButtonClicked)
|
||||
{
|
||||
item.SendSignal(0, "1", "toggle_docking", sender: null);
|
||||
item.SendSignal("1", "toggle_docking");
|
||||
GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, item.GetComponentIndex(this), true });
|
||||
}
|
||||
|
||||
|
||||
@@ -20,17 +20,20 @@ namespace Barotrauma.Items.Components
|
||||
ServerLog.MessageType.ItemInteraction);
|
||||
OutputValue = newOutputValue;
|
||||
ShowOnDisplay(newOutputValue);
|
||||
item.SendSignal(0, newOutputValue, "signal_out", null);
|
||||
item.SendSignal(newOutputValue, "signal_out");
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
}
|
||||
|
||||
partial void ShowOnDisplay(string input)
|
||||
partial void ShowOnDisplay(string input, bool addToHistory = true)
|
||||
{
|
||||
messageHistory.Add(input);
|
||||
while (messageHistory.Count > MaxMessages)
|
||||
if (addToHistory)
|
||||
{
|
||||
messageHistory.RemoveAt(0);
|
||||
messageHistory.Add(input);
|
||||
while (messageHistory.Count > MaxMessages)
|
||||
{
|
||||
messageHistory.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -269,6 +269,7 @@ namespace Barotrauma
|
||||
|
||||
msg.Write(body == null ? (byte)0 : (byte)body.BodyType);
|
||||
msg.Write(SpawnedInOutpost);
|
||||
msg.Write(AllowStealing);
|
||||
|
||||
byte teamID = 0;
|
||||
foreach (WifiComponent wifiComponent in GetComponents<WifiComponent>())
|
||||
|
||||
@@ -121,13 +121,14 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsBanned(IPAddress IP, ulong steamID, out string reason)
|
||||
public bool IsBanned(IPAddress IP, ulong steamID, ulong ownerSteamID, out string reason)
|
||||
{
|
||||
reason = string.Empty;
|
||||
if (IPAddress.IsLoopback(IP)) { return false; }
|
||||
var bannedPlayer = bannedPlayers.Find(bp =>
|
||||
bp.CompareTo(IP) ||
|
||||
(steamID > 0 && (bp.SteamID == steamID || SteamManager.SteamIDStringToUInt64(bp.EndPoint) == steamID)));
|
||||
(steamID > 0 && (bp.SteamID == steamID || SteamManager.SteamIDStringToUInt64(bp.EndPoint) == steamID)) ||
|
||||
(ownerSteamID > 0 && (bp.SteamID == ownerSteamID || SteamManager.SteamIDStringToUInt64(bp.EndPoint) == ownerSteamID)));
|
||||
reason = bannedPlayer?.Reason;
|
||||
return bannedPlayer != null;
|
||||
}
|
||||
@@ -166,6 +167,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void BanPlayer(string name, ulong steamID, string reason, TimeSpan? duration)
|
||||
{
|
||||
if (steamID == 0) { return; }
|
||||
BanPlayer(name, "", steamID, reason, duration);
|
||||
}
|
||||
|
||||
@@ -320,7 +322,17 @@ namespace Barotrauma.Networking
|
||||
|
||||
outMsg.Write(bannedPlayer.Name);
|
||||
outMsg.Write(bannedPlayer.UniqueIdentifier);
|
||||
outMsg.Write(bannedPlayer.IsRangeBan); outMsg.WritePadBits();
|
||||
outMsg.Write(bannedPlayer.IsRangeBan);
|
||||
outMsg.Write(bannedPlayer.ExpirationTime != null);
|
||||
outMsg.WritePadBits();
|
||||
if (bannedPlayer.ExpirationTime != null)
|
||||
{
|
||||
double hoursFromNow = (bannedPlayer.ExpirationTime.Value - DateTime.Now).TotalHours;
|
||||
outMsg.Write(hoursFromNow);
|
||||
}
|
||||
|
||||
outMsg.Write(bannedPlayer.Reason ?? "");
|
||||
|
||||
if (c.Connection == GameMain.Server.OwnerConnection)
|
||||
{
|
||||
outMsg.Write(bannedPlayer.EndPoint);
|
||||
|
||||
@@ -25,7 +25,54 @@ namespace Barotrauma.Networking
|
||||
int orderIndex = msg.ReadByte();
|
||||
orderTargetCharacter = Entity.FindEntityByID(msg.ReadUInt16()) as Character;
|
||||
orderTargetEntity = Entity.FindEntityByID(msg.ReadUInt16()) as Entity;
|
||||
int orderOptionIndex = msg.ReadByte();
|
||||
|
||||
Order orderPrefab = null;
|
||||
int? orderOptionIndex = null;
|
||||
string orderOption = null;
|
||||
|
||||
// The option of a Dismiss order is written differently so we know what order we target
|
||||
// now that the game supports multiple current orders simultaneously
|
||||
if (orderIndex >= 0 && orderIndex < Order.PrefabList.Count)
|
||||
{
|
||||
orderPrefab = Order.PrefabList[orderIndex];
|
||||
if (orderPrefab.Identifier != "dismissed")
|
||||
{
|
||||
orderOptionIndex = msg.ReadByte();
|
||||
}
|
||||
// Does the dismiss order have a specified target?
|
||||
else if(msg.ReadBoolean())
|
||||
{
|
||||
int identifierCount = msg.ReadByte();
|
||||
if (identifierCount > 0)
|
||||
{
|
||||
int dismissedOrderIndex = msg.ReadByte();
|
||||
Order dismissedOrderPrefab = null;
|
||||
if (dismissedOrderIndex >= 0 && dismissedOrderIndex < Order.PrefabList.Count)
|
||||
{
|
||||
dismissedOrderPrefab = Order.PrefabList[dismissedOrderIndex];
|
||||
orderOption = dismissedOrderPrefab.Identifier;
|
||||
}
|
||||
if (identifierCount > 1)
|
||||
{
|
||||
int dismissedOrderOptionIndex = msg.ReadByte();
|
||||
if (dismissedOrderPrefab != null)
|
||||
{
|
||||
var options = dismissedOrderPrefab.Options;
|
||||
if (options != null && dismissedOrderOptionIndex >= 0 && dismissedOrderOptionIndex < options.Length)
|
||||
{
|
||||
orderOption += $".{options[dismissedOrderOptionIndex]}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
orderOptionIndex = msg.ReadByte();
|
||||
}
|
||||
|
||||
int orderPriority = msg.ReadByte();
|
||||
orderTargetType = (Order.OrderTargetType)msg.ReadByte();
|
||||
if (msg.ReadBoolean())
|
||||
{
|
||||
@@ -41,14 +88,14 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count)
|
||||
{
|
||||
DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order index out of bounds ({orderIndex}, {orderOptionIndex}).");
|
||||
DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order index out of bounds ({orderIndex}).");
|
||||
if (NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID)) { c.LastSentChatMsgID = ID; }
|
||||
return;
|
||||
}
|
||||
|
||||
Order orderPrefab = Order.PrefabList[orderIndex];
|
||||
string orderOption = orderOptionIndex < 0 || orderOptionIndex >= orderPrefab.Options.Length ? "" : orderPrefab.Options[orderOptionIndex];
|
||||
orderMsg = new OrderChatMessage(orderPrefab, orderOption, orderTargetPosition ?? orderTargetEntity as ISpatialEntity, orderTargetCharacter, c.Character)
|
||||
orderPrefab ??= Order.PrefabList[orderIndex];
|
||||
orderOption ??= orderOptionIndex == null || orderOptionIndex < 0 || orderOptionIndex >= orderPrefab.Options.Length ? "" : orderPrefab.Options[orderOptionIndex.Value];
|
||||
orderMsg = new OrderChatMessage(orderPrefab, orderOption, orderPriority, orderTargetPosition ?? orderTargetEntity as ISpatialEntity, orderTargetCharacter, c.Character)
|
||||
{
|
||||
WallSectionIndex = wallSectionIndex
|
||||
};
|
||||
@@ -147,7 +194,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
if (order != null)
|
||||
{
|
||||
orderTargetCharacter.SetOrder(order, orderMsg.OrderOption, orderMsg.Sender);
|
||||
orderTargetCharacter.SetOrder(order, orderMsg.OrderOption, orderMsg.OrderPriority, orderMsg.Sender);
|
||||
}
|
||||
}
|
||||
else if (orderMsg.Order.IsIgnoreOrder)
|
||||
@@ -183,12 +230,16 @@ namespace Barotrauma.Networking
|
||||
2 + //(UInt16)NetStateID
|
||||
1 + //(byte)Type
|
||||
Encoding.UTF8.GetBytes(Text).Length + 2;
|
||||
|
||||
|
||||
if (SenderClient != null)
|
||||
{
|
||||
length += 8; //SteamID or local ID (ulong)
|
||||
}
|
||||
if (Sender != null && c.InGame)
|
||||
{
|
||||
length += 2; //sender ID (UInt16)
|
||||
}
|
||||
else if (SenderName != null)
|
||||
if (SenderName != null)
|
||||
{
|
||||
length += Encoding.UTF8.GetBytes(SenderName).Length + 2;
|
||||
}
|
||||
@@ -205,11 +256,17 @@ namespace Barotrauma.Networking
|
||||
msg.Write(Text);
|
||||
|
||||
msg.Write(SenderName);
|
||||
msg.Write(SenderClient != null);
|
||||
if (SenderClient != null)
|
||||
{
|
||||
msg.Write((SenderClient.SteamID != 0) ? SenderClient.SteamID : SenderClient.ID);
|
||||
}
|
||||
msg.Write(Sender != null && c.InGame);
|
||||
if (Sender != null && c.InGame)
|
||||
{
|
||||
msg.Write(Sender.ID);
|
||||
}
|
||||
msg.WritePadBits();
|
||||
if (Type == ChatMessageType.ServerMessageBoxInGame)
|
||||
{
|
||||
msg.Write(IconStyle);
|
||||
|
||||
@@ -73,6 +73,7 @@ namespace Barotrauma.Networking
|
||||
public NetworkConnection Connection { get; set; }
|
||||
|
||||
public bool SpectateOnly;
|
||||
public bool? WaitForNextRoundRespawn;
|
||||
|
||||
public int KarmaKickCount;
|
||||
|
||||
@@ -163,7 +164,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void RemovePermission(ClientPermissions permission)
|
||||
{
|
||||
if (this.Permissions.HasFlag(permission)) this.Permissions &= ~permission;
|
||||
this.Permissions &= ~permission;
|
||||
}
|
||||
|
||||
public bool HasPermission(ClientPermissions permission)
|
||||
|
||||
@@ -284,6 +284,7 @@ namespace Barotrauma.Networking
|
||||
newClient.Connection = connection;
|
||||
newClient.Connection.Status = NetworkConnectionStatus.Connected;
|
||||
newClient.SteamID = connection.SteamID;
|
||||
newClient.OwnerSteamID = connection.OwnerSteamID;
|
||||
newClient.Language = connection.Language;
|
||||
ConnectedClients.Add(newClient);
|
||||
|
||||
@@ -301,19 +302,20 @@ namespace Barotrauma.Networking
|
||||
|
||||
LastClientListUpdateID++;
|
||||
|
||||
if (newClient.Connection == OwnerConnection)
|
||||
if (newClient.Connection == OwnerConnection && OwnerConnection != null)
|
||||
{
|
||||
newClient.GivePermission(ClientPermissions.All);
|
||||
newClient.PermittedConsoleCommands.AddRange(DebugConsole.Commands);
|
||||
SendConsoleMessage("Granted all permissions to " + newClient.Name + ".", newClient);
|
||||
}
|
||||
|
||||
SendChatMessage($"ServerMessage.JoinedServer~[client]={clName}", ChatMessageType.Server, null, changeType: PlayerConnectionChangeType.Joined);
|
||||
SendChatMessage($"ServerMessage.JoinedServer~[client]={ClientLogName(newClient)}", ChatMessageType.Server, null, changeType: PlayerConnectionChangeType.Joined);
|
||||
serverSettings.ServerDetailsChanged = true;
|
||||
|
||||
if (previousPlayer != null && previousPlayer.Name != newClient.Name)
|
||||
{
|
||||
SendChatMessage($"ServerMessage.PreviousClientName~[client]={clName}~[previousname]={previousPlayer.Name}", ChatMessageType.Server, null);
|
||||
string prevNameSanitized = previousPlayer.Name.Replace("‖", "");
|
||||
SendChatMessage($"ServerMessage.PreviousClientName~[client]={ClientLogName(newClient)}~[previousname]={prevNameSanitized}", ChatMessageType.Server, null);
|
||||
previousPlayer.Name = newClient.Name;
|
||||
}
|
||||
|
||||
@@ -448,12 +450,12 @@ namespace Barotrauma.Networking
|
||||
//or very close and someone from the crew made it inside the outpost
|
||||
subAtLevelEnd =
|
||||
Submarine.MainSub.DockedTo.Contains(Level.Loaded.EndOutpost) ||
|
||||
(Submarine.MainSub.AtEndPosition && charactersInsideOutpost > 0) ||
|
||||
(Submarine.MainSub.AtEndExit && charactersInsideOutpost > 0) ||
|
||||
(charactersInsideOutpost > charactersOutsideOutpost);
|
||||
}
|
||||
else
|
||||
{
|
||||
subAtLevelEnd = Submarine.MainSub.AtEndPosition;
|
||||
subAtLevelEnd = Submarine.MainSub.AtEndExit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,12 +477,19 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else if (isCrewDead && respawnManager == null)
|
||||
{
|
||||
#if !DEBUG
|
||||
if (endRoundTimer <= 0.0f)
|
||||
{
|
||||
SendChatMessage(TextManager.GetWithVariable("CrewDeadNoRespawns", "[time]", "60"), ChatMessageType.Server);
|
||||
}
|
||||
endRoundDelay = 60.0f;
|
||||
endRoundTimer += deltaTime;
|
||||
#endif
|
||||
}
|
||||
else if (isCrewDead && (GameMain.GameSession?.GameMode is CampaignMode))
|
||||
{
|
||||
endRoundDelay = 1.0f;
|
||||
endRoundTimer += deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -501,10 +510,14 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
Log("Ending round (submarine reached the end of the level)", ServerLog.MessageType.ServerMessage);
|
||||
}
|
||||
else
|
||||
else if (respawnManager == null)
|
||||
{
|
||||
Log("Ending round (no living players left and respawning is not enabled during this round)", ServerLog.MessageType.ServerMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("Ending round (no living players left)", ServerLog.MessageType.ServerMessage);
|
||||
}
|
||||
EndGame();
|
||||
return;
|
||||
}
|
||||
@@ -752,6 +765,7 @@ namespace Barotrauma.Networking
|
||||
string seed = inc.ReadString();
|
||||
string subName = inc.ReadString();
|
||||
string subHash = inc.ReadString();
|
||||
CampaignSettings settings = new CampaignSettings(inc);
|
||||
|
||||
var matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash);
|
||||
|
||||
@@ -772,10 +786,10 @@ namespace Barotrauma.Networking
|
||||
string localSavePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer, saveName);
|
||||
if (connectedClient.HasPermission(ClientPermissions.SelectMode) || connectedClient.HasPermission(ClientPermissions.ManageCampaign))
|
||||
{
|
||||
MultiPlayerCampaign.StartNewCampaign(localSavePath, matchingSub.FilePath, seed);
|
||||
MultiPlayerCampaign.StartNewCampaign(localSavePath, matchingSub.FilePath, seed, settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string saveName = inc.ReadString();
|
||||
@@ -814,6 +828,9 @@ namespace Barotrauma.Networking
|
||||
case ClientPacketHeader.READY_CHECK:
|
||||
ReadyCheck.ServerRead(inc, connectedClient);
|
||||
break;
|
||||
case ClientPacketHeader.READY_TO_SPAWN:
|
||||
ReadReadyToSpawnMessage(inc, connectedClient);
|
||||
break;
|
||||
case ClientPacketHeader.FILE_REQUEST:
|
||||
if (serverSettings.AllowFileTransfers)
|
||||
{
|
||||
@@ -912,12 +929,19 @@ namespace Barotrauma.Networking
|
||||
errorLines.Add("Campaign ID: " + campaign.CampaignID);
|
||||
errorLines.Add("Campaign save ID: " + campaign.LastSaveID);
|
||||
}
|
||||
errorLines.Add("Mission: " + (GameMain.GameSession?.Mission?.Prefab.Identifier ?? "none"));
|
||||
foreach (Mission mission in GameMain.GameSession.Missions)
|
||||
{
|
||||
errorLines.Add("Mission: " + mission.Prefab.Identifier);
|
||||
}
|
||||
}
|
||||
if (GameMain.GameSession?.Submarine != null)
|
||||
{
|
||||
errorLines.Add("Submarine: " + GameMain.GameSession.Submarine.Info.Name);
|
||||
}
|
||||
if (GameMain.NetworkMember?.RespawnManager?.RespawnShuttle != null)
|
||||
{
|
||||
errorLines.Add("Respawn shuttle: " + GameMain.NetworkMember.RespawnManager.RespawnShuttle.Info.Name);
|
||||
}
|
||||
if (Level.Loaded != null)
|
||||
{
|
||||
errorLines.Add("Level: " + Level.Loaded.Seed + ", " + string.Join(", ", Level.Loaded.EqualityCheckValues.Select(cv => cv.ToString("X"))));
|
||||
@@ -1183,6 +1207,15 @@ namespace Barotrauma.Networking
|
||||
mpCampaign.ServerReadCrew(inc, sender);
|
||||
}
|
||||
}
|
||||
private void ReadReadyToSpawnMessage(IReadMessage inc, Client sender)
|
||||
{
|
||||
sender.SpectateOnly = inc.ReadBoolean() && (serverSettings.AllowSpectating || sender.Connection == OwnerConnection);
|
||||
sender.WaitForNextRoundRespawn = inc.ReadBoolean();
|
||||
if (!(GameMain.GameSession?.GameMode is CampaignMode))
|
||||
{
|
||||
sender.WaitForNextRoundRespawn = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClientReadServerCommand(IReadMessage inc)
|
||||
{
|
||||
@@ -1300,15 +1333,23 @@ namespace Barotrauma.Networking
|
||||
else if (mpCampaign != null)
|
||||
{
|
||||
var availableTransition = mpCampaign.GetAvailableTransition(out _, out _);
|
||||
//don't force location if we've teleported
|
||||
bool forceLocation = !mpCampaign.Map.AllowDebugTeleport || mpCampaign.Map.CurrentLocation == Level.Loaded.StartLocation;
|
||||
switch (availableTransition)
|
||||
{
|
||||
case CampaignMode.TransitionType.ReturnToPreviousEmptyLocation:
|
||||
mpCampaign.Map.SelectLocation(
|
||||
mpCampaign.Map.CurrentLocation.Connections.Find(c => c.LevelData == Level.Loaded?.LevelData).OtherLocation(mpCampaign.Map.CurrentLocation));
|
||||
if (forceLocation)
|
||||
{
|
||||
mpCampaign.Map.SelectLocation(
|
||||
mpCampaign.Map.CurrentLocation.Connections.Find(c => c.LevelData == Level.Loaded?.LevelData).OtherLocation(mpCampaign.Map.CurrentLocation));
|
||||
}
|
||||
mpCampaign.LoadNewLevel();
|
||||
break;
|
||||
case CampaignMode.TransitionType.ProgressToNextEmptyLocation:
|
||||
mpCampaign.Map.SetLocation(mpCampaign.Map.Locations.IndexOf(Level.Loaded.EndLocation));
|
||||
if (forceLocation)
|
||||
{
|
||||
mpCampaign.Map.SetLocation(mpCampaign.Map.Locations.IndexOf(Level.Loaded.EndLocation));
|
||||
}
|
||||
mpCampaign.LoadNewLevel();
|
||||
break;
|
||||
case CampaignMode.TransitionType.None:
|
||||
@@ -1556,11 +1597,11 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
distSqr = Math.Min(distSqr, Vector2.DistanceSquared(character.WorldPosition, c.Character.ViewTarget.WorldPosition));
|
||||
}
|
||||
if (distSqr >= NetConfig.DisableCharacterDistSqr) { continue; }
|
||||
if (distSqr >= MathUtils.Pow2(character.Params.DisableDistance)) { continue; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (character != c.Character && Vector2.DistanceSquared(character.WorldPosition, c.SpectatePos.Value) >= NetConfig.DisableCharacterDistSqr)
|
||||
if (character != c.Character && Vector2.DistanceSquared(character.WorldPosition, c.SpectatePos.Value) >= MathUtils.Pow2(character.Params.DisableDistance))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1850,6 +1891,8 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
outmsg.Write(autoRestartTimerRunning ? serverSettings.AutoRestartTimer : 0.0f);
|
||||
}
|
||||
|
||||
outmsg.Write(serverSettings.RadiationEnabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2031,12 +2074,12 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
startGameCoroutine = GameMain.Instance.ShowLoading(StartGame(selectedSub, selectedShuttle, selectedMode), false);
|
||||
startGameCoroutine = GameMain.Instance.ShowLoading(StartGame(selectedSub, selectedShuttle, selectedMode, CampaignSettings.Unsure), false);
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
private IEnumerable<object> StartGame(SubmarineInfo selectedSub, SubmarineInfo selectedShuttle, GameModePreset selectedMode)
|
||||
private IEnumerable<object> StartGame(SubmarineInfo selectedSub, SubmarineInfo selectedShuttle, GameModePreset selectedMode, CampaignSettings settings)
|
||||
{
|
||||
entityEventManager.Clear();
|
||||
|
||||
@@ -2064,7 +2107,7 @@ namespace Barotrauma.Networking
|
||||
//don't instantiate a new gamesession if we're playing a campaign
|
||||
if (campaign == null || GameMain.GameSession == null)
|
||||
{
|
||||
GameMain.GameSession = new GameSession(selectedSub, "", selectedMode, GameMain.NetLobbyScreen.LevelSeed, missionType: GameMain.NetLobbyScreen.MissionType);
|
||||
GameMain.GameSession = new GameSession(selectedSub, "", selectedMode, settings, GameMain.NetLobbyScreen.LevelSeed, missionType: GameMain.NetLobbyScreen.MissionType);
|
||||
}
|
||||
|
||||
List<Client> playingClients = new List<Client>(connectedClients);
|
||||
@@ -2110,7 +2153,6 @@ namespace Barotrauma.Networking
|
||||
Log("Game mode: " + selectedMode.Name, ServerLog.MessageType.ServerMessage);
|
||||
Log("Submarine: " + GameMain.GameSession.SubmarineInfo.Name, ServerLog.MessageType.ServerMessage);
|
||||
Log("Level seed: " + campaign.NextLevel.Seed, ServerLog.MessageType.ServerMessage);
|
||||
if (GameMain.GameSession.Mission != null) { Log("Mission: " + GameMain.GameSession.Mission.Prefab.Name, ServerLog.MessageType.ServerMessage); }
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2120,7 +2162,11 @@ namespace Barotrauma.Networking
|
||||
Log("Game mode: " + selectedMode.Name, ServerLog.MessageType.ServerMessage);
|
||||
Log("Submarine: " + selectedSub.Name, ServerLog.MessageType.ServerMessage);
|
||||
Log("Level seed: " + GameMain.NetLobbyScreen.LevelSeed, ServerLog.MessageType.ServerMessage);
|
||||
if (GameMain.GameSession.Mission != null) { Log("Mission: " + GameMain.GameSession.Mission.Prefab.Name, ServerLog.MessageType.ServerMessage); }
|
||||
}
|
||||
|
||||
foreach (Mission mission in GameMain.GameSession.Missions)
|
||||
{
|
||||
Log("Mission: " + mission.Prefab.Name, ServerLog.MessageType.ServerMessage);
|
||||
}
|
||||
|
||||
if (GameMain.GameSession.SubmarineInfo.IsFileCorrupted)
|
||||
@@ -2132,12 +2178,17 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
MissionMode missionMode = GameMain.GameSession.GameMode as MissionMode;
|
||||
bool missionAllowRespawn = GameMain.GameSession.Campaign == null && (missionMode?.Mission == null || missionMode.Mission.AllowRespawn);
|
||||
bool outpostAllowRespawn = GameMain.GameSession.Campaign != null && Level.Loaded?.Type == LevelData.LevelType.Outpost;
|
||||
bool missionAllowRespawn = missionMode == null || !missionMode.Missions.Any(m => !m.AllowRespawn);
|
||||
bool isOutpost = campaign != null && campaign.NextLevel?.Type == LevelData.LevelType.Outpost;
|
||||
|
||||
if (serverSettings.AllowRespawn && (missionAllowRespawn || outpostAllowRespawn))
|
||||
if (serverSettings.AllowRespawn && missionAllowRespawn)
|
||||
{
|
||||
respawnManager = new RespawnManager(this, serverSettings.UseRespawnShuttle && !outpostAllowRespawn ? selectedShuttle : null);
|
||||
respawnManager = new RespawnManager(this, serverSettings.UseRespawnShuttle && !isOutpost ? selectedShuttle : null);
|
||||
}
|
||||
if (campaign != null)
|
||||
{
|
||||
campaign.CargoManager.CreatePurchasedItems();
|
||||
campaign.SendCrewState(null, default, null);
|
||||
}
|
||||
|
||||
Level.Loaded?.SpawnNPCs();
|
||||
@@ -2202,7 +2253,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
client.CharacterInfo.ResetCurrentOrder();
|
||||
client.CharacterInfo.ClearCurrentOrders();
|
||||
}
|
||||
characterInfos.Add(client.CharacterInfo);
|
||||
if (client.CharacterInfo.Job == null || client.CharacterInfo.Job.Prefab != client.AssignedJob.First)
|
||||
@@ -2245,7 +2296,9 @@ namespace Barotrauma.Networking
|
||||
|
||||
List<WayPoint> spawnWaypoints = null;
|
||||
List<WayPoint> mainSubWaypoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSubs[n]).ToList();
|
||||
if (Level.Loaded?.StartOutpost != null && Level.Loaded.Type == LevelData.LevelType.Outpost &&
|
||||
if (Level.Loaded?.StartOutpost != null &&
|
||||
Level.Loaded.Type == LevelData.LevelType.Outpost &&
|
||||
(Level.Loaded.StartOutpost.Info.OutpostGenerationParams?.SpawnCrewInsideOutpost ?? false) &&
|
||||
Level.Loaded.StartOutpost.GetConnectedSubs().Any(s => s.Info.Type == SubmarineType.Player))
|
||||
{
|
||||
spawnWaypoints = WayPoint.WayPointList.FindAll(wp =>
|
||||
@@ -2322,7 +2375,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
foreach (Submarine sub in Submarine.MainSubs)
|
||||
{
|
||||
if (sub == null) continue;
|
||||
if (sub == null) { continue; }
|
||||
|
||||
List<PurchasedItem> spawnList = new List<PurchasedItem>();
|
||||
foreach (KeyValuePair<ItemPrefab, int> kvp in serverSettings.ExtraCargo)
|
||||
@@ -2330,7 +2383,7 @@ namespace Barotrauma.Networking
|
||||
spawnList.Add(new PurchasedItem(kvp.Key, kvp.Value));
|
||||
}
|
||||
|
||||
CargoManager.CreateItems(spawnList);
|
||||
CargoManager.CreateItems(spawnList, sub);
|
||||
}
|
||||
|
||||
TraitorManager = null;
|
||||
@@ -2385,12 +2438,11 @@ namespace Barotrauma.Networking
|
||||
msg.Write((byte)ServerPacketHeader.STARTGAME);
|
||||
msg.Write(seed);
|
||||
msg.Write(gameSession.GameMode.Preset.Identifier);
|
||||
|
||||
bool missionAllowRespawn = campaign == null && (missionMode?.Mission == null || missionMode.Mission.AllowRespawn);
|
||||
bool outpostAllowRespawn = campaign != null && campaign.NextLevel?.Type == LevelData.LevelType.Outpost;
|
||||
msg.Write(serverSettings.AllowRespawn && (missionAllowRespawn || outpostAllowRespawn));
|
||||
bool missionAllowRespawn = missionMode == null || !missionMode.Missions.Any(m => !m.AllowRespawn);
|
||||
msg.Write(serverSettings.AllowRespawn && missionAllowRespawn);
|
||||
msg.Write(serverSettings.AllowDisguises);
|
||||
msg.Write(serverSettings.AllowRewiring);
|
||||
msg.Write(serverSettings.LockAllDefaultWires);
|
||||
msg.Write(serverSettings.AllowRagdollButton);
|
||||
msg.Write(serverSettings.UseRespawnShuttle);
|
||||
msg.Write((byte)GameMain.Config.LosMode);
|
||||
@@ -2406,7 +2458,11 @@ namespace Barotrauma.Networking
|
||||
msg.Write(gameSession.SubmarineInfo.MD5Hash.Hash);
|
||||
msg.Write(GameMain.NetLobbyScreen.SelectedShuttle.Name);
|
||||
msg.Write(GameMain.NetLobbyScreen.SelectedShuttle.MD5Hash.Hash);
|
||||
msg.Write((short)(GameMain.GameSession.GameMode?.Mission == null ? -1 : MissionPrefab.List.IndexOf(GameMain.GameSession.GameMode.Mission.Prefab)));
|
||||
msg.Write((byte)GameMain.GameSession.GameMode.Missions.Count());
|
||||
foreach (Mission mission in GameMain.GameSession.GameMode.Missions)
|
||||
{
|
||||
msg.Write((short)MissionPrefab.List.IndexOf(mission.Prefab));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2446,13 +2502,20 @@ namespace Barotrauma.Networking
|
||||
msg.Write(contentFile.Path);
|
||||
}
|
||||
msg.Write(Submarine.MainSub?.Info.EqualityCheckVal ?? 0);
|
||||
msg.Write(GameMain.GameSession.Mission?.Prefab.Identifier ?? "");
|
||||
msg.Write((byte)GameMain.GameSession.Missions.Count());
|
||||
foreach (Mission mission in GameMain.GameSession.Missions)
|
||||
{
|
||||
msg.Write(mission.Prefab.Identifier);
|
||||
}
|
||||
msg.Write((byte)GameMain.GameSession.Level.EqualityCheckValues.Count);
|
||||
foreach (int equalityCheckValue in GameMain.GameSession.Level.EqualityCheckValues)
|
||||
{
|
||||
msg.Write(equalityCheckValue);
|
||||
}
|
||||
GameMain.GameSession.Mission?.ServerWriteInitial(msg, client);
|
||||
foreach (Mission mission in GameMain.GameSession.Missions)
|
||||
{
|
||||
mission.ServerWriteInitial(msg, client);
|
||||
}
|
||||
}
|
||||
|
||||
public void EndGame(CampaignMode.TransitionType transitionType = CampaignMode.TransitionType.None)
|
||||
@@ -2475,7 +2538,7 @@ namespace Barotrauma.Networking
|
||||
string endMessage = TextManager.FormatServerMessage("RoundSummaryRoundHasEnded");
|
||||
var traitorResults = TraitorManager?.GetEndResults() ?? new List<TraitorMissionResult>();
|
||||
|
||||
Mission mission = GameMain.GameSession.Mission;
|
||||
List<Mission> missions = GameMain.GameSession.Missions.ToList();
|
||||
if (GameMain.GameSession.IsRunning)
|
||||
{
|
||||
GameMain.GameSession.EndRound(endMessage, traitorResults);
|
||||
@@ -2517,7 +2580,11 @@ namespace Barotrauma.Networking
|
||||
msg.Write((byte)ServerPacketHeader.ENDGAME);
|
||||
msg.Write((byte)transitionType);
|
||||
msg.Write(endMessage);
|
||||
msg.Write(mission != null && mission.Completed);
|
||||
msg.Write((byte)missions.Count);
|
||||
foreach (Mission mission in missions)
|
||||
{
|
||||
msg.Write(mission.Completed);
|
||||
}
|
||||
msg.Write(GameMain.GameSession?.WinningTeam == null ? (byte)0 : (byte)GameMain.GameSession.WinningTeam);
|
||||
|
||||
msg.Write((byte)traitorResults.Count);
|
||||
@@ -2529,10 +2596,11 @@ namespace Barotrauma.Networking
|
||||
foreach (Client client in connectedClients)
|
||||
{
|
||||
serverPeer.Send(msg, client.Connection, DeliveryMethod.Reliable);
|
||||
client.Character?.ResetCurrentOrder();
|
||||
client.Character?.Info?.ClearCurrentOrders();
|
||||
client.Character = null;
|
||||
client.HasSpawned = false;
|
||||
client.InGame = false;
|
||||
client.WaitForNextRoundRespawn = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2694,6 +2762,10 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
serverSettings.BanList.BanPlayer(client.Name, client.SteamID, reason, duration);
|
||||
}
|
||||
if (client.OwnerSteamID > 0)
|
||||
{
|
||||
serverSettings.BanList.BanPlayer(client.Name, client.OwnerSteamID, reason, duration);
|
||||
}
|
||||
}
|
||||
|
||||
public void BanPreviousPlayer(PreviousPlayer previousPlayer, string reason, bool range = false, TimeSpan? duration = null)
|
||||
@@ -2713,6 +2785,10 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
serverSettings.BanList.BanPlayer(previousPlayer.Name, previousPlayer.SteamID, reason, duration);
|
||||
}
|
||||
if (previousPlayer.OwnerSteamID > 0)
|
||||
{
|
||||
serverSettings.BanList.BanPlayer(previousPlayer.Name, previousPlayer.OwnerSteamID, reason, duration);
|
||||
}
|
||||
|
||||
string msg = $"ServerMessage.BannedFromServer~[client]={previousPlayer.Name}";
|
||||
if (!string.IsNullOrWhiteSpace(reason))
|
||||
@@ -2760,9 +2836,10 @@ namespace Barotrauma.Networking
|
||||
|
||||
client.Character = null;
|
||||
client.HasSpawned = false;
|
||||
client.WaitForNextRoundRespawn = null;
|
||||
client.InGame = false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(msg)) { msg = $"ServerMessage.ClientLeftServer~[client]={client.Name}"; }
|
||||
if (string.IsNullOrWhiteSpace(msg)) { msg = $"ServerMessage.ClientLeftServer~[client]={ClientLogName(client)}"; }
|
||||
if (string.IsNullOrWhiteSpace(targetmsg)) { targetmsg = "ServerMessage.YouLeftServer"; }
|
||||
if (!string.IsNullOrWhiteSpace(reason))
|
||||
{
|
||||
@@ -2999,7 +3076,8 @@ namespace Barotrauma.Networking
|
||||
else if (type == ChatMessageType.Radio)
|
||||
{
|
||||
//send to chat-linked wifi components
|
||||
senderRadio.TransmitSignal(0, message, senderRadio.Item, senderCharacter, sentFromChat: true);
|
||||
Signal s = new Signal(message, sender: senderCharacter, source: senderRadio.Item);
|
||||
senderRadio.TransmitSignal(s, sentFromChat: true);
|
||||
}
|
||||
|
||||
//check which clients can receive the message and apply distance effects
|
||||
@@ -3050,7 +3128,7 @@ namespace Barotrauma.Networking
|
||||
string myReceivedMessage = type == ChatMessageType.Server || type == ChatMessageType.Error ? TextManager.GetServerMessage(message) : message;
|
||||
if (!string.IsNullOrWhiteSpace(myReceivedMessage))
|
||||
{
|
||||
AddChatMessage(myReceivedMessage, (ChatMessageType)type, senderName, senderCharacter);
|
||||
AddChatMessage(myReceivedMessage, (ChatMessageType)type, senderName, senderClient, senderCharacter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3072,14 +3150,14 @@ namespace Barotrauma.Networking
|
||||
if (!client.Character.CanHearCharacter(message.Sender)) { continue; }
|
||||
}
|
||||
|
||||
SendDirectChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.TargetEntity, message.TargetCharacter, message.Sender), client);
|
||||
SendDirectChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.OrderPriority, message.TargetEntity, message.TargetCharacter, message.Sender), client);
|
||||
}
|
||||
|
||||
string myReceivedMessage = message.Text;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(myReceivedMessage))
|
||||
{
|
||||
AddChatMessage(new OrderChatMessage(message.Order, message.OrderOption, myReceivedMessage, message.TargetEntity, message.TargetCharacter, message.Sender));
|
||||
AddChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.OrderPriority, myReceivedMessage, message.TargetEntity, message.TargetCharacter, message.Sender));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3461,9 +3539,9 @@ namespace Barotrauma.Networking
|
||||
unassigned.RemoveAt(i);
|
||||
}
|
||||
|
||||
//go throught the jobs whose MinNumber>0 (i.e. at least one crew member has to have the job)
|
||||
// Assign the necessary jobs that are always required at least one, in vanilla this means in practice the captain
|
||||
bool unassignedJobsFound = true;
|
||||
while (unassignedJobsFound && unassigned.Count > 0)
|
||||
while (unassignedJobsFound && unassigned.Any())
|
||||
{
|
||||
unassignedJobsFound = false;
|
||||
|
||||
@@ -3471,16 +3549,33 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (unassigned.Count == 0) { break; }
|
||||
if (jobPrefab.MinNumber < 1 || assignedClientCount[jobPrefab] >= jobPrefab.MinNumber) { continue; }
|
||||
// Find the client that wants the job the most, don't force any jobs yet, because it might be that we can meet the preference for other jobs.
|
||||
Client client = FindClientWithJobPreference(unassigned, jobPrefab, forceAssign: false);
|
||||
if (client != null)
|
||||
{
|
||||
AssignJob(client, jobPrefab);
|
||||
}
|
||||
}
|
||||
|
||||
//find the client that wants the job the most, or force it to random client if none of them want it
|
||||
Client assignedClient = FindClientWithJobPreference(unassigned, jobPrefab, true);
|
||||
if (unassigned.Any())
|
||||
{
|
||||
// Another pass, force required jobs that are not yet filled.
|
||||
foreach (JobPrefab jobPrefab in jobList)
|
||||
{
|
||||
if (unassigned.Count == 0) { break; }
|
||||
if (jobPrefab.MinNumber < 1 || assignedClientCount[jobPrefab] >= jobPrefab.MinNumber) { continue; }
|
||||
AssignJob(FindClientWithJobPreference(unassigned, jobPrefab, forceAssign: true), jobPrefab);
|
||||
}
|
||||
}
|
||||
|
||||
assignedClient.AssignedJob =
|
||||
assignedClient.JobPreferences.FirstOrDefault(jp => jp.First == jobPrefab) ??
|
||||
new Pair<JobPrefab, int>(jobPrefab, 0);
|
||||
void AssignJob(Client client, JobPrefab jobPrefab)
|
||||
{
|
||||
client.AssignedJob =
|
||||
client.JobPreferences.FirstOrDefault(jp => jp.First == jobPrefab) ??
|
||||
new Pair<JobPrefab, int>(jobPrefab, Rand.Int(jobPrefab.Variants));
|
||||
|
||||
assignedClientCount[jobPrefab]++;
|
||||
unassigned.Remove(assignedClient);
|
||||
unassigned.Remove(client);
|
||||
|
||||
//the job still needs more crew members, set unassignedJobsFound to true to keep the while loop running
|
||||
if (assignedClientCount[jobPrefab] < jobPrefab.MinNumber) { unassignedJobsFound = true; }
|
||||
@@ -3514,32 +3609,37 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
} while (unassigned.Count > 0 && canAssign);*/
|
||||
|
||||
//attempt to give the clients a job they have in their job preferences
|
||||
for (int i = unassigned.Count - 1; i >= 0; i--)
|
||||
// Attempt to give the clients a job they have in their job preferences.
|
||||
// First evaluate all the primary preferences, then all the secondary etc.
|
||||
for (int preferenceIndex = 0; preferenceIndex < 3; preferenceIndex++)
|
||||
{
|
||||
if (unassignedSpawnPoints.Count == 0) { break; }
|
||||
foreach (Pair<JobPrefab, int> preferredJob in unassigned[i].JobPreferences)
|
||||
if (unassignedSpawnPoints.None()) { break; }
|
||||
for (int i = unassigned.Count - 1; i >= 0; i--)
|
||||
{
|
||||
//can't assign this job if maximum number has reached or the clien't karma is too low
|
||||
if (assignedClientCount[preferredJob.First] >= preferredJob.First.MaxNumber || unassigned[i].Karma < preferredJob.First.MinKarma)
|
||||
if (unassignedSpawnPoints.None()) { break; }
|
||||
Client client = unassigned[i];
|
||||
if (preferenceIndex >= client.JobPreferences.Count) { continue; }
|
||||
var preferredJob = client.JobPreferences[preferenceIndex];
|
||||
JobPrefab jobPrefab = preferredJob.First;
|
||||
if (assignedClientCount[jobPrefab] >= jobPrefab.MaxNumber || client.Karma < jobPrefab.MinKarma)
|
||||
{
|
||||
//can't assign this job if maximum number has reached or the clien't karma is too low
|
||||
continue;
|
||||
}
|
||||
//give the client their preferred job if there's a spawnpoint available for that job
|
||||
var matchingSpawnPoint = unassignedSpawnPoints.Find(s => s.AssignedJob == preferredJob.First);
|
||||
//if the job is not available in any spawnpoint (custom job?), treat empty spawnpoints
|
||||
//as a matching ones
|
||||
if (matchingSpawnPoint == null && !availableSpawnPoints.Any(s => s.AssignedJob == preferredJob.First))
|
||||
var matchingSpawnPoint = unassignedSpawnPoints.Find(s => s.AssignedJob == jobPrefab);
|
||||
if (matchingSpawnPoint == null && !availableSpawnPoints.Any(s => s.AssignedJob == jobPrefab))
|
||||
{
|
||||
//if the job is not available in any spawnpoint (custom job?), treat empty spawnpoints
|
||||
//as a matching ones
|
||||
matchingSpawnPoint = unassignedSpawnPoints.Find(s => s.AssignedJob == null);
|
||||
}
|
||||
if (matchingSpawnPoint != null)
|
||||
{
|
||||
unassignedSpawnPoints.Remove(matchingSpawnPoint);
|
||||
unassigned[i].AssignedJob = preferredJob;
|
||||
assignedClientCount[preferredJob.First]++;
|
||||
client.AssignedJob = preferredJob;
|
||||
assignedClientCount[jobPrefab]++;
|
||||
unassigned.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3660,15 +3760,13 @@ namespace Barotrauma.Networking
|
||||
|
||||
private Client FindClientWithJobPreference(List<Client> clients, JobPrefab job, bool forceAssign = false)
|
||||
{
|
||||
int bestPreference = 0;
|
||||
int bestPreference = int.MaxValue;
|
||||
Client preferredClient = null;
|
||||
foreach (Client c in clients)
|
||||
{
|
||||
if (c.Karma < job.MinKarma) continue;
|
||||
if (ServerSettings.KarmaEnabled && c.Karma < job.MinKarma) { continue; }
|
||||
int index = c.JobPreferences.IndexOf(c.JobPreferences.Find(j => j.First == job));
|
||||
if (index == -1) index = 1000;
|
||||
|
||||
if (preferredClient == null || index < bestPreference)
|
||||
if (index > -1 && index < bestPreference)
|
||||
{
|
||||
bestPreference = index;
|
||||
preferredClient = c;
|
||||
@@ -3684,29 +3782,19 @@ namespace Barotrauma.Networking
|
||||
return preferredClient;
|
||||
}
|
||||
|
||||
public void UpdateMissionState(int state)
|
||||
public void UpdateMissionState(Mission mission, int state)
|
||||
{
|
||||
foreach (var client in connectedClients)
|
||||
{
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte)ServerPacketHeader.MISSION);
|
||||
int missionIndex = GameMain.GameSession.GetMissionIndex(mission);
|
||||
msg.Write((byte)(missionIndex == -1 ? 255: missionIndex));
|
||||
msg.Write((ushort)state);
|
||||
serverPeer.Send(msg, client.Connection, DeliveryMethod.Reliable);
|
||||
}
|
||||
}
|
||||
|
||||
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]"; }
|
||||
@@ -3782,6 +3870,7 @@ namespace Barotrauma.Networking
|
||||
public string Name;
|
||||
public string EndPoint;
|
||||
public UInt64 SteamID;
|
||||
public UInt64 OwnerSteamID;
|
||||
public float Karma;
|
||||
public int KarmaKickCount;
|
||||
public readonly List<Client> KickVoters = new List<Client>();
|
||||
@@ -3791,6 +3880,7 @@ namespace Barotrauma.Networking
|
||||
Name = c.Name;
|
||||
EndPoint = c.Connection?.EndPointString ?? "";
|
||||
SteamID = c.SteamID;
|
||||
OwnerSteamID = c.OwnerSteamID;
|
||||
}
|
||||
|
||||
public bool MatchesClient(Client c)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
partial class OrderChatMessage : ChatMessage
|
||||
{
|
||||
@@ -9,34 +7,19 @@ namespace Barotrauma.Networking
|
||||
msg.Write((byte)ServerNetObject.CHAT_MESSAGE);
|
||||
msg.Write(NetStateID);
|
||||
msg.Write((byte)ChatMessageType.Order);
|
||||
|
||||
msg.Write(SenderName);
|
||||
msg.Write(SenderClient != null);
|
||||
if (SenderClient != null)
|
||||
{
|
||||
msg.Write((SenderClient.SteamID != 0) ? SenderClient.SteamID : SenderClient.ID);
|
||||
}
|
||||
msg.Write(Sender != null && c.InGame);
|
||||
if (Sender != null && c.InGame)
|
||||
{
|
||||
msg.Write(Sender.ID);
|
||||
}
|
||||
|
||||
msg.Write((byte)Order.PrefabList.IndexOf(Order.Prefab));
|
||||
msg.Write(TargetCharacter == null ? (UInt16)0 : TargetCharacter.ID);
|
||||
msg.Write(TargetEntity is Entity ? (TargetEntity as Entity).ID : (UInt16)0);
|
||||
msg.Write((byte)Array.IndexOf(Order.Prefab.Options, OrderOption));
|
||||
msg.Write((byte)Order.TargetType);
|
||||
if (Order.TargetType == Order.OrderTargetType.Position && TargetEntity is OrderTarget orderTarget)
|
||||
{
|
||||
msg.Write(true);
|
||||
msg.Write(orderTarget.Position.X);
|
||||
msg.Write(orderTarget.Position.Y);
|
||||
msg.Write(orderTarget.Hull == null ? (UInt16)0 : orderTarget.Hull.ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write(false);
|
||||
if (Order.TargetType == Order.OrderTargetType.WallSection)
|
||||
{
|
||||
msg.Write((byte)(WallSectionIndex ?? Order.WallSectionIndex ?? 0));
|
||||
}
|
||||
}
|
||||
msg.WritePadBits();
|
||||
WriteOrder(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-6
@@ -184,7 +184,7 @@ namespace Barotrauma.Networking
|
||||
return;
|
||||
}
|
||||
|
||||
if (serverSettings.BanList.IsBanned(inc.SenderConnection.RemoteEndPoint.Address, 0, out string banReason))
|
||||
if (serverSettings.BanList.IsBanned(inc.SenderConnection.RemoteEndPoint.Address, 0, 0, out string banReason))
|
||||
{
|
||||
//IP banned: deny immediately
|
||||
inc.SenderConnection.Deny(DisconnectReason.Banned.ToString() + "/ " + banReason);
|
||||
@@ -233,7 +233,7 @@ namespace Barotrauma.Networking
|
||||
return;
|
||||
}
|
||||
if (pendingClient != null) { pendingClients.Remove(pendingClient); }
|
||||
if (serverSettings.BanList.IsBanned(conn.IPEndPoint.Address, conn.SteamID, out string banReason))
|
||||
if (serverSettings.BanList.IsBanned(conn.IPEndPoint.Address, conn.SteamID, conn.OwnerSteamID, out string banReason))
|
||||
{
|
||||
Disconnect(conn, DisconnectReason.Banned.ToString() + "/ " + banReason);
|
||||
return;
|
||||
@@ -308,7 +308,8 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
LidgrenConnection pendingConnection = pendingClient.Connection as LidgrenConnection;
|
||||
if (serverSettings.BanList.IsBanned(pendingConnection.NetConnection.RemoteEndPoint.Address, steamID, out string banReason))
|
||||
string banReason;
|
||||
if (serverSettings.BanList.IsBanned(pendingConnection.NetConnection.RemoteEndPoint.Address, steamID, ownerID, out banReason))
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.Banned, banReason);
|
||||
return;
|
||||
@@ -316,6 +317,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (status == Steamworks.AuthResponse.OK)
|
||||
{
|
||||
pendingClient.OwnerSteamID = ownerID;
|
||||
pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.ContentPackageOrder;
|
||||
pendingClient.UpdateTime = Timing.TotalTime;
|
||||
}
|
||||
@@ -442,8 +444,16 @@ namespace Barotrauma.Networking
|
||||
Steamworks.BeginAuthResult authSessionStartState = Steam.SteamManager.StartAuthSession(ticket, steamId);
|
||||
if (authSessionStartState != Steamworks.BeginAuthResult.OK)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed, "Steam auth session failed to start: " + authSessionStartState.ToString());
|
||||
return;
|
||||
if (requireSteamAuth)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed, "Steam auth session failed to start: " + authSessionStartState.ToString());
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
steamId = 0;
|
||||
pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.ContentPackageOrder;
|
||||
}
|
||||
}
|
||||
pendingClient.SteamID = steamId;
|
||||
pendingClient.Connection.Name = name;
|
||||
@@ -452,7 +462,7 @@ namespace Barotrauma.Networking
|
||||
pendingClient.AuthSessionStarted = true;
|
||||
}
|
||||
}
|
||||
else //TODO: could remove since this seems impossible
|
||||
else
|
||||
{
|
||||
if (pendingClient.SteamID != steamId)
|
||||
{
|
||||
|
||||
+19
-5
@@ -49,6 +49,16 @@ namespace Barotrauma.Networking
|
||||
Connection.SetSteamIDIfUnknown(value ?? 0);
|
||||
}
|
||||
}
|
||||
private UInt64? ownerSteamId;
|
||||
public UInt64? OwnerSteamID
|
||||
{
|
||||
get { return ownerSteamId; }
|
||||
set
|
||||
{
|
||||
ownerSteamId = value;
|
||||
Connection.SetOwnerSteamIDIfUnknown(value ?? 0);
|
||||
}
|
||||
}
|
||||
public Int32? PasswordSalt;
|
||||
public bool AuthSessionStarted;
|
||||
|
||||
@@ -59,6 +69,7 @@ namespace Barotrauma.Networking
|
||||
InitializationStep = ConnectionInitialization.SteamTicketAndVersion;
|
||||
Retries = 0;
|
||||
SteamID = null;
|
||||
OwnerSteamID = null;
|
||||
PasswordSalt = null;
|
||||
UpdateTime = Timing.TotalTime + Timing.Step * 3.0;
|
||||
TimeOut = NetworkConnection.TimeoutThreshold;
|
||||
@@ -107,8 +118,8 @@ namespace Barotrauma.Networking
|
||||
RemovePendingClient(pendingClient, DisconnectReason.InvalidVersion,
|
||||
$"DisconnectMessage.InvalidVersion~[version]={GameMain.Version}~[clientversion]={version}");
|
||||
|
||||
GameServer.Log(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (incompatible game version)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (incompatible game version)", Microsoft.Xna.Framework.Color.Red);
|
||||
GameServer.Log($"{name} ({steamId}) couldn't join the server (incompatible game version)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage($"{name} ({steamId}) couldn't join the server (incompatible game version)", Microsoft.Xna.Framework.Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -119,7 +130,7 @@ namespace Barotrauma.Networking
|
||||
if (nameTaken != null)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.NameTaken, "");
|
||||
GameServer.Log(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (name too similar to the name of the client \"" + nameTaken.Name + "\").", ServerLog.MessageType.Error);
|
||||
GameServer.Log($"{name} ({steamId}) couldn't join the server (name too similar to the name of the client \"" + nameTaken.Name + "\").", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -172,6 +183,7 @@ namespace Barotrauma.Networking
|
||||
else if (pendingClient.Connection is SteamP2PConnection s)
|
||||
{
|
||||
serverSettings.BanList.BanPlayer(pendingClient.Name, s.SteamID, banReason, duration);
|
||||
serverSettings.BanList.BanPlayer(pendingClient.Name, s.OwnerSteamID, banReason, duration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +195,8 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else if (pendingClient.Connection is SteamP2PConnection s)
|
||||
{
|
||||
return serverSettings.BanList.IsBanned(s.SteamID, out banReason);
|
||||
return serverSettings.BanList.IsBanned(s.SteamID, out banReason) ||
|
||||
serverSettings.BanList.IsBanned(s.OwnerSteamID, out banReason);
|
||||
}
|
||||
banReason = null;
|
||||
return false;
|
||||
@@ -199,7 +212,7 @@ namespace Barotrauma.Networking
|
||||
return;
|
||||
}
|
||||
|
||||
if (connectedClients.Count >= serverSettings.MaxPlayers - 1)
|
||||
if (connectedClients.Count >= serverSettings.MaxPlayers)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.ServerFull, "");
|
||||
}
|
||||
@@ -273,6 +286,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
Steam.SteamManager.StopAuthSession(pendingClient.SteamID.Value);
|
||||
pendingClient.SteamID = null;
|
||||
pendingClient.OwnerSteamID = null;
|
||||
pendingClient.AuthSessionStarted = false;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -123,6 +123,7 @@ namespace Barotrauma.Networking
|
||||
if (!started) { return; }
|
||||
|
||||
UInt64 senderSteamId = inc.ReadUInt64();
|
||||
UInt64 ownerSteamId = inc.ReadUInt64();
|
||||
|
||||
byte incByte = inc.ReadByte();
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
@@ -145,7 +146,9 @@ namespace Barotrauma.Networking
|
||||
pendingClient?.Heartbeat();
|
||||
connectedClient?.Heartbeat();
|
||||
|
||||
if (serverSettings.BanList.IsBanned(senderSteamId, out string banReason))
|
||||
string banReason;
|
||||
if (serverSettings.BanList.IsBanned(senderSteamId, out banReason) ||
|
||||
serverSettings.BanList.IsBanned(ownerSteamId, out banReason))
|
||||
{
|
||||
if (pendingClient != null)
|
||||
{
|
||||
@@ -181,6 +184,10 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (pendingClient != null)
|
||||
{
|
||||
if (ownerSteamId != 0)
|
||||
{
|
||||
pendingClient.Connection.SetOwnerSteamIDIfUnknown(ownerSteamId);
|
||||
}
|
||||
ReadConnectionInitializationStep(pendingClient, new ReadOnlyMessage(inc.Buffer, false, inc.BytePosition, inc.LengthBytes - inc.BytePosition, null));
|
||||
}
|
||||
else
|
||||
@@ -223,6 +230,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
Language = GameMain.Config.Language
|
||||
};
|
||||
OwnerConnection.SetOwnerSteamIDIfUnknown(OwnerSteamID);
|
||||
|
||||
OnInitializationComplete?.Invoke(OwnerConnection);
|
||||
}
|
||||
|
||||
@@ -19,14 +19,22 @@ namespace Barotrauma.Networking
|
||||
if (c.SpectateOnly && (GameMain.Server.ServerSettings.AllowSpectating || GameMain.Server.OwnerConnection == c.Connection)) { continue; }
|
||||
if (c.Character != null && !c.Character.IsDead) { continue; }
|
||||
|
||||
//don't allow respawning if the client has previously disconnected and their corpse is still present on the server
|
||||
//don't allow respawn if the client already has a character (they'll regain control once they're in sync)
|
||||
var matchingData = campaign?.GetClientCharacterData(c);
|
||||
if (matchingData != null && matchingData.HasSpawned &&
|
||||
Character.CharacterList.Any(c => c.Info == matchingData.CharacterInfo && c.CauseOfDeath?.Type == CauseOfDeathType.Disconnected))
|
||||
if (matchingData != null && matchingData.HasSpawned &&
|
||||
Character.CharacterList.Any(c => c.Info == matchingData.CharacterInfo && !c.IsDead))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (UseRespawnPrompt)
|
||||
{
|
||||
if (matchingData != null && matchingData.HasSpawned)
|
||||
{
|
||||
if (!c.WaitForNextRoundRespawn.HasValue || c.WaitForNextRoundRespawn.Value) { continue; }
|
||||
}
|
||||
}
|
||||
|
||||
yield return c;
|
||||
}
|
||||
}
|
||||
@@ -68,34 +76,53 @@ namespace Barotrauma.Networking
|
||||
return botsToRespawn;
|
||||
}
|
||||
|
||||
private bool RespawnPending()
|
||||
private bool ShouldStartRespawnCountdown()
|
||||
{
|
||||
int characterToRespawnCount = GetClientsToRespawn().Count();
|
||||
return ShouldStartRespawnCountdown(characterToRespawnCount);
|
||||
}
|
||||
|
||||
private bool ShouldStartRespawnCountdown(int characterToRespawnCount)
|
||||
{
|
||||
int totalCharacterCount = GameMain.Server.ConnectedClients.Count;
|
||||
return (float)characterToRespawnCount >= Math.Max((float)totalCharacterCount * GameMain.Server.ServerSettings.MinRespawnRatio, 1.0f);
|
||||
}
|
||||
|
||||
partial void UpdateWaiting(float deltaTime)
|
||||
{
|
||||
bool respawnPending = RespawnPending();
|
||||
if (respawnPending != RespawnCountdownStarted)
|
||||
if (RespawnShuttle != null)
|
||||
{
|
||||
RespawnCountdownStarted = respawnPending;
|
||||
RespawnTime = DateTime.Now + new TimeSpan(0,0,0,0, (int)(GameMain.Server.ServerSettings.RespawnInterval * 1000.0f));
|
||||
GameMain.Server.CreateEntityEvent(this);
|
||||
RespawnShuttle.Velocity = Vector2.Zero;
|
||||
}
|
||||
|
||||
if (!RespawnCountdownStarted) { return; }
|
||||
int clientsToRespawn = GetClientsToRespawn().Count();
|
||||
if (RespawnCountdownStarted)
|
||||
{
|
||||
if (clientsToRespawn == 0)
|
||||
{
|
||||
RespawnCountdownStarted = false;
|
||||
GameMain.Server.CreateEntityEvent(this);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool shouldStartCountdown = ShouldStartRespawnCountdown(clientsToRespawn);
|
||||
if (shouldStartCountdown)
|
||||
{
|
||||
RespawnCountdownStarted = true;
|
||||
if (RespawnTime < DateTime.Now)
|
||||
{
|
||||
RespawnTime = DateTime.Now + new TimeSpan(0, 0, 0, 0, (int)(GameMain.Server.ServerSettings.RespawnInterval * 1000.0f));
|
||||
}
|
||||
GameMain.Server.CreateEntityEvent(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (DateTime.Now > RespawnTime)
|
||||
if (RespawnCountdownStarted && DateTime.Now > RespawnTime)
|
||||
{
|
||||
DispatchShuttle();
|
||||
RespawnCountdownStarted = false;
|
||||
}
|
||||
|
||||
if (RespawnShuttle == null) { return; }
|
||||
|
||||
RespawnShuttle.Velocity = Vector2.Zero;
|
||||
}
|
||||
|
||||
private void DispatchShuttle()
|
||||
@@ -114,10 +141,10 @@ namespace Barotrauma.Networking
|
||||
|
||||
GameServer.Log("Dispatching the respawn shuttle.", ServerLog.MessageType.Spawning);
|
||||
|
||||
RespawnCharacters();
|
||||
Vector2 spawnPos = FindSpawnPos();
|
||||
RespawnCharacters(spawnPos);
|
||||
|
||||
CoroutineManager.StopCoroutines("forcepos");
|
||||
Vector2 spawnPos = FindSpawnPos();
|
||||
if (spawnPos.Y > Level.Loaded.Size.Y)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(ForceShuttleToPos(Level.Loaded.StartPosition - Vector2.UnitY * Level.ShaftHeight, 100.0f), "forcepos");
|
||||
@@ -136,7 +163,7 @@ namespace Barotrauma.Networking
|
||||
GameServer.Log("Respawning everyone in main sub.", ServerLog.MessageType.Spawning);
|
||||
GameMain.Server.CreateEntityEvent(this);
|
||||
|
||||
RespawnCharacters();
|
||||
RespawnCharacters(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +210,6 @@ namespace Barotrauma.Networking
|
||||
|
||||
partial void UpdateTransportingProjSpecific(float deltaTime)
|
||||
{
|
||||
|
||||
if (!ReturnCountdownStarted)
|
||||
{
|
||||
//if there are no living chracters inside, transporting can be stopped immediately
|
||||
@@ -192,7 +218,7 @@ namespace Barotrauma.Networking
|
||||
ReturnTime = DateTime.Now;
|
||||
ReturnCountdownStarted = true;
|
||||
}
|
||||
else if (!RespawnPending())
|
||||
else if (!ShouldStartRespawnCountdown())
|
||||
{
|
||||
//don't start counting down until someone else needs to respawn
|
||||
ReturnTime = DateTime.Now + new TimeSpan(0, 0, 0, 0, milliseconds: (int)(maxTransportTime * 1000));
|
||||
@@ -218,7 +244,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
partial void RespawnCharactersProjSpecific()
|
||||
partial void RespawnCharactersProjSpecific(Vector2? shuttlePos)
|
||||
{
|
||||
var respawnSub = RespawnShuttle ?? Submarine.MainSub;
|
||||
|
||||
@@ -230,6 +256,8 @@ namespace Barotrauma.Networking
|
||||
//get rid of the existing character
|
||||
c.Character?.DespawnNow();
|
||||
|
||||
c.WaitForNextRoundRespawn = null;
|
||||
|
||||
var matchingData = campaign?.GetClientCharacterData(c);
|
||||
if (matchingData != null && !matchingData.HasSpawned)
|
||||
{
|
||||
@@ -265,10 +293,21 @@ namespace Barotrauma.Networking
|
||||
//(in order to give them appropriate ID card tags)
|
||||
var mainSubSpawnPoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub);
|
||||
|
||||
ItemPrefab divingSuitPrefab = MapEntityPrefab.Find(null, "divingsuit") as ItemPrefab;
|
||||
ItemPrefab oxyPrefab = MapEntityPrefab.Find(null, "oxygentank") as ItemPrefab;
|
||||
ItemPrefab scooterPrefab = MapEntityPrefab.Find(null, "underwaterscooter") as ItemPrefab;
|
||||
ItemPrefab batteryPrefab = MapEntityPrefab.Find(null, "batterycell") as ItemPrefab;
|
||||
ItemPrefab divingSuitPrefab = null;
|
||||
if ((shuttlePos != null && Level.Loaded.GetRealWorldDepth(shuttlePos.Value.Y) > Level.DefaultRealWorldCrushDepth) ||
|
||||
Level.Loaded.GetRealWorldDepth(Submarine.MainSub.WorldPosition.Y) > Level.DefaultRealWorldCrushDepth)
|
||||
{
|
||||
divingSuitPrefab = ItemPrefab.Prefabs.FirstOrDefault(it => it.Tags.Any(t => t.Equals("respawnsuitdeep", StringComparison.OrdinalIgnoreCase)));
|
||||
}
|
||||
if (divingSuitPrefab == null)
|
||||
{
|
||||
divingSuitPrefab =
|
||||
ItemPrefab.Prefabs.FirstOrDefault(it => it.Tags.Any(t => t.Equals("respawnsuit", StringComparison.OrdinalIgnoreCase))) ??
|
||||
ItemPrefab.Find(null, "divingsuit");
|
||||
}
|
||||
ItemPrefab oxyPrefab = ItemPrefab.Find(null, "oxygentank");
|
||||
ItemPrefab scooterPrefab = ItemPrefab.Find(null, "underwaterscooter");
|
||||
ItemPrefab batteryPrefab = ItemPrefab.Find(null, "batterycell");
|
||||
|
||||
var cargoSp = WayPoint.WayPointList.Find(wp => wp.Submarine == respawnSub && wp.SpawnType == SpawnType.Cargo);
|
||||
|
||||
@@ -276,8 +315,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
bool bot = i >= clients.Count;
|
||||
|
||||
characterInfos[i].CurrentOrder = null;
|
||||
characterInfos[i].CurrentOrderOption = null;
|
||||
characterInfos[i].ClearCurrentOrders();
|
||||
|
||||
var character = Character.Create(characterInfos[i], shuttleSpawnPoints[i].WorldPosition, characterInfos[i].Name, isRemotePlayer: !bot, hasAi: bot);
|
||||
character.TeamID = CharacterTeamType.Team1;
|
||||
@@ -333,6 +371,15 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
var characterData = campaign?.GetClientCharacterData(clients[i]);
|
||||
if (characterData != null && Level.Loaded?.Type != LevelData.LevelType.Outpost && characterData.HasSpawned)
|
||||
{
|
||||
var respawnPenaltyAffliction = AfflictionPrefab.List.FirstOrDefault(a => a.AfflictionType.Equals("respawnpenalty", StringComparison.OrdinalIgnoreCase));
|
||||
if (respawnPenaltyAffliction != null)
|
||||
{
|
||||
character.CharacterHealth.ApplyAffliction(targetLimb: null, respawnPenaltyAffliction.Instantiate(10.0f));
|
||||
}
|
||||
}
|
||||
|
||||
if (characterData == null || characterData.HasSpawned)
|
||||
{
|
||||
//give the character the items they would've gotten if they had spawned in the main sub
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace Barotrauma.Networking
|
||||
outMsg.Write((byte)MaxPlayers);
|
||||
outMsg.Write(HasPassword);
|
||||
outMsg.Write(IsPublic);
|
||||
outMsg.Write(AllowFileTransfers);
|
||||
outMsg.WritePadBits();
|
||||
outMsg.WriteRangedInteger(TickRate, 1, 60);
|
||||
|
||||
@@ -159,6 +160,8 @@ namespace Barotrauma.Networking
|
||||
AutoRestart = autoRestart;
|
||||
}
|
||||
|
||||
RadiationEnabled = incMsg.ReadBoolean();
|
||||
|
||||
changed |= true;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Barotrauma
|
||||
|
||||
public void ServerRead(IReadMessage inc, Client sender)
|
||||
{
|
||||
if (GameMain.Server == null || sender == null) return;
|
||||
if (GameMain.Server == null || sender == null) { return; }
|
||||
|
||||
byte voteTypeByte = inc.ReadByte();
|
||||
VoteType voteType = VoteType.Unknown;
|
||||
@@ -83,7 +83,10 @@ namespace Barotrauma
|
||||
{
|
||||
case VoteType.Sub:
|
||||
int equalityCheckVal = inc.ReadInt32();
|
||||
SubmarineInfo sub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.EqualityCheckVal == equalityCheckVal);
|
||||
string hash = equalityCheckVal > 0 ? string.Empty : inc.ReadString();
|
||||
SubmarineInfo sub = equalityCheckVal > 0 ?
|
||||
SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Type == SubmarineType.Player && s.EqualityCheckVal == equalityCheckVal) :
|
||||
SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Type == SubmarineType.Player && s.MD5Hash.Hash == hash);
|
||||
sender.SetVote(voteType, sub);
|
||||
break;
|
||||
case VoteType.Mode:
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Barotrauma
|
||||
if (Math.Abs(FarseerBody.LinearVelocity.X) > MaxVel ||
|
||||
Math.Abs(FarseerBody.LinearVelocity.Y) > MaxVel)
|
||||
{
|
||||
DebugConsole.ThrowError("Item velocity out of range (" + FarseerBody.LinearVelocity + ")");
|
||||
DebugConsole.ThrowError($"Entity velocity out of range ({(UserData?.ToString() ?? "null")}, {FarseerBody.LinearVelocity})");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -42,6 +42,14 @@ namespace Barotrauma
|
||||
#endif
|
||||
Console.WriteLine("Barotrauma Dedicated Server " + GameMain.Version +
|
||||
" (" + AssemblyInfo.BuildString + ", branch " + AssemblyInfo.GitBranch + ", revision " + AssemblyInfo.GitRevision + ")");
|
||||
if(Console.IsOutputRedirected)
|
||||
{
|
||||
Console.WriteLine("Output redirection detected; colored text and command input will be disabled.");
|
||||
}
|
||||
if(Console.IsInputRedirected)
|
||||
{
|
||||
Console.WriteLine("Redirected input is detected but is not supported by this application. Input will be ignored.");
|
||||
}
|
||||
|
||||
string executableDir = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
|
||||
Directory.SetCurrentDirectory(executableDir);
|
||||
@@ -152,7 +160,11 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
string crashReport = sb.ToString();
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
|
||||
if (!Console.IsOutputRedirected)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
}
|
||||
Console.Write(crashReport);
|
||||
|
||||
File.WriteAllText(filePath,sb.ToString());
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace Barotrauma
|
||||
private SubmarineInfo selectedSub;
|
||||
private SubmarineInfo selectedShuttle;
|
||||
|
||||
public bool RadiationEnabled = true;
|
||||
|
||||
public SubmarineInfo SelectedSub
|
||||
{
|
||||
get { return selectedSub; }
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace Barotrauma
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (GameMain.GameSession.Mission is CombatMission)
|
||||
if (GameMain.GameSession.Missions.Any(m => m is CombatMission))
|
||||
{
|
||||
var teamIds = new[] { CharacterTeamType.Team1, CharacterTeamType.Team2 };
|
||||
foreach (var teamId in teamIds)
|
||||
|
||||
@@ -249,7 +249,7 @@ namespace Barotrauma
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Traitors.Values.Any(traitor => traitor.Character?.IsDead ?? true || traitor.Character.Removed))
|
||||
if (Traitors.Values.Any(traitor => traitor.Character == null || traitor.Character.IsDead || traitor.Character.Removed))
|
||||
{
|
||||
Traitors.Values.ForEach(traitor => traitor.UpdateCurrentObjective("", Identifier));
|
||||
pendingObjectives.Clear();
|
||||
|
||||
Reference in New Issue
Block a user