Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaServer/Source/GameSession/GameModes/MultiPlayerCampaign.cs
T
Joonas Rikkonen c3b5c414cb 4e002dc...f9e8100
commit f9e8100140d99d30db551c16523f04cf042fb107
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Sun Mar 24 20:37:23 2019 +0200

    Automatically grab adjacent ladders when the top/bottom of the current ladder is reached. Makes moving through docking ports a little less confusing. Closes #1337

commit 7ad697036299c3dae0145f89dc7e1f4fec22953d
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Sun Mar 24 20:11:57 2019 +0200

    Fixed windows clients being unable to start a campaign in servers running on Linux. Caused by submarine paths not matching because the clients would use backslash in the filepath while Linux uses a slash. The submarine selection logic also had an additional issue: the clients would assume the submarine is in the default Submarines folder, even though the server may actually store them somewhere else. Now the client communicates the selected sub to the server by sending the name and MD5 hash instead of the path, so mismatching paths shouldn't cause problems anymore. Closes #1332
2019-03-24 20:38:12 +02:00

257 lines
10 KiB
C#

using Barotrauma.Networking;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
namespace Barotrauma
{
partial class MultiPlayerCampaign : CampaignMode
{
private List<CharacterCampaignData> characterData = new List<CharacterCampaignData>();
public static void StartNewCampaign(string savePath, string subPath, string seed)
{
if (string.IsNullOrWhiteSpace(savePath)) return;
GameMain.GameSession = new GameSession(new Submarine(subPath, ""), savePath,
GameModePreset.List.Find(g => g.Identifier == "multiplayercampaign"));
var campaign = ((MultiPlayerCampaign)GameMain.GameSession.GameMode);
campaign.GenerateMap(seed);
campaign.SetDelegates();
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
GameMain.GameSession.Map.SelectRandomLocation(true);
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
campaign.LastSaveID++;
DebugConsole.NewMessage("Campaign started!", Color.Cyan);
DebugConsole.NewMessage(GameMain.GameSession.Map.CurrentLocation.Name + " -> " + GameMain.GameSession.Map.SelectedLocation.Name, Color.Cyan);
}
public static void LoadCampaign(string selectedSave)
{
SaveUtil.LoadGame(selectedSave);
((MultiPlayerCampaign)GameMain.GameSession.GameMode).LastSaveID++;
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
GameMain.GameSession.Map.SelectRandomLocation(true);
DebugConsole.NewMessage("Campaign loaded!", Color.Cyan);
DebugConsole.NewMessage(GameMain.GameSession.Map.CurrentLocation.Name + " -> " + GameMain.GameSession.Map.SelectedLocation.Name, Color.Cyan);
}
public static void StartCampaignSetup()
{
DebugConsole.NewMessage("********* CAMPAIGN SETUP *********", Color.White);
DebugConsole.ShowQuestionPrompt("Do you want to start a new campaign? Y/N", (string arg) =>
{
if (arg.ToLowerInvariant() == "y" || arg.ToLowerInvariant() == "yes")
{
DebugConsole.ShowQuestionPrompt("Enter a save name for the campaign:", (string saveName) =>
{
StartNewCampaign(saveName, GameMain.NetLobbyScreen.SelectedSub.FilePath, GameMain.NetLobbyScreen.LevelSeed);
});
}
else
{
string[] saveFiles = SaveUtil.GetSaveFiles(SaveUtil.SaveType.Multiplayer);
DebugConsole.NewMessage("Saved campaigns:", Color.White);
for (int i = 0; i < saveFiles.Length; i++)
{
DebugConsole.NewMessage(" " + i + ". " + saveFiles[i], Color.White);
}
DebugConsole.ShowQuestionPrompt("Select a save file to load (0 - " + (saveFiles.Length - 1) + "):", (string selectedSave) =>
{
int saveIndex = -1;
if (!int.TryParse(selectedSave, out saveIndex)) return;
LoadCampaign(saveFiles[saveIndex]);
});
}
});
}
public bool AllowedToEndRound(Character interactor)
{
if (interactor == null || Level.Loaded?.StartOutpost == null || Level.Loaded?.EndOutpost == null)
{
return false;
}
if (interactor.Submarine == Level.Loaded.StartOutpost &&
interactor.CanInteractWith(startWatchman))
{
return true;
}
if (interactor.Submarine == Level.Loaded.EndOutpost &&
interactor.CanInteractWith(endWatchman))
{
return true;
}
return false;
}
protected override void WatchmanInteract(Character watchman, Character interactor)
{
if ((watchman.Submarine == Level.Loaded.StartOutpost && !Submarine.MainSub.AtStartPosition) ||
(watchman.Submarine == Level.Loaded.EndOutpost && !Submarine.MainSub.AtEndPosition))
{
CreateDialog(new List<Character> { watchman }, "WatchmanInteractNoLeavingSub", 5.0f);
return;
}
bool hasPermissions = true;
if (GameMain.Server != null)
{
var client = GameMain.Server.ConnectedClients.Find(c => c.Character == interactor);
hasPermissions = client != null;
CreateDialog(new List<Character> { watchman }, hasPermissions ? "WatchmanInteract" : "WatchmanInteractNotAllowed", 1.0f);
}
}
partial void SetDelegates()
{
if (GameMain.Server != null)
{
CargoManager.OnItemsChanged += () => { LastUpdateID++; };
Map.OnLocationSelected += (loc, connection) => { LastUpdateID++; };
Map.OnMissionSelected += (loc, mission) => { LastUpdateID++; };
}
}
public void DiscardClientCharacterData(Client client)
{
characterData.RemoveAll(cd => cd.MatchesClient(client));
}
public CharacterCampaignData GetClientCharacterData(Client client)
{
return characterData.Find(cd => cd.MatchesClient(client));
}
public void AssignClientCharacterInfos(IEnumerable<Client> connectedClients)
{
foreach (Client client in connectedClients)
{
if (client.SpectateOnly && GameMain.Server.ServerSettings.AllowSpectating) { continue; }
var matchingData = GetClientCharacterData(client);
if (matchingData != null) client.CharacterInfo = matchingData.CharacterInfo;
}
}
public Dictionary<Client, Job> GetAssignedJobs(IEnumerable<Client> connectedClients)
{
var assignedJobs = new Dictionary<Client, Job>();
foreach (Client client in connectedClients)
{
var matchingData = GetClientCharacterData(client);
if (matchingData != null) assignedJobs.Add(client, matchingData.CharacterInfo.Job);
}
return assignedJobs;
}
public void ServerWrite(NetBuffer msg, Client c)
{
System.Diagnostics.Debug.Assert(map.Locations.Count < UInt16.MaxValue);
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);
msg.Write(map.SelectedMissionIndex == -1 ? byte.MaxValue : (byte)map.SelectedMissionIndex);
msg.Write(isRunning && startWatchman != null ? startWatchman.ID : (UInt16)0);
msg.Write(isRunning && endWatchman != null ? endWatchman.ID : (UInt16)0);
msg.Write(Money);
msg.Write((UInt16)CargoManager.PurchasedItems.Count);
foreach (PurchasedItem pi in CargoManager.PurchasedItems)
{
msg.Write((UInt16)MapEntityPrefab.List.IndexOf(pi.ItemPrefab));
msg.Write((UInt16)pi.Quantity);
}
var characterData = GetClientCharacterData(c);
if (characterData?.CharacterInfo == null)
{
msg.Write(false);
}
else
{
msg.Write(true);
characterData.CharacterInfo.ServerWrite(msg);
}
}
public void ServerRead(NetBuffer msg, Client sender)
{
UInt16 selectedLocIndex = msg.ReadUInt16();
byte selectedMissionIndex = msg.ReadByte();
UInt16 purchasedItemCount = msg.ReadUInt16();
List<PurchasedItem> purchasedItems = new List<PurchasedItem>();
for (int i = 0; i < purchasedItemCount; i++)
{
UInt16 itemPrefabIndex = msg.ReadUInt16();
UInt16 itemQuantity = msg.ReadUInt16();
purchasedItems.Add(new PurchasedItem(MapEntityPrefab.List[itemPrefabIndex] as ItemPrefab, itemQuantity));
}
if (!sender.HasPermission(ClientPermissions.ManageCampaign))
{
DebugConsole.ThrowError("Client \"" + sender.Name + "\" does not have a permission to manage the campaign");
return;
}
Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
if (Map.SelectedConnection != null)
{
Map.SelectMission(selectedMissionIndex);
}
List<PurchasedItem> currentItems = new List<PurchasedItem>(CargoManager.PurchasedItems);
foreach (PurchasedItem pi in currentItems)
{
CargoManager.SellItem(pi, pi.Quantity);
}
foreach (PurchasedItem pi in purchasedItems)
{
CargoManager.PurchaseItem(pi.ItemPrefab, pi.Quantity);
}
}
public override void Save(XElement element)
{
XElement modeElement = new XElement("MultiPlayerCampaign",
new XAttribute("money", Money),
new XAttribute("cheatsenabled", CheatsEnabled));
Map.Save(modeElement);
element.Add(modeElement);
//save character data to a separate file
string characterDataPath = GetCharacterDataSavePath();
XDocument characterDataDoc = new XDocument(new XElement("CharacterData"));
foreach (CharacterCampaignData cd in characterData)
{
characterDataDoc.Root.Add(cd.Save());
}
try
{
characterDataDoc.Save(characterDataPath);
}
catch (Exception e)
{
DebugConsole.ThrowError("Saving multiplayer campaign characters to \"" + characterDataPath + "\" failed!", e);
}
lastSaveID++;
}
}
}