Files
unity/Assets/Game/Scripts/Save/ProfileStore.cs
T

190 lines
6.7 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace Ironspore
{
[Serializable]
public sealed class CargoStack
{
public string uid = Guid.NewGuid().ToString("N");
public string itemId;
public int count;
public int x, y;
public bool rotated, borrowed;
public CargoStack(string id, int amount)
{
itemId = id;
count = amount;
}
public string Name => InventoryGrid.Slot(itemId) >= 0 ? GameLocalization.Text("equipment." + itemId + ".name") : GameLocalization.ItemName(itemId);
}
[Serializable]
public sealed class RunRecord
{
public string id;
public bool active;
public int seed;
public int stage;
public int branch;
public int biome;
public int chassis = 1;
public int[] equipment = { 0, 0, 0, 0 };
public float armor;
public float energy = 100;
public bool podUsed;
public bool objectiveDone;
public bool routeCompleted;
public int upgrades;
public float elapsed;
public float escortArmor = 250;
public List<CargoStack> cargo = new List<CargoStack>();
public List<CargoStack> safeCase = new List<CargoStack>();
public List<CargoStack> installed = new List<CargoStack>();
public bool destructionPending;
public List<string> searched = new List<string>();
}
[Serializable]
public sealed class GameSave
{
public const int CurrentVersion = 2;
public int version = CurrentVersion;
public List<CargoStack> warehouse = new List<CargoStack>();
public int alloy;
public int cells;
public int sorties;
public int extractions;
public int completed;
public List<string> blueprints = new List<string>();
public List<string> unlocked = new List<string>();
public List<string> receipts = new List<string>();
public RunRecord run = new RunRecord();
}
public sealed partial class ProfileStore
{
readonly string path;
public GameSave Data
{
get; private set;
}
public string Error
{
get; private set;
}
public static string SavePath(bool trial)
{
#if UNITY_EDITOR
string root = Path.Combine(Path.GetDirectoryName(Application.dataPath), "UserSettings");
#else
string root = Application.persistentDataPath;
#endif
return Path.Combine(root, "Ironspore", trial ? "range-v2.json" : "profile-v2.json");
}
public ProfileStore(string savePath)
{
path = savePath;
Data = Load(path) ?? Load(path + ".bak");
if (Data == null)
{
if (File.Exists(path) || File.Exists(path + ".bak"))
throw new InvalidDataException("No valid equipment snapshot: " + path);
Data = new GameSave();
for (int slot = 0; slot < 4; slot++)
Data.warehouse.Add(new CargoStack(InventoryGrid.EquipmentId(slot, 0), 1));
}
}
static GameSave Load(string file)
{
try
{
if (!File.Exists(file))
return null;
var save = JsonUtility.FromJson<GameSave>(File.ReadAllText(file));
if (save != null && save.version != GameSave.CurrentVersion)
throw new NotSupportedException("Unsupported equipment save version: " + save.version);
if (!Valid(save)) return null;
return save;
}
catch (ArgumentException) { return null; }
}
public bool Commit(Func<GameSave, bool> change)
{
if (Data.run.destructionPending) return false;
return Write(change);
}
bool Write(Func<GameSave, bool> change)
{
Error = null;
var candidate = JsonUtility.FromJson<GameSave>(JsonUtility.ToJson(Data));
if (!change(candidate) || !Valid(candidate))
return false;
try
{
Directory.CreateDirectory(Path.GetDirectoryName(path));
string temp = path + ".tmp";
using (var stream = new FileStream(temp, FileMode.Create, FileAccess.Write, FileShare.None))
{
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(JsonUtility.ToJson(candidate, true));
stream.Write(bytes, 0, bytes.Length);
stream.Flush(true);
}
if (File.Exists(path))
File.Replace(temp, path, Load(path) == null ? null : path + ".bak");
else
File.Move(temp, path);
Data = candidate;
Error = null;
return true;
}
catch (Exception ex) { Error = ex.Message; return false; }
}
public bool Begin(int chassis, int[] equipment, float armor, int seed, bool trial = false, string[] selected = null)
{
return Commit(s =>
{
if ((selected != null && selected.Length != 4) || s.run.active || equipment == null || equipment.Length != 4 || armor <= 0) return false;
s.run = new RunRecord { id = Guid.NewGuid().ToString("N"), active = true, seed = seed, chassis = chassis, equipment = (int[])equipment.Clone(), armor = armor };
for (int slot = 0; slot < 4; slot++)
{
string id = InventoryGrid.EquipmentId(slot, equipment[slot]);
if (id == null) return false;
var requested = selected?[slot];
var item = s.warehouse.Find(part => part.itemId == id && (requested == null || requested == part.uid));
if (item == null)
{
if (requested != null || (!trial && equipment[slot] != 0)) return false;
item = new CargoStack(id, 1) { borrowed = true };
}
else s.warehouse.Remove(item);
s.run.installed.Add(item);
}
s.sorties++;
return true;
});
}
public bool CompleteRoute()
{
return Commit(s =>
{
if (!s.run.active || s.run.armor <= 0 || s.run.routeCompleted)
return false;
s.run.routeCompleted = true;
s.run.objectiveDone = true;
s.completed++;
return true;
});
}
}
}