internal CompiledState(EzSembleContext context, State s) { try { EntryCommands = EzSembler.AssembleCommandScript(context, s.EntryScript); } catch (Exception ex) { context.Debug_StateSaveError(ex, "Failed to compile state entry script."); } try { ExitCommands = EzSembler.AssembleCommandScript(context, s.ExitScript); } catch (Exception ex) { context.Debug_StateSaveError(ex, "Failed to compile state exit script."); } try { WhileCommands = EzSembler.AssembleCommandScript(context, s.WhileScript); } catch (Exception ex) { context.Debug_StateSaveError(ex, "Failed to compile state while script."); } }
public static ESD ReadWithContext(string path, EzSembleContext context) { using (FileStream stream = File.OpenRead(path)) { BinaryReaderEx br = new BinaryReaderEx(false, stream); ESD file = new ESD(); br = SFUtil.GetDecompressedBR(br, out file.Compression); file.ReadWithContext(br, context); return(file); } }
byte[] WriteESD(ESDL esd) { EzSembleContext context = EzSembleContext.LoadFromXml(docPath); // ESD esd = new ESD(); using (MemoryStream stream = new MemoryStream()) { esd.WriteWithContext(new BinaryWriterEx(false, stream), context); return(stream.ToArray()); } }
private EzSembleContext LoadContext(ESDOptions.CmdType type) { if (contexts.TryGetValue(type, out EzSembleContext context)) { return(context); } string docPath = $@"dist\ESDScriptingDocumentation_{type}.xml"; context = contexts[type] = EzSembleContext.LoadFromXml(docPath); return(context); }
private ESDL ReadESD(byte[] data, string path, int check = -1) { if (check > 1) { int esdId = int.Parse(path.Substring(1)); if (esdId != check) { return(null); } } EzSembleContext context = EzSembleContext.LoadFromXml(docPath); ESDL esd = new ESDL(); esd.ReadWithContext(new BinaryReaderEx(false, data), context); return(esd); }
/// <summary> /// Writes this ESD file to the specified path, saving its metadata to "<ESDFileName>.meta". /// </summary> public void WriteWithMetadata(string path, bool isBinaryMetadata, EzSembleContext context) { using (MemoryStream corruptPreventStream = new MemoryStream()) { BinaryWriterEx bw = new BinaryWriterEx(false, corruptPreventStream); WriteWithContext(bw, context); corruptPreventStream.Position = 0; using (FileStream actualFileStream = File.Create(path)) { corruptPreventStream.CopyTo(actualFileStream); } bw.Finish(); } SaveMetadataFile(path + ".meta", isBinaryMetadata); }
internal CompiledCondition(EzSembleContext context, Condition c) { PassCommands = EzSembler.AssembleCommandScript(context, c.PassScript); Evaluator = EzSembler.AssembleExpression(context, c.Evaluator); }
internal CompiledState(EzSembleContext context, State s) { EntryCommands = EzSembler.AssembleCommandScript(context, s.EntryScript); ExitCommands = EzSembler.AssembleCommandScript(context, s.ExitScript); WhileCommands = EzSembler.AssembleCommandScript(context, s.WhileScript); }
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); }
public void ReadWithContext(BinaryReaderEx br, EzSembleContext context) { LastSavedHash = br.GetMD5HashOfStream(); string magic = br.AssertASCII("fSSL", "fsSL", "FSSL", "FsSL"); FormatType = ESDFormatByMagic[magic]; br.BigEndian = (FormatType == ESDFormatType.BigEndian32Bit || FormatType == ESDFormatType.BigEndian64Bit); context.IsBigEndian = br.BigEndian; br.AssertInt32(1); DarkSoulsCount = br.AssertInt32(1, 2, 3); br.AssertInt32(DarkSoulsCount); br.AssertInt32(0x54); int dataSize = br.ReadInt32(); br.AssertInt32(6); br.AssertInt32(LongFormat ? 0x48 : 0x2C); br.AssertInt32(1); int stateGroupSize = br.AssertInt32(LongFormat ? 0x20 : 0x10); int stateGroupCount = br.ReadInt32(); int stateSize = br.AssertInt32(LongFormat ? 0x48 : 0x24); int stateCount = br.ReadInt32(); br.AssertInt32(LongFormat ? 0x38 : 0x1C); int conditionCount = br.ReadInt32(); br.AssertInt32(LongFormat ? 0x18 : 0x10); int commandCallCount = br.ReadInt32(); br.AssertInt32(LongFormat ? 0x10 : 0x8); int commandArgCount = br.ReadInt32(); int conditionOffsetsOffset = br.ReadInt32(); int conditionOffsetsCount = br.ReadInt32(); int nameBlockOffset = br.ReadInt32(); int nameLength = br.ReadInt32(); int unkOffset1 = br.ReadInt32(); br.AssertInt32(0); int unkOffset2 = br.ReadInt32(); br.AssertInt32(0); long dataStart = br.Position; Unk6C = br.AssertInt32(1, 0); Unk70 = br.ReadInt32(); Unk74 = br.ReadInt32(); Unk78 = br.ReadInt32(); Unk7C = br.ReadInt32(); if (LongFormat) { br.AssertInt32(0); } long stateGroupsOffset = ReadVarint(br, LongFormat); AssertVarint(br, LongFormat, stateGroupCount); long nameOffset = ReadVarint(br, LongFormat); AssertVarint(br, LongFormat, nameLength); long unkNull = DarkSoulsCount == 1 ? 0 : -1; AssertVarint(br, LongFormat, unkNull); AssertVarint(br, LongFormat, unkNull); if (nameLength > 0) { Name = br.GetUTF16(dataStart + nameOffset); } else { Name = null; } var stateGroupOffsets = new Dictionary <long, long[]>(stateGroupCount); for (int i = 0; i < stateGroupCount; i++) { long id = ReadVarint(br, LongFormat); long[] stateOffsets = ReadStateGroup(br, LongFormat, dataStart, stateSize); if (stateGroupOffsets.ContainsKey(id)) { throw new FormatException("Duplicate state group ID."); } stateGroupOffsets[id] = stateOffsets; } var states = new Dictionary <long, State>(stateCount); for (int i = 0; i < stateCount; i++) { states[br.Position - dataStart] = new State(context, br, LongFormat, dataStart); } var conditions = new Dictionary <long, Condition>(conditionCount); for (int i = 0; i < conditionCount; i++) { conditions[br.Position - dataStart] = new Condition(context, br, LongFormat, dataStart); } foreach (State state in states.Values) { state.GetConditions(conditions); } StateGroups = new Dictionary <long, Dictionary <long, State> >(stateGroupCount); var groupedStateOffsets = new Dictionary <long, Dictionary <long, long> >(); foreach (long stateGroupID in stateGroupOffsets.Keys) { long[] stateOffsets = stateGroupOffsets[stateGroupID]; Dictionary <long, State> stateGroup = TakeStates(stateSize, stateOffsets, states, out Dictionary <long, long> stateIDs); StateGroups[stateGroupID] = stateGroup; groupedStateOffsets[stateGroupID] = stateIDs; foreach (State state in stateGroup.Values) { foreach (Condition condition in state.Conditions) { condition.GetStateAndConditions(stateIDs, conditions); } } } if (states.Count > 0) { throw new FormatException("Orphaned states found."); } foreach (var s in conditions) { s.Value.MetaRefID = s.Key; s.Value.Name = $"Condition[{s.Key:X8}]"; } foreach (var g in StateGroups.Keys) { foreach (var s in StateGroups[g]) { s.Value.Name = $"State{g}-{s.Value.ID}"; } } StateGroupNames.Clear(); foreach (var g in StateGroups) { StateGroupNames.Add(g.Key, $"StateGroup{g.Key}"); } }
/// <summary> /// Loads an ESD file from the specified path, loading the metadata along with it if applicable "<ESDFileName>.meta". /// If no metadata exists, generates default metadata. /// If metadata does not exist, an exception is thrown if <paramref name="assertMetadataExists"/> is true, /// and default metadata is generated if it is false. /// </summary> public static ESD ReadWithMetadata(string path, bool isBinaryMetadata, bool assertMetadataExists, EzSembleContext context) { var esd = ESD.ReadWithContext(path, context); if (System.IO.File.Exists(path + ".meta")) { esd.LoadAndApplyMetadataFile(path + ".meta", isBinaryMetadata); } else if (assertMetadataExists) { throw new Exception($"Metadata file did not exist and {nameof(assertMetadataExists)} was true."); } return(esd); }