Implement game save/load backend.
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user