Merge branch 'master' of https://github.com/Regalis11/Barotrauma.git
This commit is contained in:
@@ -10,6 +10,11 @@ namespace Barotrauma
|
||||
{
|
||||
private readonly Dictionary<Identifier, float> prevSentSkill = new Dictionary<Identifier, float>();
|
||||
|
||||
/// <summary>
|
||||
/// The client opted to create a new character and discard this one
|
||||
/// </summary>
|
||||
public bool Discarded;
|
||||
|
||||
partial void OnSkillChanged(Identifier skillIdentifier, float prevLevel, float newLevel)
|
||||
{
|
||||
if (Character == null || Character.Removed) { return; }
|
||||
@@ -37,7 +42,7 @@ namespace Barotrauma
|
||||
partial void OnPermanentStatChanged(StatTypes statType)
|
||||
{
|
||||
if (Character == null || Character.Removed) { return; }
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new Character.UpdatePermanentStatsEventData());
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new Character.UpdatePermanentStatsEventData(statType));
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg)
|
||||
|
||||
@@ -647,6 +647,7 @@ namespace Barotrauma
|
||||
{
|
||||
msg.Write(false);
|
||||
}
|
||||
msg.Write(HumanPrefabHealthMultiplier);
|
||||
msg.Write(Wallet.Balance);
|
||||
msg.WriteRangedInteger(Wallet.RewardDistribution, 0, 100);
|
||||
msg.Write((byte)TeamID);
|
||||
|
||||
@@ -1771,7 +1771,7 @@ namespace Barotrauma
|
||||
GameMain.Server.SendConsoleMessage("No campaign active.", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
mpCampaign.LastUpdateID++;
|
||||
mpCampaign.IncrementLastUpdateIdForFlag(MultiPlayerCampaign.NetFlags.MapAndMissions);
|
||||
GameMain.GameSession.Map.AllowDebugTeleport = !GameMain.GameSession.Map.AllowDebugTeleport;
|
||||
NewMessage(client.Name + (GameMain.GameSession.Map.AllowDebugTeleport ? " enabled" : " disabled") + " teleportation on the campaign map.", Color.White);
|
||||
GameMain.Server.SendConsoleMessage((GameMain.GameSession.Map.AllowDebugTeleport ? "Enabled" : "Disabled") + " teleportation on the campaign map.", client);
|
||||
@@ -2369,7 +2369,6 @@ namespace Barotrauma
|
||||
Wallet wallet = targetCharacter is null ? campaign.Bank : targetCharacter.Wallet;
|
||||
wallet.Give(money);
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(money, GameAnalyticsManager.MoneySource.Cheat, "console");
|
||||
campaign.LastUpdateID++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -25,9 +25,9 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Saves bots in multiplayer
|
||||
/// </summary>
|
||||
public void SaveMultiplayer(XElement root)
|
||||
public XElement SaveMultiplayer(XElement parentElement)
|
||||
{
|
||||
XElement saveElement = new XElement("bots", new XAttribute("hasbots", HasBots));
|
||||
var element = new XElement("bots", new XAttribute("hasbots", HasBots));
|
||||
foreach (CharacterInfo info in characterInfos)
|
||||
{
|
||||
if (Level.Loaded != null)
|
||||
@@ -35,13 +35,13 @@ namespace Barotrauma
|
||||
if (!info.IsNewHire && (info.Character == null || info.Character.IsDead)) { continue; }
|
||||
}
|
||||
|
||||
XElement characterElement = info.Save(saveElement);
|
||||
XElement characterElement = info.Save(element);
|
||||
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);
|
||||
parentElement?.Add(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
public void ServerWriteActiveOrders(IWriteMessage msg)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -10,6 +11,31 @@ namespace Barotrauma
|
||||
protected set;
|
||||
}
|
||||
|
||||
private static bool IsOwner(Client client) => client != null && client.Connection == GameMain.Server.OwnerConnection;
|
||||
|
||||
/// <summary>
|
||||
/// There is a client-side implementation of the method in <see cref="CampaignMode"/>
|
||||
/// </summary>
|
||||
public bool AllowedToManageCampaign(Client client, ClientPermissions permissions)
|
||||
{
|
||||
//allow managing the campaign if the client has permissions, is the owner, or the only client in the server,
|
||||
//or if no-one has management permissions
|
||||
return
|
||||
client.HasPermission(permissions) ||
|
||||
client.HasPermission(ClientPermissions.ManageCampaign) ||
|
||||
GameMain.Server.ConnectedClients.Count == 1 ||
|
||||
IsOwner(client) ||
|
||||
GameMain.Server.ConnectedClients.None(c => c.InGame && (IsOwner(c) || c.HasPermission(permissions)));
|
||||
}
|
||||
|
||||
public bool AllowedToManageWallets(Client client)
|
||||
{
|
||||
return
|
||||
client.HasPermission(ClientPermissions.ManageCampaign) ||
|
||||
client.HasPermission(ClientPermissions.ManageMoney) ||
|
||||
IsOwner(client);
|
||||
}
|
||||
|
||||
public override void ShowStartMessage()
|
||||
{
|
||||
foreach (Mission mission in Missions)
|
||||
|
||||
+212
-171
@@ -37,7 +37,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (forceMapUI == value) { return; }
|
||||
forceMapUI = value;
|
||||
LastUpdateID++;
|
||||
IncrementLastUpdateIdForFlag(NetFlags.MapAndMissions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,11 +71,43 @@ namespace Barotrauma
|
||||
get { return ForceMapUI || CoroutineManager.IsCoroutineRunning("LevelTransition"); }
|
||||
}
|
||||
|
||||
public static void StartNewCampaign(string savePath, string subPath, string seed, CampaignSettings settings)
|
||||
private bool purchasedHullRepairs, purchasedLostShuttles, purchasedItemRepairs;
|
||||
public override bool PurchasedHullRepairs
|
||||
{
|
||||
get { return purchasedHullRepairs; }
|
||||
set
|
||||
{
|
||||
if (purchasedHullRepairs == value) { return; }
|
||||
purchasedHullRepairs = value;
|
||||
IncrementLastUpdateIdForFlag(NetFlags.Misc);
|
||||
}
|
||||
}
|
||||
public override bool PurchasedLostShuttles
|
||||
{
|
||||
get { return purchasedLostShuttles; }
|
||||
set
|
||||
{
|
||||
if (purchasedLostShuttles == value) { return; }
|
||||
purchasedLostShuttles = value;
|
||||
IncrementLastUpdateIdForFlag(NetFlags.Misc);
|
||||
}
|
||||
}
|
||||
public override bool PurchasedItemRepairs
|
||||
{
|
||||
get { return purchasedItemRepairs; }
|
||||
set
|
||||
{
|
||||
if (purchasedItemRepairs == value) { return; }
|
||||
purchasedItemRepairs = value;
|
||||
IncrementLastUpdateIdForFlag(NetFlags.Misc);
|
||||
}
|
||||
}
|
||||
|
||||
public static void StartNewCampaign(string savePath, string subPath, string seed, CampaignSettings startingSettings)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(savePath)) { return; }
|
||||
|
||||
GameMain.GameSession = new GameSession(new SubmarineInfo(subPath), savePath, GameModePreset.MultiPlayerCampaign, settings, seed);
|
||||
GameMain.GameSession = new GameSession(new SubmarineInfo(subPath), savePath, GameModePreset.MultiPlayerCampaign, startingSettings, seed);
|
||||
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
|
||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||
|
||||
@@ -158,34 +190,11 @@ namespace Barotrauma
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
lastUpdateID++;
|
||||
IncrementAllLastUpdateIds();
|
||||
}
|
||||
|
||||
private static bool IsOwner(Client client) => client != null && client.Connection == GameMain.Server.OwnerConnection;
|
||||
|
||||
/// <summary>
|
||||
/// There is a client-side implementation of the method in <see cref="CampaignMode"/>
|
||||
/// </summary>
|
||||
public bool AllowedToManageCampaign(Client client, ClientPermissions permissions)
|
||||
{
|
||||
//allow managing the campaign if the client has permissions, is the owner, or the only client in the server,
|
||||
//or if no-one has management permissions
|
||||
return
|
||||
client.HasPermission(permissions) ||
|
||||
client.HasPermission(ClientPermissions.ManageCampaign) ||
|
||||
GameMain.Server.ConnectedClients.Count == 1 ||
|
||||
IsOwner(client) ||
|
||||
GameMain.Server.ConnectedClients.None(c => c.InGame && (IsOwner(c) || c.HasPermission(permissions)));
|
||||
}
|
||||
|
||||
public bool AllowedToManageWallets(Client client)
|
||||
{
|
||||
return
|
||||
client.HasPermission(ClientPermissions.ManageCampaign) ||
|
||||
client.HasPermission(ClientPermissions.ManageMoney) ||
|
||||
IsOwner(client);
|
||||
}
|
||||
|
||||
public void SaveExperiencePoints(Client client)
|
||||
{
|
||||
ClearSavedExperiencePoints(client);
|
||||
@@ -200,14 +209,6 @@ namespace Barotrauma
|
||||
savedExperiencePoints.RemoveAll(s => s.SteamID != 0 && client.SteamID == s.SteamID || client.EndpointMatches(s.EndPoint));
|
||||
}
|
||||
|
||||
public void LoadPets()
|
||||
{
|
||||
if (petsElement != null)
|
||||
{
|
||||
PetBehavior.LoadPets(petsElement);
|
||||
}
|
||||
}
|
||||
|
||||
public void SavePlayers()
|
||||
{
|
||||
//refresh the character data of clients who are still in the server
|
||||
@@ -229,7 +230,7 @@ namespace Barotrauma
|
||||
if (!matchingCharacterData.HasSpawned) { continue; }
|
||||
characterInfo ??= matchingCharacterData.CharacterInfo;
|
||||
}
|
||||
if (characterInfo == null) { continue; }
|
||||
if (characterInfo == null || characterInfo.Discarded) { continue; }
|
||||
//reduce skills if the character has died
|
||||
if (characterInfo.CauseOfDeath != null && characterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected)
|
||||
{
|
||||
@@ -261,8 +262,7 @@ namespace Barotrauma
|
||||
|
||||
characterData.ForEach(cd => cd.HasSpawned = false);
|
||||
|
||||
petsElement = new XElement("pets");
|
||||
PetBehavior.SavePets(petsElement);
|
||||
SavePets();
|
||||
|
||||
//remove all items that are in someone's inventory
|
||||
foreach (Character c in Character.CharacterList)
|
||||
@@ -285,6 +285,8 @@ namespace Barotrauma
|
||||
|
||||
c.Inventory.DeleteAllItems();
|
||||
}
|
||||
|
||||
SaveActiveOrders();
|
||||
}
|
||||
|
||||
public void MoveDiscardedCharacterBalancesToBank()
|
||||
@@ -304,7 +306,7 @@ namespace Barotrauma
|
||||
|
||||
protected override IEnumerable<CoroutineStatus> DoLevelTransition(TransitionType transitionType, LevelData newLevel, Submarine leavingSub, bool mirror, List<TraitorMissionResult> traitorResults)
|
||||
{
|
||||
lastUpdateID++;
|
||||
IncrementAllLastUpdateIds();
|
||||
|
||||
switch (transitionType)
|
||||
{
|
||||
@@ -348,44 +350,11 @@ namespace Barotrauma
|
||||
if (success)
|
||||
{
|
||||
SavePlayers();
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
if (leavingSub != Submarine.MainSub && !leavingSub.DockedTo.Contains(Submarine.MainSub))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
LeaveUnconnectedSubs(leavingSub);
|
||||
NextLevel = newLevel;
|
||||
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
|
||||
|
||||
if (PendingSubmarineSwitch != null)
|
||||
{
|
||||
SubmarineInfo previousSub = GameMain.GameSession.SubmarineInfo;
|
||||
GameMain.GameSession.SubmarineInfo = PendingSubmarineSwitch;
|
||||
|
||||
for (int i = 0; i < GameMain.GameSession.OwnedSubmarines.Count; i++)
|
||||
{
|
||||
if (GameMain.GameSession.OwnedSubmarines[i].Name == previousSub.Name)
|
||||
{
|
||||
GameMain.GameSession.OwnedSubmarines[i] = previousSub;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||
PendingSubmarineSwitch = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -393,7 +362,7 @@ namespace Barotrauma
|
||||
GameMain.Server.EndGame(TransitionType.None, wasSaved: false);
|
||||
LoadCampaign(GameMain.GameSession.SavePath);
|
||||
LastSaveID++;
|
||||
LastUpdateID++;
|
||||
IncrementAllLastUpdateIds();
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
@@ -424,14 +393,14 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
partial void InitProjSpecific()
|
||||
{
|
||||
CargoManager.OnItemsInBuyCrateChanged += () => { LastUpdateID++; };
|
||||
CargoManager.OnPurchasedItemsChanged += () => { LastUpdateID++; };
|
||||
CargoManager.OnSoldItemsChanged += () => { LastUpdateID++; };
|
||||
UpgradeManager.OnUpgradesChanged += () => { LastUpdateID++; };
|
||||
Map.OnLocationSelected += (loc, connection) => { LastUpdateID++; };
|
||||
Map.OnMissionsSelected += (loc, mission) => { LastUpdateID++; };
|
||||
Reputation.OnAnyReputationValueChanged += () => { LastUpdateID++; };
|
||||
{
|
||||
CargoManager.OnItemsInBuyCrateChanged += () => { IncrementLastUpdateIdForFlag(NetFlags.ItemsInBuyCrate); };
|
||||
CargoManager.OnPurchasedItemsChanged += () => { IncrementLastUpdateIdForFlag(NetFlags.PurchasedItems); };
|
||||
CargoManager.OnSoldItemsChanged += () => { IncrementLastUpdateIdForFlag(NetFlags.SoldItems); };
|
||||
UpgradeManager.OnUpgradesChanged += () => { IncrementLastUpdateIdForFlag(NetFlags.UpgradeManager); };
|
||||
Map.OnLocationSelected += (loc, connection) => { IncrementLastUpdateIdForFlag(NetFlags.MapAndMissions); };
|
||||
Map.OnMissionsSelected += (loc, mission) => { IncrementLastUpdateIdForFlag(NetFlags.MapAndMissions); };
|
||||
Reputation.OnAnyReputationValueChanged += () => { IncrementLastUpdateIdForFlag(NetFlags.Reputation); };
|
||||
|
||||
//increment save ID so clients know they're lacking the most up-to-date save file
|
||||
LastSaveID++;
|
||||
@@ -451,7 +420,10 @@ namespace Barotrauma
|
||||
{
|
||||
discardedCharacters.Add(data);
|
||||
}
|
||||
DebugConsole.Log($"Client \"{client}\" discarded the character ({data.Name})");
|
||||
data.CharacterInfo.Discarded = true;
|
||||
characterData.Remove(data);
|
||||
IncrementLastUpdateIdForFlag(NetFlags.CharacterInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -466,6 +438,7 @@ namespace Barotrauma
|
||||
characterData.RemoveAll(cd => cd.MatchesClient(client));
|
||||
var data = new CharacterCampaignData(client);
|
||||
characterData.Add(data);
|
||||
IncrementLastUpdateIdForFlag(NetFlags.CharacterInfo);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -477,6 +450,7 @@ namespace Barotrauma
|
||||
var matchingData = GetClientCharacterData(client);
|
||||
if (matchingData != null) { client.CharacterInfo = matchingData.CharacterInfo; }
|
||||
}
|
||||
IncrementLastUpdateIdForFlag(NetFlags.CharacterInfo);
|
||||
}
|
||||
|
||||
public Dictionary<Client, Job> GetAssignedJobs(IEnumerable<Client> connectedClients)
|
||||
@@ -581,127 +555,187 @@ namespace Barotrauma
|
||||
base.End(transitionType);
|
||||
}
|
||||
|
||||
private bool IsFlagRequired(Client c, NetFlags flag)
|
||||
=> !c.LastRecvCampaignUpdate.TryGetValue(flag, out var id) || NetIdUtils.IdMoreRecent(GetLastUpdateIdForFlag(flag), id);
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(map.Locations.Count < UInt16.MaxValue);
|
||||
|
||||
Reputation reputation = Map?.CurrentLocation?.Reputation;
|
||||
NetFlags requiredFlags = lastUpdateID.Keys.Where(k => IsFlagRequired(c, k)).Aggregate((NetFlags)0, (f1, f2) => f1 | f2);
|
||||
|
||||
msg.Write((UInt16)requiredFlags);
|
||||
|
||||
msg.Write(IsFirstRound);
|
||||
msg.Write(CampaignID);
|
||||
msg.Write(lastUpdateID);
|
||||
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);
|
||||
|
||||
var selectedMissionIndices = map.GetSelectedMissionIndices();
|
||||
msg.Write((byte)selectedMissionIndices.Count());
|
||||
foreach (int selectedMissionIndex in selectedMissionIndices)
|
||||
|
||||
if (requiredFlags.HasFlag(NetFlags.Misc))
|
||||
{
|
||||
msg.Write((byte)selectedMissionIndex);
|
||||
msg.Write(GetLastUpdateIdForFlag(NetFlags.Misc));
|
||||
msg.Write(PurchasedHullRepairs);
|
||||
msg.Write(PurchasedItemRepairs);
|
||||
msg.Write(PurchasedLostShuttles);
|
||||
}
|
||||
|
||||
var subList = GameMain.NetLobbyScreen.GetSubList();
|
||||
List<int> ownedSubmarineIndices = new List<int>();
|
||||
for (int i = 0; i < subList.Count; i++)
|
||||
if (requiredFlags.HasFlag(NetFlags.MapAndMissions))
|
||||
{
|
||||
if (GameMain.GameSession.OwnedSubmarines.Any(s => s.Name == subList[i].Name))
|
||||
msg.Write(GetLastUpdateIdForFlag(NetFlags.MapAndMissions));
|
||||
msg.Write(ForceMapUI);
|
||||
msg.Write(map.AllowDebugTeleport);
|
||||
msg.Write(map.CurrentLocationIndex == -1 ? UInt16.MaxValue : (UInt16)map.CurrentLocationIndex);
|
||||
msg.Write(map.SelectedLocationIndex == -1 ? UInt16.MaxValue : (UInt16)map.SelectedLocationIndex);
|
||||
|
||||
if (map.CurrentLocation != null)
|
||||
{
|
||||
ownedSubmarineIndices.Add(i);
|
||||
}
|
||||
}
|
||||
msg.Write((ushort)ownedSubmarineIndices.Count);
|
||||
foreach (int index in ownedSubmarineIndices)
|
||||
{
|
||||
msg.Write((ushort)index);
|
||||
}
|
||||
|
||||
msg.Write(map.AllowDebugTeleport);
|
||||
msg.Write(reputation != null);
|
||||
if (reputation != null) { msg.Write(reputation.Value); }
|
||||
|
||||
// hopefully we'll never have more than 128 factions
|
||||
msg.Write((byte)Factions.Count);
|
||||
foreach (Faction faction in Factions)
|
||||
{
|
||||
msg.Write(faction.Prefab.Identifier);
|
||||
msg.Write(faction.Reputation.Value);
|
||||
}
|
||||
|
||||
msg.Write(ForceMapUI);
|
||||
|
||||
msg.Write(PurchasedHullRepairs);
|
||||
msg.Write(PurchasedItemRepairs);
|
||||
msg.Write(PurchasedLostShuttles);
|
||||
|
||||
if (map.CurrentLocation != null)
|
||||
{
|
||||
msg.Write((byte)map.CurrentLocation?.AvailableMissions.Count());
|
||||
foreach (Mission mission in map.CurrentLocation.AvailableMissions)
|
||||
{
|
||||
msg.Write(mission.Prefab.Identifier);
|
||||
if (mission.Locations[0] == mission.Locations[1])
|
||||
msg.Write((byte)map.CurrentLocation.AvailableMissions.Count());
|
||||
foreach (Mission mission in map.CurrentLocation.AvailableMissions)
|
||||
{
|
||||
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));
|
||||
msg.Write(mission.Prefab.Identifier);
|
||||
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
|
||||
bool hasStores = map.CurrentLocation.Stores != null && map.CurrentLocation.Stores.Any();
|
||||
msg.Write(hasStores);
|
||||
if (hasStores)
|
||||
else
|
||||
{
|
||||
msg.Write((byte)map.CurrentLocation.Stores.Count);
|
||||
foreach (var store in map.CurrentLocation.Stores.Values)
|
||||
msg.Write((byte)0);
|
||||
}
|
||||
|
||||
var selectedMissionIndices = map.GetSelectedMissionIndices();
|
||||
msg.Write((byte)selectedMissionIndices.Count());
|
||||
foreach (int selectedMissionIndex in selectedMissionIndices)
|
||||
{
|
||||
msg.Write((byte)selectedMissionIndex);
|
||||
}
|
||||
|
||||
WriteStores(msg);
|
||||
}
|
||||
|
||||
if (requiredFlags.HasFlag(NetFlags.SubList))
|
||||
{
|
||||
msg.Write(GetLastUpdateIdForFlag(NetFlags.SubList));
|
||||
var subList = GameMain.NetLobbyScreen.GetSubList();
|
||||
List<int> ownedSubmarineIndices = new List<int>();
|
||||
for (int i = 0; i < subList.Count; i++)
|
||||
{
|
||||
if (GameMain.GameSession.OwnedSubmarines.Any(s => s.Name == subList[i].Name))
|
||||
{
|
||||
msg.Write(store.Identifier);
|
||||
msg.Write((UInt16)store.Balance);
|
||||
ownedSubmarineIndices.Add(i);
|
||||
}
|
||||
}
|
||||
msg.Write((ushort)ownedSubmarineIndices.Count);
|
||||
foreach (int index in ownedSubmarineIndices)
|
||||
{
|
||||
msg.Write((ushort)index);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (requiredFlags.HasFlag(NetFlags.UpgradeManager))
|
||||
{
|
||||
msg.Write((byte)0);
|
||||
// Store balance
|
||||
msg.Write(false);
|
||||
msg.Write(GetLastUpdateIdForFlag(NetFlags.UpgradeManager));
|
||||
msg.Write((ushort)UpgradeManager.PendingUpgrades.Count);
|
||||
foreach (var (prefab, category, level) in UpgradeManager.PendingUpgrades)
|
||||
{
|
||||
msg.Write(prefab.Identifier);
|
||||
msg.Write(category.Identifier);
|
||||
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 ?? Identifier.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
WriteItems(msg, CargoManager.ItemsInBuyCrate);
|
||||
WriteItems(msg, CargoManager.ItemsInSellFromSubCrate);
|
||||
WriteItems(msg, CargoManager.PurchasedItems);
|
||||
WriteItems(msg, CargoManager.SoldItems);
|
||||
|
||||
msg.Write((ushort)UpgradeManager.PendingUpgrades.Count);
|
||||
foreach (var (prefab, category, level) in UpgradeManager.PendingUpgrades)
|
||||
if (requiredFlags.HasFlag(NetFlags.ItemsInBuyCrate))
|
||||
{
|
||||
msg.Write(prefab.Identifier);
|
||||
msg.Write(category.Identifier);
|
||||
msg.Write((byte)level);
|
||||
msg.Write(GetLastUpdateIdForFlag(NetFlags.ItemsInBuyCrate));
|
||||
WriteItems(msg, CargoManager.ItemsInBuyCrate);
|
||||
WriteStores(msg);
|
||||
}
|
||||
|
||||
msg.Write((ushort)UpgradeManager.PurchasedItemSwaps.Count);
|
||||
foreach (var itemSwap in UpgradeManager.PurchasedItemSwaps)
|
||||
if (requiredFlags.HasFlag(NetFlags.ItemsInSellFromSubCrate))
|
||||
{
|
||||
msg.Write(itemSwap.ItemToRemove.ID);
|
||||
msg.Write(itemSwap.ItemToInstall?.Identifier ?? Identifier.Empty);
|
||||
msg.Write(GetLastUpdateIdForFlag(NetFlags.ItemsInSellFromSubCrate));
|
||||
WriteItems(msg, CargoManager.ItemsInSellFromSubCrate);
|
||||
WriteStores(msg);
|
||||
}
|
||||
|
||||
var characterData = GetClientCharacterData(c);
|
||||
if (characterData?.CharacterInfo == null)
|
||||
if (requiredFlags.HasFlag(NetFlags.PurchasedItems))
|
||||
{
|
||||
msg.Write(false);
|
||||
msg.Write(GetLastUpdateIdForFlag(NetFlags.PurchasedItems));
|
||||
WriteItems(msg, CargoManager.PurchasedItems);
|
||||
WriteStores(msg);
|
||||
|
||||
}
|
||||
else
|
||||
if (requiredFlags.HasFlag(NetFlags.SoldItems))
|
||||
{
|
||||
msg.Write(true);
|
||||
characterData.CharacterInfo.ServerWrite(msg);
|
||||
msg.Write(GetLastUpdateIdForFlag(NetFlags.SoldItems));
|
||||
WriteItems(msg, CargoManager.SoldItems);
|
||||
WriteStores(msg);
|
||||
}
|
||||
if (requiredFlags.HasFlag(NetFlags.Reputation))
|
||||
{
|
||||
msg.Write(GetLastUpdateIdForFlag(NetFlags.Reputation));
|
||||
Reputation reputation = Map?.CurrentLocation?.Reputation;
|
||||
msg.Write(reputation != null);
|
||||
if (reputation != null) { msg.Write(reputation.Value); }
|
||||
|
||||
// hopefully we'll never have more than 128 factions
|
||||
msg.Write((byte)Factions.Count);
|
||||
foreach (Faction faction in Factions)
|
||||
{
|
||||
msg.Write(faction.Prefab.Identifier);
|
||||
msg.Write(faction.Reputation.Value);
|
||||
}
|
||||
}
|
||||
if (requiredFlags.HasFlag(NetFlags.CharacterInfo))
|
||||
{
|
||||
msg.Write(GetLastUpdateIdForFlag(NetFlags.CharacterInfo));
|
||||
var characterData = GetClientCharacterData(c);
|
||||
if (characterData?.CharacterInfo == null)
|
||||
{
|
||||
msg.Write(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write(true);
|
||||
characterData.CharacterInfo.ServerWrite(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteStores(IWriteMessage msg)
|
||||
{
|
||||
if (map.CurrentLocation != null)
|
||||
{
|
||||
// Store balance
|
||||
bool hasStores = map.CurrentLocation.Stores != null && map.CurrentLocation.Stores.Any();
|
||||
msg.Write(hasStores);
|
||||
if (hasStores)
|
||||
{
|
||||
msg.Write((byte)map.CurrentLocation.Stores.Count);
|
||||
foreach (var store in map.CurrentLocation.Stores.Values)
|
||||
{
|
||||
msg.Write(store.Identifier);
|
||||
msg.Write((UInt16)store.Balance);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write((byte)0);
|
||||
// Store balance
|
||||
msg.Write(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -977,6 +1011,8 @@ namespace Barotrauma
|
||||
{
|
||||
NetWalletTransfer transfer = INetSerializableStruct.Read<NetWalletTransfer>(msg);
|
||||
|
||||
if (GameMain.Server is null) { return; }
|
||||
|
||||
switch (transfer.Sender)
|
||||
{
|
||||
case Some<ushort> { Value: var id }:
|
||||
@@ -992,7 +1028,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (transfer.Receiver is Some<ushort> { Value: var receiverId } && receiverId == sender.CharacterID)
|
||||
{
|
||||
GameMain.Server?.Voting.StartTransferVote(sender, null, transfer.Amount, sender);
|
||||
if (transfer.Amount > GameMain.Server.ServerSettings.MaximumMoneyTransferRequest) { return; }
|
||||
GameMain.Server.Voting.StartTransferVote(sender, null, transfer.Amount, sender);
|
||||
GameServer.Log($"{sender.Name} started a vote to transfer {transfer.Amount} mk from the bank.", ServerLog.MessageType.Money);
|
||||
}
|
||||
return;
|
||||
@@ -1301,7 +1338,11 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
// save bots
|
||||
CrewManager.SaveMultiplayer(modeElement);
|
||||
var crewManagerElement = CrewManager.SaveMultiplayer(modeElement);
|
||||
if (ActiveOrdersElement != null)
|
||||
{
|
||||
crewManagerElement.Add(ActiveOrdersElement);
|
||||
}
|
||||
|
||||
XElement savedExperiencePointsElement = new XElement("SavedExperiencePoints");
|
||||
foreach (var savedExperiencePoint in savedExperiencePoints)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Barotrauma.Networking;
|
||||
@@ -18,7 +19,8 @@ namespace Barotrauma
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte) ServerPacketHeader.READY_CHECK);
|
||||
msg.Write((byte) ReadyCheckState.Start);
|
||||
msg.Write(endTime);
|
||||
msg.Write(new DateTimeOffset(startTime).ToUnixTimeSeconds());
|
||||
msg.Write(new DateTimeOffset(endTime).ToUnixTimeSeconds());
|
||||
msg.Write(author);
|
||||
|
||||
if (sender != null)
|
||||
@@ -53,10 +55,9 @@ namespace Barotrauma
|
||||
foreach (Client client in ActivePlayers)
|
||||
{
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte) ServerPacketHeader.READY_CHECK);
|
||||
msg.Write((byte) ReadyCheckState.Update);
|
||||
msg.Write(time); // sync time
|
||||
msg.Write((byte) state);
|
||||
msg.Write((byte)ServerPacketHeader.READY_CHECK);
|
||||
msg.Write((byte)ReadyCheckState.Update);
|
||||
msg.Write((byte)state);
|
||||
msg.Write(otherClient);
|
||||
GameMain.Server.ServerPeer.Send(msg, client.Connection, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class DockingPort : ItemComponent, IDrawableComponent, IServerSerializable
|
||||
partial class DockingPort : ItemComponent, IDrawableComponent, IServerSerializable, IClientSerializable
|
||||
{
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write(docked);
|
||||
|
||||
if (docked)
|
||||
{
|
||||
msg.Write(DockingTarget.item.ID);
|
||||
msg.Write(IsLocked);
|
||||
}
|
||||
}
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
var allowOutpostAutoDocking = (AllowOutpostAutoDocking)msg.ReadByte();
|
||||
if (outpostAutoDockingPromptShown &&
|
||||
(GameMain.GameSession?.Campaign?.AllowedToManageCampaign(c, ClientPermissions.ManageMap) ?? false))
|
||||
{
|
||||
this.allowOutpostAutoDocking = allowOutpostAutoDocking;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||
{
|
||||
//do nothing
|
||||
}
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Pump : Powered, IServerSerializable, IClientSerializable
|
||||
{
|
||||
const float NetworkUpdateInterval = 5.0f;
|
||||
private float networkUpdateTimer;
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
networkUpdateTimer -= deltaTime;
|
||||
if (networkUpdateTimer <= 0.0f)
|
||||
{
|
||||
item.CreateServerEvent(this);
|
||||
networkUpdateTimer = NetworkUpdateInterval;
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
float newFlowPercentage = msg.ReadRangedInteger(-10, 10) * 10.0f;
|
||||
|
||||
@@ -102,6 +102,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
msg.Write(autoPilot);
|
||||
msg.Write(TryExtractEventData<EventData>(extraData, out var eventData) && eventData.DockingButtonClicked);
|
||||
msg.Write(user?.ID ?? Entity.NullEntityID);
|
||||
|
||||
if (!autoPilot)
|
||||
{
|
||||
|
||||
@@ -15,7 +15,8 @@ namespace Barotrauma.Items.Components
|
||||
for (int i = 0; i < Connections.Count; i++)
|
||||
{
|
||||
wires[i] = new List<Wire>();
|
||||
for (int j = 0; j < Connections[i].MaxWires; j++)
|
||||
uint wireCount = msg.ReadVariableUInt32();
|
||||
for (int j = 0; j < wireCount; j++)
|
||||
{
|
||||
ushort wireId = msg.ReadUInt16();
|
||||
|
||||
@@ -91,12 +92,8 @@ namespace Barotrauma.Items.Components
|
||||
//go through existing wire links
|
||||
for (int i = 0; i < Connections.Count; i++)
|
||||
{
|
||||
int j = -1;
|
||||
foreach (Wire existingWire in Connections[i].Wires)
|
||||
foreach (Wire existingWire in Connections[i].Wires.ToArray())
|
||||
{
|
||||
j++;
|
||||
if (existingWire == null) { continue; }
|
||||
|
||||
//existing wire not in the list of new wires -> disconnect it
|
||||
if (!wires[i].Contains(existingWire))
|
||||
{
|
||||
@@ -163,7 +160,7 @@ namespace Barotrauma.Items.Components
|
||||
}*/
|
||||
}
|
||||
|
||||
Connections[i].SetWire(j, null);
|
||||
Connections[i].DisconnectWire(existingWire);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
-13
@@ -26,26 +26,34 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
for (int i = 0; i < customInterfaceElementList.Count; i++)
|
||||
{
|
||||
if (customInterfaceElementList[i].HasPropertyName)
|
||||
var element = customInterfaceElementList[i];
|
||||
if (element.HasPropertyName)
|
||||
{
|
||||
if (!customInterfaceElementList[i].IsIntegerInput)
|
||||
if (!element.IsNumberInput)
|
||||
{
|
||||
TextChanged(customInterfaceElementList[i], elementValues[i]);
|
||||
TextChanged(element, elementValues[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
int.TryParse(elementValues[i], out int value);
|
||||
ValueChanged(customInterfaceElementList[i], value);
|
||||
switch (element.NumberType)
|
||||
{
|
||||
case NumberType.Int when int.TryParse(elementValues[i], out int value):
|
||||
ValueChanged(element, value);
|
||||
break;
|
||||
case NumberType.Float when TryParseFloatInvariantCulture(elementValues[i], out float value):
|
||||
ValueChanged(element, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (customInterfaceElementList[i].ContinuousSignal)
|
||||
else if (element.ContinuousSignal)
|
||||
{
|
||||
TickBoxToggled(customInterfaceElementList[i], elementStates[i]);
|
||||
TickBoxToggled(element, elementStates[i]);
|
||||
}
|
||||
else if (elementStates[i])
|
||||
{
|
||||
clickedButton = customInterfaceElementList[i];
|
||||
ButtonClicked(customInterfaceElementList[i]);
|
||||
clickedButton = element;
|
||||
ButtonClicked(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,13 +69,14 @@ namespace Barotrauma.Items.Components
|
||||
//extradata contains an array of buttons clicked by a client (or nothing if nothing was clicked)
|
||||
for (int i = 0; i < customInterfaceElementList.Count; i++)
|
||||
{
|
||||
if (customInterfaceElementList[i].HasPropertyName)
|
||||
var element = customInterfaceElementList[i];
|
||||
if (element.HasPropertyName)
|
||||
{
|
||||
msg.Write(customInterfaceElementList[i].Signal);
|
||||
msg.Write(element.Signal);
|
||||
}
|
||||
else if (customInterfaceElementList[i].ContinuousSignal)
|
||||
else if(element.ContinuousSignal)
|
||||
{
|
||||
msg.Write(customInterfaceElementList[i].State);
|
||||
msg.Write(element.State);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
foreach (BallastFloraBranch branch in Branches)
|
||||
{
|
||||
//don't notify about minuscule amounts of damage (<= 1.0f)
|
||||
if (branch.AccumulatedDamage > 1.0f)
|
||||
if (Math.Abs(branch.AccumulatedDamage) > 1.0f)
|
||||
{
|
||||
CreateNetworkMessage(new BranchDamageEventData(branch));
|
||||
branch.AccumulatedDamage = 0.0f;
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.MapCreatures.Behavior;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -39,9 +36,9 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
statusUpdateTimer -= deltaTime;
|
||||
decalUpdateTimer -= deltaTime;
|
||||
backgroundSectionUpdateTimer -= deltaTime;
|
||||
statusUpdateTimer += deltaTime;
|
||||
decalUpdateTimer += deltaTime;
|
||||
backgroundSectionUpdateTimer += deltaTime;
|
||||
|
||||
//update client hulls if the amount of water has changed by >10%
|
||||
//or if oxygen percentage has changed by 5%
|
||||
@@ -49,33 +46,32 @@ namespace Barotrauma
|
||||
(Math.Abs(lastSentVolume - waterVolume) > Volume * 0.1f
|
||||
|| Math.Abs(lastSentOxygen - OxygenPercentage) > 5f
|
||||
|| lastSentFireCount != FireSources.Count)
|
||||
&& statusUpdateTimer <= 0.0f;
|
||||
&& (statusUpdateTimer > NetConfig.HullUpdateInterval);
|
||||
|
||||
if (shouldSendStatusUpdate)
|
||||
//force an update every 5 seconds even if nothing's changed (in case a client's gotten out of sync somehow)
|
||||
if (shouldSendStatusUpdate || statusUpdateTimer > NetConfig.SparseHullUpdateInterval)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new StatusEventData());
|
||||
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new StatusEventData());
|
||||
lastSentVolume = waterVolume;
|
||||
lastSentOxygen = OxygenPercentage;
|
||||
lastSentFireCount = FireSources.Count;
|
||||
|
||||
statusUpdateTimer = NetConfig.SparseHullUpdateInterval;
|
||||
statusUpdateTimer = 0;
|
||||
}
|
||||
if (decalUpdatePending && decalUpdateTimer <= 0.0f)
|
||||
if (decalUpdatePending && decalUpdateTimer > NetConfig.HullUpdateInterval)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new DecalEventData());
|
||||
|
||||
decalUpdateTimer = NetConfig.HullUpdateInterval;
|
||||
decalUpdateTimer = 0;
|
||||
decalUpdatePending = false;
|
||||
}
|
||||
if (pendingSectionUpdates.Count > 0 && backgroundSectionUpdateTimer <= 0.0f)
|
||||
if (pendingSectionUpdates.Count > 0 && backgroundSectionUpdateTimer > NetConfig.HullUpdateInterval)
|
||||
{
|
||||
foreach (int pendingSectionUpdate in pendingSectionUpdates)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new BackgroundSectionsEventData(pendingSectionUpdate));
|
||||
}
|
||||
|
||||
backgroundSectionUpdateTimer = NetConfig.HullUpdateInterval;
|
||||
backgroundSectionUpdateTimer = 0;
|
||||
pendingSectionUpdates.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ namespace Barotrauma.Networking
|
||||
c.KickAFKTimer = 0.0f;
|
||||
|
||||
UInt16 ID = msg.ReadUInt16();
|
||||
ChatMessageType type = (ChatMessageType)msg.ReadByte();
|
||||
ChatMessageType type = (ChatMessageType)msg.ReadRangedInteger(0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
|
||||
ChatMode chatMode = (ChatMode)msg.ReadRangedInteger(0, Enum.GetValues(typeof(ChatMode)).Length - 1);
|
||||
string txt;
|
||||
|
||||
Character orderTargetCharacter = null;
|
||||
@@ -180,7 +181,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendChatMessage(txt, null, c);
|
||||
GameMain.Server.SendChatMessage(txt, senderClient: c, chatMode: chatMode);
|
||||
}
|
||||
|
||||
|
||||
@@ -213,7 +214,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
msg.Write((byte)ServerNetObject.CHAT_MESSAGE);
|
||||
msg.Write(NetStateID);
|
||||
msg.Write((byte)Type);
|
||||
msg.WriteRangedInteger((int)Type, 0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
|
||||
msg.Write((byte)ChangeType);
|
||||
msg.Write(Text);
|
||||
|
||||
|
||||
@@ -21,10 +21,10 @@ namespace Barotrauma.Networking
|
||||
public UInt16 LastSentEntityEventID = 0;
|
||||
public UInt16 LastRecvEntityEventID = 0;
|
||||
|
||||
public UInt16 LastRecvCampaignUpdate = 0;
|
||||
public readonly Dictionary<MultiPlayerCampaign.NetFlags, UInt16> LastRecvCampaignUpdate = new Dictionary<MultiPlayerCampaign.NetFlags, ushort>();
|
||||
public UInt16 LastRecvCampaignSave = 0;
|
||||
|
||||
public Pair<UInt16, float> LastCampaignSaveSendTime;
|
||||
public (UInt16 saveId, float time) LastCampaignSaveSendTime;
|
||||
|
||||
public readonly List<ChatMessage> ChatMsgQueue = new List<ChatMessage>();
|
||||
public UInt16 LastChatMsgQueueID;
|
||||
@@ -73,6 +73,9 @@ namespace Barotrauma.Networking
|
||||
characterInfo = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string PendingName;
|
||||
|
||||
public NetworkConnection Connection { get; set; }
|
||||
|
||||
public bool SpectateOnly;
|
||||
|
||||
@@ -391,7 +391,7 @@ namespace Barotrauma.Networking
|
||||
StartTransfer(inc.Sender, FileTransferType.CampaignSave, GameMain.GameSession.SavePath);
|
||||
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign)
|
||||
{
|
||||
client.LastCampaignSaveSendTime = new Pair<ushort, float>(campaign.LastSaveID, (float)Lidgren.Network.NetTime.Now);
|
||||
client.LastCampaignSaveSendTime = (campaign.LastSaveID, (float)Lidgren.Network.NetTime.Now);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
@@ -759,7 +759,7 @@ namespace Barotrauma.Networking
|
||||
string seed = inc.ReadString();
|
||||
string subName = inc.ReadString();
|
||||
string subHash = inc.ReadString();
|
||||
CampaignSettings settings = new CampaignSettings(inc);
|
||||
CampaignSettings settings = INetSerializableStruct.Read<CampaignSettings>(inc);
|
||||
|
||||
var matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.StringRepresentation == subHash);
|
||||
|
||||
@@ -780,8 +780,7 @@ namespace Barotrauma.Networking
|
||||
string localSavePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer, saveName);
|
||||
if (connectedClient.HasPermission(ClientPermissions.SelectMode) || connectedClient.HasPermission(ClientPermissions.ManageCampaign))
|
||||
{
|
||||
ServerSettings.RadiationEnabled = settings.RadiationEnabled;
|
||||
ServerSettings.MaxMissionCount = settings.MaxMissionCount;
|
||||
ServerSettings.CampaignSettings = settings;
|
||||
ServerSettings.SaveSettings();
|
||||
MultiPlayerCampaign.StartNewCampaign(localSavePath, matchingSub.FilePath, seed, settings);
|
||||
}
|
||||
@@ -846,6 +845,9 @@ namespace Barotrauma.Networking
|
||||
case ClientPacketHeader.EVENTMANAGER_RESPONSE:
|
||||
GameMain.GameSession?.EventManager.ServerRead(inc, connectedClient);
|
||||
break;
|
||||
case ClientPacketHeader.UPDATE_CHARACTERINFO:
|
||||
UpdateCharacterInfo(inc, connectedClient);
|
||||
break;
|
||||
case ClientPacketHeader.ERROR:
|
||||
HandleClientError(inc, connectedClient);
|
||||
break;
|
||||
@@ -968,7 +970,9 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
if (Level.Loaded != null)
|
||||
{
|
||||
errorLines.Add("Level: " + Level.Loaded.Seed + ", " + string.Join(", ", Level.Loaded.EqualityCheckValues.Select(cv => cv.ToString("X"))));
|
||||
errorLines.Add("Level: " + Level.Loaded.Seed + ", "
|
||||
+ string.Join("; ", Level.Loaded.EqualityCheckValues.Select(cv
|
||||
=> cv.Key + "=" + cv.Value.ToString("X"))));
|
||||
errorLines.Add("Entity count before generating level: " + Level.Loaded.EntityCountBeforeGenerate);
|
||||
errorLines.Add("Entities:");
|
||||
foreach (Entity e in Level.Loaded.EntitiesBeforeGenerate.OrderBy(e => e.CreationIndex))
|
||||
@@ -1055,15 +1059,17 @@ namespace Barotrauma.Networking
|
||||
c.LastRecvChatMsgID = NetIdUtils.Clamp(inc.ReadUInt16(), c.LastRecvChatMsgID, c.LastChatMsgQueueID);
|
||||
c.LastRecvClientListUpdate = NetIdUtils.Clamp(inc.ReadUInt16(), c.LastRecvClientListUpdate, LastClientListUpdateID);
|
||||
|
||||
TryChangeClientName(c, inc);
|
||||
ReadClientNameChange(c, inc);
|
||||
|
||||
c.LastRecvCampaignSave = inc.ReadUInt16();
|
||||
if (c.LastRecvCampaignSave > 0)
|
||||
{
|
||||
byte campaignID = inc.ReadByte();
|
||||
c.LastRecvCampaignUpdate = inc.ReadUInt16();
|
||||
foreach (MultiPlayerCampaign.NetFlags netFlag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
|
||||
{
|
||||
c.LastRecvCampaignUpdate[netFlag] = inc.ReadUInt16();
|
||||
}
|
||||
bool characterDiscarded = inc.ReadBoolean();
|
||||
|
||||
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign)
|
||||
{
|
||||
if (characterDiscarded) { campaign.DiscardClientCharacterData(c); }
|
||||
@@ -1072,7 +1078,11 @@ namespace Barotrauma.Networking
|
||||
if (campaign.CampaignID != campaignID)
|
||||
{
|
||||
c.LastRecvCampaignSave = (ushort)(campaign.LastSaveID - 1);
|
||||
c.LastRecvCampaignUpdate = (ushort)(campaign.LastUpdateID - 1);
|
||||
foreach (MultiPlayerCampaign.NetFlags netFlag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
|
||||
{
|
||||
c.LastRecvCampaignUpdate[netFlag] =
|
||||
(UInt16)(campaign.GetLastUpdateIdForFlag(netFlag) - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1133,9 +1143,11 @@ namespace Barotrauma.Networking
|
||||
if (c.LastRecvCampaignSave > 0)
|
||||
{
|
||||
byte campaignID = inc.ReadByte();
|
||||
c.LastRecvCampaignUpdate = inc.ReadUInt16();
|
||||
foreach (MultiPlayerCampaign.NetFlags netFlag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
|
||||
{
|
||||
c.LastRecvCampaignUpdate[netFlag] = inc.ReadUInt16();
|
||||
}
|
||||
bool characterDiscarded = inc.ReadBoolean();
|
||||
|
||||
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign)
|
||||
{
|
||||
if (characterDiscarded) { campaign.DiscardClientCharacterData(c); }
|
||||
@@ -1144,7 +1156,11 @@ namespace Barotrauma.Networking
|
||||
if (campaign.CampaignID != campaignID)
|
||||
{
|
||||
c.LastRecvCampaignSave = (ushort)(campaign.LastSaveID - 1);
|
||||
c.LastRecvCampaignUpdate = (ushort)(campaign.LastUpdateID - 1);
|
||||
foreach (MultiPlayerCampaign.NetFlags netFlag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
|
||||
{
|
||||
c.LastRecvCampaignUpdate[netFlag] =
|
||||
(UInt16)(campaign.GetLastUpdateIdForFlag(netFlag) - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1381,7 +1397,7 @@ namespace Barotrauma.Networking
|
||||
if (gameStarted)
|
||||
{
|
||||
Log("Client \"" + GameServer.ClientLogName(sender) + "\" ended the round.", ServerLog.MessageType.ServerMessage);
|
||||
if (mpCampaign != null && Level.IsLoadedOutpost && save)
|
||||
if (mpCampaign != null && Level.IsLoadedFriendlyOutpost && save)
|
||||
{
|
||||
mpCampaign.SavePlayers();
|
||||
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
|
||||
@@ -1561,11 +1577,11 @@ namespace Barotrauma.Networking
|
||||
NetIdUtils.IdMoreRecent(campaign.LastSaveID, c.LastRecvCampaignSave))
|
||||
{
|
||||
//already sent an up-to-date campaign save
|
||||
if (c.LastCampaignSaveSendTime != null && campaign.LastSaveID == c.LastCampaignSaveSendTime.First)
|
||||
if (c.LastCampaignSaveSendTime != default && campaign.LastSaveID == c.LastCampaignSaveSendTime.saveId)
|
||||
{
|
||||
//the save was sent less than 5 second ago, don't attempt to resend yet
|
||||
//(the client may have received it but hasn't acked us yet)
|
||||
if (c.LastCampaignSaveSendTime.Second > NetTime.Now - 5.0f)
|
||||
if (c.LastCampaignSaveSendTime.time > NetTime.Now - 5.0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1574,7 +1590,7 @@ namespace Barotrauma.Networking
|
||||
if (!FileSender.ActiveTransfers.Any(t => t.Connection == c.Connection && t.FileType == FileTransferType.CampaignSave))
|
||||
{
|
||||
FileSender.StartTransfer(c.Connection, FileTransferType.CampaignSave, GameMain.GameSession.SavePath);
|
||||
c.LastCampaignSaveSendTime = new Pair<ushort, float>(campaign.LastSaveID, (float)NetTime.Now);
|
||||
c.LastCampaignSaveSendTime = (campaign.LastSaveID, (float)NetTime.Now);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1683,8 +1699,7 @@ namespace Barotrauma.Networking
|
||||
outmsg.Write(c.LastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server
|
||||
outmsg.Write(c.LastSentEntityEventID);
|
||||
|
||||
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode &&
|
||||
NetIdUtils.IdMoreRecent(campaign.LastUpdateID, c.LastRecvCampaignUpdate))
|
||||
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode)
|
||||
{
|
||||
outmsg.Write(true);
|
||||
outmsg.WritePadBits();
|
||||
@@ -1919,8 +1934,7 @@ namespace Barotrauma.Networking
|
||||
int campaignBytes = outmsg.LengthBytes;
|
||||
var campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
|
||||
if (outmsg.LengthBytes < MsgConstants.MTU - 500 &&
|
||||
campaign != null && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode &&
|
||||
NetIdUtils.IdMoreRecent(campaign.LastUpdateID, c.LastRecvCampaignUpdate))
|
||||
campaign != null && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode)
|
||||
{
|
||||
outmsg.Write(true);
|
||||
outmsg.WritePadBits();
|
||||
@@ -2069,7 +2083,10 @@ namespace Barotrauma.Networking
|
||||
var campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
|
||||
msg.Write(campaign == null ? (byte)0 : campaign.CampaignID);
|
||||
msg.Write(campaign == null ? (UInt16)0 : campaign.LastSaveID);
|
||||
msg.Write(campaign == null ? (UInt16)0 : campaign.LastUpdateID);
|
||||
foreach (MultiPlayerCampaign.NetFlags flag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
|
||||
{
|
||||
msg.Write(campaign == null ? (UInt16)0 : campaign.GetLastUpdateIdForFlag(flag));
|
||||
}
|
||||
|
||||
connectedClients.ForEach(c => c.ReadyToStart = false);
|
||||
|
||||
@@ -2097,7 +2114,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
startGameCoroutine = GameMain.Instance.ShowLoading(StartGame(selectedSub, selectedShuttle, selectedMode, CampaignSettings.Unsure), false);
|
||||
startGameCoroutine = GameMain.Instance.ShowLoading(StartGame(selectedSub, selectedShuttle, selectedMode, CampaignSettings.Empty), false);
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
@@ -2215,7 +2232,7 @@ namespace Barotrauma.Networking
|
||||
Level.Loaded?.SpawnNPCs();
|
||||
Level.Loaded?.SpawnCorpses();
|
||||
Level.Loaded?.PrepareBeaconStation();
|
||||
AutoItemPlacer.PlaceIfNeeded();
|
||||
AutoItemPlacer.SpawnItems(campaign?.Settings.StartItemSet);
|
||||
|
||||
CrewManager crewManager = campaign?.CrewManager;
|
||||
|
||||
@@ -2412,7 +2429,9 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
campaign?.LoadPets();
|
||||
crewManager?.LoadActiveOrders();
|
||||
campaign?.LoadActiveOrders();
|
||||
|
||||
campaign?.CargoManager.InitPurchasedIDCards();
|
||||
|
||||
foreach (Submarine sub in Submarine.MainSubs)
|
||||
{
|
||||
@@ -2424,7 +2443,7 @@ namespace Barotrauma.Networking
|
||||
spawnList.Add(new PurchasedItem(kvp.Key, kvp.Value, buyer: null));
|
||||
}
|
||||
|
||||
CargoManager.CreateItems(spawnList, sub);
|
||||
CargoManager.CreateItems(spawnList, sub, cargoManager: null);
|
||||
}
|
||||
|
||||
TraitorManager = null;
|
||||
@@ -2490,6 +2509,7 @@ namespace Barotrauma.Networking
|
||||
msg.Write(serverSettings.LockAllDefaultWires);
|
||||
msg.Write(serverSettings.AllowRagdollButton);
|
||||
msg.Write(serverSettings.AllowLinkingWifiToChat);
|
||||
msg.Write(serverSettings.MaximumMoneyTransferRequest);
|
||||
msg.Write(IsUsingRespawnShuttle());
|
||||
msg.Write((byte)serverSettings.LosMode);
|
||||
msg.Write(includesFinalize); msg.WritePadBits();
|
||||
@@ -2560,10 +2580,9 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
msg.Write(mission.Prefab.Identifier);
|
||||
}
|
||||
msg.Write((byte)GameMain.GameSession.Level.EqualityCheckValues.Count);
|
||||
foreach (int equalityCheckValue in GameMain.GameSession.Level.EqualityCheckValues)
|
||||
foreach (Level.LevelGenStage stage in Enum.GetValues(typeof(Level.LevelGenStage)).OfType<Level.LevelGenStage>().OrderBy(s => s))
|
||||
{
|
||||
msg.Write(equalityCheckValue);
|
||||
msg.Write(GameMain.GameSession.Level.EqualityCheckValues[stage]);
|
||||
}
|
||||
foreach (Mission mission in GameMain.GameSession.Missions)
|
||||
{
|
||||
@@ -2691,7 +2710,7 @@ namespace Barotrauma.Networking
|
||||
base.AddChatMessage(message);
|
||||
}
|
||||
|
||||
private bool TryChangeClientName(Client c, IReadMessage inc)
|
||||
private bool ReadClientNameChange(Client c, IReadMessage inc)
|
||||
{
|
||||
UInt16 nameId = inc.ReadUInt16();
|
||||
string newName = inc.ReadString();
|
||||
@@ -2701,7 +2720,6 @@ namespace Barotrauma.Networking
|
||||
if (c == null || string.IsNullOrEmpty(newName) || !NetIdUtils.IdMoreRecent(nameId, c.NameID)) { return false; }
|
||||
|
||||
c.NameID = nameId;
|
||||
newName = Client.SanitizeName(newName);
|
||||
if (newName == c.Name && newJob == c.PreferredJob && newTeam == c.PreferredTeam) { return false; }
|
||||
|
||||
var result = GameMain.LuaCs.Hook.Call<bool?>("tryChangeClientName", c, newName, newJob, newTeam);
|
||||
@@ -2715,11 +2733,36 @@ namespace Barotrauma.Networking
|
||||
c.PreferredJob = newJob;
|
||||
c.PreferredTeam = newTeam;
|
||||
|
||||
return TryChangeClientName(c, newName);
|
||||
}
|
||||
|
||||
public bool TryChangeClientName(Client c, string newName)
|
||||
{
|
||||
newName = Client.SanitizeName(newName);
|
||||
//update client list even if the name cannot be changed to the one sent by the client,
|
||||
//so the client will be informed what their actual name is
|
||||
LastClientListUpdateID++;
|
||||
|
||||
if (newName == c.Name) { return false; }
|
||||
if (newName == c.Name || string.IsNullOrEmpty(newName)) { return false; }
|
||||
|
||||
if (IsNameValid(c, newName))
|
||||
{
|
||||
string oldName = c.Name;
|
||||
c.Name = newName;
|
||||
c.Connection.Name = newName;
|
||||
SendChatMessage($"ServerMessage.NameChangeSuccessful~[oldname]={oldName}~[newname]={newName}", ChatMessageType.Server);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private bool IsNameValid(Client c, string newName)
|
||||
{
|
||||
newName = Client.SanitizeName(newName);
|
||||
|
||||
if (c.Connection != OwnerConnection)
|
||||
{
|
||||
@@ -2748,9 +2791,6 @@ namespace Barotrauma.Networking
|
||||
return false;
|
||||
}
|
||||
|
||||
SendChatMessage($"ServerMessage.NameChangeSuccessful~[oldname]={c.Name}~[newname]={newName}", ChatMessageType.Server);
|
||||
c.Name = newName;
|
||||
c.Connection.Name = newName;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2994,7 +3034,7 @@ namespace Barotrauma.Networking
|
||||
/// <summary>
|
||||
/// Add the message to the chatbox and pass it to all clients who can receive it
|
||||
/// </summary>
|
||||
public void SendChatMessage(string message, ChatMessageType? type = null, Client senderClient = null, Character senderCharacter = null, PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None)
|
||||
public void SendChatMessage(string message, ChatMessageType? type = null, Client senderClient = null, Character senderCharacter = null, PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None, ChatMode chatMode = ChatMode.None)
|
||||
{
|
||||
string senderName = "";
|
||||
|
||||
@@ -3050,6 +3090,10 @@ namespace Barotrauma.Networking
|
||||
|
||||
type = ChatMessageType.Private;
|
||||
}
|
||||
else if (chatMode == ChatMode.Radio)
|
||||
{
|
||||
type = ChatMessageType.Radio;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = ChatMessageType.Default;
|
||||
@@ -3078,7 +3122,6 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
senderCharacter = senderClient.Character;
|
||||
senderName = senderCharacter == null ? senderClient.Name : senderCharacter.Name;
|
||||
|
||||
if (type == ChatMessageType.Private)
|
||||
{
|
||||
if (senderCharacter != null && !senderCharacter.IsDead || targetClient.Character != null && !targetClient.Character.IsDead)
|
||||
@@ -3233,9 +3276,9 @@ namespace Barotrauma.Networking
|
||||
Client recipient = connectedClients.Find(c => c.Connection == transfer.Connection);
|
||||
if (transfer.FileType == FileTransferType.CampaignSave &&
|
||||
(transfer.Status == FileTransferStatus.Sending || transfer.Status == FileTransferStatus.Finished) &&
|
||||
recipient.LastCampaignSaveSendTime != null)
|
||||
recipient.LastCampaignSaveSendTime != default)
|
||||
{
|
||||
recipient.LastCampaignSaveSendTime.Second = (float)Lidgren.Network.NetTime.Now;
|
||||
recipient.LastCampaignSaveSendTime.time = (float)NetTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3254,18 +3297,27 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (checkActiveVote && Voting.ActiveVote != null)
|
||||
{
|
||||
int yes = GameMain.Server.ConnectedClients.Count(c => c.InGame && c.GetVote<int>(Voting.ActiveVote.VoteType) == 2);
|
||||
int no = GameMain.Server.ConnectedClients.Count(c => c.InGame && c.GetVote<int>(Voting.ActiveVote.VoteType) == 1);
|
||||
int max = GameMain.Server.ConnectedClients.Count(c => c.InGame);
|
||||
// Required ratio cannot be met
|
||||
if (no / (float)max > 1f - serverSettings.VoteRequiredRatio)
|
||||
{
|
||||
Voting.ActiveVote.Finish(Voting, passed: false);
|
||||
}
|
||||
else if (yes / (float)max >= serverSettings.VoteRequiredRatio)
|
||||
var inGameClients = GameMain.Server.ConnectedClients.Where(c => c.InGame);
|
||||
if (inGameClients.Count() == 1)
|
||||
{
|
||||
Voting.ActiveVote.Finish(Voting, passed: true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var eligibleClients = inGameClients.Where(c => c != Voting.ActiveVote.VoteStarter);
|
||||
int yes = eligibleClients.Count(c => c.GetVote<int>(Voting.ActiveVote.VoteType) == 2);
|
||||
int no = eligibleClients.Count(c => c.GetVote<int>(Voting.ActiveVote.VoteType) == 1);
|
||||
int max = eligibleClients.Count();
|
||||
// Required ratio cannot be met
|
||||
if (no / (float)max > 1f - serverSettings.VoteRequiredRatio)
|
||||
{
|
||||
Voting.ActiveVote.Finish(Voting, passed: false);
|
||||
}
|
||||
else if (yes / (float)max >= serverSettings.VoteRequiredRatio)
|
||||
{
|
||||
Voting.ActiveVote.Finish(Voting, passed: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Client.UpdateKickVotes(connectedClients);
|
||||
@@ -3346,7 +3398,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (voteType != VoteType.PurchaseSub)
|
||||
{
|
||||
GameMain.GameSession.SwitchSubmarine(targetSubmarine, deliveryFee, starter);
|
||||
GameMain.GameSession.SwitchSubmarine(targetSubmarine, subVote.TransferItems, deliveryFee, starter);
|
||||
}
|
||||
|
||||
Voting.StopSubmarineVote(true);
|
||||
@@ -3539,6 +3591,24 @@ namespace Barotrauma.Networking
|
||||
return;
|
||||
}
|
||||
|
||||
string newName = message.ReadString();
|
||||
if (string.IsNullOrEmpty(newName))
|
||||
{
|
||||
newName = sender.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
newName = Client.SanitizeName(newName);
|
||||
if (!IsNameValid(sender, newName))
|
||||
{
|
||||
newName = sender.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
sender.PendingName = newName;
|
||||
}
|
||||
}
|
||||
|
||||
int tagCount = message.ReadByte();
|
||||
HashSet<Identifier> tagSet = new HashSet<Identifier>();
|
||||
for (int i = 0; i < tagCount; i++)
|
||||
@@ -3566,7 +3636,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
sender.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, sender.Name);
|
||||
sender.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, newName);
|
||||
sender.CharacterInfo.RecreateHead(tagSet.ToImmutableHashSet(), hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
|
||||
sender.CharacterInfo.Head.SkinColor = skinColor;
|
||||
sender.CharacterInfo.Head.HairColor = hairColor;
|
||||
|
||||
@@ -278,12 +278,12 @@ namespace Barotrauma
|
||||
|
||||
static bool isValid(Item item)
|
||||
{
|
||||
return item.Prefab.Identifier == "idcard" || item.GetComponent<RangedWeapon>() != null || item.GetComponent<MeleeWeapon>() != null;
|
||||
return item.GetComponent<IdCard>() != null || item.GetComponent<RangedWeapon>() != null || item.GetComponent<MeleeWeapon>() != null;
|
||||
}
|
||||
|
||||
if (foundItem == null) { return; }
|
||||
|
||||
bool isIdCard = ((MapEntity)foundItem).Prefab.Identifier == "idcard";
|
||||
bool isIdCard = foundItem.GetComponent<IdCard>() != null;
|
||||
bool isWeapon = foundItem.GetComponent<RangedWeapon>() != null || foundItem.GetComponent<MeleeWeapon>() != null;
|
||||
|
||||
if (isIdCard)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Barotrauma.Networking
|
||||
using System;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
partial class OrderChatMessage : ChatMessage
|
||||
{
|
||||
@@ -6,7 +8,7 @@
|
||||
{
|
||||
msg.Write((byte)ServerNetObject.CHAT_MESSAGE);
|
||||
msg.Write(NetStateID);
|
||||
msg.Write((byte)ChatMessageType.Order);
|
||||
msg.WriteRangedInteger((int)ChatMessageType.Order, 0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
|
||||
msg.Write(SenderName);
|
||||
msg.Write(SenderClient != null);
|
||||
if (SenderClient != null)
|
||||
|
||||
@@ -411,8 +411,16 @@ namespace Barotrauma.Networking
|
||||
characterInfos[i].ClearCurrentOrders();
|
||||
|
||||
bool forceSpawnInMainSub = false;
|
||||
if (!bot && campaign != null)
|
||||
if (!bot)
|
||||
{
|
||||
//the client has opted to change the name of their new character
|
||||
//when the character spawns, set the client's name to match
|
||||
if (clients[i].PendingName == characterInfos[i].Name)
|
||||
{
|
||||
GameMain.Server?.TryChangeClientName(clients[i], clients[i].PendingName);
|
||||
clients[i].PendingName = null;
|
||||
}
|
||||
|
||||
var matchingData = campaign?.GetClientCharacterData(clients[i]);
|
||||
if (matchingData != null)
|
||||
{
|
||||
@@ -462,32 +470,43 @@ namespace Barotrauma.Networking
|
||||
GameServer.Log(string.Format("Respawning {0} ({1}) as {2}", GameServer.ClientLogName(clients[i]), clients[i].Connection?.EndPointString, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning);
|
||||
}
|
||||
|
||||
if (divingSuitPrefab != null && oxyPrefab != null && RespawnShuttle != null)
|
||||
if (RespawnShuttle != null)
|
||||
{
|
||||
Vector2 pos = cargoSp == null ? character.Position : cargoSp.Position;
|
||||
if (divingSuitPrefab != null && oxyPrefab != null)
|
||||
if (divingSuitPrefab != null)
|
||||
{
|
||||
var divingSuit = new Item(divingSuitPrefab, pos, respawnSub);
|
||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(divingSuit));
|
||||
respawnItems.Add(divingSuit);
|
||||
|
||||
var oxyTank = new Item(oxyPrefab, pos, respawnSub);
|
||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(oxyTank));
|
||||
divingSuit.Combine(oxyTank, user: null);
|
||||
respawnItems.Add(oxyTank);
|
||||
if (oxyPrefab != null && divingSuit.GetComponent<ItemContainer>() != null)
|
||||
{
|
||||
var oxyTank = new Item(oxyPrefab, pos, respawnSub);
|
||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(oxyTank));
|
||||
divingSuit.Combine(oxyTank, user: null);
|
||||
respawnItems.Add(oxyTank);
|
||||
}
|
||||
}
|
||||
|
||||
if (scooterPrefab != null && batteryPrefab != null)
|
||||
if (!(GameMain.GameSession.GameMode is CampaignMode))
|
||||
{
|
||||
var scooter = new Item(scooterPrefab, pos, respawnSub);
|
||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(scooter));
|
||||
|
||||
var battery = new Item(batteryPrefab, pos, respawnSub);
|
||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(battery));
|
||||
|
||||
scooter.Combine(battery, user: null);
|
||||
respawnItems.Add(scooter);
|
||||
respawnItems.Add(battery);
|
||||
if (scooterPrefab != null)
|
||||
{
|
||||
var scooter = new Item(scooterPrefab, pos, respawnSub);
|
||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(scooter));
|
||||
respawnItems.Add(scooter);
|
||||
if (batteryPrefab != null)
|
||||
{
|
||||
var battery = new Item(batteryPrefab, pos, respawnSub);
|
||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(battery));
|
||||
scooter.Combine(battery, user: null);
|
||||
respawnItems.Add(battery);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (respawnContainer != null)
|
||||
{
|
||||
AutoItemPlacer.RegenerateLoot(RespawnShuttle, respawnContainer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -525,7 +544,7 @@ namespace Barotrauma.Networking
|
||||
//add the ID card tags they should've gotten when spawning in the shuttle
|
||||
foreach (Item item in character.Inventory.AllItems.Distinct())
|
||||
{
|
||||
if (item.Prefab.Identifier != "idcard") { continue; }
|
||||
if (item.GetComponent<IdCard>() == null) { continue; }
|
||||
foreach (string s in shuttleSpawnPoints[i].IdCardTags)
|
||||
{
|
||||
item.AddTag(s);
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
using Barotrauma.IO;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
@@ -36,7 +34,7 @@ namespace Barotrauma.Networking
|
||||
=> LastUpdateIdForFlag[flag] = (UInt16)(GameMain.NetLobbyScreen.LastUpdateID + 1);
|
||||
|
||||
private bool IsFlagRequired(Client c, NetFlags flag)
|
||||
=> LastUpdateIdForFlag[flag] > c.LastRecvLobbyUpdate;
|
||||
=> NetIdUtils.IdMoreRecent(LastUpdateIdForFlag[flag], c.LastRecvLobbyUpdate);
|
||||
|
||||
public NetFlags GetRequiredFlags(Client c)
|
||||
=> LastUpdateIdForFlag.Keys
|
||||
@@ -56,7 +54,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
var property = netProperties[key];
|
||||
property.SyncValue();
|
||||
if (property.LastUpdateID > c.LastRecvLobbyUpdate)
|
||||
if (NetIdUtils.IdMoreRecent(property.LastUpdateID, c.LastRecvLobbyUpdate))
|
||||
{
|
||||
outMsg.Write(key);
|
||||
netProperties[key].Write(outMsg);
|
||||
@@ -257,7 +255,7 @@ namespace Barotrauma.Networking
|
||||
doc.Root.SetAttributeValue("queryport", QueryPort);
|
||||
#endif
|
||||
doc.Root.SetAttributeValue("password", password ?? "");
|
||||
|
||||
|
||||
doc.Root.SetAttributeValue("enableupnp", EnableUPnP);
|
||||
doc.Root.SetAttributeValue("autorestart", autoRestart);
|
||||
|
||||
@@ -266,11 +264,12 @@ namespace Barotrauma.Networking
|
||||
doc.Root.SetAttributeValue("ServerMessage", ServerMessageText);
|
||||
|
||||
doc.Root.SetAttributeValue("HiddenSubs", string.Join(",", HiddenSubs));
|
||||
|
||||
|
||||
doc.Root.SetAttributeValue("AllowedRandomMissionTypes", string.Join(",", AllowedRandomMissionTypes));
|
||||
doc.Root.SetAttributeValue("AllowedClientNameChars", string.Join(",", AllowedClientNameChars.Select(c => $"{c.Start}-{c.End}")));
|
||||
|
||||
SerializableProperty.SerializeProperties(this, doc.Root, true);
|
||||
doc.Root.Add(CampaignSettings.Save());
|
||||
|
||||
System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings
|
||||
{
|
||||
@@ -399,7 +398,7 @@ namespace Barotrauma.Networking
|
||||
ServerName = doc.Root.GetAttributeString("name", "");
|
||||
if (ServerName.Length > NetConfig.ServerNameMaxLength) { ServerName = ServerName.Substring(0, NetConfig.ServerNameMaxLength); }
|
||||
ServerMessageText = doc.Root.GetAttributeString("ServerMessage", "");
|
||||
|
||||
|
||||
GameMain.NetLobbyScreen.SelectedModeIdentifier = GameModeIdentifier;
|
||||
//handle Random as the mission type, which is no longer a valid setting
|
||||
//MissionType.All offers equivalent functionality
|
||||
@@ -410,6 +409,14 @@ namespace Barotrauma.Networking
|
||||
GameMain.NetLobbyScreen.SetBotCount(BotCount);
|
||||
|
||||
MonsterEnabled ??= CharacterPrefab.Prefabs.Select(p => (p.Identifier, true)).ToDictionary();
|
||||
|
||||
foreach (XElement element in doc.Root.Elements())
|
||||
{
|
||||
if (element.Name.ToIdentifier() == nameof(Barotrauma.CampaignSettings))
|
||||
{
|
||||
CampaignSettings = new CampaignSettings(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string SelectNonHiddenSubmarine(string current = null)
|
||||
|
||||
@@ -27,11 +27,13 @@ namespace Barotrauma
|
||||
public VoteState State { get; set; }
|
||||
|
||||
public SubmarineInfo Sub;
|
||||
public bool TransferItems;
|
||||
public int DeliveryFee;
|
||||
|
||||
public SubmarineVote(Client starter, SubmarineInfo subInfo, int deliveryFee, VoteType voteType)
|
||||
public SubmarineVote(Client starter, SubmarineInfo subInfo, bool transferItems, int deliveryFee, VoteType voteType)
|
||||
{
|
||||
Sub = subInfo;
|
||||
TransferItems = transferItems;
|
||||
DeliveryFee = deliveryFee;
|
||||
VoteType = voteType;
|
||||
State = VoteState.Started;
|
||||
@@ -44,12 +46,14 @@ namespace Barotrauma
|
||||
{
|
||||
GameMain.Server?.SwitchSubmarine();
|
||||
}
|
||||
else
|
||||
{
|
||||
voting.RegisterRejectedVote(this);
|
||||
}
|
||||
voting.StopSubmarineVote(passed);
|
||||
}
|
||||
}
|
||||
|
||||
public static IVote ActiveVote;
|
||||
|
||||
public class TransferVote : IVote
|
||||
{
|
||||
public Client VoteStarter { get; }
|
||||
@@ -83,21 +87,28 @@ namespace Barotrauma
|
||||
toWallet.Give(TransferAmount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
voting.RegisterRejectedVote(this);
|
||||
}
|
||||
voting.StopMoneyTransferVote(passed);
|
||||
}
|
||||
}
|
||||
|
||||
public static IVote ActiveVote;
|
||||
|
||||
private static readonly Queue<IVote> pendingVotes = new Queue<IVote>();
|
||||
|
||||
private void StartSubmarineVote(SubmarineInfo subInfo, VoteType voteType, Client sender)
|
||||
private readonly TimeSpan rejectedVoteCooldown = new TimeSpan(0, 1, 0);
|
||||
|
||||
private readonly Dictionary<Client, (VoteType voteType, DateTime time)> rejectedVoteTimes = new Dictionary<Client, (VoteType voteType, DateTime time)>();
|
||||
|
||||
private void StartSubmarineVote(SubmarineInfo subInfo, bool transferItems, VoteType voteType, Client sender)
|
||||
{
|
||||
if (ActiveVote == null)
|
||||
{
|
||||
sender.SetVote(voteType, 2);
|
||||
}
|
||||
var subVote = new SubmarineVote(
|
||||
sender,
|
||||
subInfo,
|
||||
transferItems,
|
||||
voteType == VoteType.SwitchSub ? GameMain.GameSession.Map.DistanceToClosestLocationWithOutpost(GameMain.GameSession.Map.CurrentLocation, out Location endLocation) : 0,
|
||||
voteType);
|
||||
StartOrEnqueueVote(subVote);
|
||||
@@ -136,9 +147,9 @@ namespace Barotrauma
|
||||
|
||||
public void StartTransferVote(Client starter, Client from, int transferAmount, Client to)
|
||||
{
|
||||
if (ActiveVote == null)
|
||||
if (ShouldRejectVote(starter, VoteType.TransferMoney))
|
||||
{
|
||||
starter.SetVote(VoteType.TransferMoney, 2);
|
||||
return;
|
||||
}
|
||||
StartOrEnqueueVote(new TransferVote(starter, from, transferAmount, to));
|
||||
GameMain.Server.UpdateVoteStatus(checkActiveVote: false);
|
||||
@@ -156,6 +167,31 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldRejectVote(Client sender, VoteType voteType)
|
||||
{
|
||||
if (rejectedVoteTimes.ContainsKey(sender))
|
||||
{
|
||||
TimeSpan remainingCooldown = (rejectedVoteTimes[sender].time + rejectedVoteCooldown) - DateTime.Now;
|
||||
if (rejectedVoteTimes[sender].voteType == voteType &&
|
||||
remainingCooldown.TotalSeconds > 0)
|
||||
{
|
||||
GameMain.Server.SendDirectChatMessage(
|
||||
TextManager.FormatServerMessage("voterejectedpleasewait", ("[time]", ((int)remainingCooldown.TotalSeconds).ToString())),
|
||||
sender, ChatMessageType.ServerMessageBox);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void RegisterRejectedVote(IVote vote)
|
||||
{
|
||||
if (vote.VoteStarter != null)
|
||||
{
|
||||
rejectedVoteTimes[vote.VoteStarter] = (vote.VoteType, DateTime.Now);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (ActiveVote == null) { return; }
|
||||
@@ -164,10 +200,19 @@ namespace Barotrauma
|
||||
|
||||
if (ActiveVote.Timer >= GameMain.NetworkMember.ServerSettings.VoteTimeout)
|
||||
{
|
||||
var inGameClients = GameMain.Server.ConnectedClients.Where(c => c.InGame);
|
||||
var eligibleClients = inGameClients.Where(c => c != ActiveVote.VoteStarter);
|
||||
|
||||
// Do not take unanswered into account for total
|
||||
int yes = GameMain.Server.ConnectedClients.Count(c => c.InGame && c.GetVote<int>(ActiveVote.VoteType) == 2);
|
||||
int no = GameMain.Server.ConnectedClients.Count(c => c.InGame && c.GetVote<int>(ActiveVote.VoteType) == 1);
|
||||
ActiveVote.Finish(this, passed: yes / (float)(yes + no) >= GameMain.NetworkMember.ServerSettings.VoteRequiredRatio);
|
||||
int yes = eligibleClients.Count(c => c.GetVote<int>(ActiveVote.VoteType) == 2);
|
||||
int no = eligibleClients.Count(c => c.GetVote<int>(ActiveVote.VoteType) == 1);
|
||||
int total = Math.Max(yes + no, 1);
|
||||
|
||||
bool passed =
|
||||
yes / (float)total >= GameMain.NetworkMember.ServerSettings.VoteRequiredRatio ||
|
||||
inGameClients.Count() == 1;
|
||||
|
||||
ActiveVote.Finish(this, passed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,7 +272,6 @@ namespace Barotrauma
|
||||
GameServer.Log(GameServer.ClientLogName(sender) + (ready ? " is ready to start the game." : " is not ready to start the game."), ServerLog.MessageType.ServerMessage);
|
||||
}
|
||||
break;
|
||||
|
||||
case VoteType.PurchaseAndSwitchSub:
|
||||
case VoteType.PurchaseSub:
|
||||
case VoteType.SwitchSub:
|
||||
@@ -240,18 +284,26 @@ namespace Barotrauma
|
||||
int amount = inc.ReadInt32();
|
||||
int fromClientId = inc.ReadByte();
|
||||
int toClientId = inc.ReadByte();
|
||||
pendingVotes.Enqueue(new TransferVote(sender,
|
||||
GameMain.Server.ConnectedClients.Find(c => c.ID == fromClientId),
|
||||
amount,
|
||||
GameMain.Server.ConnectedClients.Find(c => c.ID == toClientId)));
|
||||
if (!ShouldRejectVote(sender, voteType))
|
||||
{
|
||||
pendingVotes.Enqueue(new TransferVote(sender,
|
||||
GameMain.Server.ConnectedClients.Find(c => c.ID == fromClientId),
|
||||
amount,
|
||||
GameMain.Server.ConnectedClients.Find(c => c.ID == toClientId)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string subName = inc.ReadString();
|
||||
SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName);
|
||||
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign campaign && (campaign.CanPurchaseSub(subInfo, sender) || GameMain.GameSession.IsSubmarineOwned(subInfo)))
|
||||
bool transferItems = inc.ReadBoolean();
|
||||
if (!ShouldRejectVote(sender, voteType))
|
||||
{
|
||||
StartSubmarineVote(subInfo, voteType, sender);
|
||||
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign campaign &&
|
||||
(campaign.CanPurchaseSub(subInfo, sender) || GameMain.GameSession.IsSubmarineOwned(subInfo)))
|
||||
{
|
||||
StartSubmarineVote(subInfo, transferItems, voteType, sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -307,22 +359,24 @@ namespace Barotrauma
|
||||
{
|
||||
msg.Write((byte)ActiveVote.VoteType);
|
||||
if (ActiveVote.State != VoteState.None && ActiveVote.VoteType != VoteType.Unknown)
|
||||
{
|
||||
var yesClients = GameMain.Server.ConnectedClients.FindAll(c => c.InGame && c.GetVote<int>(ActiveVote.VoteType) == 2);
|
||||
msg.Write((byte)yesClients.Count);
|
||||
{
|
||||
var eligibleClients = GameMain.Server.ConnectedClients.Where(c => c.InGame && c != ActiveVote.VoteStarter);
|
||||
|
||||
var yesClients = eligibleClients.Where(c => c.GetVote<int>(ActiveVote.VoteType) == 2);
|
||||
msg.Write((byte)yesClients.Count());
|
||||
foreach (Client c in yesClients)
|
||||
{
|
||||
msg.Write(c.ID);
|
||||
}
|
||||
|
||||
var noClients = GameMain.Server.ConnectedClients.FindAll(c => c.InGame && c.GetVote<int>(ActiveVote.VoteType) == 1);
|
||||
msg.Write((byte)noClients.Count);
|
||||
var noClients = eligibleClients.Where(c => c.GetVote<int>(ActiveVote.VoteType) == 1);
|
||||
msg.Write((byte)noClients.Count());
|
||||
foreach (Client c in noClients)
|
||||
{
|
||||
msg.Write(c.ID);
|
||||
}
|
||||
|
||||
msg.Write((byte)GameMain.Server.ConnectedClients.Count(c => c.InGame));
|
||||
msg.Write((byte)eligibleClients.Count());
|
||||
|
||||
switch (ActiveVote.State)
|
||||
{
|
||||
@@ -336,6 +390,7 @@ namespace Barotrauma
|
||||
case VoteType.PurchaseAndSwitchSub:
|
||||
case VoteType.SwitchSub:
|
||||
msg.Write((ActiveVote as SubmarineVote).Sub.Name);
|
||||
msg.Write((ActiveVote as SubmarineVote).TransferItems);
|
||||
break;
|
||||
case VoteType.TransferMoney:
|
||||
var transferVote = (ActiveVote as TransferVote);
|
||||
@@ -357,8 +412,10 @@ namespace Barotrauma
|
||||
case VoteType.PurchaseSub:
|
||||
case VoteType.PurchaseAndSwitchSub:
|
||||
case VoteType.SwitchSub:
|
||||
msg.Write((ActiveVote as SubmarineVote).Sub.Name);
|
||||
msg.Write((short)(ActiveVote as SubmarineVote).DeliveryFee);
|
||||
var subVote = ActiveVote as SubmarineVote;
|
||||
msg.Write(subVote.Sub.Name);
|
||||
msg.Write(subVote.TransferItems);
|
||||
msg.Write((short)subVote.DeliveryFee);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user