/// <summary> /// Applies metadata to an in-memory ESD, adding additional info. /// </summary> public static void Apply(SoulsFormats.ESD.ESD esd, ESDMetadata meta) { if (meta.ESDHash.Trim().ToUpper() != esd.LastSavedHash.Trim().ToUpper()) { throw new Exception("MD5 Hash of ESD file does not match that of the saved metadata. Metadata was not made for this ESD file."); } esd.StateGroupNames = meta.StateGroupNames; foreach (var g in esd.StateGroups.Keys) { foreach (var s in esd.StateGroups[g].Keys) { esd.StateGroups[g][s].Name = meta.StateMetadatas[g][s].Name; esd.StateGroups[g][s].EntryScript = meta.StateMetadatas[g][s].EntryScript; esd.StateGroups[g][s].ExitScript = meta.StateMetadatas[g][s].ExitScript; esd.StateGroups[g][s].WhileScript = meta.StateMetadatas[g][s].WhileScript; } } foreach (var g in esd.GetAllConditions()) { foreach (var c in g.Value) { c.Name = meta.ConditionMetadatas[c.MetaRefID].Name; c.Evaluator = meta.ConditionMetadatas[c.MetaRefID].Evaluator; c.PassScript = meta.ConditionMetadatas[c.MetaRefID].PassScript; } } }
private static ESDMetadata InnerReadFromBinary(string binFileName) { var meta = new ESDMetadata(); using (var fileStream = System.IO.File.Open(binFileName, System.IO.FileMode.Open, System.IO.FileAccess.Read)) { var br = new BinaryReaderEx(bigEndian: false, stream: fileStream); br.AssertASCII("ESD_META"); br.AssertInt64(CURRENT_BINARY_VERSION); meta.ESDHash = br.ReadASCII(); int stateGroupCount = br.ReadInt32(); for (int i = 0; i < stateGroupCount; i++) { long stateGroupID = br.ReadInt64(); string stateGroupName = br.ReadShiftJIS(); meta.StateGroupNames.Add(stateGroupID, stateGroupName); meta.StateMetadatas.Add(stateGroupID, new Dictionary <long, StateMetadata>()); int stateCount = br.ReadInt32(); for (int j = 0; j < stateCount; j++) { long stateID = br.ReadInt64(); string stateName = br.ReadShiftJIS(); string stateEntryScript = br.ReadShiftJIS(); string stateExitScript = br.ReadShiftJIS(); string stateWhileScript = br.ReadShiftJIS(); meta.StateMetadatas[stateGroupID].Add(stateID, new StateMetadata() { Name = stateName, EntryScript = stateEntryScript, ExitScript = stateExitScript, WhileScript = stateWhileScript, }); } } int conditionCount = br.ReadInt32(); for (int i = 0; i < conditionCount; i++) { long conditionID = br.ReadInt64(); string conditionName = br.ReadShiftJIS(); string conditionEvaluator = br.ReadShiftJIS(); string conditionPassScript = br.ReadShiftJIS(); meta.ConditionMetadatas.Add(conditionID, new ConditionMetadata() { Name = conditionName, Evaluator = conditionEvaluator, PassScript = conditionPassScript, }); } } return(meta); }
private static ESDMetadata InnerReadFromXml(string xmlFileName) { var meta = new ESDMetadata(); XmlDocument xml = new XmlDocument(); xml.Load(xmlFileName); meta.ESDHash = xml.SelectSingleNode("EzStateMetadata").Attributes["Hash"].InnerText; foreach (XmlNode groupNode in xml.SelectNodes("EzStateMetadata/StateGroups/StateGroup")) { long stateGroupID = long.Parse(groupNode.Attributes["ID"].InnerText); string stateGroupName = groupNode.Attributes["Name"].InnerText; meta.StateGroupNames.Add(stateGroupID, stateGroupName); meta.StateMetadatas.Add(stateGroupID, new Dictionary <long, StateMetadata>()); foreach (XmlNode stateNode in groupNode.SelectNodes("States/State")) { long stateID = long.Parse(stateNode.Attributes["ID"].InnerText); string stateName = stateNode.Attributes["Name"].InnerText; string stateEntryScript = stateNode.SelectSingleNode("EntryScript").InnerText; string stateExitScript = stateNode.SelectSingleNode("ExitScript").InnerText; string stateWhileScript = stateNode.SelectSingleNode("WhileScript").InnerText; meta.StateMetadatas[stateGroupID].Add(stateID, new StateMetadata() { Name = stateName, EntryScript = stateEntryScript, ExitScript = stateExitScript, WhileScript = stateWhileScript, }); } } foreach (XmlNode conditionNode in xml.SelectNodes("EzStateMetadata/Conditions/Condition")) { long conditionID = long.Parse(conditionNode.Attributes["ID"].InnerText); string conditionName = conditionNode.Attributes["Name"].InnerText; string conditionEvaluator = conditionNode.SelectSingleNode("Evaluator").InnerText; string conditionPassScript = conditionNode.SelectSingleNode("PassScript").InnerText; meta.ConditionMetadatas.Add(conditionID, new ConditionMetadata() { Name = conditionName, Evaluator = conditionEvaluator, PassScript = conditionPassScript, }); } return(meta); }
/// <summary> /// Creates a new ESD with the given format and no state groups. /// </summary> public ESD(ESDFormatType formatType, int darkSoulsCount) { FormatType = formatType; DarkSoulsCount = darkSoulsCount; Name = null; Unk6C = 1; Unk70 = 0; Unk74 = 0; Unk78 = 0; Unk7C = 0; StateGroups = new Dictionary <long, Dictionary <long, State> >(); StateGroupNames = new Dictionary <long, string>(); Metadata = new ESDMetadata(); LastSavedHash = ""; }
/// <summary> /// Generates metadata based on the in-memory ESD file. /// </summary> public static ESDMetadata Generate(SoulsFormats.ESD.ESD esd) { var meta = new ESDMetadata(); meta.ESDHash = esd.LastSavedHash; meta.StateGroupNames = esd.StateGroupNames; foreach (var g in esd.StateGroups.Keys) { meta.StateMetadatas.Add(g, new Dictionary <long, StateMetadata>()); foreach (var s in esd.StateGroups[g].Keys) { meta.StateMetadatas[g].Add(s, new StateMetadata() { Name = esd.StateGroups[g][s].Name, EntryScript = esd.StateGroups[g][s].EntryScript, ExitScript = esd.StateGroups[g][s].ExitScript, WhileScript = esd.StateGroups[g][s].WhileScript, }); } } foreach (var g in esd.GetAllConditions()) { foreach (var c in g.Value) { meta.ConditionMetadatas.Add(c.MetaRefID, new ConditionMetadata() { Name = c.Name, Evaluator = c.Evaluator, PassScript = c.PassScript, }); } } return(meta); }
public void ImportNamesFromOther(ESDMetadata other) { foreach (var kvp in other.StateGroupNames) { StateGroupNames[kvp.Key] = kvp.Value; } foreach (var g in other.StateMetadatas.Keys) { foreach (var s in other.StateMetadatas[g].Keys) { StateMetadatas[g][s].Name = other.StateMetadatas[g][s].Name; } } var thisCondKeys = ConditionMetadatas.Keys.ToList(); var otherValues = other.ConditionMetadatas.Values.ToList(); for (int i = 0; i < otherValues.Count; i++) { var matchingKey = thisCondKeys[i]; ConditionMetadatas[matchingKey].Name = otherValues[i].Name; } }
/// <summary> /// Loads metadata from the specified file and applies it to this ESD file. /// </summary> public void LoadAndApplyMetadataFile(string filePath, bool isBinary) { var meta = ESDMetadata.Read(filePath, isBinary); ApplyMetadata(meta); }
/// <summary> /// Applies metadata to this ESD file. /// Warning: If anything has been modified in this ESD file since it was opened, /// this metadata will no longer be valid! /// </summary> public void ApplyMetadata(ESDMetadata meta) { ESDMetadata.Apply(this, meta); }
public void WriteWithContext(BinaryWriterEx bw, EzSembleContext context) { bw.WriteASCII(ESDMagicByFormat[FormatType]); bw.BigEndian = (FormatType == ESDFormatType.BigEndian32Bit || FormatType == ESDFormatType.BigEndian64Bit); context.IsBigEndian = bw.BigEndian; bw.WriteInt32(1); bw.WriteInt32(DarkSoulsCount); bw.WriteInt32(DarkSoulsCount); bw.WriteInt32(0x54); bw.ReserveInt32("DataSize"); bw.WriteInt32(6); bw.WriteInt32(LongFormat ? 0x48 : 0x2C); bw.WriteInt32(1); bw.WriteInt32(LongFormat ? 0x20 : 0x10); bw.WriteInt32(StateGroups.Count); int stateSize = LongFormat ? 0x48 : 0x24; bw.WriteInt32(stateSize); bw.WriteInt32(StateGroups.Values.Sum(sg => sg.Count + (sg.Count == 1 ? 0 : 1))); bw.WriteInt32(LongFormat ? 0x38 : 0x1C); bw.ReserveInt32("ConditionCount"); bw.WriteInt32(LongFormat ? 0x18 : 0x10); bw.ReserveInt32("CommandCallCount"); bw.WriteInt32(LongFormat ? 0x10 : 0x8); bw.ReserveInt32("CommandArgCount"); bw.ReserveInt32("ConditionOffsetsOffset"); bw.ReserveInt32("ConditionOffsetsCount"); bw.ReserveInt32("NameBlockOffset"); bw.WriteInt32(Name == null ? 0 : Name.Length + 1); bw.ReserveInt32("UnkOffset1"); bw.WriteInt32(0); bw.ReserveInt32("UnkOffset2"); bw.WriteInt32(0); long dataStart = bw.Position; bw.WriteInt32(Unk6C); bw.WriteInt32(Unk70); bw.WriteInt32(Unk74); bw.WriteInt32(Unk78); bw.WriteInt32(Unk7C); if (LongFormat) { bw.WriteInt32(0); } ReserveVarint(bw, LongFormat, "StateGroupsOffset"); WriteVarint(bw, LongFormat, StateGroups.Count); ReserveVarint(bw, LongFormat, "NameOffset"); WriteVarint(bw, LongFormat, Name == null ? 0 : Name.Length + 1); long unkNull = DarkSoulsCount == 1 ? 0 : -1; WriteVarint(bw, LongFormat, unkNull); WriteVarint(bw, LongFormat, unkNull); // Collect and sort all the IDs so everything is definitely in the same order everywhere List <long> stateGroupIDs = StateGroups.Keys.ToList(); stateGroupIDs.Sort(); var stateIDs = new Dictionary <long, List <long> >(); foreach (long groupID in stateGroupIDs) { stateIDs[groupID] = StateGroups[groupID].Keys.ToList(); stateIDs[groupID].Sort(); } if (StateGroups.Count == 0) { FillVarint(bw, LongFormat, "StateGroupsOffset", -1); } else { FillVarint(bw, LongFormat, "StateGroupsOffset", bw.Position - dataStart); foreach (long groupID in stateGroupIDs) { WriteVarint(bw, LongFormat, groupID); ReserveVarint(bw, LongFormat, $"StateGroup{groupID}:StatesOffset1"); WriteVarint(bw, LongFormat, StateGroups[groupID].Count); ReserveVarint(bw, LongFormat, $"StateGroup{groupID}:StatesOffset2"); } } var stateOffsets = new Dictionary <long, Dictionary <long, long> >(); var weirdStateOffsets = new List <long[]>(); foreach (long groupID in stateGroupIDs) { stateOffsets[groupID] = new Dictionary <long, long>(); FillVarint(bw, LongFormat, $"StateGroup{groupID}:StatesOffset1", bw.Position - dataStart); FillVarint(bw, LongFormat, $"StateGroup{groupID}:StatesOffset2", bw.Position - dataStart); long firstStateOffset = bw.Position; foreach (long stateID in stateIDs[groupID]) { stateOffsets[groupID][stateID] = bw.Position - dataStart; StateGroups[groupID][stateID].WriteHeader(context, bw, LongFormat, groupID, stateID); } if (StateGroups[groupID].Count > 1) { weirdStateOffsets.Add(new long[] { firstStateOffset, bw.Position }); bw.Position += stateSize; } } // Make a list of every unique condition var conditions = new Dictionary <long, List <Condition> >(); foreach (long groupID in stateGroupIDs) { conditions[groupID] = new List <Condition>(); void addCondition(Condition cond) { if (!conditions[groupID].Any(c => ReferenceEquals(cond, c))) { conditions[groupID].Add(cond); foreach (Condition subCond in cond.Subconditions) { addCondition(subCond); } } } foreach (State state in StateGroups[groupID].Values) { foreach (Condition cond in state.Conditions) { addCondition(cond); } } } bw.FillInt32("ConditionCount", conditions.Values.Sum(group => group.Count)); // Yes, I do in fact want this to be keyed by reference var conditionOffsets = new Dictionary <Condition, long>(); foreach (long groupID in stateGroupIDs) { for (int i = 0; i < conditions[groupID].Count; i++) { Condition cond = conditions[groupID][i]; cond.MetaRefID = conditionOffsets[cond] = bw.Position - dataStart; cond.WriteHeader(context, bw, LongFormat, groupID, i, stateOffsets[groupID]); } } var commands = new List <CommandCall>(); foreach (long groupID in stateGroupIDs) { foreach (long stateID in stateIDs[groupID]) { StateGroups[groupID][stateID].WriteCommandCalls(context, bw, LongFormat, groupID, stateID, dataStart, commands); } for (int i = 0; i < conditions[groupID].Count; i++) { conditions[groupID][i].WriteCommandCalls(context, bw, LongFormat, groupID, i, dataStart, commands); } } bw.FillInt32("CommandCallCount", commands.Count); bw.FillInt32("CommandArgCount", commands.Sum(command => command.Arguments.Count)); for (int i = 0; i < commands.Count; i++) { commands[i].WriteArgs(context, bw, LongFormat, i, dataStart); } bw.FillInt32("ConditionOffsetsOffset", (int)(bw.Position - dataStart)); int conditionOffsetsCount = 0; foreach (long groupID in stateGroupIDs) { foreach (long stateID in stateIDs[groupID]) { conditionOffsetsCount += StateGroups[groupID][stateID].WriteConditionOffsets(bw, LongFormat, groupID, stateID, dataStart, conditionOffsets); } for (int i = 0; i < conditions[groupID].Count; i++) { conditionOffsetsCount += conditions[groupID][i].WriteConditionOffsets(bw, LongFormat, groupID, i, dataStart, conditionOffsets); } } bw.FillInt32("ConditionOffsetsCount", conditionOffsetsCount); foreach (long groupID in stateGroupIDs) { for (int i = 0; i < conditions[groupID].Count; i++) { conditions[groupID][i].WriteEvaluator(context, bw, LongFormat, groupID, i, dataStart); } } for (int i = 0; i < commands.Count; i++) { commands[i].WriteBytecode(context, bw, LongFormat, i, dataStart); } bw.FillInt32("NameBlockOffset", (int)(bw.Position - dataStart)); if (Name == null) { FillVarint(bw, LongFormat, "NameOffset", -1); } else { bw.Pad(2); FillVarint(bw, LongFormat, "NameOffset", bw.Position - dataStart); bw.WriteUTF16(Name, true); } bw.FillInt32("UnkOffset1", (int)(bw.Position - dataStart)); bw.FillInt32("UnkOffset2", (int)(bw.Position - dataStart)); bw.FillInt32("DataSize", (int)(bw.Position - dataStart)); if (DarkSoulsCount == 1) { bw.Pad(4); } else if (DarkSoulsCount == 2) { bw.Pad(0x10); } foreach (long[] offsets in weirdStateOffsets) { bw.Position = offsets[0]; byte[] bytes = new byte[stateSize]; bw.Stream.Read(bytes, 0, stateSize); bw.Position = offsets[1]; bw.WriteBytes(bytes); } LastSavedHash = bw.GetMD5HashOfStream(); Metadata = ESDMetadata.Generate(this); }