Unstable 1.8.4.0

This commit is contained in:
Markus Isberg
2025-03-12 12:56:27 +00:00
parent a4c3e868e4
commit a4a3427e4e
627 changed files with 29860 additions and 10018 deletions
@@ -366,7 +366,7 @@ namespace Barotrauma
default:
ShowCampaignUI = true;
CampaignUI.SelectTab(npc.CampaignInteractionType, npc);
CampaignUI.UpgradeStore?.RequestRefresh();
CampaignUI.UpgradeStore?.RequestRefresh(refreshUpgrades: true);
break;
}
@@ -395,13 +395,15 @@ namespace Barotrauma
protected void TryEndRoundWithFuelCheck(Action onConfirm, Action onReturnToMapScreen)
{
if (Submarine.MainSub == null) { return; }
Submarine.MainSub.CheckFuel();
bool lowFuel = Submarine.MainSub.Info.LowFuel;
if (PendingSubmarineSwitch != null)
{
lowFuel = TransferItemsOnSubSwitch ? (lowFuel && PendingSubmarineSwitch.LowFuel) : PendingSubmarineSwitch.LowFuel;
}
if (Level.IsLoadedFriendlyOutpost && lowFuel && CargoManager.PurchasedItems.None(i => i.Value.Any(pi => pi.ItemPrefab.Tags.Contains("reactorfuel"))))
if (Level.IsLoadedFriendlyOutpost && lowFuel && CargoManager.PurchasedItems.None(i => i.Value.Any(pi => pi.ItemPrefab.Tags.Contains(Tags.ReactorFuel))))
{
var extraConfirmationBox =
new GUIMessageBox(TextManager.Get("lowfuelheader"),
@@ -532,6 +532,7 @@ namespace Barotrauma
bool isFirstRound = msg.ReadBoolean();
byte campaignID = msg.ReadByte();
byte roundId = msg.ReadByte();
UInt16 saveID = msg.ReadUInt16();
string mapSeed = msg.ReadString();
@@ -541,7 +542,7 @@ namespace Barotrauma
{
string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer);
GameMain.GameSession = new GameSession(null, savePath, GameModePreset.MultiPlayerCampaign, CampaignSettings.Empty, mapSeed);
GameMain.GameSession = new GameSession(null, Option.None, CampaignDataPath.CreateRegular(savePath), GameModePreset.MultiPlayerCampaign, CampaignSettings.Empty, mapSeed);
campaign = (MultiPlayerCampaign)GameMain.GameSession.GameMode;
campaign.CampaignID = campaignID;
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
@@ -553,7 +554,7 @@ namespace Barotrauma
if (requiredFlags.HasFlag(NetFlags.Misc))
{
DebugConsole.Log("Received campaign update (Misc)");
DebugConsole.Log("Received campaign update (Misc), round id: " + roundId);
UInt16 id = msg.ReadUInt16();
bool purchasedHullRepairs = msg.ReadBoolean();
bool purchasedItemRepairs = msg.ReadBoolean();
@@ -571,7 +572,7 @@ namespace Barotrauma
if (requiredFlags.HasFlag(NetFlags.MapAndMissions))
{
DebugConsole.Log("Received campaign update (MapAndMissions)");
DebugConsole.Log("Received campaign update (MapAndMissions), round id: " + roundId);
UInt16 id = msg.ReadUInt16();
bool forceMapUI = msg.ReadBoolean();
bool allowDebugTeleport = msg.ReadBoolean();
@@ -634,7 +635,7 @@ namespace Barotrauma
if (requiredFlags.HasFlag(NetFlags.SubList))
{
DebugConsole.Log("Received campaign update (SubList)");
DebugConsole.Log("Received campaign update (SubList), round id: " + roundId);
UInt16 id = msg.ReadUInt16();
ushort ownedSubCount = msg.ReadUInt16();
List<ushort> ownedSubIndices = new List<ushort>();
@@ -679,7 +680,7 @@ namespace Barotrauma
if (requiredFlags.HasFlag(NetFlags.UpgradeManager))
{
DebugConsole.Log("Received campaign update (UpgradeManager)");
DebugConsole.Log("Received campaign update (UpgradeManager), round id: " + roundId);
UInt16 id = msg.ReadUInt16();
ushort pendingUpgradeCount = msg.ReadUInt16();
@@ -737,7 +738,7 @@ namespace Barotrauma
if (requiredFlags.HasFlag(NetFlags.ItemsInBuyCrate))
{
DebugConsole.Log("Received campaign update (ItemsInBuyCrate)");
DebugConsole.Log("Received campaign update (ItemsInBuyCrate), round id: " + roundId);
UInt16 id = msg.ReadUInt16();
var buyCrateItems = ReadPurchasedItems(msg, sender: null);
if (ShouldApply(NetFlags.ItemsInBuyCrate, id, requireUpToDateSave: true))
@@ -753,7 +754,7 @@ namespace Barotrauma
}
if (requiredFlags.HasFlag(NetFlags.ItemsInSellFromSubCrate))
{
DebugConsole.Log("Received campaign update (ItemsInSellFromSubCrate)");
DebugConsole.Log("Received campaign update (ItemsInSellFromSubCrate), round id: " + roundId);
UInt16 id = msg.ReadUInt16();
var subSellCrateItems = ReadPurchasedItems(msg, sender: null);
if (ShouldApply(NetFlags.ItemsInSellFromSubCrate, id, requireUpToDateSave: true))
@@ -769,7 +770,7 @@ namespace Barotrauma
}
if (requiredFlags.HasFlag(NetFlags.PurchasedItems))
{
DebugConsole.Log("Received campaign update (PuchasedItems)");
DebugConsole.Log("Received campaign update (PuchasedItems), round id: " + roundId);
UInt16 id = msg.ReadUInt16();
var purchasedItems = ReadPurchasedItems(msg, sender: null);
if (ShouldApply(NetFlags.PurchasedItems, id, requireUpToDateSave: true))
@@ -785,7 +786,7 @@ namespace Barotrauma
}
if (requiredFlags.HasFlag(NetFlags.SoldItems))
{
DebugConsole.Log("Received campaign update (SoldItems)");
DebugConsole.Log("Received campaign update (SoldItems), round id: " + roundId);
UInt16 id = msg.ReadUInt16();
var soldItems = ReadSoldItems(msg);
if (ShouldApply(NetFlags.SoldItems, id, requireUpToDateSave: true))
@@ -801,7 +802,7 @@ namespace Barotrauma
}
if (requiredFlags.HasFlag(NetFlags.Reputation))
{
DebugConsole.Log("Received campaign update (Reputation)");
DebugConsole.Log("Received campaign update (Reputation), round id: " + roundId);
UInt16 id = msg.ReadUInt16();
Dictionary<Identifier, float> factionReps = new Dictionary<Identifier, float>();
byte factionsCount = msg.ReadByte();
@@ -828,7 +829,7 @@ namespace Barotrauma
}
if (requiredFlags.HasFlag(NetFlags.CharacterInfo))
{
DebugConsole.Log("Received campaign update (CharacterInfo)");
DebugConsole.Log("Received campaign update (CharacterInfo), round id: " + roundId);
UInt16 id = msg.ReadUInt16();
bool hasCharacterData = msg.ReadBoolean();
CharacterInfo myCharacterInfo = null;
@@ -837,16 +838,27 @@ namespace Barotrauma
{
myCharacterInfo = CharacterInfo.ClientRead(CharacterPrefab.HumanSpeciesName, msg, requireJobPrefabFound: !waitForModsDownloaded);
}
if (!waitForModsDownloaded && ShouldApply(NetFlags.CharacterInfo, id, requireUpToDateSave: true))
//don't require the correct round ID for the character info if we're in the lobby
// = allow updating the character to the latest one in the lobby, even though we've not loaded to the same round as the server
if (!waitForModsDownloaded && ShouldApply(NetFlags.CharacterInfo, id, requireUpToDateSave: true, requireCorrectRoundId: Screen.Selected != GameMain.NetLobbyScreen))
{
if (myCharacterInfo != null)
{
GameMain.Client.CharacterInfo = myCharacterInfo;
GameMain.NetLobbyScreen.SetCampaignCharacterInfo(myCharacterInfo);
GameMain.GameSession.RefreshAnyOpenPlayerInfo();
}
else
{
//don't reset the character info nor the open UI here here,
//the client needs it to be able to customize the character they want to next spawn as
GameMain.NetLobbyScreen.SetCampaignCharacterInfo(null);
//if we've already discarded our current character and the server is just "verifying" that,
//no need to refresh the UI (no changes, refreshing would just throw the client out of the character settings panel)
if (!GameMain.NetLobbyScreen.CampaignCharacterDiscarded)
{
GameMain.GameSession.RefreshAnyOpenPlayerInfo();
}
}
}
}
@@ -863,8 +875,14 @@ namespace Barotrauma
}
campaign.SuppressStateSending = false;
bool ShouldApply(NetFlags flag, UInt16 id, bool requireUpToDateSave)
bool ShouldApply(NetFlags flag, UInt16 id, bool requireUpToDateSave, bool requireCorrectRoundId = true)
{
if (requireCorrectRoundId && roundId != campaign.RoundID)
{
DebugConsole.Log($"Received campaing update for a different round (client: {campaign.RoundID}, server: {roundId}), ignoring...");
return false;
}
if (NetIdUtils.IdMoreRecent(id, campaign.GetLastUpdateIdForFlag(flag)) &&
(!requireUpToDateSave || saveID == campaign.LastSaveID))
{
@@ -919,26 +937,42 @@ namespace Barotrauma
ushort pendingHireLength = msg.ReadUInt16();
List<UInt16> pendingHires = new List<UInt16>();
bool[] pendingHiresToReserveBench = new bool[pendingHireLength];
for (int i = 0; i < pendingHireLength; i++)
{
pendingHires.Add(msg.ReadUInt16());
pendingHiresToReserveBench[i] = msg.ReadBoolean();
}
ushort hiredLength = msg.ReadUInt16();
List<CharacterInfo> hiredCharacters = new List<CharacterInfo>();
for (int i = 0; i < hiredLength; i++)
List<CharacterInfo> updatedCrewManager = new List<CharacterInfo>();
ushort crewLength = msg.ReadUInt16();
for (int i = 0; i < crewLength; i++)
{
CharacterInfo hired = CharacterInfo.ClientRead(CharacterPrefab.HumanSpeciesName, msg);
hired.Salary = msg.ReadInt32();
hiredCharacters.Add(hired);
CharacterInfo crewMember = CharacterInfo.ClientRead(CharacterPrefab.HumanSpeciesName, msg);
if (crewMember.IsNewHire)
{
hiredCharacters.Add(crewMember);
}
updatedCrewManager.Add(crewMember);
}
bool crewManagerUpdated = GameMain.GameSession.CrewManager?.UpdateCrewManagerIfNecessary(updatedCrewManager) ?? false;
ushort reserveBenchLength = msg.ReadUInt16();
List<CharacterInfo> updatedReserveBench = new List<CharacterInfo>();
for (int i = 0; i < reserveBenchLength; i++)
{
CharacterInfo info = CharacterInfo.ClientRead(CharacterPrefab.HumanSpeciesName, msg);
updatedReserveBench.Add(info);
}
bool reserveBenchUpdated = GameMain.GameSession.CrewManager?.UpdateReserveBenchIfNeeded(updatedReserveBench) ?? false;
bool renameCrewMember = msg.ReadBoolean();
if (renameCrewMember)
{
UInt16 renamedIdentifier = msg.ReadUInt16();
string newName = msg.ReadString();
CharacterInfo renamedCharacter = CrewManager.GetCharacterInfos().FirstOrDefault(info => info.ID == renamedIdentifier);
CharacterInfo renamedCharacter = CrewManager.GetCharacterInfos(includeReserveBench: true).FirstOrDefault(info => info.ID == renamedIdentifier);
if (renamedCharacter != null)
{
CrewManager.RenameCharacter(renamedCharacter, newName);
@@ -955,7 +989,7 @@ namespace Barotrauma
if (fireCharacter)
{
UInt16 firedIdentifier = msg.ReadUInt16();
CharacterInfo firedCharacter = CrewManager.GetCharacterInfos().FirstOrDefault(info => info.ID == firedIdentifier);
CharacterInfo firedCharacter = CrewManager.GetCharacterInfos(includeReserveBench: true).FirstOrDefault(info => info.ID == firedIdentifier);
// this one might and is allowed to be null since the character is already fired on the original sender's game
if (firedCharacter != null) { CrewManager.FireCharacter(firedCharacter); }
}
@@ -967,8 +1001,8 @@ namespace Barotrauma
{
CampaignUI.HRManagerUI.SetHireables(map.CurrentLocation, availableHires);
if (hiredCharacters.Any()) { CampaignUI.HRManagerUI.ValidateHires(hiredCharacters, takeMoney: false, createNotification: createNotification); }
CampaignUI.HRManagerUI.SetPendingHires(pendingHires, map.CurrentLocation);
if (renameCrewMember || fireCharacter) { CampaignUI.HRManagerUI.UpdateCrew(); }
//don't check the crew size limit: if the server says someone's hired, then it's so
CampaignUI.HRManagerUI.SetPendingHires(pendingHires, pendingHiresToReserveBench, map.CurrentLocation, checkCrewSizeLimit: false);
}
}
else
@@ -979,6 +1013,11 @@ namespace Barotrauma
CurrentLocation?.ForceHireableCharacters(availableHires);
}
if (fireCharacter || renameCrewMember || crewManagerUpdated || reserveBenchUpdated)
{
CampaignUI?.HRManagerUI?.RefreshHRView();
GameMain.GameSession?.DeathPrompt?.UpdateBotList();
}
}
public void ClientReadMoney(IReadMessage inc)
@@ -1044,7 +1083,7 @@ namespace Barotrauma
return false;
}
public override void Save(XElement element)
public override void Save(XElement element, bool isSavingOnLoading)
{
//do nothing, the clients get the save files from the server
}
@@ -240,7 +240,7 @@ namespace Barotrauma
if (!savedOnStart)
{
GUI.SetSavingIndicatorState(true);
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
SaveUtil.SaveGame(GameMain.GameSession.DataPath, isSavingOnLoading: true);
savedOnStart = true;
}
@@ -379,7 +379,7 @@ namespace Barotrauma
if (success)
{
// Event history must be registered before ending the round or it will be cleared
GameMain.GameSession.EventManager.RegisterEventHistory();
GameMain.GameSession.EventManager.StoreEventDataAtRoundEnd();
}
GameMain.GameSession.EndRound("", transitionType);
var continueButton = GameMain.GameSession.RoundSummary?.ContinueButton;
@@ -448,7 +448,7 @@ namespace Barotrauma
if (success)
{
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
SaveUtil.SaveGame(GameMain.GameSession.DataPath);
}
else
{
@@ -479,7 +479,7 @@ namespace Barotrauma
protected override void EndCampaignProjSpecific()
{
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
SaveUtil.SaveGame(GameMain.GameSession.DataPath);
GameMain.CampaignEndScreen.Select();
GUI.DisableHUD = false;
GameMain.CampaignEndScreen.OnFinished = () =>
@@ -672,7 +672,7 @@ namespace Barotrauma
}
}
public override void Save(XElement element)
public override void Save(XElement element, bool isSavingOnLoading)
{
XElement modeElement = new XElement("SinglePlayerCampaign",
new XAttribute("purchasedlostshuttles", PurchasedLostShuttles),
@@ -7,7 +7,7 @@ using Barotrauma.Items.Components;
namespace Barotrauma
{
class TestGameMode : GameMode
partial class TestGameMode : GameMode
{
public Action OnRoundEnd;
@@ -22,18 +22,6 @@ namespace Barotrauma
private GUIButton createEventButton;
public TestGameMode(GameModePreset preset) : base(preset)
{
foreach (JobPrefab jobPrefab in JobPrefab.Prefabs.OrderBy(p => p.Identifier))
{
for (int i = 0; i < jobPrefab.InitialCount; i++)
{
var variant = Rand.Range(0, jobPrefab.Variants);
CrewManager.AddCharacterInfo(new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: jobPrefab, variant: variant));
}
}
}
public override void Start()
{
base.Start();
@@ -42,17 +30,24 @@ namespace Barotrauma
foreach (Submarine submarine in Submarine.Loaded)
{
submarine.NeutralizeBallast();
//normally the body would be made static during level generation,
//but in the test mode we load the outpost/wreck/beacon as if it was a normal sub and need to do this manually
if (submarine.Info.Type == SubmarineType.Outpost ||
submarine.Info.Type == SubmarineType.OutpostModule ||
submarine.Info.Type == SubmarineType.Wreck ||
submarine.Info.Type == SubmarineType.BeaconStation)
switch (submarine.Info.Type)
{
submarine.PhysicsBody.BodyType = FarseerPhysics.BodyType.Static;
case SubmarineType.Outpost:
case SubmarineType.OutpostModule:
case SubmarineType.Wreck:
case SubmarineType.BeaconStation:
//normally the body would be made static during level generation,
//but in the test mode we load the outpost/wreck/beacon as if it was a normal sub and need to do this manually
submarine.PhysicsBody.BodyType = FarseerPhysics.BodyType.Static;
if (submarine.Info.ShouldBeRuin)
{
submarine.Info.Type = SubmarineType.Ruin;
}
submarine.TeamID = submarine.Info.IsOutpost ? CharacterTeamType.FriendlyNPC : CharacterTeamType.None;
break;
}
}
if (SpawnOutpost)
{
GenerateOutpost(Submarine.MainSub);
@@ -86,7 +86,7 @@ namespace Barotrauma.Tutorials
yield return CoroutineStatus.Running;
GameMain.GameSession = new GameSession(subInfo, GameModePreset.Tutorial, missionPrefabs: null);
GameMain.GameSession = new GameSession(subInfo, Option.None, GameModePreset.Tutorial, missionPrefabs: null);
(GameMain.GameSession.GameMode as TutorialMode).Tutorial = this;
if (generationParams is not null)
@@ -138,7 +138,7 @@ namespace Barotrauma.Tutorials
character = Character.Create(charInfo, wayPoint.WorldPosition, "", isRemotePlayer: false, hasAi: false);
character.TeamID = CharacterTeamType.Team1;
Character.Controlled = character;
character.GiveJobItems(null);
character.GiveJobItems(isPvPMode: false, null);
var idCard = character.Inventory.FindItemByTag("identitycard".ToIdentifier());
if (idCard == null)