646 lines
19 KiB
C#
646 lines
19 KiB
C#
using System;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Xml.Linq;
|
|
using HG;
|
|
using JetBrains.Annotations;
|
|
using RoR2.Networking;
|
|
using RoR2.Stats;
|
|
using UnityEngine;
|
|
using UnityEngine.Networking;
|
|
|
|
namespace RoR2;
|
|
|
|
public class RunReport
|
|
{
|
|
public class PlayerInfo
|
|
{
|
|
[CanBeNull]
|
|
public NetworkUser networkUser;
|
|
|
|
[CanBeNull]
|
|
public CharacterMaster master;
|
|
|
|
public int localPlayerIndex = -1;
|
|
|
|
public string name = string.Empty;
|
|
|
|
public BodyIndex bodyIndex = BodyIndex.None;
|
|
|
|
public BodyIndex killerBodyIndex = BodyIndex.None;
|
|
|
|
public bool isDead;
|
|
|
|
public StatSheet statSheet = StatSheet.New();
|
|
|
|
public ItemIndex[] itemAcquisitionOrder = Array.Empty<ItemIndex>();
|
|
|
|
public int[] itemStacks = ItemCatalog.RequestItemStackArray();
|
|
|
|
public EquipmentIndex[] equipment = Array.Empty<EquipmentIndex>();
|
|
|
|
public string finalMessageToken = string.Empty;
|
|
|
|
public string userProfileFileName = string.Empty;
|
|
|
|
private static readonly HGXml.SerializationRules<int[]> itemStacksRules = new HGXml.SerializationRules<int[]>
|
|
{
|
|
serializer = delegate(XElement element, int[] value)
|
|
{
|
|
element.RemoveAll();
|
|
element.Add(from itemIndex in ItemCatalog.allItems
|
|
where value[(int)itemIndex] > 0
|
|
select new XElement(ItemCatalog.GetItemDef(itemIndex).name, value[(int)itemIndex]));
|
|
},
|
|
deserializer = delegate(XElement element, ref int[] value)
|
|
{
|
|
Array.Resize(ref value, ItemCatalog.itemCount);
|
|
for (ItemIndex itemIndex2 = ItemIndex.Count; (int)itemIndex2 < ItemCatalog.itemCount; itemIndex2++)
|
|
{
|
|
value[(int)itemIndex2] = 0;
|
|
}
|
|
foreach (XElement item in element.Elements())
|
|
{
|
|
ItemIndex itemIndex3 = ItemCatalog.FindItemIndex(item.Name.LocalName);
|
|
if (ItemCatalog.IsIndexValid(in itemIndex3))
|
|
{
|
|
HGXml.FromXml(item, ref value[(int)itemIndex3]);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
private static readonly HGXml.SerializationRules<EquipmentIndex[]> equipmentRules = new HGXml.SerializationRules<EquipmentIndex[]>
|
|
{
|
|
serializer = delegate(XElement element, EquipmentIndex[] value)
|
|
{
|
|
element.Value = string.Join(" ", value.Select((EquipmentIndex equipmentIndex) => EquipmentCatalog.GetEquipmentDef(equipmentIndex)?.name ?? "None"));
|
|
},
|
|
deserializer = delegate(XElement element, ref EquipmentIndex[] value)
|
|
{
|
|
value = element.Value.Split(' ').Select(EquipmentCatalog.FindEquipmentIndex).ToArray();
|
|
return true;
|
|
}
|
|
};
|
|
|
|
[CanBeNull]
|
|
public LocalUser localUser
|
|
{
|
|
get
|
|
{
|
|
if (!networkUser)
|
|
{
|
|
return null;
|
|
}
|
|
return networkUser.localUser;
|
|
}
|
|
}
|
|
|
|
public bool isLocalPlayer => localPlayerIndex >= 0;
|
|
|
|
public string bodyName
|
|
{
|
|
get
|
|
{
|
|
return BodyCatalog.GetBodyPrefab(bodyIndex)?.gameObject.name ?? "InvalidBody";
|
|
}
|
|
set
|
|
{
|
|
bodyIndex = BodyCatalog.FindBodyIndex(value);
|
|
}
|
|
}
|
|
|
|
public string killerBodyName
|
|
{
|
|
get
|
|
{
|
|
return BodyCatalog.GetBodyPrefab(killerBodyIndex)?.gameObject.name ?? "InvalidBody";
|
|
}
|
|
set
|
|
{
|
|
killerBodyIndex = BodyCatalog.FindBodyIndex(value);
|
|
}
|
|
}
|
|
|
|
public void Write(NetworkWriter writer)
|
|
{
|
|
writer.WriteBodyIndex(bodyIndex);
|
|
writer.WriteBodyIndex(killerBodyIndex);
|
|
writer.Write(isDead);
|
|
writer.Write(master ? master.gameObject : null);
|
|
statSheet.Write(writer);
|
|
writer.WritePackedUInt32((uint)itemAcquisitionOrder.Length);
|
|
for (int i = 0; i < itemAcquisitionOrder.Length; i++)
|
|
{
|
|
writer.Write(itemAcquisitionOrder[i]);
|
|
}
|
|
writer.WriteItemStacks(itemStacks);
|
|
writer.WritePackedUInt32((uint)equipment.Length);
|
|
for (int j = 0; j < equipment.Length; j++)
|
|
{
|
|
writer.Write(equipment[j]);
|
|
}
|
|
writer.Write(finalMessageToken);
|
|
}
|
|
|
|
public void Read(NetworkReader reader)
|
|
{
|
|
bodyIndex = reader.ReadBodyIndex();
|
|
killerBodyIndex = reader.ReadBodyIndex();
|
|
isDead = reader.ReadBoolean();
|
|
GameObject gameObject = reader.ReadGameObject();
|
|
master = (gameObject ? gameObject.GetComponent<CharacterMaster>() : null);
|
|
statSheet.ReadOrSetDefault(reader);
|
|
int newSize = (int)reader.ReadPackedUInt32();
|
|
Array.Resize(ref itemAcquisitionOrder, newSize);
|
|
for (int i = 0; i < itemAcquisitionOrder.Length; i++)
|
|
{
|
|
ItemIndex itemIndex = reader.ReadItemIndex();
|
|
itemAcquisitionOrder[i] = itemIndex;
|
|
}
|
|
reader.ReadItemStacks(itemStacks);
|
|
int newSize2 = (int)reader.ReadPackedUInt32();
|
|
Array.Resize(ref equipment, newSize2);
|
|
for (int j = 0; j < equipment.Length; j++)
|
|
{
|
|
EquipmentIndex equipmentIndex = reader.ReadEquipmentIndex();
|
|
equipment[j] = equipmentIndex;
|
|
}
|
|
finalMessageToken = reader.ReadString();
|
|
ResolveLocalInformation();
|
|
}
|
|
|
|
public void ResolveLocalInformation()
|
|
{
|
|
name = Util.GetBestMasterName(master);
|
|
PlayerCharacterMasterController playerCharacterMasterController = null;
|
|
if ((bool)master)
|
|
{
|
|
playerCharacterMasterController = master.GetComponent<PlayerCharacterMasterController>();
|
|
}
|
|
networkUser = null;
|
|
if ((bool)playerCharacterMasterController)
|
|
{
|
|
networkUser = playerCharacterMasterController.networkUser;
|
|
}
|
|
localPlayerIndex = -1;
|
|
userProfileFileName = string.Empty;
|
|
if ((bool)networkUser && networkUser.localUser != null)
|
|
{
|
|
localPlayerIndex = networkUser.localUser.id;
|
|
userProfileFileName = networkUser.localUser.userProfile.fileName;
|
|
}
|
|
}
|
|
|
|
public static PlayerInfo Generate(PlayerCharacterMasterController playerCharacterMasterController, GameEndingDef gameEnding)
|
|
{
|
|
CharacterMaster characterMaster = playerCharacterMasterController.master;
|
|
Inventory inventory = characterMaster.inventory;
|
|
PlayerStatsComponent component = playerCharacterMasterController.GetComponent<PlayerStatsComponent>();
|
|
PlayerInfo playerInfo = new PlayerInfo
|
|
{
|
|
networkUser = playerCharacterMasterController.networkUser,
|
|
master = characterMaster,
|
|
bodyIndex = BodyCatalog.FindBodyIndex(characterMaster.bodyPrefab),
|
|
killerBodyIndex = characterMaster.GetKillerBodyIndex(),
|
|
isDead = characterMaster.lostBodyToDeath
|
|
};
|
|
if (playerInfo.killerBodyIndex == BodyIndex.None && (bool)gameEnding && (bool)gameEnding.defaultKillerOverride)
|
|
{
|
|
playerInfo.killerBodyIndex = BodyCatalog.FindBodyIndex(gameEnding.defaultKillerOverride);
|
|
}
|
|
StatSheet.Copy(component.currentStats, playerInfo.statSheet);
|
|
playerInfo.itemAcquisitionOrder = inventory.itemAcquisitionOrder.ToArray();
|
|
ItemIndex itemIndex = ItemIndex.Count;
|
|
for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++)
|
|
{
|
|
playerInfo.itemStacks[(int)itemIndex] = inventory.GetItemCount(itemIndex);
|
|
}
|
|
playerInfo.equipment = new EquipmentIndex[inventory.GetEquipmentSlotCount()];
|
|
for (uint num = 0u; num < playerInfo.equipment.Length; num++)
|
|
{
|
|
playerInfo.equipment[num] = inventory.GetEquipment(num).equipmentIndex;
|
|
}
|
|
playerInfo.finalMessageToken = playerCharacterMasterController.finalMessageTokenServer;
|
|
return playerInfo;
|
|
}
|
|
|
|
public static void ToXml(XElement element, PlayerInfo playerInfo)
|
|
{
|
|
element.RemoveAll();
|
|
element.Add(HGXml.ToXml("name", playerInfo.name));
|
|
element.Add(HGXml.ToXml("bodyName", playerInfo.bodyName));
|
|
element.Add(HGXml.ToXml("killerBodyName", playerInfo.killerBodyName));
|
|
element.Add(HGXml.ToXml("isDead", playerInfo.isDead));
|
|
element.Add(HGXml.ToXml("statSheet", playerInfo.statSheet));
|
|
element.Add(HGXml.ToXml("itemAcquisitionOrder", playerInfo.itemAcquisitionOrder));
|
|
element.Add(HGXml.ToXml("itemStacks", playerInfo.itemStacks, itemStacksRules));
|
|
element.Add(HGXml.ToXml("equipment", playerInfo.equipment, equipmentRules));
|
|
element.Add(HGXml.ToXml("finalMessageToken", playerInfo.finalMessageToken));
|
|
element.Add(HGXml.ToXml("localPlayerIndex", playerInfo.localPlayerIndex));
|
|
element.Add(HGXml.ToXml("userProfileFileName", playerInfo.userProfileFileName));
|
|
}
|
|
|
|
public static bool FromXml(XElement element, ref PlayerInfo playerInfo)
|
|
{
|
|
playerInfo = new PlayerInfo();
|
|
element.Element("name")?.Deserialize(ref playerInfo.name);
|
|
string dest = playerInfo.bodyName;
|
|
element.Element("bodyName")?.Deserialize(ref dest);
|
|
playerInfo.bodyName = dest;
|
|
string dest2 = playerInfo.killerBodyName;
|
|
element.Element("killerBodyName")?.Deserialize(ref dest2);
|
|
playerInfo.killerBodyName = dest2;
|
|
element.Element("isDead")?.Deserialize(ref playerInfo.isDead);
|
|
element.Element("statSheet")?.Deserialize(ref playerInfo.statSheet);
|
|
element.Element("itemAcquisitionOrder")?.Deserialize(ref playerInfo.itemAcquisitionOrder);
|
|
element.Element("itemStacks")?.Deserialize(ref playerInfo.itemStacks, itemStacksRules);
|
|
element.Element("equipment")?.Deserialize(ref playerInfo.equipment, equipmentRules);
|
|
element.Element("finalMessageToken")?.Deserialize(ref playerInfo.finalMessageToken);
|
|
element.Element("localPlayerIndex")?.Deserialize(ref playerInfo.localPlayerIndex);
|
|
element.Element("userProfileFileName")?.Deserialize(ref playerInfo.userProfileFileName);
|
|
return true;
|
|
}
|
|
|
|
public static void ArrayToXml(XElement element, PlayerInfo[] playerInfos)
|
|
{
|
|
element.RemoveAll();
|
|
for (int i = 0; i < playerInfos.Length; i++)
|
|
{
|
|
element.Add(HGXml.ToXml("PlayerInfo", playerInfos[i]));
|
|
}
|
|
}
|
|
|
|
public static bool ArrayFromXml(XElement element, ref PlayerInfo[] playerInfos)
|
|
{
|
|
playerInfos = (from e in element.Elements()
|
|
where e.Name == "PlayerInfo"
|
|
select e).Select(delegate(XElement e)
|
|
{
|
|
PlayerInfo value = null;
|
|
HGXml.FromXml(e, ref value);
|
|
return value;
|
|
}).ToArray();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private const string currentXmlVersion = "2";
|
|
|
|
public Guid runGuid;
|
|
|
|
private GameModeIndex gameModeIndex = GameModeIndex.Invalid;
|
|
|
|
public GameEndingDef gameEnding;
|
|
|
|
public ulong seed;
|
|
|
|
public DateTime runStartTimeUtc;
|
|
|
|
public DateTime snapshotTimeUtc;
|
|
|
|
public Run.FixedTimeStamp snapshotRunTime;
|
|
|
|
public float runStopwatchValue;
|
|
|
|
public RuleBook ruleBook = new RuleBook();
|
|
|
|
private PlayerInfo[] playerInfos = Array.Empty<PlayerInfo>();
|
|
|
|
private static string runReportsFolder;
|
|
|
|
public string gameModeName
|
|
{
|
|
get
|
|
{
|
|
return gameMode?.name ?? "InvalidGameMode";
|
|
}
|
|
set
|
|
{
|
|
gameMode = GameModeCatalog.FindGameModePrefabComponent(value);
|
|
}
|
|
}
|
|
|
|
public Run gameMode
|
|
{
|
|
get
|
|
{
|
|
return GameModeCatalog.GetGameModePrefabComponent(gameModeIndex);
|
|
}
|
|
set
|
|
{
|
|
gameModeIndex = value?.gameModeIndex ?? GameModeIndex.Invalid;
|
|
}
|
|
}
|
|
|
|
public int playerInfoCount => playerInfos.Length;
|
|
|
|
public static RunReport GetLocalUserRunReport(RunReport oldReport, LocalUser localUser)
|
|
{
|
|
if (localUser.id == 0 || oldReport.playerInfoCount == 1)
|
|
{
|
|
return oldReport;
|
|
}
|
|
PlayerInfo playerInfo = null;
|
|
int num = -1;
|
|
PlayerInfo playerInfo2 = null;
|
|
int num2 = -1;
|
|
for (int i = 0; i < oldReport.playerInfoCount; i++)
|
|
{
|
|
PlayerInfo playerInfo3 = oldReport.GetPlayerInfo(i);
|
|
if (playerInfo3.localPlayerIndex == 0)
|
|
{
|
|
playerInfo = playerInfo3;
|
|
num = i;
|
|
}
|
|
else if (playerInfo3.localPlayerIndex == localUser.id)
|
|
{
|
|
playerInfo2 = playerInfo3;
|
|
num2 = i;
|
|
}
|
|
}
|
|
oldReport.playerInfos[num] = playerInfo2;
|
|
oldReport.playerInfos[num2] = playerInfo;
|
|
return oldReport;
|
|
}
|
|
|
|
[NotNull]
|
|
public PlayerInfo GetPlayerInfo(int i)
|
|
{
|
|
return playerInfos[i];
|
|
}
|
|
|
|
[CanBeNull]
|
|
public PlayerInfo GetPlayerInfoSafe(int i)
|
|
{
|
|
return ArrayUtils.GetSafe(playerInfos, i);
|
|
}
|
|
|
|
public int FindPlayerIndex(LocalUser localUser)
|
|
{
|
|
if (localUser != null)
|
|
{
|
|
for (int i = 0; i < playerInfos.Length; i++)
|
|
{
|
|
if (playerInfos[i].localUser == localUser)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
public int FindPlayerIndex([CanBeNull] UserProfile userProfile)
|
|
{
|
|
if (userProfile != null)
|
|
{
|
|
for (int i = 0; i < playerInfos.Length; i++)
|
|
{
|
|
if (string.Equals(userProfile.fileName, playerInfos[i].userProfileFileName, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
public bool HasUserParticipated([CanBeNull] LocalUser localUser)
|
|
{
|
|
if (localUser != null)
|
|
{
|
|
for (int i = 0; i < playerInfos.Length; i++)
|
|
{
|
|
if (playerInfos[i].localPlayerIndex == localUser.id)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
[CanBeNull]
|
|
public PlayerInfo FindPlayerInfo(LocalUser localUser)
|
|
{
|
|
return ArrayUtils.GetSafe(playerInfos, FindPlayerIndex(localUser));
|
|
}
|
|
|
|
[CanBeNull]
|
|
public PlayerInfo FindPlayerInfo([CanBeNull] UserProfile userProfile)
|
|
{
|
|
return ArrayUtils.GetSafe(playerInfos, FindPlayerIndex(userProfile));
|
|
}
|
|
|
|
[CanBeNull]
|
|
public PlayerInfo FindFirstPlayerInfo()
|
|
{
|
|
if (playerInfoCount <= 0)
|
|
{
|
|
return null;
|
|
}
|
|
return playerInfos[0];
|
|
}
|
|
|
|
public static RunReport Generate([NotNull] Run run, GameEndingDef gameEnding)
|
|
{
|
|
RunReport runReport = new RunReport();
|
|
runReport.runGuid = run.GetUniqueId();
|
|
runReport.gameModeIndex = GameModeCatalog.FindGameModeIndex(run.gameObject.name);
|
|
runReport.seed = run.seed;
|
|
runReport.runStartTimeUtc = run.GetStartTimeUtc();
|
|
runReport.snapshotTimeUtc = DateTime.UtcNow;
|
|
runReport.snapshotRunTime = Run.FixedTimeStamp.now;
|
|
runReport.runStopwatchValue = run.GetRunStopwatch();
|
|
runReport.gameEnding = gameEnding;
|
|
runReport.ruleBook.Copy(run.ruleBook);
|
|
runReport.playerInfos = new PlayerInfo[PlayerCharacterMasterController.instances.Count];
|
|
for (int i = 0; i < runReport.playerInfos.Length; i++)
|
|
{
|
|
runReport.playerInfos[i] = PlayerInfo.Generate(PlayerCharacterMasterController.instances[i], gameEnding);
|
|
}
|
|
runReport.ResolveLocalInformation();
|
|
return runReport;
|
|
}
|
|
|
|
private void ResolveLocalInformation()
|
|
{
|
|
PlayerInfo[] array = playerInfos;
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
array[i].ResolveLocalInformation();
|
|
}
|
|
}
|
|
|
|
public void Write(NetworkWriter writer)
|
|
{
|
|
writer.WriteGuid(in runGuid);
|
|
writer.WritePackedIndex32((int)GameEndingCatalog.GetGameEndingIndex(gameEnding));
|
|
writer.WritePackedIndex32((int)gameModeIndex);
|
|
writer.Write(seed);
|
|
NetworkDateTime networkDateTime = (NetworkDateTime)runStartTimeUtc;
|
|
writer.Write(in networkDateTime);
|
|
networkDateTime = (NetworkDateTime)snapshotTimeUtc;
|
|
writer.Write(in networkDateTime);
|
|
writer.Write(snapshotRunTime);
|
|
writer.Write(runStopwatchValue);
|
|
writer.Write(ruleBook);
|
|
writer.Write((byte)playerInfos.Length);
|
|
for (int i = 0; i < playerInfos.Length; i++)
|
|
{
|
|
playerInfos[i].Write(writer);
|
|
}
|
|
}
|
|
|
|
public void Read(NetworkReader reader)
|
|
{
|
|
runGuid = reader.ReadGuid();
|
|
gameEnding = GameEndingCatalog.GetGameEndingDef((GameEndingIndex)reader.ReadPackedIndex32());
|
|
gameModeIndex = (GameModeIndex)reader.ReadPackedIndex32();
|
|
seed = reader.ReadUInt64();
|
|
runStartTimeUtc = (DateTime)reader.ReadNetworkDateTime();
|
|
snapshotTimeUtc = (DateTime)reader.ReadNetworkDateTime();
|
|
snapshotRunTime = reader.ReadFixedTimeStamp();
|
|
runStopwatchValue = reader.ReadSingle();
|
|
reader.ReadRuleBook(ruleBook);
|
|
int newSize = reader.ReadByte();
|
|
Array.Resize(ref playerInfos, newSize);
|
|
for (int i = 0; i < playerInfos.Length; i++)
|
|
{
|
|
if (playerInfos[i] == null)
|
|
{
|
|
playerInfos[i] = new PlayerInfo();
|
|
}
|
|
playerInfos[i].Read(reader);
|
|
}
|
|
SortByLocalPlayers();
|
|
}
|
|
|
|
public void SortByLocalPlayers()
|
|
{
|
|
Array.Sort(playerInfos, delegate(PlayerInfo a, PlayerInfo b)
|
|
{
|
|
if (a.isLocalPlayer == b.isLocalPlayer)
|
|
{
|
|
if (a.isLocalPlayer)
|
|
{
|
|
return a.localPlayerIndex - b.localPlayerIndex;
|
|
}
|
|
return 0;
|
|
}
|
|
return (!a.isLocalPlayer) ? 1 : (-1);
|
|
});
|
|
}
|
|
|
|
public static void ToXml(XElement element, RunReport runReport)
|
|
{
|
|
element.RemoveAll();
|
|
element.Add(HGXml.ToXml("version", "2"));
|
|
element.Add(HGXml.ToXml("runGuid", runReport.runGuid));
|
|
element.Add(HGXml.ToXml("gameModeName", runReport.gameModeName));
|
|
element.Add(HGXml.ToXml("gameEnding", runReport.gameEnding));
|
|
element.Add(HGXml.ToXml("seed", runReport.seed));
|
|
element.Add(HGXml.ToXml("runStartTimeUtc", runReport.runStartTimeUtc));
|
|
element.Add(HGXml.ToXml("snapshotTimeUtc", runReport.snapshotTimeUtc));
|
|
element.Add(HGXml.ToXml("snapshotRunTime", runReport.snapshotRunTime));
|
|
element.Add(HGXml.ToXml("runStopwatchValue", runReport.runStopwatchValue));
|
|
element.Add(HGXml.ToXml("ruleBook", runReport.ruleBook));
|
|
element.Add(HGXml.ToXml("playerInfos", runReport.playerInfos));
|
|
}
|
|
|
|
public static bool FromXml(XElement element, ref RunReport runReport)
|
|
{
|
|
string dest = "NO_VERSION";
|
|
element.Element("version")?.Deserialize(ref dest);
|
|
if (dest != "2" && !(dest == "1"))
|
|
{
|
|
Debug.LogFormat("Could not load RunReport with non-upgradeable version \"{0}\".", dest);
|
|
runReport = null;
|
|
return false;
|
|
}
|
|
element.Element("runGuid")?.Deserialize(ref runReport.runGuid);
|
|
string dest2 = runReport.gameModeName;
|
|
element.Element("gameModeName")?.Deserialize(ref dest2);
|
|
runReport.gameModeName = dest2;
|
|
element.Element("gameEnding")?.Deserialize(ref runReport.gameEnding);
|
|
element.Element("seed")?.Deserialize(ref runReport.seed);
|
|
element.Element("runStartTimeUtc")?.Deserialize(ref runReport.runStartTimeUtc);
|
|
element.Element("snapshotTimeUtc")?.Deserialize(ref runReport.snapshotTimeUtc);
|
|
element.Element("snapshotRunTime")?.Deserialize(ref runReport.snapshotRunTime);
|
|
element.Element("runStopwatchValue")?.Deserialize(ref runReport.runStopwatchValue);
|
|
element.Element("ruleBook")?.Deserialize(ref runReport.ruleBook);
|
|
element.Element("playerInfos")?.Deserialize(ref runReport.playerInfos);
|
|
return true;
|
|
}
|
|
|
|
[SystemInitializer(new Type[] { })]
|
|
private static void Init()
|
|
{
|
|
runReportsFolder = Application.dataPath + "/RunReports/";
|
|
HGXml.Register<RunReport>(ToXml, FromXml);
|
|
HGXml.Register<PlayerInfo>(PlayerInfo.ToXml, PlayerInfo.FromXml);
|
|
HGXml.Register<PlayerInfo[]>(PlayerInfo.ArrayToXml, PlayerInfo.ArrayFromXml);
|
|
}
|
|
|
|
[NotNull]
|
|
private static string FileNameToPath([NotNull] string fileName)
|
|
{
|
|
return string.Format(CultureInfo.InvariantCulture, "{0}{1}.xml", runReportsFolder, fileName);
|
|
}
|
|
|
|
[CanBeNull]
|
|
public static RunReport Load([NotNull] string fileName)
|
|
{
|
|
string text = FileNameToPath(fileName);
|
|
try
|
|
{
|
|
XElement xElement = XDocument.Load(text).Element("RunReport");
|
|
if (xElement == null)
|
|
{
|
|
Debug.LogFormat("Could not load RunReport {0}: {1}", text, "File is malformed.");
|
|
return null;
|
|
}
|
|
RunReport runReport = new RunReport();
|
|
FromXml(xElement, ref runReport);
|
|
return runReport;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogFormat("Could not load RunReport {0}: {1}", text, ex.Message);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static bool Save([NotNull] RunReport runReport, [NotNull] string fileName)
|
|
{
|
|
string text = FileNameToPath(fileName);
|
|
try
|
|
{
|
|
if (!Directory.Exists(runReportsFolder))
|
|
{
|
|
Directory.CreateDirectory(runReportsFolder);
|
|
}
|
|
XDocument xDocument = new XDocument();
|
|
xDocument.Add(HGXml.ToXml("RunReport", runReport));
|
|
xDocument.Save(text);
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogFormat("Could not save RunReport {0}: {1}", text, ex.Message);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static void TestSerialization(RunReport runReport)
|
|
{
|
|
NetworkWriter networkWriter = new NetworkWriter();
|
|
runReport.Write(networkWriter);
|
|
NetworkReader reader = new NetworkReader(networkWriter.AsArray());
|
|
new RunReport().Read(reader);
|
|
}
|
|
}
|