예제 #1
0
        public static void Reconstruct(string filepath, string animPath, string directory, string rootName)
        {
            var path = Path.GetDirectoryName(directory);

            HSDRawFile file = new HSDRawFile();

            HSDRootNode root = new HSDRootNode();

            root.Name = rootName;
            var ftData = new SBM_FighterData();

            root.Data = ftData;
            file.Roots.Add(root);
            var prop = root.Data.GetType().GetProperties().ToList();

            foreach (var f in Directory.GetFiles(directory))
            {
                if (f.EndsWith(".dat"))
                {
                    HSDRawFile chunk = new HSDRawFile(f);
                    Console.WriteLine(f + " " + chunk.Roots.Count);
                    var property = prop.Find(e => e.Name == chunk.Roots[0].Name);

                    if (property != null)
                    {
                        var newt = Activator.CreateInstance(property.PropertyType);
                        {
                            var dset = newt as HSDAccessor;
                            if (dset != null)
                            {
                                dset._s = chunk.Roots[0].Data._s;
                            }
                        }
                        property.SetValue(root.Data, newt);
                    }
                }
                else if (f.EndsWith(".ini"))
                {
                    SBM_CommonFighterAttributes attr = new SBM_CommonFighterAttributes();
                    using (StreamReader r = new StreamReader(new FileStream(f, FileMode.Open)))
                    {
                        foreach (var v in attr.GetType().GetProperties())
                        {
                            if (v.Name.Equals("TrimmedSize"))
                            {
                                continue;
                            }
                            var line = r.ReadLine().Split('=');
                            if (line.Length < 2 || line[0] != v.Name)
                            {
                                throw new InvalidDataException("Invalid Attribute " + string.Join("=", line));
                            }
                            if (v.PropertyType == typeof(int))
                            {
                                v.SetValue(attr, int.Parse(line[1].Trim()));
                            }
                            if (v.PropertyType == typeof(float))
                            {
                                v.SetValue(attr, float.Parse(line[1].Trim()));
                            }
                        }
                    }
                    ftData.Attributes = attr;
                }
                else if (f.EndsWith(".txt"))
                {
                    XmlSerializer writer = new XmlSerializer(typeof(ScriptFile));
                    var           script = (ScriptFile)writer.Deserialize(new FileStream(f, FileMode.Open));

                    Dictionary <string, Tuple <int, int> > animationToOffset = new Dictionary <string, Tuple <int, int> >();

                    List <SBM_FighterAction> SubActions = new List <SBM_FighterAction>();
                    Dictionary <SBM_FighterAction, string> subActionToScript = new Dictionary <SBM_FighterAction, string>();

                    Dictionary <string, HSDStruct> stringToStruct = new Dictionary <string, HSDStruct>();

                    using (BinaryWriter w = new BinaryWriter(new FileStream(animPath, FileMode.Create)))
                    {
                        foreach (var s in script.Actions)
                        {
                            SBM_FighterAction subaction = new SBM_FighterAction();
                            subaction.Flags = (uint)s.flags;
                            if (s.animation_name != null)
                            {
                                if (!stringToStruct.ContainsKey(s.animation_name))
                                {
                                    var    namestruct = new HSDStruct();
                                    byte[] data       = new byte[s.animation_name.Length + 1];
                                    var    bytes      = UTF8Encoding.UTF8.GetBytes(s.animation_name);
                                    for (int i = 0; i < s.animation_name.Length; i++)
                                    {
                                        data[i] = bytes[i];
                                    }
                                    namestruct.SetData(data);
                                    stringToStruct.Add(s.animation_name, namestruct);
                                }
                                subaction._s.SetReferenceStruct(0, stringToStruct[s.animation_name]);
                                //subaction.Name = s.animation_name;
                                if (!animationToOffset.ContainsKey(s.animation_name))
                                {
                                    if (File.Exists(path + "\\Animations\\" + s.animation_name + ".dat"))
                                    {
                                        var data = File.ReadAllBytes(path + "\\Animations\\" + s.animation_name + ".dat");
                                        animationToOffset.Add(s.animation_name, new Tuple <int, int>((int)w.BaseStream.Position, data.Length));
                                        w.Write(data);
                                        if (w.BaseStream.Length % 0x20 != 0)
                                        {
                                            var padd = new byte[0x20 - (w.BaseStream.Position % 0x20)];
                                            for (int i = 0; i < padd.Length; i++)
                                            {
                                                padd[i] = 0xFF;
                                            }
                                            w.Write(padd);
                                        }
                                    }
                                    else
                                    {
                                        throw new FileNotFoundException("Could not find animation " + path + "\\Animations\\" + s.animation_name + ".dat");
                                    }
                                }
                                subaction.AnimationOffset = animationToOffset[s.animation_name].Item1;
                                subaction.AnimationSize   = animationToOffset[s.animation_name].Item2;
                            }

                            if (s.script != null)
                            {
                                ActionCompiler.Compile(s.script);
                                subActionToScript.Add(subaction, s.script);
                            }

                            SubActions.Add(subaction);
                        }
                    }

                    ftData.FighterActionTable = new SBM_FighterActionTable();

                    ActionCompiler.LinkStructs();

                    ftData.FighterActionTable.Commands = SubActions.ToArray();

                    Console.WriteLine("recompiled count " + ftData.FighterActionTable._s.GetSubStructs().Count);
                }
            }

            file.Save(filepath);
        }
예제 #2
0
        /// <summary>
        /// Generates and saves a SEM file
        /// </summary>
        public static void SaveSEMFile(string path, List <SEMEntry> Entries, MEX_Data mexData)
        {
            if (mexData != null)
            {
                mexData.SSMTable.SSM_SSMFiles.Array    = new HSD_String[0];
                mexData.SSMTable.SSM_BufferSizes.Array = new MEX_SSMSizeAndFlags[0];
                mexData.SSMTable.SSM_LookupTable.Array = new MEX_SSMLookup[0];

                mexData.SSMTable.SSM_BufferSizes.Set(Entries.Count, new MEX_SSMSizeAndFlags()); // blank entry at end
                mexData.SSMTable.SSM_LookupTable.Set(Entries.Count, new MEX_SSMLookup());       // blank entry at beginning

                // generate runtime struct
                mexData.MetaData.NumOfSSMs = Entries.Count;

                HSDStruct rtTable = new HSDStruct(6 * 4);

                rtTable.SetReferenceStruct(0x00, new HSDStruct(GeneratePaddedBuffer(0x180, 0x01)));
                rtTable.SetReferenceStruct(0x04, new HSDStruct(GeneratePaddedBuffer(Entries.Count * 4, 0x02)));
                rtTable.SetReferenceStruct(0x08, new HSDStruct(GeneratePaddedBuffer(Entries.Count * 4, 0x03)));
                rtTable.SetReferenceStruct(0x0C, new HSDStruct(GeneratePaddedBuffer(Entries.Count * 4, 0x04)));
                rtTable.SetReferenceStruct(0x10, new HSDStruct(GeneratePaddedBuffer(Entries.Count * 4, 0x05)));
                rtTable.SetReferenceStruct(0x14, new HSDStruct(GeneratePaddedBuffer(Entries.Count * 4, 0x06)));

                mexData.SSMTable._s.SetReferenceStruct(0x0C, rtTable);
            }

            var soundOffset = 0;

            using (BinaryWriterExt w = new BinaryWriterExt(new FileStream(path, FileMode.Create)))
            {
                w.BigEndian = true;

                w.Write(0);
                w.Write(0);
                w.Write(Entries.Count);
                int index = 0;
                foreach (var e in Entries)
                {
                    w.Write(index);
                    index += e.Scripts.Length;
                }
                w.Write(index);

                var offset    = w.BaseStream.Position + 4 * index + 4;
                var dataindex = 0;

                foreach (var e in Entries)
                {
                    foreach (var v in e.Scripts)
                    {
                        w.Write((int)(offset + dataindex));
                        dataindex += v.CommandData.Length;
                    }
                }

                w.Write(0);

                int entryIndex = -1;
                foreach (var e in Entries)
                {
                    entryIndex++;
                    // fix sound offset ids
                    if (e.SoundBank != null)
                    {
                        // set start offset in sem and save
                        e.SoundBank.StartIndex = soundOffset;
                        int bufSize;
                        e.SoundBank.Save(Path.GetDirectoryName(path) + "\\" + e.SoundBank.Name, out bufSize);

                        if (mexData != null)
                        {
                            mexData.SSMTable.SSM_SSMFiles.Set(entryIndex, new HSD_String()
                            {
                                Value = e.SoundBank.Name
                            });
                            mexData.SSMTable.SSM_BufferSizes.Set(entryIndex, new MEX_SSMSizeAndFlags()
                            {
                                Flag = e.SoundBank.Flag, SSMFileSize = bufSize
                            });
                            var lu = new MEX_SSMLookup();
                            lu._s.SetInt32(0x00, e.SoundBank.GroupFlags);
                            mexData.SSMTable.SSM_LookupTable.Set(entryIndex, lu);
                        }

                        // add sound offset
                        foreach (var v in e.Scripts)
                        {
                            v.SoundCommandIndex += soundOffset;
                        }

                        foreach (var v in e.Scripts)
                        {
                            w.Write(v.CommandData);
                        }

                        //return to normal
                        foreach (var v in e.Scripts)
                        {
                            v.SoundCommandIndex -= soundOffset;
                        }

                        soundOffset += e.SoundBank.Sounds.Length;
                    }
                    else
                    {
                        foreach (var v in e.Scripts)
                        {
                            w.Write(v.CommandData);
                        }
                    }
                }
            }
        }
예제 #3
0
 public int GetStructLocation(HSDStruct str)
 {
     return(RawHSDFile.GetOffsetFromStruct(str));
 }
        /// <summary>
        ///
        /// </summary>
        /// <param name="output"></param>
        /// <param name="name"></param>
        /// <param name="datas"></param>
        /// <param name="structToFunctionName"></param>
        private void DecompileGroup(StringBuilder output, string name, HSDStruct datas)
        {
            if (structToFunctionName.ContainsKey(datas))
            {
                return;
            }
            structToFunctionName.Add(datas, name);

            output.AppendLine(name);
            output.AppendLine("{");
            using (BinaryReaderExt r = new BinaryReaderExt(new MemoryStream(datas.GetData())))
            {
                byte flag = (byte)(r.ReadByte() >> 2);

                var cmd = ActionCommon.GetMeleeCMDAction(flag);

                while (flag != 0)
                {
                    r.BaseStream.Position -= 1;
                    var size    = cmd.ByteSize;
                    var command = r.GetSection(r.Position, size);
                    r.Skip((uint)size);

                    if (flag == 5 || flag == 7) //goto
                    {
                        var re = datas.GetReference <HSDAccessor>((int)r.BaseStream.Position - 4);
                        if (re != null)
                        {
                            if (!tempStructToName.ContainsKey(re._s))
                            {
                                if (structToFunctionName.ContainsKey(re._s))
                                {
                                    tempStructToName.Add(re._s, structToFunctionName[re._s]);
                                }
                                else
                                {
                                    tempStructToName.Add(re._s, name + "_" + ((int)r.BaseStream.Position - 4).ToString("X4"));
                                }
                            }
                            var funcname = tempStructToName[re._s];
                            output.AppendLine("\t" + (flag == 5 ? "Goto" : "Subroutine") + "(" + funcname + ");");
                        }
                    }
                    else
                    {
                        output.AppendLine("\t" + DecompileCommand(command));
                    }

                    if (r.BaseStream.Position >= r.BaseStream.Length)
                    {
                        break;
                    }

                    flag = (byte)(r.ReadByte() >> 2);
                    cmd  = ActionCommon.GetMeleeCMDAction(flag);
                }
            }
            output.AppendLine("}");

            foreach (var re in datas.References)
            {
                DecompileGroup(output, name + "_" + re.Key.ToString("X4"), re.Value);
            }
        }
예제 #5
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="data"></param>
        private List <Command> GetCommands(HSDStruct str, SubactionGroup subGroup, Dictionary <HSDStruct, List <Command> > structToComman = null)
        {
            if (subGroup != SubactionGroup.Fighter)
            {
                return(new List <Command>());
            }

            if (structToComman == null)
            {
                structToComman = new Dictionary <HSDStruct, List <Command> >();
            }

            if (structToComman.ContainsKey(str))
            {
                return(structToComman[str]);
            }

            var data = str.GetData();

            var Commands = new List <Command>();

            structToComman.Add(str, Commands);

            for (int i = 0; i < data.Length;)
            {
                var sa = SubactionManager.GetSubaction(data[i], subGroup);

                var cmd = new Command();

                foreach (var r in str.References)
                {
                    if (r.Key >= i && r.Key < i + sa.ByteSize)
                    {
                        if (cmd.Reference != null)
                        {
                            throw new NotSupportedException("Multiple References not supported");
                        }
                        else
                        {
                            if (r.Value != str) // prevent self reference
                            {
                                cmd.Reference         = r.Value;
                                cmd.ReferenceCommands = GetCommands(cmd.Reference, subGroup, structToComman);
                            }
                        }
                    }
                }

                var sub = new byte[sa.ByteSize];

                if (i + sub.Length > data.Length)
                {
                    break;
                }

                for (int j = 0; j < sub.Length; j++)
                {
                    sub[j] = data[i + j];
                }

                cmd.Parameters = sa.GetParameters(sub);
                cmd.Action     = sa;
                Commands.Add(cmd);

                i += sa.ByteSize;

                if (sa.Code == 0)
                {
                    break;
                }
            }

            return(Commands);
        }
예제 #6
0
파일: RelocELF.cs 프로젝트: akaneia/MexTK
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public static HSDAccessor GenerateFunctionDAT(LinkedELF lelf, LinkFile link, string[] functions, bool debug, bool quiet = false)
        {
            // Generate Function DAT
            var function = new HSDAccessor()
            {
                _s = new HSDStruct(0x20)
            };

            // Generate code section
            HSDStruct debug_symbol_table = null;
            int       debug_symbol_count = 0;
            Dictionary <SymbolData, long> dataToOffset = new Dictionary <SymbolData, long>();

            byte[] codedata;
            using (MemoryStream code = new MemoryStream())
            {
                // create debug symbol table
                if (debug)
                {
                    debug_symbol_table = new HSDStruct((lelf.AllSymbols.Count + 1) * 0xC);
                }

                // process all code
                foreach (var v in lelf.AllSymbols)
                {
                    // align
                    if (code.Length % 4 != 0)
                    {
                        code.Write(new byte[4 - (code.Length % 4)], 0, 4 - ((int)code.Length % 4));
                    }

                    int code_start = (int)code.Position;
                    // write code
                    if (v.Data.Length == 0 && link.TryGetSymbolAddress(CppSanatize(v.Symbol), out uint addr))
                    {
                        dataToOffset.Add(v, addr);
                    }
                    else
                    {
                        dataToOffset.Add(v, code.Length);
                        code.Write(v.Data, 0, v.Data.Length);
                    }
                    int code_end = (int)code.Position;

                    //Console.WriteLine($"{v.SectionName} {v.Symbol} Start: {code_start.ToString("X")} End: {code_end.ToString("X")} ");

                    if (debug && code_start != code_end)
                    {
                        debug_symbol_table.SetInt32(debug_symbol_count * 0xC, code_start);
                        debug_symbol_table.SetInt32(debug_symbol_count * 0xC + 4, code_end);
                        debug_symbol_table.SetString(debug_symbol_count * 0xC + 8, string.IsNullOrEmpty(v.Symbol) ? v.SectionName : v.Symbol, true);
                        debug_symbol_count++;
                    }
                }
                codedata = code.ToArray();

                // resize debug table
                if (debug)
                {
                    debug_symbol_table.Resize(debug_symbol_count * 0xC);
                }
            }

            // generate function table
            HSDStruct functionTable = new HSDStruct(8);
            var       funcCount     = 0;
            var       fl            = functions.ToList();

            foreach (var v in lelf.SymbolToData)
            {
                functionTable.Resize(8 * (funcCount + 1));
                functionTable.SetInt32(funcCount * 8, fl.IndexOf(v.Key));
                functionTable.SetInt32(funcCount * 8 + 4, (int)dataToOffset[v.Value]);
                funcCount++;
            }


            // set function table
            function._s.SetReferenceStruct(0x0C, functionTable);
            function._s.SetInt32(0x10, funcCount);


            // Generate Relocation Table
            HSDStruct relocationTable = new HSDStruct(0);
            var       relocCount      = 0;

            foreach (var v in lelf.AllSymbols)
            {
                // check data length
                if (v.Data.Length == 0)
                {
                    if (link.ContainsSymbol(CppSanatize(v.Symbol)))
                    {
                        continue;
                    }
                    else
                    {
                        throw new Exception($"Error: {v.Symbol} length is {v.Data.Length.ToString("X")}");
                    }
                }

                // print debug info
                if (!quiet)
                {
                    Console.WriteLine($"{v.Symbol,-30} {v.SectionName, -50} Offset: {dataToOffset[v].ToString("X8"), -16} Length: {v.Data.Length.ToString("X8")}");

                    if (v.Relocations.Count > 0)
                    {
                        Console.WriteLine($"\t {"Section:",-50} {"RelocType:",-20} {"FuncOffset:", -16} {"SectionOffset:"}");
                    }
                }

                // process and create relocation table
                foreach (var reloc in v.Relocations)
                {
                    if (!quiet)
                    {
                        Console.WriteLine($"\t {reloc.Symbol.SectionName, -50} {reloc.Type, -20} {reloc.Offset.ToString("X8"), -16} {reloc.AddEnd.ToString("X8")}");
                    }

                    // gather code positions
                    var codeOffset       = (int)(dataToOffset[v] + reloc.Offset);
                    var toFunctionOffset = (int)(dataToOffset[reloc.Symbol] + reloc.AddEnd);

                    // currently supported types check
                    switch (reloc.Type)
                    {
                    case RelocType.R_PPC_REL32:
                    case RelocType.R_PPC_REL24:
                    case RelocType.R_PPC_ADDR32:
                    case RelocType.R_PPC_ADDR16_LO:
                    case RelocType.R_PPC_ADDR16_HA:
                        break;

                    case (RelocType)0x6D:
                        break;

                    default:
                        // no exception, but not guarenteed to work
                        Console.WriteLine($"Warning: unsupported reloc type {toFunctionOffset.ToString("X")} " + reloc.Type.ToString("X") + $" in {v.Symbol} to {reloc.Symbol.Symbol} send this to Ploaj or UnclePunch");
                        break;
                    }

                    bool addEntry = true;

                    // only apply optimization if not external
                    if (!reloc.Symbol.External)
                    {
                        // calculate relative offset
                        var rel = toFunctionOffset - codeOffset;

                        // apply relocation automatically if possible
                        switch (reloc.Type)
                        {
                        case (RelocType)0x6D:
                        case RelocType.R_PPC_REL32:
                            codedata[codeOffset]     = (byte)((rel >> 24) & 0xFF);
                            codedata[codeOffset + 1] = (byte)((rel >> 16) & 0xFF);
                            codedata[codeOffset + 2] = (byte)((rel >> 8) & 0xFF);
                            codedata[codeOffset + 3] = (byte)((rel) & 0xFF);

                            addEntry = false;
                            break;

                        case RelocType.R_PPC_REL24:
                            var cur = ((codedata[codeOffset] & 0xFF) << 24) | ((codedata[codeOffset + 1] & 0xFF) << 16) | ((codedata[codeOffset + 2] & 0xFF) << 8) | ((codedata[codeOffset + 3] & 0xFF));
                            rel = cur | (rel & 0x03FFFFFC);

                            codedata[codeOffset]     = (byte)((rel >> 24) & 0xFF);
                            codedata[codeOffset + 1] = (byte)((rel >> 16) & 0xFF);
                            codedata[codeOffset + 2] = (byte)((rel >> 8) & 0xFF);
                            codedata[codeOffset + 3] = (byte)((rel) & 0xFF);

                            addEntry = false;
                            break;
                        }
                    }

                    // add relocation to table
                    if (addEntry)
                    {
                        relocationTable.Resize((relocCount + 1) * 0x08);
                        relocationTable.SetInt32(0x00 + relocCount * 8, codeOffset);
                        relocationTable.SetByte(0x00 + relocCount * 8, (byte)reloc.Type);
                        relocationTable.SetInt32(0x04 + relocCount * 8, toFunctionOffset);

                        relocCount++;
                    }
                }
            }

            function._s.SetReferenceStruct(0x00, new HSDStruct(codedata));
            function._s.SetReferenceStruct(0x04, relocationTable);
            function._s.SetInt32(0x08, relocCount);

            if (debug_symbol_table != null)
            {
                function._s.SetInt32(0x14, codedata.Length);
                function._s.SetInt32(0x18, debug_symbol_count);
                function._s.SetReferenceStruct(0x1C, debug_symbol_table);
            }

            return(function);
        }
예제 #7
0
        /// <summary>
        /// Compiles script into subaction byte code
        /// </summary>
        public static void Compile(string script)
        {
            if (scriptToBinary.ContainsKey(script) || scriptToReference.ContainsKey(script))
            {
                return;
            }

            HSDStruct main = null;

            var stream = Regex.Replace(script, @"\s+", string.Empty);

            if (script.StartsWith("ref:"))
            {
                var name = stream.Split(':')[1];
                scriptToReference.Add(script, name);
                return;
            }

            var functions = Regex.Matches(stream, @"([^\{])*\{([^\}]*)\}");

            foreach (Match g in functions)
            {
                var name = Regex.Match(g.Value, @".+?(?={)").Value;
                var code = Regex.Match(g.Value, @"(?<=\{).+?(?=\})").Value.Split(';');

                if (nameToFunction.ContainsKey(name))
                {
                    continue;
                }

                HSDStruct s = new HSDStruct();
                nameToFunction.Add(name, s);
                structToOffsetToFunction.Add(s, new Dictionary <int, string>());

                if (main == null)
                {
                    main = s;
                }

                List <byte> output   = new List <byte>();
                bool        returned = false;
                foreach (var c in code)
                {
                    var cname       = Regex.Match(c, @".+?(?=\()").Value;
                    var cparameters = Regex.Match(c, @"(?<=\().+?(?=\))").Value.Split(',');

                    if (cname == "Return")
                    {
                        returned = true;
                    }

                    byte flag = ActionCommon.GetMeleeCMDAction(cname).Command;

                    if (flag == 0x5 || flag == 0x7) //goto and subroutine
                    {
                        structToOffsetToFunction[s].Add(output.Count + 4, cparameters[0]);
                        output.AddRange(new byte[] { (byte)(flag << 2), 0, 0, 0, 0, 0, 0, 0 });
                    }
                    else
                    {
                        output.AddRange(CompileCommand(cname, cparameters));
                    }

                    // padd
                    if (output.Count % 4 != 0)
                    {
                        output.AddRange(new byte[4 - (output.Count % 4)]);
                    }
                }
                if (true)
                {
                    output.Add(0);
                    if (output.Count % 4 != 0)
                    {
                        output.AddRange(new byte[4 - (output.Count % 4)]);
                    }
                }
                s.SetData(output.ToArray());
            }

            if (main == null)
            {
                main = new HSDStruct(4);
            }

            scriptToBinary.Add(script, main);
        }