190 lines
6.7 KiB
C#
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;
|
|
});
|
|
}
|
|
}
|
|
}
|