Added testing and save/load mechanic to the game. Game is now entering final phase.
This commit is contained in:
@@ -0,0 +1,357 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
|
||||
public static class SaveGameManager
|
||||
{
|
||||
private const string SaveDirectory = "user://savegame";
|
||||
private const string GameDataPath = SaveDirectory + "/gamedata.json";
|
||||
private const string RobotsPath = SaveDirectory + "/robots.json";
|
||||
private const string ResearchPath = SaveDirectory + "/research.json";
|
||||
private const string LayerPrefix = SaveDirectory + "/layer_";
|
||||
private const string JsonExtension = ".json";
|
||||
|
||||
private static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
public static bool SaveExists()
|
||||
{
|
||||
return FileAccess.FileExists(GameDataPath);
|
||||
}
|
||||
|
||||
public static void SaveGame()
|
||||
{
|
||||
SaveGameData saveGame = CreateSaveData();
|
||||
CreateSaveDirectory();
|
||||
ClearOldLayerFiles();
|
||||
|
||||
SaveJson(GameDataPath, CreateCoreSaveData(saveGame));
|
||||
SaveJson(RobotsPath, saveGame.Robots);
|
||||
SaveJson(ResearchPath, saveGame.Research);
|
||||
|
||||
foreach (LayerSaveData layer in saveGame.Layers)
|
||||
{
|
||||
SaveJson(GetLayerPath(layer.Level), layer);
|
||||
}
|
||||
}
|
||||
|
||||
public static SaveGameData LoadSaveData()
|
||||
{
|
||||
if (!SaveExists()) return null;
|
||||
|
||||
SaveGameData saveGame = LoadJson<SaveGameData>(GameDataPath);
|
||||
if (saveGame == null) return null;
|
||||
|
||||
saveGame.Robots = LoadJson<List<RobotSaveData>>(RobotsPath) ?? new List<RobotSaveData>();
|
||||
saveGame.Research = LoadJson<List<ResearchSaveData>>(ResearchPath) ?? new List<ResearchSaveData>();
|
||||
saveGame.Layers = LoadLayerSaveData();
|
||||
|
||||
return saveGame;
|
||||
}
|
||||
|
||||
public static SaveGameData CreateSaveData()
|
||||
{
|
||||
return new SaveGameData
|
||||
{
|
||||
Seed = GameData.seed,
|
||||
CurrentLayer = GameData.currentLayer,
|
||||
VisibleLayer = GameData.visibleLayer,
|
||||
LowestLayer = GameData.lowestLayer,
|
||||
MaxRobotCount = GameData.maxRobotCount,
|
||||
CanMove = GameData.canMove,
|
||||
Survival = CreateSurvivalSaveData(),
|
||||
Inventory = CreateInventorySaveData(),
|
||||
Research = CreateResearchSaveData(),
|
||||
Layers = CreateLayerSaveData(),
|
||||
Robots = CreateRobotSaveData()
|
||||
};
|
||||
}
|
||||
|
||||
public static void ApplyWorldData(SaveGameData saveGame)
|
||||
{
|
||||
if (saveGame == null) return;
|
||||
|
||||
GameData.seed = saveGame.Seed;
|
||||
GameData.currentLayer = saveGame.CurrentLayer;
|
||||
GameData.visibleLayer = saveGame.VisibleLayer;
|
||||
GameData.lowestLayer = saveGame.LowestLayer;
|
||||
GameData.maxRobotCount = saveGame.MaxRobotCount;
|
||||
GameData.canMove = saveGame.CanMove;
|
||||
|
||||
ApplySurvivalData(saveGame.Survival);
|
||||
ApplyInventoryData(saveGame.Inventory);
|
||||
ApplyResearchData(saveGame.Research);
|
||||
ApplyLayerData(saveGame.Layers);
|
||||
}
|
||||
|
||||
private static SurvivalSaveData CreateSurvivalSaveData()
|
||||
{
|
||||
return new SurvivalSaveData
|
||||
{
|
||||
Hunger = GameData.survival.hunger,
|
||||
Thirst = GameData.survival.thirst,
|
||||
Energy = GameData.survival.energy,
|
||||
IsDead = GameData.survival.isDead,
|
||||
DeathReason = GameData.survival.deathReason,
|
||||
CurrentStatus = GameData.survival.currentStatus
|
||||
};
|
||||
}
|
||||
|
||||
private static List<ItemSaveData> CreateInventorySaveData()
|
||||
{
|
||||
List<ItemSaveData> result = new List<ItemSaveData>();
|
||||
|
||||
foreach (Item item in GameData.inventory.items)
|
||||
{
|
||||
result.Add(new ItemSaveData
|
||||
{
|
||||
Id = item.data.Id,
|
||||
Amount = item.currentAmount
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<ResearchSaveData> CreateResearchSaveData()
|
||||
{
|
||||
List<ResearchSaveData> result = new List<ResearchSaveData>();
|
||||
|
||||
foreach (Research research in GameData.availableResearch.Values)
|
||||
{
|
||||
result.Add(new ResearchSaveData
|
||||
{
|
||||
Id = research.data.Id,
|
||||
State = research.state,
|
||||
ElapsedResearchTime = research.elapsedResearchTime,
|
||||
PaidResources = research.paidResources
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<LayerSaveData> CreateLayerSaveData()
|
||||
{
|
||||
List<LayerSaveData> result = new List<LayerSaveData>();
|
||||
if (GameData.map == null) return result;
|
||||
|
||||
foreach (Layer layer in GameData.map)
|
||||
{
|
||||
if (layer == null) continue;
|
||||
|
||||
result.Add(new LayerSaveData
|
||||
{
|
||||
Level = layer.level,
|
||||
IsGateOpen = layer.isGateOpen,
|
||||
HasContentGenerated = layer.hasContentGenerated,
|
||||
GateIngredients = new List<Ingredient>(layer.gateIngredients),
|
||||
CurrentResources = new List<string>(layer.currentResources),
|
||||
Tiles = CreateTileSaveData(layer)
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<TileSaveData> CreateTileSaveData(Layer layer)
|
||||
{
|
||||
List<TileSaveData> result = new List<TileSaveData>();
|
||||
|
||||
foreach (Tile tile in layer.tiles)
|
||||
{
|
||||
result.Add(new TileSaveData
|
||||
{
|
||||
X = tile.GridPosition.X,
|
||||
Y = tile.GridPosition.Y,
|
||||
CollapsedMesh = tile.collapsedMesh,
|
||||
ContainsLight = tile.containsLight,
|
||||
ContainsDecoration = tile.containsDecoration,
|
||||
ContainsResource = tile.containsResource,
|
||||
WasVisited = tile.wasVisited,
|
||||
Resource = tile.resource == null ? null : tile.resource.CreateSaveData()
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<RobotSaveData> CreateRobotSaveData()
|
||||
{
|
||||
List<RobotSaveData> result = new List<RobotSaveData>();
|
||||
|
||||
foreach (Robot robot in GameData.robots)
|
||||
{
|
||||
result.Add(robot.CreateSaveData());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static SaveGameData CreateCoreSaveData(SaveGameData saveGame)
|
||||
{
|
||||
return new SaveGameData
|
||||
{
|
||||
Seed = saveGame.Seed,
|
||||
CurrentLayer = saveGame.CurrentLayer,
|
||||
VisibleLayer = saveGame.VisibleLayer,
|
||||
LowestLayer = saveGame.LowestLayer,
|
||||
MaxRobotCount = saveGame.MaxRobotCount,
|
||||
CanMove = saveGame.CanMove,
|
||||
Survival = saveGame.Survival,
|
||||
Inventory = saveGame.Inventory,
|
||||
Research = new List<ResearchSaveData>(),
|
||||
Layers = new List<LayerSaveData>(),
|
||||
Robots = new List<RobotSaveData>()
|
||||
};
|
||||
}
|
||||
|
||||
private static List<LayerSaveData> LoadLayerSaveData()
|
||||
{
|
||||
List<LayerSaveData> result = new List<LayerSaveData>();
|
||||
|
||||
for (int i = 0; i < GameData.ruinSize; i++)
|
||||
{
|
||||
string path = GetLayerPath(i);
|
||||
if (!FileAccess.FileExists(path)) continue;
|
||||
|
||||
LayerSaveData layer = LoadJson<LayerSaveData>(path);
|
||||
if (layer != null)
|
||||
{
|
||||
result.Add(layer);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string GetLayerPath(int level)
|
||||
{
|
||||
return LayerPrefix + level + JsonExtension;
|
||||
}
|
||||
|
||||
private static void CreateSaveDirectory()
|
||||
{
|
||||
DirAccess.MakeDirRecursiveAbsolute(SaveDirectory);
|
||||
}
|
||||
|
||||
private static void ClearOldLayerFiles()
|
||||
{
|
||||
DirAccess directory = DirAccess.Open(SaveDirectory);
|
||||
if (directory == null) return;
|
||||
|
||||
directory.ListDirBegin();
|
||||
while (true)
|
||||
{
|
||||
string fileName = directory.GetNext();
|
||||
if (fileName == "") break;
|
||||
if (directory.CurrentIsDir()) continue;
|
||||
if (!fileName.StartsWith("layer_") || !fileName.EndsWith(JsonExtension)) continue;
|
||||
|
||||
directory.Remove(fileName);
|
||||
}
|
||||
directory.ListDirEnd();
|
||||
}
|
||||
|
||||
private static void SaveJson<T>(string path, T data)
|
||||
{
|
||||
string json = JsonSerializer.Serialize(data, JsonOptions);
|
||||
FileAccess file = FileAccess.Open(path, FileAccess.ModeFlags.Write);
|
||||
file.StoreString(json);
|
||||
file.Flush();
|
||||
}
|
||||
|
||||
private static T LoadJson<T>(string path)
|
||||
{
|
||||
if (!FileAccess.FileExists(path)) return default;
|
||||
|
||||
FileAccess file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
|
||||
string json = file.GetAsText();
|
||||
return JsonSerializer.Deserialize<T>(json);
|
||||
}
|
||||
|
||||
private static void ApplySurvivalData(SurvivalSaveData survival)
|
||||
{
|
||||
if (survival == null) return;
|
||||
|
||||
GameData.survival.hunger = survival.Hunger;
|
||||
GameData.survival.thirst = survival.Thirst;
|
||||
GameData.survival.energy = survival.Energy;
|
||||
GameData.survival.isDead = survival.IsDead;
|
||||
GameData.survival.deathReason = survival.DeathReason ?? "";
|
||||
GameData.survival.currentStatus = survival.CurrentStatus ?? "";
|
||||
}
|
||||
|
||||
private static void ApplyInventoryData(List<ItemSaveData> savedItems)
|
||||
{
|
||||
GameData.inventory = new Inventory();
|
||||
if (savedItems == null) return;
|
||||
|
||||
foreach (ItemSaveData savedItem in savedItems)
|
||||
{
|
||||
if (!GameData.availableItems.ContainsKey(savedItem.Id)) continue;
|
||||
|
||||
GameData.inventory.AddItem(
|
||||
new Item { data = GameData.availableItems[savedItem.Id] },
|
||||
savedItem.Amount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplyResearchData(List<ResearchSaveData> savedResearch)
|
||||
{
|
||||
if (savedResearch == null) return;
|
||||
|
||||
foreach (ResearchSaveData savedState in savedResearch)
|
||||
{
|
||||
if (!GameData.availableResearch.ContainsKey(savedState.Id)) continue;
|
||||
|
||||
Research research = GameData.availableResearch[savedState.Id];
|
||||
research.state = savedState.State;
|
||||
research.elapsedResearchTime = savedState.ElapsedResearchTime;
|
||||
research.paidResources = savedState.PaidResources;
|
||||
}
|
||||
|
||||
GameData.RebuildRobotStatsFromResearch();
|
||||
}
|
||||
|
||||
private static void ApplyLayerData(List<LayerSaveData> savedLayers)
|
||||
{
|
||||
if (savedLayers == null || GameData.map == null) return;
|
||||
|
||||
foreach (LayerSaveData savedLayer in savedLayers)
|
||||
{
|
||||
if (savedLayer.Level < 0 || savedLayer.Level >= GameData.map.Length) continue;
|
||||
|
||||
Layer layer = GameData.map[savedLayer.Level];
|
||||
layer.isGateOpen = savedLayer.IsGateOpen;
|
||||
layer.hasContentGenerated = savedLayer.HasContentGenerated;
|
||||
layer.gateIngredients = savedLayer.GateIngredients ?? new List<Ingredient>();
|
||||
layer.currentResources = savedLayer.CurrentResources ?? new List<string>();
|
||||
|
||||
ApplyTileData(layer, savedLayer.Tiles);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplyTileData(Layer layer, List<TileSaveData> savedTiles)
|
||||
{
|
||||
if (savedTiles == null) return;
|
||||
|
||||
foreach (TileSaveData savedTile in savedTiles)
|
||||
{
|
||||
if (savedTile.X < 0 || savedTile.X >= GameData.layerSize) continue;
|
||||
if (savedTile.Y < 0 || savedTile.Y >= GameData.layerSize) continue;
|
||||
|
||||
Tile tile = layer.tiles[savedTile.X, savedTile.Y];
|
||||
tile.collapsedMesh = savedTile.CollapsedMesh;
|
||||
tile.containsLight = savedTile.ContainsLight;
|
||||
tile.containsDecoration = savedTile.ContainsDecoration;
|
||||
tile.containsResource = savedTile.ContainsResource;
|
||||
tile.wasVisited = savedTile.WasVisited;
|
||||
tile.resource = savedTile.Resource == null ? null : GameResource.FromSaveData(savedTile.Resource);
|
||||
tile.ContentNode.Visible = savedTile.WasVisited || tile.collapsedMesh == "gate";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user