(bcb06cc5c) Unstable v0.9.9.0
This commit is contained in:
@@ -15,6 +15,7 @@ namespace Barotrauma.Networking
|
||||
public byte ID;
|
||||
public UInt16 CharacterID;
|
||||
public bool Muted;
|
||||
public bool InGame;
|
||||
public bool AllowKicking;
|
||||
}
|
||||
|
||||
@@ -71,7 +72,8 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
{
|
||||
VoipSound.SetPosition(null);
|
||||
}
|
||||
VoipSound.Gain = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
partial void InitProjSpecific()
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
@@ -60,11 +61,24 @@ namespace Barotrauma.Networking
|
||||
|
||||
private bool connected;
|
||||
|
||||
private enum RoundInitStatus
|
||||
{
|
||||
NotStarted,
|
||||
Starting,
|
||||
WaitingForStartGameFinalize,
|
||||
Started,
|
||||
TimedOut,
|
||||
Error,
|
||||
Interrupted
|
||||
}
|
||||
|
||||
private RoundInitStatus roundInitStatus = RoundInitStatus.NotStarted;
|
||||
|
||||
private byte myID;
|
||||
|
||||
private List<Client> otherClients;
|
||||
|
||||
private readonly List<Submarine> serverSubmarines = new List<Submarine>();
|
||||
private readonly List<SubmarineInfo> serverSubmarines = new List<SubmarineInfo>();
|
||||
|
||||
private string serverIP, serverName;
|
||||
|
||||
@@ -148,6 +162,8 @@ namespace Barotrauma.Networking
|
||||
this.ownerKey = ownerKey;
|
||||
this.steamP2POwner = steamP2POwner;
|
||||
|
||||
roundInitStatus = RoundInitStatus.NotStarted;
|
||||
|
||||
allowReconnect = true;
|
||||
|
||||
netStats = new NetStats();
|
||||
@@ -472,13 +488,17 @@ namespace Barotrauma.Networking
|
||||
|
||||
var msgBox = new GUIMessageBox(pwMsg, "", new string[] { TextManager.Get("OK"), TextManager.Get("Cancel") },
|
||||
relativeSize: new Vector2(0.25f, 0.1f), minSize: new Point(400, 170));
|
||||
var passwordHolder = new GUILayoutGroup(new RectTransform(Vector2.One, msgBox.Content.RectTransform), childAnchor: Anchor.TopCenter);
|
||||
var passwordBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 1f) , passwordHolder.RectTransform) { MinSize = new Point(0, 20) })
|
||||
var passwordHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), msgBox.Content.RectTransform), childAnchor: Anchor.TopCenter);
|
||||
var passwordBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 1f), passwordHolder.RectTransform) { MinSize = new Point(0, 20) })
|
||||
{
|
||||
UserData = "password",
|
||||
Censor = true
|
||||
};
|
||||
|
||||
msgBox.Content.Recalculate();
|
||||
msgBox.Content.RectTransform.MinSize = new Point(0, msgBox.Content.RectTransform.Children.Sum(c => c.Rect.Height));
|
||||
msgBox.Content.Parent.RectTransform.MinSize = new Point(0, (int)(msgBox.Content.RectTransform.MinSize.Y / msgBox.Content.RectTransform.RelativeSize.Y));
|
||||
|
||||
var okButton = msgBox.Buttons[0];
|
||||
var cancelButton = msgBox.Buttons[1];
|
||||
|
||||
@@ -524,6 +544,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
foreach (Client c in ConnectedClients)
|
||||
{
|
||||
if (c.Character != null && c.Character.Removed) { c.Character = null; }
|
||||
c.UpdateSoundPosition();
|
||||
}
|
||||
|
||||
@@ -558,6 +579,13 @@ namespace Barotrauma.Networking
|
||||
|
||||
try
|
||||
{
|
||||
incomingMessagesToProcess.Clear();
|
||||
incomingMessagesToProcess.AddRange(pendingIncomingMessages);
|
||||
foreach (var inc in incomingMessagesToProcess)
|
||||
{
|
||||
ReadDataMessage(inc);
|
||||
}
|
||||
pendingIncomingMessages.Clear();
|
||||
clientPeer?.Update(deltaTime);
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -632,11 +660,23 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
private CoroutineHandle startGameCoroutine;
|
||||
private readonly List<IReadMessage> pendingIncomingMessages = new List<IReadMessage>();
|
||||
private readonly List<IReadMessage> incomingMessagesToProcess = new List<IReadMessage>();
|
||||
|
||||
private void ReadDataMessage(IReadMessage inc)
|
||||
{
|
||||
ServerPacketHeader header = (ServerPacketHeader)inc.ReadByte();
|
||||
|
||||
if (header != ServerPacketHeader.STARTGAMEFINALIZE &&
|
||||
header != ServerPacketHeader.ENDGAME &&
|
||||
roundInitStatus == RoundInitStatus.WaitingForStartGameFinalize)
|
||||
{
|
||||
//rewind the header byte we just read
|
||||
inc.BitPosition -= 8;
|
||||
pendingIncomingMessages.Add(inc);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (header)
|
||||
{
|
||||
case ServerPacketHeader.UPDATE_LOBBY:
|
||||
@@ -714,7 +754,13 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
break;
|
||||
case ServerPacketHeader.STARTGAME:
|
||||
startGameCoroutine = GameMain.Instance.ShowLoading(StartGame(inc), false);
|
||||
GameMain.Instance.ShowLoading(StartGame(inc), false);
|
||||
break;
|
||||
case ServerPacketHeader.STARTGAMEFINALIZE:
|
||||
if (roundInitStatus == RoundInitStatus.WaitingForStartGameFinalize)
|
||||
{
|
||||
ReadStartGameFinalize(inc);
|
||||
}
|
||||
break;
|
||||
case ServerPacketHeader.ENDGAME:
|
||||
string endMessage = inc.ReadString();
|
||||
@@ -725,6 +771,8 @@ namespace Barotrauma.Networking
|
||||
GameMain.GameSession.WinningTeam = winningTeam;
|
||||
GameMain.GameSession.Mission.Completed = true;
|
||||
}
|
||||
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
CoroutineManager.StartCoroutine(EndGame(endMessage), "EndGame");
|
||||
break;
|
||||
case ServerPacketHeader.CAMPAIGN_SETUP_INFO:
|
||||
@@ -775,7 +823,37 @@ namespace Barotrauma.Networking
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ReadStartGameFinalize(IReadMessage inc)
|
||||
{
|
||||
ushort contentToPreloadCount = inc.ReadUInt16();
|
||||
List<ContentFile> contentToPreload = new List<ContentFile>();
|
||||
for (int i = 0; i < contentToPreloadCount; i++)
|
||||
{
|
||||
ContentType contentType = (ContentType)inc.ReadByte();
|
||||
string filePath = inc.ReadString();
|
||||
contentToPreload.Add(new ContentFile(filePath, contentType));
|
||||
}
|
||||
|
||||
GameMain.GameSession.EventManager.PreloadContent(contentToPreload);
|
||||
|
||||
int levelEqualityCheckVal = inc.ReadInt32();
|
||||
|
||||
if (Level.Loaded.EqualityCheckVal != levelEqualityCheckVal)
|
||||
{
|
||||
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server (seed: " + Level.Loaded.Seed +
|
||||
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortHash + ")" +
|
||||
", mirrored: " + Level.Loaded.Mirrored + ").";
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
|
||||
GameMain.GameSession.Mission?.ClientReadInitial(inc);
|
||||
|
||||
roundInitStatus = RoundInitStatus.Started;
|
||||
}
|
||||
|
||||
|
||||
private void OnDisconnect()
|
||||
{
|
||||
if (SteamManager.IsInitialized)
|
||||
@@ -884,6 +962,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
connected = false;
|
||||
connectCancelled = true;
|
||||
|
||||
string msg = "";
|
||||
@@ -1108,6 +1187,7 @@ namespace Barotrauma.Networking
|
||||
if (Character != null) Character.Remove();
|
||||
HasSpawned = false;
|
||||
eventErrorWritten = false;
|
||||
GameMain.NetLobbyScreen.StopWaitingForStartRound();
|
||||
|
||||
while (CoroutineManager.IsCoroutineRunning("EndGame"))
|
||||
{
|
||||
@@ -1126,9 +1206,11 @@ namespace Barotrauma.Networking
|
||||
|
||||
EndVoteTickBox.Selected = false;
|
||||
|
||||
roundInitStatus = RoundInitStatus.Starting;
|
||||
|
||||
int seed = inc.ReadInt32();
|
||||
string levelSeed = inc.ReadString();
|
||||
int levelEqualityCheckVal = inc.ReadInt32();
|
||||
//int levelEqualityCheckVal = inc.ReadInt32();
|
||||
float levelDifficulty = inc.ReadSingle();
|
||||
|
||||
byte losMode = inc.ReadByte();
|
||||
@@ -1146,24 +1228,16 @@ namespace Barotrauma.Networking
|
||||
int missionIndex = inc.ReadInt16();
|
||||
|
||||
bool respawnAllowed = inc.ReadBoolean();
|
||||
bool loadSecondSub = inc.ReadBoolean();
|
||||
|
||||
bool disguisesAllowed = inc.ReadBoolean();
|
||||
bool rewiringAllowed = inc.ReadBoolean();
|
||||
|
||||
bool allowRagdollButton = inc.ReadBoolean();
|
||||
|
||||
ushort contentToPreloadCount = inc.ReadUInt16();
|
||||
List<ContentFile> contentToPreload = new List<ContentFile>();
|
||||
for (int i = 0; i < contentToPreloadCount; i++)
|
||||
{
|
||||
ContentType contentType = (ContentType)inc.ReadByte();
|
||||
string filePath = inc.ReadString();
|
||||
contentToPreload.Add(new ContentFile(filePath, contentType));
|
||||
}
|
||||
|
||||
serverSettings.ReadMonsterEnabled(inc);
|
||||
|
||||
bool includesFinalize = inc.ReadBoolean(); inc.ReadPadBits();
|
||||
|
||||
GameModePreset gameMode = GameModePreset.List.Find(gm => gm.Identifier == modeIdentifier);
|
||||
MultiPlayerCampaign campaign =
|
||||
GameMain.NetLobbyScreen.SelectedMode == GameMain.GameSession?.GameMode.Preset && gameMode == GameMain.NetLobbyScreen.SelectedMode ?
|
||||
@@ -1237,31 +1311,114 @@ namespace Barotrauma.Networking
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
|
||||
MissionPrefab missionPrefab = missionIndex < 0 ? null : MissionPrefab.List[missionIndex];
|
||||
|
||||
GameMain.GameSession = missionIndex < 0 ?
|
||||
new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, MissionType.None) :
|
||||
new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, MissionPrefab.List[missionIndex]);
|
||||
GameMain.GameSession.StartRound(levelSeed, levelDifficulty, loadSecondSub);
|
||||
new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, missionPrefab);
|
||||
|
||||
//startRoundTask = Task.Run(async () => { await Task.Yield(); GameMain.GameSession.StartRound(levelSeed, levelDifficulty); });
|
||||
GameMain.GameSession.StartRound(levelSeed, levelDifficulty);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GameMain.GameSession?.CrewManager != null) GameMain.GameSession.CrewManager.Reset();
|
||||
/*startRoundTask = Task.Run(async () =>
|
||||
{
|
||||
await Task.Yield();
|
||||
GameMain.GameSession.StartRound(campaign.Map.SelectedConnection.Level,
|
||||
reloadSub: true,
|
||||
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
|
||||
});*/
|
||||
GameMain.GameSession.StartRound(campaign.Map.SelectedConnection.Level,
|
||||
reloadSub: true,
|
||||
loadSecondSub: false,
|
||||
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
|
||||
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
|
||||
}
|
||||
|
||||
GameMain.GameSession.Mission?.ClientReadInitial(inc);
|
||||
roundInitStatus = RoundInitStatus.WaitingForStartGameFinalize;
|
||||
|
||||
if (GameMain.GameSession.Submarine.IsFileCorrupted)
|
||||
DateTime? timeOut = null;
|
||||
DateTime requestFinalizeTime = DateTime.Now;
|
||||
TimeSpan requestFinalizeInterval = new TimeSpan(0, 0, 2);
|
||||
|
||||
while (true)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to start a round. Could not load the submarine \"{GameMain.GameSession.Submarine.Name}\".");
|
||||
try
|
||||
{
|
||||
if (timeOut.HasValue)
|
||||
{
|
||||
if (DateTime.Now > requestFinalizeTime)
|
||||
{
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte)ClientPacketHeader.REQUEST_STARTGAMEFINALIZE);
|
||||
clientPeer.Send(msg, DeliveryMethod.Unreliable);
|
||||
requestFinalizeTime = DateTime.Now + requestFinalizeInterval;
|
||||
}
|
||||
if (DateTime.Now > timeOut)
|
||||
{
|
||||
DebugConsole.ThrowError("Error while starting the round (did not receive STARTGAMEFINALIZE message from the server). Stopping the round...");
|
||||
roundInitStatus = RoundInitStatus.TimedOut;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (includesFinalize)
|
||||
{
|
||||
ReadStartGameFinalize(inc);
|
||||
break;
|
||||
}
|
||||
|
||||
//wait for up to 30 seconds for the server to send the STARTGAMEFINALIZE message
|
||||
timeOut = DateTime.Now + new TimeSpan(0, 0, seconds: 30);
|
||||
}
|
||||
|
||||
if (!connected)
|
||||
{
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
break;
|
||||
}
|
||||
|
||||
if (roundInitStatus != RoundInitStatus.WaitingForStartGameFinalize)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
clientPeer.Update((float)Timing.Step);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("There was an error initializing the round.", e, true);
|
||||
roundInitStatus = RoundInitStatus.Error;
|
||||
break;
|
||||
}
|
||||
|
||||
//waiting for a STARTGAMEFINALIZE message
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
|
||||
if (roundInitStatus != RoundInitStatus.Started)
|
||||
{
|
||||
if (roundInitStatus != RoundInitStatus.Interrupted)
|
||||
{
|
||||
DebugConsole.ThrowError(roundInitStatus.ToString());
|
||||
CoroutineManager.StartCoroutine(EndGame(""));
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.GameSession.Submarine.Info.IsFileCorrupted)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to start a round. Could not load the submarine \"{GameMain.GameSession.Submarine.Info.Name}\".");
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Submarine.MainSubs.Length; i++)
|
||||
{
|
||||
if (!loadSecondSub && i > 0) { break; }
|
||||
if (Submarine.MainSubs[i] == null) { break; }
|
||||
|
||||
var teamID = i == 0 ? Character.TeamType.Team1 : Character.TeamType.Team2;
|
||||
Submarine.MainSubs[i].TeamID = teamID;
|
||||
@@ -1271,23 +1428,10 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
if (Level.Loaded.EqualityCheckVal != levelEqualityCheckVal)
|
||||
{
|
||||
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server (seed: " + Level.Loaded.Seed +
|
||||
", sub: " + Submarine.MainSub.Name + " (" + Submarine.MainSub.MD5Hash.ShortHash + ")" +
|
||||
", mirrored: " + Level.Loaded.Mirrored + ").";
|
||||
DebugConsole.ThrowError(errorMsg, createMessageBox: true);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + levelSeed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
CoroutineManager.StartCoroutine(EndGame(""));
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
|
||||
if (respawnAllowed) { respawnManager = new RespawnManager(this, GameMain.NetLobbyScreen.UsingShuttle ? GameMain.NetLobbyScreen.SelectedShuttle : null); }
|
||||
|
||||
GameMain.GameSession.EventManager.PreloadContent(contentToPreload);
|
||||
|
||||
ServerSettings.ServerDetailsChanged = true;
|
||||
gameStarted = true;
|
||||
ServerSettings.ServerDetailsChanged = true;
|
||||
|
||||
GameMain.GameScreen.Select();
|
||||
|
||||
@@ -1358,8 +1502,8 @@ namespace Barotrauma.Networking
|
||||
bool requiredContentPackagesInstalled = inc.ReadBoolean();
|
||||
|
||||
var matchingSub =
|
||||
Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash) ??
|
||||
new Submarine(Path.Combine(Submarine.SavePath, subName) + ".sub", subHash, false);
|
||||
SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash) ??
|
||||
new SubmarineInfo(Path.Combine(SubmarineInfo.SavePath, subName) + ".sub", subHash);
|
||||
|
||||
matchingSub.RequiredContentPackagesInstalled = requiredContentPackagesInstalled;
|
||||
serverSubmarines.Add(matchingSub);
|
||||
@@ -1394,6 +1538,7 @@ namespace Barotrauma.Networking
|
||||
string preferredJob = inc.ReadString();
|
||||
UInt16 characterID = inc.ReadUInt16();
|
||||
bool muted = inc.ReadBoolean();
|
||||
bool inGame = inc.ReadBoolean();
|
||||
bool allowKicking = inc.ReadBoolean();
|
||||
inc.ReadPadBits();
|
||||
|
||||
@@ -1406,6 +1551,7 @@ namespace Barotrauma.Networking
|
||||
PreferredJob = preferredJob,
|
||||
CharacterID = characterID,
|
||||
Muted = muted,
|
||||
InGame = inGame,
|
||||
AllowKicking = allowKicking
|
||||
});
|
||||
}
|
||||
@@ -1424,6 +1570,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
SteamID = tc.SteamID,
|
||||
Muted = tc.Muted,
|
||||
InGame = tc.InGame,
|
||||
AllowKicking = tc.AllowKicking
|
||||
};
|
||||
ConnectedClients.Add(existingClient);
|
||||
@@ -1433,15 +1580,12 @@ namespace Barotrauma.Networking
|
||||
existingClient.PreferredJob = tc.PreferredJob;
|
||||
existingClient.Character = null;
|
||||
existingClient.Muted = tc.Muted;
|
||||
existingClient.InGame = tc.InGame;
|
||||
existingClient.AllowKicking = tc.AllowKicking;
|
||||
GameMain.NetLobbyScreen.SetPlayerNameAndJobPreference(existingClient);
|
||||
if (tc.CharacterID > 0)
|
||||
if (Screen.Selected != GameMain.NetLobbyScreen && tc.CharacterID > 0)
|
||||
{
|
||||
existingClient.Character = Entity.FindEntityByID(tc.CharacterID) as Character;
|
||||
if (existingClient.Character == null)
|
||||
{
|
||||
updateClientListId = false;
|
||||
}
|
||||
existingClient.CharacterID = tc.CharacterID;
|
||||
}
|
||||
if (existingClient.ID == myID)
|
||||
{
|
||||
@@ -1888,15 +2032,15 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
case FileTransferType.Submarine:
|
||||
new GUIMessageBox(TextManager.Get("ServerDownloadFinished"), TextManager.GetWithVariable("FileDownloadedNotification", "[filename]", transfer.FileName));
|
||||
var newSub = new Submarine(transfer.FilePath);
|
||||
var newSub = new SubmarineInfo(transfer.FilePath);
|
||||
if (newSub.IsFileCorrupted) { return; }
|
||||
|
||||
var existingSubs = Submarine.SavedSubmarines.Where(s => s.Name == newSub.Name && s.MD5Hash.Hash == newSub.MD5Hash.Hash).ToList();
|
||||
foreach (Submarine existingSub in existingSubs)
|
||||
var existingSubs = SubmarineInfo.SavedSubmarines.Where(s => s.Name == newSub.Name && s.MD5Hash.Hash == newSub.MD5Hash.Hash).ToList();
|
||||
foreach (SubmarineInfo existingSub in existingSubs)
|
||||
{
|
||||
existingSub.Dispose();
|
||||
}
|
||||
Submarine.AddToSavedSubs(newSub);
|
||||
SubmarineInfo.AddToSavedSubs(newSub);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
@@ -1905,8 +2049,8 @@ namespace Barotrauma.Networking
|
||||
GameMain.NetLobbyScreen.SubList.Content.Children;
|
||||
|
||||
var subElement = subListChildren.FirstOrDefault(c =>
|
||||
((Submarine)c.UserData).Name == newSub.Name &&
|
||||
((Submarine)c.UserData).MD5Hash.Hash == newSub.MD5Hash.Hash);
|
||||
((SubmarineInfo)c.UserData).Name == newSub.Name &&
|
||||
((SubmarineInfo)c.UserData).MD5Hash.Hash == newSub.MD5Hash.Hash);
|
||||
if (subElement == null) continue;
|
||||
|
||||
subElement.GetChild<GUITextBlock>().TextColor = new Color(subElement.GetChild<GUITextBlock>().TextColor, 1.0f);
|
||||
@@ -1934,17 +2078,17 @@ namespace Barotrauma.Networking
|
||||
if (campaign == null) { return; }
|
||||
|
||||
GameMain.GameSession.SavePath = transfer.FilePath;
|
||||
if (GameMain.GameSession.Submarine == null)
|
||||
if (GameMain.GameSession.SubmarineInfo == null)
|
||||
{
|
||||
var gameSessionDoc = SaveUtil.LoadGameSessionDoc(GameMain.GameSession.SavePath);
|
||||
string subPath = Path.Combine(SaveUtil.TempPath, gameSessionDoc.Root.GetAttributeString("submarine", "")) + ".sub";
|
||||
GameMain.GameSession.Submarine = new Submarine(subPath, "");
|
||||
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(subPath, "");
|
||||
}
|
||||
SaveUtil.LoadGame(GameMain.GameSession.SavePath, GameMain.GameSession);
|
||||
GameMain.GameSession?.Submarine?.CheckSubsLeftBehind();
|
||||
if (GameMain.GameSession?.Submarine?.Name != null)
|
||||
if (GameMain.GameSession?.SubmarineInfo?.Name != null)
|
||||
{
|
||||
GameMain.NetLobbyScreen.TryDisplayCampaignSubmarine(GameMain.GameSession.Submarine);
|
||||
GameMain.NetLobbyScreen.TryDisplayCampaignSubmarine(GameMain.GameSession.SubmarineInfo);
|
||||
}
|
||||
campaign.LastSaveID = campaign.PendingSaveID;
|
||||
|
||||
@@ -1979,8 +2123,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (!permissions.HasFlag(ClientPermissions.ConsoleCommands)) { return false; }
|
||||
|
||||
commandName = commandName.ToLowerInvariant();
|
||||
if (permittedConsoleCommands.Any(c => c.ToLowerInvariant() == commandName)) { return true; }
|
||||
if (permittedConsoleCommands.Any(c => c.Equals(commandName, StringComparison.OrdinalIgnoreCase))) { return true; }
|
||||
|
||||
//check aliases
|
||||
foreach (DebugConsole.Command command in DebugConsole.Commands)
|
||||
@@ -2231,7 +2374,7 @@ namespace Barotrauma.Networking
|
||||
clientPeer.Send(msg, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
public void SetupNewCampaign(Submarine sub, string saveName, string mapSeed)
|
||||
public void SetupNewCampaign(SubmarineInfo sub, string saveName, string mapSeed)
|
||||
{
|
||||
GameMain.NetLobbyScreen.CampaignSetupFrame.Visible = false;
|
||||
|
||||
@@ -2440,7 +2583,7 @@ namespace Barotrauma.Networking
|
||||
if (GUI.KeyboardDispatcher.Subscriber == null)
|
||||
{
|
||||
bool chatKeyHit = PlayerInput.KeyHit(InputType.Chat);
|
||||
bool radioKeyHit = PlayerInput.KeyHit(InputType.RadioChat);
|
||||
bool radioKeyHit = PlayerInput.KeyHit(InputType.RadioChat) && (Character.Controlled == null || Character.Controlled.SpeechImpediment < 0);
|
||||
|
||||
if (chatKeyHit || radioKeyHit)
|
||||
{
|
||||
@@ -2498,6 +2641,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
var transfer = fileReceiver.ActiveTransfers.First();
|
||||
GameMain.NetLobbyScreen.FileTransferFrame.Visible = true;
|
||||
GameMain.NetLobbyScreen.FileTransferFrame.UserData = transfer;
|
||||
GameMain.NetLobbyScreen.FileTransferTitle.Text =
|
||||
ToolBox.LimitString(
|
||||
TextManager.GetWithVariable("DownloadingFile", "[filename]", transfer.FileName),
|
||||
@@ -2789,7 +2933,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
if (GameMain.GameSession?.Submarine != null)
|
||||
{
|
||||
errorLines.Add("Submarine: " + GameMain.GameSession.Submarine.Name);
|
||||
errorLines.Add("Submarine: " + GameMain.GameSession.Submarine.Info.Name);
|
||||
}
|
||||
if (Level.Loaded != null)
|
||||
{
|
||||
@@ -2811,8 +2955,8 @@ namespace Barotrauma.Networking
|
||||
errorLines.Add(" " + DebugConsole.Messages[i].Time + " - " + DebugConsole.Messages[i].Text);
|
||||
}
|
||||
|
||||
string filePath = "event_error_log_client_" + Name + "_" + ToolBox.RemoveInvalidFileNameChars(DateTime.UtcNow.ToShortTimeString() + ".log");
|
||||
filePath = Path.Combine(ServerLog.SavePath, filePath);
|
||||
string filePath = "event_error_log_client_" + Name + "_" + DateTime.UtcNow.ToShortTimeString() + ".log";
|
||||
filePath = Path.Combine(ServerLog.SavePath, ToolBox.RemoveInvalidFileNameChars(filePath));
|
||||
|
||||
if (!Directory.Exists(ServerLog.SavePath))
|
||||
{
|
||||
|
||||
+1
-2
@@ -91,6 +91,7 @@ namespace Barotrauma.Networking
|
||||
return;
|
||||
}
|
||||
|
||||
incomingLidgrenMessages.Clear();
|
||||
netClient.ReadMessages(incomingLidgrenMessages);
|
||||
|
||||
foreach (NetIncomingMessage inc in incomingLidgrenMessages)
|
||||
@@ -107,8 +108,6 @@ namespace Barotrauma.Networking
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
incomingLidgrenMessages.Clear();
|
||||
}
|
||||
|
||||
private void HandleDataMessage(NetIncomingMessage inc)
|
||||
|
||||
+2
-1
@@ -204,8 +204,9 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
while (Steamworks.SteamNetworking.IsP2PPacketAvailable())
|
||||
for (int i=0;i<100;i++)
|
||||
{
|
||||
if (!Steamworks.SteamNetworking.IsP2PPacketAvailable()) { break; }
|
||||
var packet = Steamworks.SteamNetworking.ReadP2PPacket();
|
||||
if (packet.HasValue)
|
||||
{
|
||||
|
||||
@@ -571,6 +571,9 @@ namespace Barotrauma.Networking
|
||||
var ragdollButtonBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsAllowRagdollButton"));
|
||||
GetPropertyData("AllowRagdollButton").AssignGUIComponent(ragdollButtonBox);
|
||||
|
||||
var disableBotConversationsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsDisableBotConversations"));
|
||||
GetPropertyData("DisableBotConversations").AssignGUIComponent(disableBotConversationsBox);
|
||||
|
||||
/*var traitorRatioBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsUseTraitorRatio"));
|
||||
|
||||
CreateLabeledSlider(roundsTab, "", out slider, out sliderLabel);
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
static partial class SteamManager
|
||||
{
|
||||
private static Dictionary<Steamworks.Data.PublishedFileId, Task> modCopiesInProgress = new Dictionary<Steamworks.Data.PublishedFileId, Task>();
|
||||
|
||||
private static void InitializeProjectSpecific()
|
||||
{
|
||||
if (isInitialized) { return; }
|
||||
@@ -63,20 +65,6 @@ namespace Barotrauma.Steam
|
||||
|
||||
private static void UpdateProjectSpecific(float deltaTime)
|
||||
{
|
||||
for (int i=0;i<(ugcResultPageTasks?.Count ?? 0);i++)
|
||||
{
|
||||
var task = ugcResultPageTasks[i];
|
||||
if (task.IsCompleted)
|
||||
{
|
||||
if (!task.IsCompletedSuccessfully)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to retrieve Steam Workshop page info: TaskStatus = "+task.Status.ToString());
|
||||
}
|
||||
ugcResultPageTasks.RemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if (ugcSubscriptionTasks != null)
|
||||
{
|
||||
var ugcSubscriptionKeys = ugcSubscriptionTasks.Keys.ToList();
|
||||
@@ -525,7 +513,37 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Task> ugcResultPageTasks;
|
||||
private static async Task<List<Steamworks.Ugc.Item>> GetWorkshopItemsAsync(Steamworks.Ugc.Query query, int clampResults = 0, Predicate<Steamworks.Ugc.Item> itemPredicate=null)
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
int pageIndex = 1;
|
||||
Steamworks.Ugc.ResultPage? resultPage = await query.GetPageAsync(pageIndex);
|
||||
|
||||
List<Steamworks.Ugc.Item> retVal = new List<Steamworks.Ugc.Item>();
|
||||
while (resultPage.HasValue && resultPage?.ResultCount > 0)
|
||||
{
|
||||
if (itemPredicate != null)
|
||||
{
|
||||
retVal.AddRange(resultPage.Value.Entries.Where(it => itemPredicate(it)));
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal.AddRange(resultPage.Value.Entries);
|
||||
}
|
||||
|
||||
if (clampResults > 0 && retVal.Count >= clampResults)
|
||||
{
|
||||
retVal = retVal.Take(clampResults).ToList();
|
||||
break;
|
||||
}
|
||||
|
||||
pageIndex++;
|
||||
resultPage = await query.GetPageAsync(pageIndex);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static void GetSubscribedWorkshopItems(Action<IList<Steamworks.Ugc.Item>> onItemsFound, List<string> requireTags = null)
|
||||
{
|
||||
@@ -535,30 +553,9 @@ namespace Barotrauma.Steam
|
||||
.RankedByTotalUniqueSubscriptions()
|
||||
.WhereUserSubscribed()
|
||||
.WithLongDescription();
|
||||
if (requireTags != null) query.WithTags(requireTags);
|
||||
if (requireTags != null) { query = query.WithTags(requireTags); }
|
||||
|
||||
ugcResultPageTasks ??= new List<Task>();
|
||||
ugcResultPageTasks.Add(Task.Run(async () =>
|
||||
{
|
||||
int processedResults = 0; int pageIndex = 1;
|
||||
Steamworks.Ugc.ResultPage? resultPage = await query.GetPageAsync(pageIndex);
|
||||
|
||||
while (resultPage.HasValue && resultPage?.ResultCount > 0)
|
||||
{
|
||||
onItemsFound?.Invoke(resultPage.Value.Entries.ToList());
|
||||
|
||||
processedResults += resultPage.Value.ResultCount;
|
||||
pageIndex++;
|
||||
if (processedResults < resultPage?.TotalCount)
|
||||
{
|
||||
resultPage = await query.GetPageAsync(pageIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultPage = null;
|
||||
}
|
||||
}
|
||||
}));
|
||||
TaskPool.Add(GetWorkshopItemsAsync(query), (task) => { onItemsFound?.Invoke(task.Result); });
|
||||
}
|
||||
|
||||
public static void GetPopularWorkshopItems(Action<IList<Steamworks.Ugc.Item>> onItemsFound, int amount, List<string> requireTags = null)
|
||||
@@ -570,65 +567,40 @@ namespace Barotrauma.Steam
|
||||
.WithLongDescription();
|
||||
if (requireTags != null) query.WithTags(requireTags);
|
||||
|
||||
ugcResultPageTasks ??= new List<Task>();
|
||||
ugcResultPageTasks.Add(Task.Run(async () =>
|
||||
{
|
||||
int processedResults = 0; int pageIndex = 1;
|
||||
Steamworks.Ugc.ResultPage? resultPage = await query.GetPageAsync(pageIndex);
|
||||
TaskPool.Add(GetWorkshopItemsAsync(query, amount, (item) => !item.IsSubscribed), (task) => {
|
||||
var entries = task.Result;
|
||||
|
||||
while (resultPage.HasValue && resultPage?.ResultCount > 0)
|
||||
//count the number of each unique tag
|
||||
foreach (var item in entries)
|
||||
{
|
||||
var entries = resultPage.Value.Entries.ToList();
|
||||
//count the number of each unique tag
|
||||
foreach (var item in entries)
|
||||
foreach (string tag in item.Tags)
|
||||
{
|
||||
foreach (string tag in item.Tags)
|
||||
if (string.IsNullOrEmpty(tag)) { continue; }
|
||||
string caseInvariantTag = tag.ToLowerInvariant();
|
||||
if (!tagCommonness.ContainsKey(caseInvariantTag))
|
||||
{
|
||||
if (string.IsNullOrEmpty(tag)) { continue; }
|
||||
string caseInvariantTag = tag.ToLowerInvariant();
|
||||
if (!tagCommonness.ContainsKey(caseInvariantTag))
|
||||
{
|
||||
tagCommonness[caseInvariantTag] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
tagCommonness[caseInvariantTag]++;
|
||||
}
|
||||
tagCommonness[caseInvariantTag] = 1;
|
||||
}
|
||||
}
|
||||
//populate the popularTags list with tags sorted by commonness
|
||||
popularTags.Clear();
|
||||
foreach (KeyValuePair<string, int> tagCommonnessKVP in tagCommonness)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < popularTags.Count &&
|
||||
tagCommonness[popularTags[i]] > tagCommonnessKVP.Value)
|
||||
else
|
||||
{
|
||||
i++;
|
||||
tagCommonness[caseInvariantTag]++;
|
||||
}
|
||||
popularTags.Insert(i, tagCommonnessKVP.Key);
|
||||
}
|
||||
|
||||
var nonSubscribedItems = entries.Where(it => !it.IsSubscribed);
|
||||
if (nonSubscribedItems.Count() > (amount-processedResults))
|
||||
{
|
||||
nonSubscribedItems = nonSubscribedItems.Take(amount - processedResults);
|
||||
}
|
||||
|
||||
onItemsFound?.Invoke(nonSubscribedItems.ToList());
|
||||
|
||||
processedResults += resultPage.Value.ResultCount;
|
||||
pageIndex++;
|
||||
if (processedResults < resultPage?.TotalCount && processedResults < amount)
|
||||
{
|
||||
resultPage = await query.GetPageAsync(pageIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultPage = null;
|
||||
}
|
||||
}
|
||||
}));
|
||||
//populate the popularTags list with tags sorted by commonness
|
||||
popularTags.Clear();
|
||||
foreach (KeyValuePair<string, int> tagCommonnessKVP in tagCommonness)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < popularTags.Count &&
|
||||
tagCommonness[popularTags[i]] > tagCommonnessKVP.Value)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
popularTags.Insert(i, tagCommonnessKVP.Key);
|
||||
}
|
||||
onItemsFound?.Invoke(task.Result);
|
||||
});
|
||||
}
|
||||
|
||||
public static void GetPublishedWorkshopItems(Action<IList<Steamworks.Ugc.Item>> onItemsFound, List<string> requireTags = null)
|
||||
@@ -641,28 +613,7 @@ namespace Barotrauma.Steam
|
||||
.WithLongDescription();
|
||||
if (requireTags != null) query.WithTags(requireTags);
|
||||
|
||||
ugcResultPageTasks ??= new List<Task>();
|
||||
ugcResultPageTasks.Add(Task.Run(async () =>
|
||||
{
|
||||
int processedResults = 0; int pageIndex = 1;
|
||||
Steamworks.Ugc.ResultPage? resultPage = await query.GetPageAsync(pageIndex);
|
||||
|
||||
while (resultPage.HasValue && resultPage?.ResultCount > 0)
|
||||
{
|
||||
onItemsFound?.Invoke(resultPage.Value.Entries.ToList());
|
||||
|
||||
processedResults += resultPage.Value.ResultCount;
|
||||
pageIndex++;
|
||||
if (processedResults < resultPage?.TotalCount)
|
||||
{
|
||||
resultPage = await query.GetPageAsync(pageIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultPage = null;
|
||||
}
|
||||
}
|
||||
}));
|
||||
TaskPool.Add(GetWorkshopItemsAsync(query), (task) => { onItemsFound?.Invoke(task.Result); });
|
||||
}
|
||||
|
||||
private static Dictionary<ulong, Task> ugcSubscriptionTasks;
|
||||
@@ -926,7 +877,7 @@ namespace Barotrauma.Steam
|
||||
/// <summary>
|
||||
/// Enables a workshop item by moving it to the game folder.
|
||||
/// </summary>
|
||||
public static bool EnableWorkShopItem(Steamworks.Ugc.Item? item, bool allowFileOverwrite, out string errorMsg)
|
||||
public static bool EnableWorkShopItem(Steamworks.Ugc.Item? item, bool allowFileOverwrite, out string errorMsg, bool selectContentPackage = false, bool suppressInstallNotif = false)
|
||||
{
|
||||
if (!(item?.IsInstalled ?? false))
|
||||
{
|
||||
@@ -972,57 +923,116 @@ namespace Barotrauma.Steam
|
||||
return false;
|
||||
}
|
||||
|
||||
GameMain.Config.SuppressModFolderWatcher = true;
|
||||
Task<string> newTask = null;
|
||||
|
||||
CopyWorkShopItem(item, contentPackage, newContentPackagePath, metaDataFilePath, allowFileOverwrite, out errorMsg);
|
||||
|
||||
var newPackage = new ContentPackage(contentPackage.Path, newContentPackagePath)
|
||||
lock (modCopiesInProgress)
|
||||
{
|
||||
SteamWorkshopUrl = item?.Url,
|
||||
InstallTime = item?.Updated > item?.Created ? item?.Updated : item?.Created
|
||||
};
|
||||
|
||||
foreach (ContentFile contentFile in newPackage.Files)
|
||||
{
|
||||
contentFile.Path = CorrectContentFilePath(contentFile.Path, contentPackage, true);
|
||||
if (modCopiesInProgress.ContainsKey(item.Value.Id))
|
||||
{
|
||||
if (!modCopiesInProgress[item.Value.Id].IsCompleted &&
|
||||
!modCopiesInProgress[item.Value.Id].IsFaulted &&
|
||||
!modCopiesInProgress[item.Value.Id].IsCanceled)
|
||||
{
|
||||
errorMsg = ""; return true;
|
||||
}
|
||||
modCopiesInProgress.Remove(item.Value.Id);
|
||||
}
|
||||
newTask = CopyWorkShopItemAsync(item, contentPackage, newContentPackagePath, metaDataFilePath, allowFileOverwrite);
|
||||
modCopiesInProgress.Add(item.Value.Id, newTask);
|
||||
}
|
||||
|
||||
TaskPool.Add(newTask,
|
||||
contentPackage,
|
||||
(task, cp) =>
|
||||
{
|
||||
if (task.IsFaulted || task.IsCanceled)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to copy \"{item?.Title}\"", task.Exception);
|
||||
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Red);
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(task.Result))
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to copy \"{item?.Title}\": {task.Result}");
|
||||
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(Path.GetDirectoryName(newContentPackagePath)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(newContentPackagePath));
|
||||
}
|
||||
newPackage.Save(newContentPackagePath);
|
||||
ContentPackage.List.Add(newPackage);
|
||||
if (newPackage.CorePackage)
|
||||
{
|
||||
GameMain.Config.SelectCorePackage(newPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Config.SelectContentPackage(newPackage);
|
||||
}
|
||||
GameMain.Config.SaveNewPlayerConfig();
|
||||
GameMain.Config.SuppressModFolderWatcher = true;
|
||||
|
||||
GameMain.Config.WarnIfContentPackageSelectionDirty();
|
||||
var newPackage = new ContentPackage(cp.Path, newContentPackagePath)
|
||||
{
|
||||
SteamWorkshopUrl = item?.Url,
|
||||
InstallTime = item?.Updated > item?.Created ? item?.Updated : item?.Created
|
||||
};
|
||||
|
||||
GameMain.Config.SuppressModFolderWatcher = false;
|
||||
foreach (ContentFile contentFile in newPackage.Files)
|
||||
{
|
||||
contentFile.Path = CorrectContentFilePath(contentFile.Path, cp, true);
|
||||
}
|
||||
|
||||
if (newPackage.Files.Any(f => f.Type == ContentType.Submarine))
|
||||
{
|
||||
Submarine.RefreshSavedSubs();
|
||||
}
|
||||
if (!Directory.Exists(Path.GetDirectoryName(newContentPackagePath)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(newContentPackagePath));
|
||||
}
|
||||
newPackage.Save(newContentPackagePath);
|
||||
ContentPackage.List.Add(newPackage);
|
||||
|
||||
if (selectContentPackage)
|
||||
{
|
||||
if (newPackage.CorePackage)
|
||||
{
|
||||
GameMain.Config.SelectCorePackage(newPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Config.SelectContentPackage(newPackage);
|
||||
}
|
||||
GameMain.Config.SaveNewPlayerConfig();
|
||||
|
||||
GameMain.Config.WarnIfContentPackageSelectionDirty();
|
||||
|
||||
if (newPackage.Files.Any(f => f.Type == ContentType.Submarine))
|
||||
{
|
||||
SubmarineInfo.RefreshSavedSubs();
|
||||
}
|
||||
}
|
||||
else if (!suppressInstallNotif)
|
||||
{
|
||||
GameMain.MainMenuScreen?.SetEnableModsNotification(true);
|
||||
}
|
||||
|
||||
GameMain.Config.SuppressModFolderWatcher = false;
|
||||
|
||||
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Green);
|
||||
|
||||
});
|
||||
|
||||
errorMsg = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool CopyWorkShopItem(Steamworks.Ugc.Item? item, ContentPackage contentPackage, string newContentPackagePath, string metaDataFilePath, bool allowFileOverwrite, out string errorMsg)
|
||||
/// <summary>
|
||||
/// Asynchronously copies a Workshop item into the Mods folder.
|
||||
/// </summary>
|
||||
/// <returns>Returns an empty string on success, otherwise returns an error message.</returns>
|
||||
private async static Task<string> CopyWorkShopItemAsync(Steamworks.Ugc.Item? item, ContentPackage contentPackage, string newContentPackagePath, string metaDataFilePath, bool allowFileOverwrite)
|
||||
{
|
||||
errorMsg = "";
|
||||
await Task.Yield();
|
||||
|
||||
string targetPath = Path.GetDirectoryName(GetWorkshopItemContentPackagePath(contentPackage));
|
||||
string copyingPath = Path.Combine(targetPath, CopyIndicatorFileName);
|
||||
|
||||
string errorMsg = "";
|
||||
if (contentPackage.GameVersion > new Version(0, 9, 1, 0))
|
||||
{
|
||||
SaveUtil.CopyFolder(item?.Directory, Path.GetDirectoryName(GetWorkshopItemContentPackagePath(contentPackage)), copySubDirs: true, overwriteExisting: true);
|
||||
return true;
|
||||
Directory.CreateDirectory(targetPath);
|
||||
File.WriteAllText(copyingPath, "TEMPORARY FILE");
|
||||
|
||||
SaveUtil.CopyFolder(item?.Directory, targetPath, copySubDirs: true, overwriteExisting: true);
|
||||
|
||||
File.Delete(copyingPath);
|
||||
return "";
|
||||
}
|
||||
|
||||
var allPackageFiles = Directory.GetFiles(item?.Directory, "*", SearchOption.AllDirectories);
|
||||
@@ -1042,7 +1052,7 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariables("WorkshopErrorOverwriteOnEnable", new string[2] { "[itemname]", "[filename]" }, new string[2] { item?.Title, newContentPackagePath });
|
||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||
return false;
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
foreach (ContentFile contentFile in contentPackage.Files)
|
||||
@@ -1053,84 +1063,79 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariables("WorkshopErrorOverwriteOnEnable", new string[2] { "[itemname]", "[filename]" }, new string[2] { item?.Title, contentFile.Path });
|
||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||
return false;
|
||||
return errorMsg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
Directory.CreateDirectory(targetPath);
|
||||
File.WriteAllText(copyingPath, "TEMPORARY FILE");
|
||||
|
||||
foreach (ContentFile contentFile in contentPackage.Files)
|
||||
{
|
||||
foreach (ContentFile contentFile in contentPackage.Files)
|
||||
contentFile.Path = contentFile.Path.CleanUpPath();
|
||||
string sourceFile = Path.Combine(item?.Directory, contentFile.Path);
|
||||
if (!File.Exists(sourceFile))
|
||||
{
|
||||
contentFile.Path = contentFile.Path.CleanUpPath();
|
||||
string sourceFile = Path.Combine(item?.Directory, contentFile.Path);
|
||||
if (!File.Exists(sourceFile))
|
||||
string[] splitPath = contentFile.Path.Split('/');
|
||||
if (splitPath.Length >= 2 && splitPath[0] == "Mods")
|
||||
{
|
||||
string[] splitPath = contentFile.Path.Split('/');
|
||||
if (splitPath.Length >= 2 && splitPath[0] == "Mods")
|
||||
{
|
||||
sourceFile = Path.Combine(item?.Directory, string.Join("/", splitPath.Skip(2)));
|
||||
}
|
||||
sourceFile = Path.Combine(item?.Directory, string.Join("/", splitPath.Skip(2)));
|
||||
}
|
||||
}
|
||||
|
||||
contentFile.Path = CorrectContentFilePath(contentFile.Path, contentPackage, false);
|
||||
contentFile.Path = CorrectContentFilePath(contentFile.Path, contentPackage,
|
||||
contentFile.Type != ContentType.Submarine);
|
||||
|
||||
|
||||
//path not allowed -> the content file must be a reference to an external file (such as some vanilla file outside the Mods folder)
|
||||
if (!ContentPackage.IsModFilePathAllowed(contentFile))
|
||||
//path not allowed -> the content file must be a reference to an external file (such as some vanilla file outside the Mods folder)
|
||||
if (!ContentPackage.IsModFilePathAllowed(contentFile))
|
||||
{
|
||||
//the content package is trying to copy a file to a prohibited path, which is not allowed
|
||||
if (File.Exists(sourceFile))
|
||||
{
|
||||
//the content package is trying to copy a file to a prohibited path, which is not allowed
|
||||
if (File.Exists(sourceFile))
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariable("WorkshopErrorIllegalPathOnEnable", "[filename]", contentFile.Path);
|
||||
return false;
|
||||
}
|
||||
//not trying to copy anything, so this is a reference to an external file
|
||||
//if the external file doesn't exist, we cannot enable the package
|
||||
else if (!File.Exists(contentFile.Path))
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item?.Title) + " " + TextManager.GetWithVariable("WorkshopFileNotFound", "[path]", "\"" + contentFile.Path + "\"");
|
||||
return false;
|
||||
}
|
||||
errorMsg = TextManager.GetWithVariable("WorkshopErrorIllegalPathOnEnable", "[filename]", contentFile.Path);
|
||||
return errorMsg;
|
||||
}
|
||||
//not trying to copy anything, so this is a reference to an external file
|
||||
//if the external file doesn't exist, we cannot enable the package
|
||||
else if (!File.Exists(contentFile.Path))
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item?.Title) + " " + TextManager.GetWithVariable("WorkshopFileNotFound", "[path]", "\"" + contentFile.Path + "\"");
|
||||
return errorMsg;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (!File.Exists(sourceFile))
|
||||
{
|
||||
if (File.Exists(contentFile.Path))
|
||||
{
|
||||
//the file is already present in the game folder, all good
|
||||
continue;
|
||||
}
|
||||
else if (!File.Exists(sourceFile))
|
||||
else
|
||||
{
|
||||
if (File.Exists(contentFile.Path))
|
||||
{
|
||||
//the file is already present in the game folder, all good
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
//file not present in either the mod or the game folder -> cannot enable the package
|
||||
errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item?.Title) + " " + TextManager.GetWithVariable("WorkshopFileNotFound", "[path]", "\"" + contentFile.Path + "\"");
|
||||
return false;
|
||||
}
|
||||
//file not present in either the mod or the game folder -> cannot enable the package
|
||||
errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item?.Title) + " " + TextManager.GetWithVariable("WorkshopFileNotFound", "[path]", "\"" + contentFile.Path + "\"");
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
//make sure the destination directory exists
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(contentFile.Path));
|
||||
CorrectContentFileCopy(contentPackage, sourceFile, contentFile.Path, overwrite: true);
|
||||
}
|
||||
|
||||
foreach (string nonContentFile in nonContentFiles)
|
||||
{
|
||||
string sourceFile = Path.Combine(item?.Directory, nonContentFile);
|
||||
if (!File.Exists(sourceFile)) { continue; }
|
||||
string destinationPath = CorrectContentFilePath(nonContentFile, contentPackage, false);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
|
||||
CorrectContentFileCopy(contentPackage, sourceFile, destinationPath, overwrite: true);
|
||||
}
|
||||
//make sure the destination directory exists
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(contentFile.Path));
|
||||
CorrectContentFileCopy(contentPackage, sourceFile, contentFile.Path, overwrite: true);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
foreach (string nonContentFile in nonContentFiles)
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item?.Title) + " {" + e.Message + "}";
|
||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||
return false;
|
||||
string sourceFile = Path.Combine(item?.Directory, nonContentFile);
|
||||
if (!File.Exists(sourceFile)) { continue; }
|
||||
string destinationPath = CorrectContentFilePath(nonContentFile, contentPackage, false);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
|
||||
CorrectContentFileCopy(contentPackage, sourceFile, destinationPath, overwrite: true);
|
||||
}
|
||||
|
||||
return true;
|
||||
File.Delete(copyingPath);
|
||||
return "";
|
||||
}
|
||||
|
||||
private static bool CheckFileEquality(string filePath1, string filePath2)
|
||||
@@ -1149,6 +1154,44 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
}
|
||||
|
||||
private static void RemoveMods(Func<ContentPackage, bool> predicate)
|
||||
{
|
||||
var toRemove = ContentPackage.List.Where(predicate).ToList();
|
||||
var packagesToDeselect = GameMain.Config.SelectedContentPackages.Where(p => toRemove.Contains(p)).ToList();
|
||||
foreach (var cp in packagesToDeselect)
|
||||
{
|
||||
if (cp.CorePackage)
|
||||
{
|
||||
GameMain.Config.SelectCorePackage(ContentPackage.List.Find(cpp => cpp.CorePackage && !toRemove.Contains(cpp)));
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Config.DeselectContentPackage(cp);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var cp in toRemove)
|
||||
{
|
||||
try
|
||||
{
|
||||
string path = Path.GetDirectoryName(cp.Path);
|
||||
if (Directory.Exists(path)) { Directory.Delete(path, true); }
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError($"An error occurred while attempting to delete {Path.GetDirectoryName(cp.Path)}", e);
|
||||
}
|
||||
}
|
||||
|
||||
ContentPackage.List.RemoveAll(cp => toRemove.Contains(cp));
|
||||
GameMain.Config.SelectedContentPackages.RemoveAll(cp => !ContentPackage.List.Contains(cp));
|
||||
|
||||
ContentPackage.SortContentPackages();
|
||||
GameMain.Config.SaveNewPlayerConfig();
|
||||
|
||||
GameMain.Config.WarnIfContentPackageSelectionDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables a workshop item by removing the files from the game folder.
|
||||
/// </summary>
|
||||
@@ -1173,44 +1216,11 @@ namespace Barotrauma.Steam
|
||||
GameMain.Config.SuppressModFolderWatcher = true;
|
||||
try
|
||||
{
|
||||
|
||||
var toRemove = ContentPackage.List.Where(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && cp.SteamWorkshopUrl == contentPackage.SteamWorkshopUrl).ToList();
|
||||
var packagesToDeselect = GameMain.Config.SelectedContentPackages.Where(p => toRemove.Contains(p)).ToList();
|
||||
foreach (var cp in packagesToDeselect)
|
||||
{
|
||||
if (cp.CorePackage)
|
||||
{
|
||||
GameMain.Config.SelectCorePackage(ContentPackage.List.Find(cpp => cpp.CorePackage && !toRemove.Contains(cpp)));
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Config.DeselectContentPackage(cp);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var cp in toRemove)
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(Path.GetDirectoryName(cp.Path), true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError($"An error occurred while attempting to delete {Path.GetDirectoryName(cp.Path)}", e);
|
||||
}
|
||||
}
|
||||
|
||||
ContentPackage.List.RemoveAll(cp => toRemove.Contains(cp));
|
||||
GameMain.Config.SelectedContentPackages.RemoveAll(cp => !ContentPackage.List.Contains(cp));
|
||||
|
||||
ContentPackage.SortContentPackages();
|
||||
GameMain.Config.SaveNewPlayerConfig();
|
||||
|
||||
GameMain.Config.WarnIfContentPackageSelectionDirty();
|
||||
RemoveMods(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && cp.SteamWorkshopUrl == contentPackage.SteamWorkshopUrl);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
errorMsg = "Disabling the workshop item \"" + item?.Title + "\" failed. " + e.Message;
|
||||
errorMsg = "Disabling the workshop item \"" + item?.Title + "\" failed. " + e.Message + "\n" + e.StackTrace;
|
||||
if (!noLog)
|
||||
{
|
||||
DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
|
||||
@@ -1219,6 +1229,8 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
GameMain.Config.SuppressModFolderWatcher = false;
|
||||
|
||||
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, false, null);
|
||||
|
||||
errorMsg = "";
|
||||
return true;
|
||||
}
|
||||
@@ -1314,79 +1326,77 @@ namespace Barotrauma.Steam
|
||||
return upToDate;
|
||||
}
|
||||
|
||||
public static bool AutoUpdateWorkshopItems()
|
||||
public static async Task<bool> AutoUpdateWorkshopItemsAsync()
|
||||
{
|
||||
if (!isInitialized) { return false; }
|
||||
|
||||
var query = new Steamworks.Ugc.Query(Steamworks.UgcType.All)
|
||||
.WhereUserSubscribed()
|
||||
.WithLongDescription();
|
||||
//ugcResultPageTasks ??= new List<Task>();
|
||||
//ugcResultPageTasks.Add();
|
||||
CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
|
||||
CancellationToken cancelToken = cancelTokenSource.Token;
|
||||
Task task = Task.Factory.StartNew(async () =>
|
||||
{
|
||||
int processedResults = 0; int pageIndex = 1;
|
||||
Steamworks.Ugc.ResultPage? resultPage = await query.GetPageAsync(pageIndex);
|
||||
|
||||
while (resultPage.HasValue && resultPage?.ResultCount > 0)
|
||||
List<Steamworks.Ugc.Item> items = await GetWorkshopItemsAsync(query);
|
||||
|
||||
GameMain.Config.SuppressModFolderWatcher = true;
|
||||
|
||||
//remove mods that the player is no longer subscribed to
|
||||
RemoveMods(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && !items.Any(it => it.Id == GetWorkshopItemIDFromUrl(cp.SteamWorkshopUrl)));
|
||||
|
||||
GameMain.Config.SuppressModFolderWatcher = false;
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var item in resultPage.Value.Entries)
|
||||
if (!item.IsInstalled) { continue; }
|
||||
|
||||
bool installedSuccessfully = false;
|
||||
string errorMsg;
|
||||
if (!CheckWorkshopItemEnabled(item))
|
||||
{
|
||||
if (cancelToken.IsCancellationRequested)
|
||||
{
|
||||
cancelToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!item.IsInstalled || !CheckWorkshopItemEnabled(item) || CheckWorkshopItemUpToDate(item)) { continue; }
|
||||
if (!UpdateWorkshopItem(item, out string errorMsg))
|
||||
{
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
new GUIMessageBox(
|
||||
TextManager.Get("Error"),
|
||||
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, errorMsg }));
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: potential race condition
|
||||
new GUIMessageBox("", TextManager.GetWithVariable("WorkshopItemUpdated", "[itemname]", item.Title));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
new GUIMessageBox(
|
||||
TextManager.Get("Error"),
|
||||
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, e.Message + ", " + e.TargetSite }));
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"SteamManager.AutoUpdateWorkshopItems:" + e.Message,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Failed to autoupdate workshop item \"" + item.Title + "\". " + e.Message + "\n" + e.StackTrace);
|
||||
}
|
||||
installedSuccessfully = EnableWorkShopItem(item, true, out errorMsg);
|
||||
}
|
||||
|
||||
processedResults += resultPage.Value.ResultCount;
|
||||
pageIndex++;
|
||||
if (processedResults < resultPage?.TotalCount)
|
||||
else if (!CheckWorkshopItemUpToDate(item))
|
||||
{
|
||||
resultPage = await query.GetPageAsync(pageIndex);
|
||||
installedSuccessfully = UpdateWorkshopItem(item, out errorMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultPage = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!installedSuccessfully)
|
||||
{
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
new GUIMessageBox(
|
||||
TextManager.Get("Error"),
|
||||
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, errorMsg }));
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: potential race condition
|
||||
new GUIMessageBox("", TextManager.GetWithVariable("WorkshopItemUpdated", "[itemname]", item.Title));
|
||||
}
|
||||
}
|
||||
}, cancelToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
|
||||
|
||||
task.Wait(10000);
|
||||
if (!task.IsCompleted)
|
||||
{
|
||||
cancelTokenSource.Cancel();
|
||||
task.Wait();
|
||||
catch (Exception e)
|
||||
{
|
||||
new GUIMessageBox(
|
||||
TextManager.Get("Error"),
|
||||
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, e.Message + ", " + e.TargetSite }));
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"SteamManager.AutoUpdateWorkshopItems:" + e.Message,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Failed to autoupdate workshop item \"" + item.Title + "\". " + e.Message + "\n" + e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
return task.Status == TaskStatus.RanToCompletion;
|
||||
|
||||
List<Task> tasks;
|
||||
lock (modCopiesInProgress)
|
||||
{
|
||||
tasks = modCopiesInProgress.Values.ToList();
|
||||
}
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool UpdateWorkshopItem(Steamworks.Ugc.Item? item, out string errorMsg)
|
||||
@@ -1431,7 +1441,7 @@ namespace Barotrauma.Steam
|
||||
|
||||
private static void CorrectContentFileCopy(ContentPackage package, string src, string dest, bool overwrite)
|
||||
{
|
||||
if (Path.GetExtension(src).ToLowerInvariant() == ".xml")
|
||||
if (Path.GetExtension(src).Equals(".xml", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(src);
|
||||
if (doc != null)
|
||||
@@ -1481,7 +1491,7 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
if (checkIfFileExists)
|
||||
{
|
||||
ContentPackage otherContentPackage = ContentPackage.List.Find(cp => cp.Name.ToLowerInvariant() == splitPath[1].ToLowerInvariant());
|
||||
ContentPackage otherContentPackage = ContentPackage.List.Find(cp => cp.Name.Equals(splitPath[1], StringComparison.OrdinalIgnoreCase));
|
||||
if (otherContentPackage != null)
|
||||
{
|
||||
string otherPackageName = Path.GetDirectoryName(otherContentPackage.Path);
|
||||
@@ -1493,7 +1503,8 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
}
|
||||
}
|
||||
newPath = Path.Combine(packageName, string.Join("/", splitPath.Skip(2)));
|
||||
splitPath = splitPath.Skip(Math.Clamp(splitPath.Length-1, 0, 2)).ToArray();
|
||||
newPath = Path.Combine(packageName, string.Join("/", splitPath));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace Barotrauma.Networking
|
||||
if (client.VoipSound == null)
|
||||
{
|
||||
DebugConsole.Log("Recreating voipsound " + queueId);
|
||||
client.VoipSound = new VoipSound(GameMain.SoundManager, client.VoipQueue);
|
||||
client.VoipSound = new VoipSound(client.Name, GameMain.SoundManager, client.VoipQueue);
|
||||
}
|
||||
|
||||
if (client.Character != null && !client.Character.IsDead && !client.Character.Removed && client.Character.SpeechImpediment <= 100.0f)
|
||||
@@ -119,7 +119,7 @@ namespace Barotrauma.Networking
|
||||
GameMain.NetLobbyScreen?.SetPlayerSpeaking(client);
|
||||
GameMain.GameSession?.CrewManager?.SetClientSpeaking(client);
|
||||
|
||||
if (client.VoipSound.CurrentAmplitude > 0.1f) //TODO: might need to tweak
|
||||
if ((client.VoipSound.CurrentAmplitude * client.VoipSound.Gain * GameMain.SoundManager.GetCategoryGainMultiplier("voip")) > 0.1f) //TODO: might need to tweak
|
||||
{
|
||||
if (client.Character != null && !client.Character.Removed)
|
||||
{
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace Barotrauma
|
||||
Submarine sub = data as Submarine;
|
||||
if (sub == null) return;
|
||||
|
||||
msg.Write(sub.Name);
|
||||
msg.Write(sub.Info.Name);
|
||||
break;
|
||||
case VoteType.Mode:
|
||||
GameModePreset gameMode = data as GameModePreset;
|
||||
@@ -158,7 +158,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (item.UserData != null && item.UserData is Submarine) serversubs.Add(item.UserData as Submarine);
|
||||
}
|
||||
Submarine sub = serversubs.FirstOrDefault(sm => sm.Name == subName);
|
||||
Submarine sub = serversubs.FirstOrDefault(sm => sm.Info.Name == subName);
|
||||
SetVoteText(GameMain.NetLobbyScreen.SubList, sub, votes);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user