예제 #1
0
        /// <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;
                }
            }
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
 /// <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   = "";
 }
예제 #5
0
        /// <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);
        }
예제 #6
0
        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;
            }
        }
예제 #7
0
        /// <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);
        }
예제 #8
0
 /// <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);
 }
예제 #9
0
        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);
        }