Implement game save/load backend.

This commit is contained in:
Paul Chote
2019-04-14 20:58:11 +00:00
committed by reaperrr
parent 877215c86a
commit 1f3b30c2d2
9 changed files with 618 additions and 10 deletions

View File

@@ -98,6 +98,16 @@ namespace OpenRA
get { return OrderManager.Connection is ReplayConnection; }
}
public bool IsLoadingGameSave
{
get { return OrderManager.NetFrameNumber <= OrderManager.GameSaveLastFrame; }
}
public int GameSaveLoadingPercentage
{
get { return OrderManager.NetFrameNumber * 100 / OrderManager.GameSaveLastFrame; }
}
void SetLocalPlayer(Player localPlayer)
{
if (localPlayer == null)
@@ -162,6 +172,8 @@ namespace OpenRA
public bool RulesContainTemporaryBlocker { get; private set; }
bool wasLoadingGameSave;
internal World(ModData modData, Map map, OrderManager orderManager, WorldType type)
{
Type = type;
@@ -230,6 +242,14 @@ namespace OpenRA
public void LoadComplete(WorldRenderer wr)
{
if (IsLoadingGameSave)
{
wasLoadingGameSave = true;
Game.Sound.DisableAllSounds = true;
foreach (var nsr in WorldActor.TraitsImplementing<INotifyGameLoading>())
nsr.GameLoading(this);
}
// ScreenMap must be initialized before anything else
using (new PerfTimer("ScreenMap.WorldLoaded"))
ScreenMap.WorldLoaded(this, wr);
@@ -344,6 +364,12 @@ namespace OpenRA
public int WorldTick { get; private set; }
Dictionary<int, MiniYaml> gameSaveTraitData = new Dictionary<int, MiniYaml>();
internal void AddGameSaveTraitData(int traitIndex, MiniYaml yaml)
{
gameSaveTraitData[traitIndex] = yaml;
}
public void SetPauseState(bool paused)
{
if (PauseStateLocked)
@@ -360,6 +386,29 @@ namespace OpenRA
public void Tick()
{
if (wasLoadingGameSave && !IsLoadingGameSave)
{
foreach (var kv in gameSaveTraitData)
{
var tp = TraitDict.ActorsWithTrait<IGameSaveTraitData>()
.Skip(kv.Key)
.FirstOrDefault();
if (tp.Actor == null)
break;
tp.Trait.ResolveTraitData(tp.Actor, kv.Value.Nodes);
}
gameSaveTraitData.Clear();
Game.Sound.DisableAllSounds = false;
foreach (var nsr in WorldActor.TraitsImplementing<INotifyGameLoaded>())
nsr.GameLoaded(this);
wasLoadingGameSave = false;
}
if (!Paused)
{
WorldTick++;
@@ -460,6 +509,35 @@ namespace OpenRA
}
}
public void RequestGameSave(string filename)
{
// Allow traits to save arbitrary data that will be passed back via IGameSaveTraitData.ResolveTraitData
// at the end of the save restoration
// TODO: This will need to be generalized to a request / response pair for multiplayer game saves
var i = 0;
foreach (var tp in TraitDict.ActorsWithTrait<IGameSaveTraitData>())
{
var data = tp.Trait.IssueTraitData(tp.Actor);
if (data != null)
{
var yaml = new List<MiniYamlNode>() { new MiniYamlNode(i.ToString(), new MiniYaml("", data)) };
IssueOrder(new Order("GameSaveTraitData", null, false)
{
IsImmediate = true,
TargetString = yaml.WriteToString()
});
}
i++;
}
IssueOrder(new Order("CreateGameSave", null, false)
{
IsImmediate = true,
TargetString = filename
});
}
public bool Disposing;
public void Dispose()
@@ -470,6 +548,8 @@ namespace OpenRA
Game.Sound.StopAudio();
Game.Sound.StopVideo();
if (IsLoadingGameSave)
Game.Sound.DisableAllSounds = false;
ModelCache.Dispose();