v0.14.6.0
This commit is contained in:
@@ -283,24 +283,25 @@ namespace Barotrauma
|
||||
|
||||
if (extraData != null)
|
||||
{
|
||||
const int min = 0, max = 9;
|
||||
switch ((NetEntityEvent.Type)extraData[0])
|
||||
{
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
msg.WriteRangedInteger(0, 0, 6);
|
||||
msg.WriteRangedInteger(0, min, max);
|
||||
msg.Write(GameMain.Server.EntityEventManager.Events.Last()?.ID ?? (ushort)0);
|
||||
Inventory.ServerWrite(msg, c);
|
||||
break;
|
||||
case NetEntityEvent.Type.Control:
|
||||
msg.WriteRangedInteger(1, 0, 6);
|
||||
msg.WriteRangedInteger(1, min, max);
|
||||
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, 6);
|
||||
msg.WriteRangedInteger(2, min, max);
|
||||
WriteStatus(msg);
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdateSkills:
|
||||
msg.WriteRangedInteger(3, 0, 6);
|
||||
msg.WriteRangedInteger(3, min, max);
|
||||
if (Info?.Job == null)
|
||||
{
|
||||
msg.Write((byte)0);
|
||||
@@ -315,39 +316,83 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetEntityEvent.Type.SetAttackTarget:
|
||||
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, 6);
|
||||
msg.WriteRangedInteger(extraData[0] is NetEntityEvent.Type.SetAttackTarget ? 4 : 5, min, max);
|
||||
msg.Write((byte)(Removed ? 255 : Array.IndexOf(AnimController.Limbs, attackLimb)));
|
||||
msg.Write(targetEntityID);
|
||||
msg.Write((byte)targetLimbIndex);
|
||||
msg.Write(extraData.Length > 4 ? (float)extraData[4] : 0);
|
||||
msg.Write(extraData.Length > 5 ? (float)extraData[5] : 0);
|
||||
break;
|
||||
case NetEntityEvent.Type.AssignCampaignInteraction:
|
||||
msg.WriteRangedInteger(5, 0, 6);
|
||||
msg.WriteRangedInteger(6, min, max);
|
||||
msg.Write((byte)CampaignInteractionType);
|
||||
msg.Write(RequireConsciousnessForCustomInteract);
|
||||
break;
|
||||
case NetEntityEvent.Type.ObjectiveManagerOrderState:
|
||||
msg.WriteRangedInteger(6, 0, 6);
|
||||
case NetEntityEvent.Type.ObjectiveManagerState:
|
||||
msg.WriteRangedInteger(7, min, max);
|
||||
int type = (extraData[1] as string) switch
|
||||
{
|
||||
"order" => 1,
|
||||
"objective" => 2,
|
||||
_ => 0
|
||||
};
|
||||
msg.WriteRangedInteger(type, 0, 2);
|
||||
if (!(AIController is HumanAIController controller))
|
||||
{
|
||||
msg.Write(false);
|
||||
break;
|
||||
}
|
||||
var currentOrderInfo = controller.ObjectiveManager.GetCurrentOrderInfo();
|
||||
if (!currentOrderInfo.HasValue)
|
||||
if (type == 1)
|
||||
{
|
||||
msg.Write(false);
|
||||
break;
|
||||
var currentOrderInfo = controller.ObjectiveManager.GetCurrentOrderInfo();
|
||||
bool validOrder = currentOrderInfo.HasValue;
|
||||
msg.Write(validOrder);
|
||||
if (!validOrder) { break; }
|
||||
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.AllOptions.IndexOf(currentOrderInfo.Value.OrderOption);
|
||||
if (optionIndex == -1)
|
||||
{
|
||||
DebugConsole.AddWarning($"Error while writing order data. Order option \"{(currentOrderInfo.Value.OrderOption ?? null)}\" not found in the order prefab \"{orderPrefab.Name}\".");
|
||||
}
|
||||
msg.WriteRangedInteger(optionIndex, -1, orderPrefab.AllOptions.Length);
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
var objective = controller.ObjectiveManager.CurrentObjective;
|
||||
bool validObjective = !string.IsNullOrEmpty(objective?.Identifier);
|
||||
msg.Write(validObjective);
|
||||
if (!validObjective) { break; }
|
||||
msg.Write(objective.Identifier);
|
||||
msg.Write(objective.Option ?? "");
|
||||
UInt16 targetEntityId = 0;
|
||||
if (objective is AIObjectiveOperateItem operateObjective && operateObjective.OperateTarget != null)
|
||||
{
|
||||
targetEntityId = operateObjective.OperateTarget.ID;
|
||||
}
|
||||
msg.Write(targetEntityId);
|
||||
}
|
||||
break;
|
||||
case NetEntityEvent.Type.TeamChange:
|
||||
msg.WriteRangedInteger(8, min, max);
|
||||
msg.Write((byte)TeamID);
|
||||
break;
|
||||
case NetEntityEvent.Type.AddToCrew:
|
||||
msg.WriteRangedInteger(9, min, max);
|
||||
msg.Write((byte)(CharacterTeamType)extraData[1]); // team id
|
||||
ushort[] inventoryItemIDs = (ushort[])extraData[2];
|
||||
msg.Write((ushort)inventoryItemIDs.Length);
|
||||
for (int i = 0; i < inventoryItemIDs.Length; i++)
|
||||
{
|
||||
msg.Write(inventoryItemIDs[i]);
|
||||
}
|
||||
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] + ")");
|
||||
|
||||
@@ -1688,13 +1688,18 @@ namespace Barotrauma
|
||||
"heal",
|
||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
Character healedCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args);
|
||||
bool healAll = args.Length > 1 && args[1].Equals("all", StringComparison.OrdinalIgnoreCase);
|
||||
Character healedCharacter = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(healAll ? args.Take(args.Length - 1).ToArray() : args);
|
||||
if (healedCharacter != null)
|
||||
{
|
||||
healedCharacter.SetAllDamage(0.0f, 0.0f, 0.0f);
|
||||
healedCharacter.Oxygen = 100.0f;
|
||||
healedCharacter.Bloodloss = 0.0f;
|
||||
healedCharacter.SetStun(0.0f, true);
|
||||
if (healAll)
|
||||
{
|
||||
healedCharacter.CharacterHealth.RemoveAllAfflictions();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -15,9 +17,45 @@ namespace Barotrauma
|
||||
private static readonly Dictionary<Client, ConversationAction> lastActiveAction = new Dictionary<Client, ConversationAction>();
|
||||
|
||||
private readonly HashSet<Client> targetClients = new HashSet<Client>();
|
||||
private readonly Dictionary<Client, DateTime> ignoredClients = new Dictionary<Client, DateTime>();
|
||||
|
||||
public IEnumerable<Client> TargetClients
|
||||
{
|
||||
get { return targetClients; }
|
||||
get
|
||||
{
|
||||
UpdateIgnoredClients();
|
||||
return targetClients.Where(c => !ignoredClients.ContainsKey(c));
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateIgnoredClients()
|
||||
{
|
||||
if (ignoredClients.Any())
|
||||
{
|
||||
HashSet<Client> clientsToRemove = null;
|
||||
foreach (var k in ignoredClients.Keys)
|
||||
{
|
||||
if (ignoredClients[k] < DateTime.Now)
|
||||
{
|
||||
clientsToRemove ??= new HashSet<Client>();
|
||||
clientsToRemove.Add(k);
|
||||
}
|
||||
}
|
||||
if (!(clientsToRemove is null))
|
||||
{
|
||||
foreach (var k in clientsToRemove)
|
||||
{
|
||||
ignoredClients.Remove(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void IgnoreClient(Client c, float seconds)
|
||||
{
|
||||
if (!ignoredClients.ContainsKey(c)) { ignoredClients.Add(c, DateTime.Now); }
|
||||
ignoredClients[c] = DateTime.Now + TimeSpan.FromSeconds(seconds);
|
||||
Reset();
|
||||
}
|
||||
|
||||
private bool IsBlockedByAnotherConversation(IEnumerable<Entity> targets)
|
||||
|
||||
@@ -28,7 +28,14 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
|
||||
convAction.SelectedOption = selectedOption;
|
||||
if (selectedOption == byte.MaxValue)
|
||||
{
|
||||
convAction.IgnoreClient(sender, 3f);
|
||||
}
|
||||
else
|
||||
{
|
||||
convAction.SelectedOption = selectedOption;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class AbandonedOutpostMission : Mission
|
||||
{
|
||||
private readonly List<Item> spawnedItems = new List<Item>();
|
||||
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
if (characters.Count == 0)
|
||||
msg.Write((ushort)spawnedItems.Count);
|
||||
foreach (Item item in spawnedItems)
|
||||
{
|
||||
throw new InvalidOperationException("Server attempted to write AbandonedOutpostMission data when no characters had been spawned.");
|
||||
item.WriteSpawnData(msg, item.ID, Entity.NullEntityID, 0);
|
||||
}
|
||||
|
||||
msg.Write((byte)characters.Count);
|
||||
@@ -22,7 +26,7 @@ namespace Barotrauma
|
||||
msg.Write((ushort)characterItems[character].Count());
|
||||
foreach (Item item in characterItems[character])
|
||||
{
|
||||
item.WriteSpawnData(msg, item.ID, item.ParentInventory.Owner?.ID ?? Entity.NullEntityID, 0);
|
||||
item.WriteSpawnData(msg, item.ID, item.ParentInventory?.Owner?.ID ?? Entity.NullEntityID, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
protected override void UpdateMissionSpecific(float deltaTime)
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class EscortMission : Mission
|
||||
{
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
if (characters.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Server attempted to write escort mission 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(terroristCharacters.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,12 @@ namespace Barotrauma
|
||||
{
|
||||
partial void ShowMessageProjSpecific(int missionState)
|
||||
{
|
||||
if (missionState >= Headers.Count && missionState >= Messages.Count) return;
|
||||
int messageIndex = missionState - 1;
|
||||
if (messageIndex >= Headers.Count && messageIndex >= Messages.Count) { return; }
|
||||
if (messageIndex < 0) { return; }
|
||||
|
||||
string header = missionState < Headers.Count ? Headers[missionState] : "";
|
||||
string message = missionState < Messages.Count ? Messages[missionState] : "";
|
||||
string header = messageIndex < Headers.Count ? Headers[messageIndex] : "";
|
||||
string message = messageIndex < Messages.Count ? Messages[messageIndex] : "";
|
||||
|
||||
GameServer.Log(TextManager.Get("MissionInfo") + ": " + header + " - " + message, ServerLog.MessageType.ServerMessage);
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class PirateMission : Mission
|
||||
{
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
// duplicate code from escortmission, should possibly be combined, though additional loot items might be added so maybe not
|
||||
if (characters.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Server attempted to write escort mission 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((ushort)characterItems[character].Count());
|
||||
foreach (Item item in characterItems[character])
|
||||
{
|
||||
item.WriteSpawnData(msg, item.ID, item.ParentInventory?.Owner?.ID ?? Entity.NullEntityID, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,8 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
public static Thread MainThread { get; private set; }
|
||||
|
||||
//only screens the server implements
|
||||
public static GameScreen GameScreen;
|
||||
public static NetLobbyScreen NetLobbyScreen;
|
||||
@@ -91,6 +93,8 @@ namespace Barotrauma
|
||||
|
||||
Console.WriteLine("Initializing GameScreen");
|
||||
GameScreen = new GameScreen();
|
||||
|
||||
MainThread = Thread.CurrentThread;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
@@ -388,6 +392,8 @@ namespace Barotrauma
|
||||
|
||||
if (GameSettings.SaveDebugConsoleLogs) { DebugConsole.SaveLogs(); }
|
||||
if (GameSettings.SendUserStatistics) { GameAnalytics.OnQuit(); }
|
||||
|
||||
MainThread = null;
|
||||
}
|
||||
|
||||
public static void ResetFrameTime()
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using Barotrauma.Networking;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -26,7 +25,6 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Saves bots in multiplayer
|
||||
/// </summary>
|
||||
/// <param name="root"></param>
|
||||
public void SaveMultiplayer(XElement root)
|
||||
{
|
||||
XElement saveElement = new XElement("bots", new XAttribute("hasbots", HasBots));
|
||||
@@ -40,8 +38,30 @@ namespace Barotrauma
|
||||
XElement characterElement = info.Save(saveElement);
|
||||
if (info.InventoryData != null) { characterElement.Add(info.InventoryData); }
|
||||
if (info.HealthData != null) { characterElement.Add(info.HealthData); }
|
||||
if (info.OrderData != null) { characterElement.Add(info.OrderData); }
|
||||
}
|
||||
SaveActiveOrders(saveElement);
|
||||
root.Add(saveElement);
|
||||
}
|
||||
|
||||
public void ServerWriteActiveOrders(IWriteMessage msg)
|
||||
{
|
||||
ushort count = (ushort)ActiveOrders.Count(o => o.First != null && !o.Second.HasValue);
|
||||
msg.Write(count);
|
||||
if (count > 0)
|
||||
{
|
||||
foreach (var activeOrder in ActiveOrders)
|
||||
{
|
||||
if (!(activeOrder?.First is Order order) || activeOrder.Second.HasValue) { continue; }
|
||||
OrderChatMessage.WriteOrder(msg, order, null, order.TargetSpatialEntity, null, 0, order.WallSectionIndex);
|
||||
bool hasOrderGiver = order.OrderGiver != null;
|
||||
msg.Write(hasOrderGiver);
|
||||
if (hasOrderGiver)
|
||||
{
|
||||
msg.Write(order.OrderGiver.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -35,9 +35,14 @@ namespace Barotrauma
|
||||
character.SpawnInventoryItems(inventory, itemData);
|
||||
}
|
||||
|
||||
public void ApplyHealthData(CharacterInfo characterInfo, Character character)
|
||||
public void ApplyHealthData(Character character)
|
||||
{
|
||||
characterInfo.ApplyHealthData(character, healthData);
|
||||
CharacterInfo.ApplyHealthData(character, healthData);
|
||||
}
|
||||
|
||||
public void ApplyOrderData(Character character)
|
||||
{
|
||||
CharacterInfo.ApplyOrderData(character, OrderData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+138
-60
@@ -49,7 +49,15 @@ namespace Barotrauma
|
||||
{
|
||||
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
|
||||
SaveUtil.LoadGame(selectedSave);
|
||||
((MultiPlayerCampaign)GameMain.GameSession.GameMode).LastSaveID++;
|
||||
if (GameMain.GameSession.GameMode is MultiPlayerCampaign mpCampaign)
|
||||
{
|
||||
mpCampaign.LastSaveID++;
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Unexpected game mode: " + GameMain.GameSession.GameMode);
|
||||
return;
|
||||
}
|
||||
DebugConsole.NewMessage("Campaign loaded!", Color.Cyan);
|
||||
DebugConsole.NewMessage(
|
||||
GameMain.GameSession.Map.SelectedLocation == null ?
|
||||
@@ -155,6 +163,64 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveInventories()
|
||||
{
|
||||
List<CharacterCampaignData> prevCharacterData = new List<CharacterCampaignData>(characterData);
|
||||
//client character has spawned this round -> remove old data (and replace with an up-to-date one if the client still has a character)
|
||||
characterData.RemoveAll(cd => cd.HasSpawned);
|
||||
|
||||
//refresh the character data of clients who are still in the server
|
||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
if (c.Character?.Info == null) { continue; }
|
||||
if (c.Character.IsDead && c.Character.CauseOfDeath?.Type != CauseOfDeathType.Disconnected) { continue; }
|
||||
c.CharacterInfo = c.Character.Info;
|
||||
characterData.RemoveAll(cd => cd.MatchesClient(c));
|
||||
characterData.Add(new CharacterCampaignData(c));
|
||||
}
|
||||
|
||||
//refresh the character data of clients who aren't in the server anymore
|
||||
foreach (CharacterCampaignData data in prevCharacterData)
|
||||
{
|
||||
if (data.HasSpawned && !characterData.Any(cd => cd.IsDuplicate(data)))
|
||||
{
|
||||
var character = Character.CharacterList.Find(c => c.Info == data.CharacterInfo && !c.IsHusk);
|
||||
if (character != null && (!character.IsDead || character.CauseOfDeath?.Type == CauseOfDeathType.Disconnected))
|
||||
{
|
||||
data.Refresh(character);
|
||||
characterData.Add(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
characterData.ForEach(cd => cd.HasSpawned = false);
|
||||
|
||||
petsElement = new XElement("pets");
|
||||
PetBehavior.SavePets(petsElement);
|
||||
|
||||
//remove all items that are in someone's inventory
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
if (c.Inventory == null) { continue; }
|
||||
if (Level.Loaded.Type == LevelData.LevelType.Outpost && c.Submarine != Level.Loaded.StartOutpost)
|
||||
{
|
||||
Map.CurrentLocation.RegisterTakenItems(c.Inventory.AllItems.Where(it => it.SpawnedInOutpost && it.OriginalModuleIndex > 0));
|
||||
}
|
||||
|
||||
if (c.Info != null && c.IsBot)
|
||||
{
|
||||
if (c.IsDead && c.CauseOfDeath?.Type != CauseOfDeathType.Disconnected) { CrewManager.RemoveCharacterInfo(c.Info); }
|
||||
c.Info.HealthData = new XElement("health");
|
||||
c.CharacterHealth.Save(c.Info.HealthData);
|
||||
c.Info.InventoryData = new XElement("inventory");
|
||||
c.SaveInventory();
|
||||
c.Info.SaveOrderData();
|
||||
}
|
||||
|
||||
c.Inventory.DeleteAllItems();
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<object> DoLevelTransition(TransitionType transitionType, LevelData newLevel, Submarine leavingSub, bool mirror, List<TraitorMissionResult> traitorResults)
|
||||
{
|
||||
lastUpdateID++;
|
||||
@@ -186,59 +252,7 @@ namespace Barotrauma
|
||||
|
||||
if (success)
|
||||
{
|
||||
List<CharacterCampaignData> prevCharacterData = new List<CharacterCampaignData>(characterData);
|
||||
//client character has spawned this round -> remove old data (and replace with an up-to-date one if the client still has a character)
|
||||
characterData.RemoveAll(cd => cd.HasSpawned);
|
||||
|
||||
//refresh the character data of clients who are still in the server
|
||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
if (c.Character?.Info == null) { continue; }
|
||||
if (c.Character.IsDead && c.Character.CauseOfDeath?.Type != CauseOfDeathType.Disconnected) { continue; }
|
||||
c.CharacterInfo = c.Character.Info;
|
||||
characterData.RemoveAll(cd => cd.MatchesClient(c));
|
||||
characterData.Add(new CharacterCampaignData(c));
|
||||
}
|
||||
|
||||
//refresh the character data of clients who aren't in the server anymore
|
||||
foreach (CharacterCampaignData data in prevCharacterData)
|
||||
{
|
||||
if (data.HasSpawned && !characterData.Any(cd => cd.IsDuplicate(data)))
|
||||
{
|
||||
var character = Character.CharacterList.Find(c => c.Info == data.CharacterInfo && !c.IsHusk);
|
||||
if (character != null && (!character.IsDead || character.CauseOfDeath?.Type == CauseOfDeathType.Disconnected))
|
||||
{
|
||||
data.Refresh(character);
|
||||
characterData.Add(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
characterData.ForEach(cd => cd.HasSpawned = false);
|
||||
|
||||
petsElement = new XElement("pets");
|
||||
PetBehavior.SavePets(petsElement);
|
||||
|
||||
//remove all items that are in someone's inventory
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
if (c.Inventory == null) { continue; }
|
||||
if (Level.Loaded.Type == LevelData.LevelType.Outpost && c.Submarine != Level.Loaded.StartOutpost)
|
||||
{
|
||||
Map.CurrentLocation.RegisterTakenItems(c.Inventory.AllItems.Where(it => it.SpawnedInOutpost && it.OriginalModuleIndex > 0));
|
||||
}
|
||||
|
||||
if (c.Info != null && c.IsBot)
|
||||
{
|
||||
if (c.IsDead && c.CauseOfDeath?.Type != CauseOfDeathType.Disconnected) { CrewManager.RemoveCharacterInfo(c.Info); }
|
||||
c.Info.HealthData = new XElement("health");
|
||||
c.CharacterHealth.Save(c.Info.HealthData);
|
||||
c.Info.InventoryData = new XElement("inventory");
|
||||
c.SaveInventory(c.Inventory, c.Info.InventoryData);
|
||||
}
|
||||
|
||||
c.Inventory.DeleteAllItems();
|
||||
}
|
||||
SaveInventories();
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
@@ -246,9 +260,13 @@ namespace Barotrauma
|
||||
{
|
||||
Submarine.MainSub = leavingSub;
|
||||
GameMain.GameSession.Submarine = leavingSub;
|
||||
GameMain.GameSession.SubmarineInfo = leavingSub.Info;
|
||||
leavingSub.Info.FilePath = System.IO.Path.Combine(SaveUtil.TempPath, leavingSub.Info.Name + ".sub");
|
||||
var subsToLeaveBehind = GetSubsToLeaveBehind(leavingSub);
|
||||
GameMain.GameSession.OwnedSubmarines.Add(leavingSub.Info);
|
||||
foreach (Submarine sub in subsToLeaveBehind)
|
||||
{
|
||||
GameMain.GameSession.OwnedSubmarines.RemoveAll(s => s != leavingSub.Info && s.Name == sub.Info.Name);
|
||||
MapEntity.mapEntityList.RemoveAll(e => e.Submarine == sub && e is LinkedSubmarine);
|
||||
LinkedSubmarine.CreateDummy(leavingSub, sub);
|
||||
}
|
||||
@@ -284,6 +302,8 @@ namespace Barotrauma
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
CrewManager?.ClearCurrentOrders();
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
GameMain.Server.EndGame(transitionType);
|
||||
@@ -317,7 +337,7 @@ namespace Barotrauma
|
||||
CargoManager.OnSoldItemsChanged += () => { LastUpdateID++; };
|
||||
UpgradeManager.OnUpgradesChanged += () => { LastUpdateID++; };
|
||||
Map.OnLocationSelected += (loc, connection) => { LastUpdateID++; };
|
||||
Map.OnMissionSelected += (loc, mission) => { LastUpdateID++; };
|
||||
Map.OnMissionsSelected += (loc, mission) => { LastUpdateID++; };
|
||||
Reputation.OnAnyReputationValueChanged += () => { LastUpdateID++; };
|
||||
}
|
||||
//increment save ID so clients know they're lacking the most up-to-date save file
|
||||
@@ -416,8 +436,15 @@ namespace Barotrauma
|
||||
msg.Write(lastSaveID);
|
||||
msg.Write(map.Seed);
|
||||
msg.Write(map.CurrentLocationIndex == -1 ? UInt16.MaxValue : (UInt16)map.CurrentLocationIndex);
|
||||
msg.Write(map.SelectedLocationIndex == -1 ? UInt16.MaxValue : (UInt16)map.SelectedLocationIndex);
|
||||
msg.Write(map.SelectedMissionIndex == -1 ? byte.MaxValue : (byte)map.SelectedMissionIndex);
|
||||
msg.Write(map.SelectedLocationIndex == -1 ? UInt16.MaxValue : (UInt16)map.SelectedLocationIndex);
|
||||
|
||||
var selectedMissionIndices = map.GetSelectedMissionIndices();
|
||||
msg.Write((byte)selectedMissionIndices.Count());
|
||||
foreach (int selectedMissionIndex in selectedMissionIndices)
|
||||
{
|
||||
msg.Write((byte)selectedMissionIndex);
|
||||
}
|
||||
|
||||
msg.Write(map.AllowDebugTeleport);
|
||||
msg.Write(reputation != null);
|
||||
if (reputation != null) { msg.Write(reputation.Value); }
|
||||
@@ -497,6 +524,13 @@ namespace Barotrauma
|
||||
msg.Write((byte)level);
|
||||
}
|
||||
|
||||
msg.Write((ushort)UpgradeManager.PurchasedItemSwaps.Count);
|
||||
foreach (var itemSwap in UpgradeManager.PurchasedItemSwaps)
|
||||
{
|
||||
msg.Write(itemSwap.ItemToRemove.ID);
|
||||
msg.Write(itemSwap.ItemToInstall?.Identifier ?? string.Empty);
|
||||
}
|
||||
|
||||
var characterData = GetClientCharacterData(c);
|
||||
if (characterData?.CharacterInfo == null)
|
||||
{
|
||||
@@ -513,7 +547,14 @@ namespace Barotrauma
|
||||
{
|
||||
UInt16 currentLocIndex = msg.ReadUInt16();
|
||||
UInt16 selectedLocIndex = msg.ReadUInt16();
|
||||
byte selectedMissionIndex = msg.ReadByte();
|
||||
|
||||
byte selectedMissionCount = msg.ReadByte();
|
||||
List<int> selectedMissionIndices = new List<int>();
|
||||
for (int i = 0; i < selectedMissionCount; i++)
|
||||
{
|
||||
selectedMissionIndices.Add(msg.ReadByte());
|
||||
}
|
||||
|
||||
bool purchasedHullRepairs = msg.ReadBoolean();
|
||||
bool purchasedItemRepairs = msg.ReadBoolean();
|
||||
bool purchasedLostShuttles = msg.ReadBoolean();
|
||||
@@ -563,6 +604,21 @@ namespace Barotrauma
|
||||
purchasedUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel));
|
||||
}
|
||||
|
||||
ushort purchasedItemSwapCount = msg.ReadUInt16();
|
||||
List<PurchasedItemSwap> purchasedItemSwaps = new List<PurchasedItemSwap>();
|
||||
for (int i = 0; i < purchasedItemSwapCount; i++)
|
||||
{
|
||||
UInt16 itemToRemoveID = msg.ReadUInt16();
|
||||
Item itemToRemove = Entity.FindEntityByID(itemToRemoveID) as Item;
|
||||
|
||||
string itemToInstallIdentifier = msg.ReadString();
|
||||
ItemPrefab itemToInstall = string.IsNullOrEmpty(itemToInstallIdentifier) ? null : ItemPrefab.Find(string.Empty, itemToInstallIdentifier);
|
||||
|
||||
if (itemToRemove == null) { continue; }
|
||||
|
||||
purchasedItemSwaps.Add(new PurchasedItemSwap(itemToRemove, itemToInstall));
|
||||
}
|
||||
|
||||
if (!AllowedToManageCampaign(sender))
|
||||
{
|
||||
DebugConsole.ThrowError("Client \"" + sender.Name + "\" does not have a permission to manage the campaign");
|
||||
@@ -626,7 +682,9 @@ namespace Barotrauma
|
||||
|
||||
Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
|
||||
if (Map.SelectedLocation == null) { Map.SelectRandomLocation(preferUndiscovered: true); }
|
||||
if (Map.SelectedConnection != null) { Map.SelectMission(selectedMissionIndex); }
|
||||
if (Map.SelectedConnection != null) { Map.SelectMission(selectedMissionIndices); }
|
||||
|
||||
CheckTooManyMissions(Map.CurrentLocation, sender);
|
||||
|
||||
List<PurchasedItem> currentBuyCrateItems = new List<PurchasedItem>(CargoManager.ItemsInBuyCrate);
|
||||
currentBuyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, -i.Quantity));
|
||||
@@ -649,6 +707,26 @@ namespace Barotrauma
|
||||
int level = UpgradeManager.GetUpgradeLevel(prefab, category);
|
||||
GameServer.Log($"SERVER: Purchased level {level} {category.Identifier}.{prefab.Identifier} for {price}", ServerLog.MessageType.ServerMessage);
|
||||
}
|
||||
|
||||
foreach (var purchasedItemSwap in purchasedItemSwaps)
|
||||
{
|
||||
if (purchasedItemSwap.ItemToInstall == null)
|
||||
{
|
||||
UpgradeManager.CancelItemSwap(purchasedItemSwap.ItemToRemove);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall);
|
||||
}
|
||||
}
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.PendingItemSwap != null && !purchasedItemSwaps.Any(it => it.ItemToRemove == item))
|
||||
{
|
||||
UpgradeManager.CancelItemSwap(item);
|
||||
item.PendingItemSwap = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerReadCrew(IReadMessage msg, Client sender)
|
||||
@@ -863,7 +941,7 @@ namespace Barotrauma
|
||||
CampaignMetadata?.Save(modeElement);
|
||||
Map.Save(modeElement);
|
||||
CargoManager?.SavePurchasedItems(modeElement);
|
||||
UpgradeManager?.SavePendingUpgrades(modeElement, UpgradeManager?.PendingUpgrades);
|
||||
UpgradeManager?.Save(modeElement);
|
||||
|
||||
if (petsElement != null)
|
||||
{
|
||||
|
||||
@@ -20,33 +20,5 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to all clients telling them that all upgrades on the submarine were reset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <param name="newUpgrades"/> is supposed to have a list of reloaded metadata but seeing as
|
||||
/// this method is currently only used when switching submarines and that disables the repair NPC
|
||||
/// until the next round so currently there's no need for it as we get the new values from the save
|
||||
/// file anyways.
|
||||
/// </remarks>
|
||||
/// <see cref="UpgradeManager.ClientRead"/>
|
||||
private void SendUpgradeResetMessage(Dictionary<string, int> newUpgrades)
|
||||
{
|
||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
IWriteMessage outmsg = new WriteOnlyMessage();
|
||||
outmsg.Write((byte)ServerPacketHeader.RESET_UPGRADES);
|
||||
outmsg.Write(true);
|
||||
outmsg.Write(Campaign.Money);
|
||||
// outmsg.Write((uint)newUpgrades.Count);
|
||||
// foreach (var (key, value) in newUpgrades)
|
||||
// {
|
||||
// outmsg.Write(key);
|
||||
// outmsg.Write((byte)value);
|
||||
// }
|
||||
GameMain.Server?.ServerPeer?.Send(outmsg, c.Connection, DeliveryMethod.Reliable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
//don't allow rewiring locked panels
|
||||
if (Locked || !GameMain.NetworkMember.ServerSettings.AllowRewiring) { return; }
|
||||
if (Locked || TemporarilyLocked || !GameMain.NetworkMember.ServerSettings.AllowRewiring) { return; }
|
||||
|
||||
item.CreateServerEvent(this);
|
||||
|
||||
|
||||
@@ -8,11 +8,18 @@ namespace Barotrauma
|
||||
{
|
||||
partial class Item : MapEntity, IDamageable, ISerializableEntity, IServerSerializable, IClientSerializable
|
||||
{
|
||||
private CoroutineHandle logPropertyChangeCoroutine;
|
||||
|
||||
public override Sprite Sprite
|
||||
{
|
||||
get { return prefab?.sprite; }
|
||||
}
|
||||
|
||||
partial void AssignCampaignInteractionTypeProjSpecific(CampaignMode.InteractionType interactionType)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.AssignCampaignInteraction });
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
string errorMsg = "";
|
||||
@@ -86,6 +93,9 @@ namespace Barotrauma
|
||||
case NetEntityEvent.Type.Status:
|
||||
msg.Write(condition);
|
||||
break;
|
||||
case NetEntityEvent.Type.AssignCampaignInteraction:
|
||||
msg.Write((byte)CampaignInteractionType);
|
||||
break;
|
||||
case NetEntityEvent.Type.Treatment:
|
||||
{
|
||||
ItemComponent targetComponent = (ItemComponent)extraData[1];
|
||||
|
||||
@@ -22,80 +22,23 @@ namespace Barotrauma.Networking
|
||||
int? wallSectionIndex = null;
|
||||
if (type == ChatMessageType.Order)
|
||||
{
|
||||
int orderIndex = msg.ReadByte();
|
||||
orderTargetCharacter = Entity.FindEntityByID(msg.ReadUInt16()) as Character;
|
||||
orderTargetEntity = Entity.FindEntityByID(msg.ReadUInt16()) as Entity;
|
||||
|
||||
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)
|
||||
var orderMessageInfo = OrderChatMessage.ReadOrder(msg);
|
||||
if (orderMessageInfo.OrderIndex < 0 || orderMessageInfo.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())
|
||||
{
|
||||
var x = msg.ReadSingle();
|
||||
var y = msg.ReadSingle();
|
||||
var hull = Entity.FindEntityByID(msg.ReadUInt16()) as Hull;
|
||||
orderTargetPosition = new OrderTarget(new Vector2(x, y), hull, true);
|
||||
}
|
||||
else if (orderTargetType == Order.OrderTargetType.WallSection)
|
||||
{
|
||||
wallSectionIndex = msg.ReadByte();
|
||||
}
|
||||
|
||||
if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count)
|
||||
{
|
||||
DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order index out of bounds ({orderIndex}).");
|
||||
DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order index out of bounds ({orderMessageInfo.OrderIndex}).");
|
||||
if (NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID)) { c.LastSentChatMsgID = ID; }
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
orderTargetCharacter = orderMessageInfo.TargetCharacter;
|
||||
orderTargetEntity = orderMessageInfo.TargetEntity;
|
||||
orderTargetPosition = orderMessageInfo.TargetPosition;
|
||||
orderTargetType = orderMessageInfo.TargetType;
|
||||
wallSectionIndex = orderMessageInfo.WallSectionIndex;
|
||||
var orderPrefab = orderMessageInfo.OrderPrefab ?? Order.PrefabList[orderMessageInfo.OrderIndex];
|
||||
string orderOption = orderMessageInfo.OrderOption ??
|
||||
(orderMessageInfo.OrderOptionIndex == null || orderMessageInfo.OrderOptionIndex < 0 || orderMessageInfo.OrderOptionIndex >= orderPrefab.Options.Length ?
|
||||
"" : orderPrefab.Options[orderMessageInfo.OrderOptionIndex.Value]);
|
||||
orderMsg = new OrderChatMessage(orderPrefab, orderOption, orderMessageInfo.Priority, orderTargetPosition ?? orderTargetEntity as ISpatialEntity, orderTargetCharacter, c.Character)
|
||||
{
|
||||
WallSectionIndex = wallSectionIndex
|
||||
};
|
||||
@@ -176,46 +119,49 @@ namespace Barotrauma.Networking
|
||||
if (type == ChatMessageType.Order)
|
||||
{
|
||||
if (c.Character == null || c.Character.SpeechImpediment >= 100.0f || c.Character.IsDead) { return; }
|
||||
Order order = null;
|
||||
if (orderMsg.Order.IsReport)
|
||||
{
|
||||
HumanAIController.ReportProblem(orderMsg.Sender, orderMsg.Order);
|
||||
}
|
||||
else if (orderTargetCharacter != null && !orderMsg.Order.TargetAllCharacters)
|
||||
Order order = orderTargetType switch
|
||||
{
|
||||
switch (orderTargetType)
|
||||
Order.OrderTargetType.Entity =>
|
||||
new Order(orderMsg.Order, orderTargetEntity, orderMsg.Order?.GetTargetItemComponent(orderTargetEntity as Item), orderGiver: orderMsg.Sender),
|
||||
Order.OrderTargetType.Position =>
|
||||
new Order(orderMsg.Order, orderTargetPosition, orderGiver: orderMsg.Sender),
|
||||
Order.OrderTargetType.WallSection when orderTargetEntity is Structure s && wallSectionIndex.HasValue =>
|
||||
new Order(orderMsg.Order, s, wallSectionIndex, orderGiver: orderMsg.Sender),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
if (order != null)
|
||||
{
|
||||
if (order.TargetAllCharacters)
|
||||
{
|
||||
case Order.OrderTargetType.Entity:
|
||||
order = new Order(orderMsg.Order.Prefab, orderTargetEntity, orderMsg.Order.Prefab?.GetTargetItemComponent(orderTargetEntity as Item), orderGiver: orderMsg.Sender);
|
||||
break;
|
||||
case Order.OrderTargetType.Position:
|
||||
order = new Order(orderMsg.Order.Prefab, orderTargetPosition, orderGiver: orderMsg.Sender);
|
||||
break;
|
||||
if (order.IsIgnoreOrder)
|
||||
{
|
||||
switch (orderTargetType)
|
||||
{
|
||||
case Order.OrderTargetType.Entity:
|
||||
if (!(orderTargetEntity is IIgnorable ignorableEntity)) { break; }
|
||||
ignorableEntity.OrderedToBeIgnored = order.Identifier == "ignorethis";
|
||||
break;
|
||||
case Order.OrderTargetType.Position:
|
||||
throw new NotImplementedException();
|
||||
case Order.OrderTargetType.WallSection:
|
||||
if (!wallSectionIndex.HasValue) { break; }
|
||||
if (!(orderTargetEntity is Structure s)) { break; }
|
||||
if (!(s.GetSection(wallSectionIndex.Value) is IIgnorable ignorableWall)) { break; }
|
||||
ignorableWall.OrderedToBeIgnored = order.Identifier == "ignorethis";
|
||||
break;
|
||||
}
|
||||
}
|
||||
GameMain.GameSession?.CrewManager?.AddOrder(order, order.IsIgnoreOrder ? (float?)null : order.FadeOutTime);
|
||||
}
|
||||
if (order != null)
|
||||
else if (orderTargetCharacter != null)
|
||||
{
|
||||
orderTargetCharacter.SetOrder(order, orderMsg.OrderOption, orderMsg.OrderPriority, orderMsg.Sender);
|
||||
}
|
||||
}
|
||||
else if (orderMsg.Order.IsIgnoreOrder)
|
||||
{
|
||||
switch (orderTargetType)
|
||||
{
|
||||
case Order.OrderTargetType.Entity:
|
||||
if (orderTargetEntity is IIgnorable ignorableEntity)
|
||||
{
|
||||
ignorableEntity.OrderedToBeIgnored = orderMsg.Order.Identifier == "ignorethis";
|
||||
}
|
||||
break;
|
||||
case Order.OrderTargetType.WallSection:
|
||||
if (!wallSectionIndex.HasValue) { break; }
|
||||
if (orderTargetEntity is Structure s && s.GetSection(wallSectionIndex.Value) is IIgnorable ignorableWall)
|
||||
{
|
||||
ignorableWall.OrderedToBeIgnored = orderMsg.Order.Identifier == "ignorethis";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
GameMain.Server.SendOrderChatMessage(orderMsg);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -378,7 +378,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (gameStarted)
|
||||
{
|
||||
if (respawnManager != null) { respawnManager.Update(deltaTime); }
|
||||
respawnManager?.Update(deltaTime);
|
||||
|
||||
entityEventManager.Update(connectedClients);
|
||||
|
||||
@@ -406,10 +406,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
if (TraitorManager != null)
|
||||
{
|
||||
TraitorManager.Update(deltaTime);
|
||||
}
|
||||
TraitorManager?.Update(deltaTime);
|
||||
|
||||
if (serverSettings.Voting.VoteRunning)
|
||||
{
|
||||
@@ -433,7 +430,7 @@ namespace Barotrauma.Networking
|
||||
connectedClients.All(c => c.Character == null || c.Character.IsDead || c.Character.IsIncapacitated);
|
||||
|
||||
bool subAtLevelEnd = false;
|
||||
if (Submarine.MainSub != null && Submarine.MainSubs[1] == null)
|
||||
if (Submarine.MainSub != null && !(GameMain.GameSession.GameMode is PvPMode))
|
||||
{
|
||||
if (Level.Loaded?.EndOutpost != null)
|
||||
{
|
||||
@@ -488,8 +485,10 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else if (isCrewDead && (GameMain.GameSession?.GameMode is CampaignMode))
|
||||
{
|
||||
#if !DEBUG
|
||||
endRoundDelay = 1.0f;
|
||||
endRoundTimer += deltaTime;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -537,7 +536,8 @@ namespace Barotrauma.Networking
|
||||
initiatedStartGame = false;
|
||||
}
|
||||
}
|
||||
else if (Screen.Selected == GameMain.NetLobbyScreen && !gameStarted && !initiatedStartGame)
|
||||
else if (Screen.Selected == GameMain.NetLobbyScreen && !gameStarted && !initiatedStartGame &&
|
||||
(GameMain.NetLobbyScreen.SelectedMode != GameModePreset.MultiPlayerCampaign || GameMain.GameSession?.GameMode is MultiPlayerCampaign))
|
||||
{
|
||||
if (serverSettings.AutoRestart)
|
||||
{
|
||||
@@ -1207,6 +1207,7 @@ namespace Barotrauma.Networking
|
||||
mpCampaign.ServerReadCrew(inc, sender);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadReadyToSpawnMessage(IReadMessage inc, Client sender)
|
||||
{
|
||||
sender.SpectateOnly = inc.ReadBoolean() && (serverSettings.AllowSpectating || sender.Connection == OwnerConnection);
|
||||
@@ -1315,6 +1316,12 @@ namespace Barotrauma.Networking
|
||||
if (gameStarted)
|
||||
{
|
||||
Log("Client \"" + GameServer.ClientLogName(sender) + "\" ended the round.", ServerLog.MessageType.ServerMessage);
|
||||
if (mpCampaign != null && Level.IsLoadedOutpost)
|
||||
{
|
||||
mpCampaign.SaveInventories();
|
||||
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
|
||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||
}
|
||||
EndGame();
|
||||
}
|
||||
}
|
||||
@@ -1492,7 +1499,6 @@ namespace Barotrauma.Networking
|
||||
inc.ReadPadBits();
|
||||
}
|
||||
|
||||
|
||||
private void ClientWrite(Client c)
|
||||
{
|
||||
if (gameStarted && c.InGame)
|
||||
@@ -1893,6 +1899,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
outmsg.Write(serverSettings.RadiationEnabled);
|
||||
outmsg.Write((byte)serverSettings.MaxMissionCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2251,10 +2258,6 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
client.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, client.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
client.CharacterInfo.ClearCurrentOrders();
|
||||
}
|
||||
characterInfos.Add(client.CharacterInfo);
|
||||
if (client.CharacterInfo.Job == null || client.CharacterInfo.Job.Prefab != client.AssignedJob.First)
|
||||
{
|
||||
@@ -2340,7 +2343,8 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
{
|
||||
characterData.SpawnInventoryItems(spawnedCharacter, spawnedCharacter.Inventory);
|
||||
characterData.ApplyHealthData(spawnedCharacter.Info, spawnedCharacter);
|
||||
characterData.ApplyHealthData(spawnedCharacter);
|
||||
characterData.ApplyOrderData(spawnedCharacter);
|
||||
spawnedCharacter.GiveIdCardTags(mainSubWaypoints[i]);
|
||||
characterData.HasSpawned = true;
|
||||
}
|
||||
@@ -2362,7 +2366,7 @@ namespace Barotrauma.Networking
|
||||
if (hadBots)
|
||||
{
|
||||
//loaded existing bots -> init them
|
||||
crewManager?.InitRound();
|
||||
crewManager.InitRound();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2372,6 +2376,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
campaign?.LoadPets();
|
||||
crewManager?.LoadActiveOrders();
|
||||
|
||||
foreach (Submarine sub in Submarine.MainSubs)
|
||||
{
|
||||
@@ -2516,6 +2521,8 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
mission.ServerWriteInitial(msg, client);
|
||||
}
|
||||
msg.Write(GameMain.GameSession.CrewManager != null);
|
||||
GameMain.GameSession.CrewManager?.ServerWriteActiveOrders(msg);
|
||||
}
|
||||
|
||||
public void EndGame(CampaignMode.TransitionType transitionType = CampaignMode.TransitionType.None)
|
||||
@@ -3274,7 +3281,6 @@ namespace Barotrauma.Networking
|
||||
if (voteType != VoteType.PurchaseSub)
|
||||
{
|
||||
SubmarineInfo newSub = GameMain.GameSession.SwitchSubmarine(targetSubmarine, deliveryFee);
|
||||
GameMain.GameSession.Campaign.UpgradeManager.RefundResetAndReload(newSub, true);
|
||||
}
|
||||
|
||||
serverSettings.Voting.StopSubmarineVote(true);
|
||||
@@ -3314,7 +3320,6 @@ namespace Barotrauma.Networking
|
||||
serverSettings.SaveClientPermissions();
|
||||
}
|
||||
|
||||
|
||||
private IEnumerable<object> SendClientPermissionsAfterClientListSynced(Client recipient, Client client)
|
||||
{
|
||||
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 10);
|
||||
@@ -3331,7 +3336,6 @@ namespace Barotrauma.Networking
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
|
||||
private void SendClientPermissions(Client recipient, Client client)
|
||||
{
|
||||
if (recipient?.Connection == null) { return; }
|
||||
|
||||
@@ -10,6 +10,11 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
private DateTime despawnTime;
|
||||
|
||||
private float shuttleEmptyTimer;
|
||||
|
||||
private int pendingRespawnCount, requiredRespawnCount;
|
||||
private int prevPendingRespawnCount, prevRequiredRespawnCount;
|
||||
|
||||
private IEnumerable<Client> GetClientsToRespawn()
|
||||
{
|
||||
MultiPlayerCampaign campaign = GameMain.GameSession.GameMode as MultiPlayerCampaign;
|
||||
@@ -95,10 +100,19 @@ namespace Barotrauma.Networking
|
||||
RespawnShuttle.Velocity = Vector2.Zero;
|
||||
}
|
||||
|
||||
int clientsToRespawn = GetClientsToRespawn().Count();
|
||||
pendingRespawnCount = GetClientsToRespawn().Count();
|
||||
requiredRespawnCount = (int)Math.Max((float)GameMain.Server.ConnectedClients.Count * GameMain.Server.ServerSettings.MinRespawnRatio, 1.0f);
|
||||
if (pendingRespawnCount != prevPendingRespawnCount ||
|
||||
requiredRespawnCount != prevRequiredRespawnCount)
|
||||
{
|
||||
prevPendingRespawnCount = pendingRespawnCount;
|
||||
prevRequiredRespawnCount = requiredRespawnCount;
|
||||
GameMain.Server.CreateEntityEvent(this);
|
||||
}
|
||||
|
||||
if (RespawnCountdownStarted)
|
||||
{
|
||||
if (clientsToRespawn == 0)
|
||||
if (pendingRespawnCount == 0)
|
||||
{
|
||||
RespawnCountdownStarted = false;
|
||||
GameMain.Server.CreateEntityEvent(this);
|
||||
@@ -106,7 +120,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
bool shouldStartCountdown = ShouldStartRespawnCountdown(clientsToRespawn);
|
||||
bool shouldStartCountdown = ShouldStartRespawnCountdown(pendingRespawnCount);
|
||||
if (shouldStartCountdown)
|
||||
{
|
||||
RespawnCountdownStarted = true;
|
||||
@@ -167,8 +181,14 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
partial void UpdateReturningProjSpecific()
|
||||
partial void UpdateReturningProjSpecific(float deltaTime)
|
||||
{
|
||||
//speed up despawning if there's no-one inside the shuttle
|
||||
if (despawnTime > DateTime.Now + new TimeSpan(0, 0, seconds: 30) && CheckShuttleEmpty(deltaTime))
|
||||
{
|
||||
despawnTime = DateTime.Now + new TimeSpan(0, 0, seconds: 30);
|
||||
}
|
||||
|
||||
foreach (Door door in shuttleDoors)
|
||||
{
|
||||
if (door.IsOpen) door.TrySetState(false, false, true);
|
||||
@@ -214,7 +234,7 @@ namespace Barotrauma.Networking
|
||||
if (!ReturnCountdownStarted)
|
||||
{
|
||||
//if there are no living chracters inside, transporting can be stopped immediately
|
||||
if (!Character.CharacterList.Any(c => c.Submarine == RespawnShuttle && !c.IsDead))
|
||||
if (CheckShuttleEmpty(deltaTime))
|
||||
{
|
||||
ReturnTime = DateTime.Now;
|
||||
ReturnCountdownStarted = true;
|
||||
@@ -232,6 +252,10 @@ namespace Barotrauma.Networking
|
||||
GameMain.Server.CreateEntityEvent(this);
|
||||
}
|
||||
}
|
||||
else if (CheckShuttleEmpty(deltaTime))
|
||||
{
|
||||
ReturnTime = DateTime.Now;
|
||||
}
|
||||
|
||||
if (DateTime.Now > ReturnTime)
|
||||
{
|
||||
@@ -245,6 +269,19 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
private bool CheckShuttleEmpty(float deltaTime)
|
||||
{
|
||||
if (!Character.CharacterList.Any(c => c.Submarine == RespawnShuttle && !c.IsDead))
|
||||
{
|
||||
shuttleEmptyTimer += deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
shuttleEmptyTimer = 0.0f;
|
||||
}
|
||||
return shuttleEmptyTimer > 1.0f;
|
||||
}
|
||||
|
||||
partial void RespawnCharactersProjSpecific(Vector2? shuttlePos)
|
||||
{
|
||||
var respawnSub = RespawnShuttle ?? Submarine.MainSub;
|
||||
@@ -394,7 +431,7 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
{
|
||||
characterData.SpawnInventoryItems(character, character.Inventory);
|
||||
characterData.ApplyHealthData(character.Info, character);
|
||||
characterData.ApplyHealthData(character);
|
||||
character.GiveIdCardTags(mainSubSpawnPoints[i]);
|
||||
characterData.HasSpawned = true;
|
||||
}
|
||||
@@ -427,6 +464,8 @@ namespace Barotrauma.Networking
|
||||
msg.Write((float)(ReturnTime - DateTime.Now).TotalSeconds);
|
||||
break;
|
||||
case State.Waiting:
|
||||
msg.Write((ushort)pendingRespawnCount);
|
||||
msg.Write((ushort)requiredRespawnCount);
|
||||
msg.Write(RespawnCountdownStarted);
|
||||
msg.Write((float)(RespawnTime - DateTime.Now).TotalSeconds);
|
||||
break;
|
||||
|
||||
@@ -162,6 +162,11 @@ namespace Barotrauma.Networking
|
||||
|
||||
RadiationEnabled = incMsg.ReadBoolean();
|
||||
|
||||
int maxMissionCount = MaxMissionCount + incMsg.ReadByte() - 1;
|
||||
if (maxMissionCount < CampaignSettings.MinMissionCountLimit) maxMissionCount = CampaignSettings.MaxMissionCountLimit;
|
||||
if (maxMissionCount > CampaignSettings.MaxMissionCountLimit) maxMissionCount = CampaignSettings.MinMissionCountLimit;
|
||||
MaxMissionCount = maxMissionCount;
|
||||
|
||||
changed |= true;
|
||||
}
|
||||
|
||||
@@ -306,7 +311,8 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (Enum.TryParse(missionTypeName, out MissionType missionType))
|
||||
{
|
||||
if (missionType == Barotrauma.MissionType.None) continue;
|
||||
if (missionType == Barotrauma.MissionType.None) { continue; }
|
||||
if (MissionPrefab.HiddenMissionClasses.Contains(missionType)) { continue; }
|
||||
AllowedRandomMissionTypes.Add(missionType);
|
||||
}
|
||||
}
|
||||
@@ -323,6 +329,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
GameMain.NetLobbyScreen.SetBotSpawnMode(BotSpawnMode);
|
||||
GameMain.NetLobbyScreen.SetBotCount(BotCount);
|
||||
GameMain.NetLobbyScreen.SetMaxMissionCount(MaxMissionCount);
|
||||
|
||||
List<string> monsterNames = CharacterPrefab.Prefabs.Select(p => p.Identifier).ToList();
|
||||
MonsterEnabled = new Dictionary<string, bool>();
|
||||
|
||||
@@ -37,6 +37,11 @@ namespace Barotrauma
|
||||
targetItems.Add(item);
|
||||
}
|
||||
}
|
||||
//only target items in the main sub if there are any
|
||||
if (targetItems.Count > 1 && targetItems.Any(it => it.Submarine == Submarine.MainSub))
|
||||
{
|
||||
targetItems.RemoveAll(it => it.Submarine != Submarine.MainSub);
|
||||
}
|
||||
if (targetItems.Count > 0)
|
||||
{
|
||||
var textId = targetItems[0].Prefab.GetItemNameTextId();
|
||||
|
||||
Reference in New Issue
Block a user