예제 #1
0
        public void UnpackEvent(Event evt, StringBuilder code, bool compatibilityMode = false)
        {
            CurrentEventID = (int)evt.ID;

            string id           = evt.ID.ToString();
            string restBehavior = evt.RestBehavior.ToString();

            Dictionary <Parameter, string> paramNames  = ParamNames(evt);
            IEnumerable <string>           argNameList = paramNames.Values.Distinct();
            string evtArgs = string.Join(", ", argNameList);

            string eventName = EventName(evt.ID);

            if (eventName != null)
            {
                code.AppendLine($"// {eventName}");
            }
            code.AppendLine($"Event({id}, {restBehavior}, function({evtArgs}) {{");
            for (int insIndex = 0; insIndex < evt.Instructions.Count; insIndex++)
            {
                CurrentInsIndex = insIndex;
                Instruction    ins = evt.Instructions[insIndex];
                EMEDF.InstrDoc doc = docs.DOC[ins.Bank]?[ins.ID];
                if (doc == null)
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendLine($@"Unable to read instruction at Event {CurrentEventID}, Index {CurrentInsIndex}.");
                    sb.AppendLine($@"Unknown instruction id: {InstructionDocs.InstrDebugString(ins)}");
                    throw new Exception(sb.ToString());
                }
                string funcName = doc.DisplayName;

                List <object> args;
                try
                {
                    args = docs.UnpackArgsWithParams(ins, insIndex, doc, paramNames, (argDoc, val) => argDoc.GetDisplayValue(val), compatibilityMode);
                }
                catch (Exception ex)
                {
                    var sb = new StringBuilder();
                    sb.AppendLine($@"Unable to unpack arguments for {funcName}({InstructionDocs.InstrDocDebugString(doc)}) at Event {CurrentEventID}, Index {CurrentInsIndex}.");
                    sb.AppendLine($@"Instruction arg data: {InstructionDocs.InstrDebugString(ins)}");
                    sb.AppendLine(ex.Message);
                    throw new Exception(sb.ToString());
                }

                if (ins.Layer.HasValue)
                {
                    args.Add(InstructionDocs.LayerString(ins.Layer.Value));
                }

                string lineOfCode = $"{doc.DisplayName}({string.Join(", ", args)});";
                code.AppendLine("\t" + lineOfCode);
            }
            code.AppendLine("});");
            code.AppendLine("");

            CurrentInsIndex = -1;
            CurrentEventID  = -1;
        }
예제 #2
0
        // Usages

        // Usages for display names of these symbols: instruction name, enum name, enum value
        private Dictionary <string, Usages> GetSymbolUsages(string game, string emevdDir, InstructionDocs docs)
        {
            Dictionary <string, HashSet <string> > symbolsByFile = new Dictionary <string, HashSet <string> >();
            HashSet <string> allSymbols = new HashSet <string>();

            interestingEmevds.TryGetValue(game, out Regex mainRegex);
            List <string> files = new List <string>();

            Console.WriteLine($"------ Usages from [{emevdDir}]");
            foreach (string emevdPath in Directory.GetFiles(emevdDir))
            {
                if (mainRegex != null && !mainRegex.Match(Path.GetFileName(emevdPath)).Success)
                {
                    continue;
                }
                string name = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(emevdPath));
                files.Add(name);
                Console.WriteLine($"--- {name}");
                HashSet <string> symbols = symbolsByFile[name] = new HashSet <string>();
                EMEVD            emevd   = EMEVD.Read(emevdPath);
                foreach (EMEVD.Event evt in emevd.Events)
                {
                    for (int insIndex = 0; insIndex < evt.Instructions.Count; insIndex++)
                    {
                        // This is all very best-effort
                        EMEVD.Instruction ins = evt.Instructions[insIndex];
                        EMEDF.InstrDoc    doc = docs.DOC[ins.Bank]?[ins.ID];
                        if (doc == null)
                        {
                            continue;
                        }
                        symbols.Add(doc.DisplayName);
                        Dictionary <EMEVD.Parameter, string> paramNames = docs.ParamNames(evt);
                        try
                        {
                            // A slight abuse of this function, ignoring the returned list
                            docs.UnpackArgsWithParams(ins, insIndex, doc, paramNames, (argDoc, val) =>
                            {
                                if (argDoc.GetDisplayValue(val) is string displayStr)
                                {
                                    symbols.Add(displayStr);
                                }
                                return(val);
                            });
                            // Also add a usage if the enum is present at all, even if parameterized
                            foreach (EMEDF.ArgDoc argDoc in doc.Arguments)
                            {
                                if (argDoc.EnumDoc != null && argDoc.EnumName != "BOOL")
                                {
                                    symbols.Add(argDoc.EnumDoc.DisplayName);
                                }
                            }
                        }
                        catch
                        {
                        }
                    }
                }
                allSymbols.UnionWith(symbols);
            }

            Dictionary <string, Usages> symbolUsages = new Dictionary <string, Usages>();
            List <string> primaryFiles = null;

            if (secondaryEmevd.TryGetValue(game, out Regex secondaryRegex))
            {
                primaryFiles = files.Where(f => !secondaryRegex.Match(f).Success).ToList();
            }
            foreach (string symbol in allSymbols)
            {
                List <string> matchFiles = files.Where(f => symbolsByFile[f].Contains(symbol)).ToList();
                List <string> target     = files;
                if (primaryFiles != null)
                {
                    List <string> primaryMatchFiles = matchFiles.Intersect(primaryFiles).ToList();
                    if (primaryMatchFiles.Count > 0)
                    {
                        matchFiles = primaryMatchFiles;
                        target     = primaryFiles;
                    }
                }
                // Combining PTDE and DS1R is done after.
                symbolUsages[symbol] = new Usages {
                    Files = matchFiles, AllFiles = target
                };
            }
            return(symbolUsages);
        }
예제 #3
0
        private void Decompile(TextWriter writer)
        {
            EMEDF DOC = docs.DOC;
            InstructionTranslator info = docs.Translator;

            for (int i = 0; i < scripter.EVD.Events.Count; i++)
            {
                Event  evt          = scripter.EVD.Events[i];
                string id           = evt.ID.ToString();
                string restBehavior = evt.RestBehavior.ToString();

                Dictionary <Parameter, string> paramNames = docs.ParamNames(evt);
                List <string> argNameList = paramNames.Values.Distinct().ToList();
                Dictionary <Parameter, ParamArg> paramArgs = paramNames.ToDictionary(e => e.Key, e => new ParamArg {
                    Name = e.Value
                });

                EventFunction func = new EventFunction {
                    ID = (int)evt.ID, RestBehavior = evt.RestBehavior, Params = argNameList
                };

                string eventName = scripter.EventName(evt.ID);
                if (eventName != null)
                {
                    writer.WriteLine($"// {eventName}");
                }

                for (int insIndex = 0; insIndex < evt.Instructions.Count; insIndex++)
                {
                    Instruction    ins = evt.Instructions[insIndex];
                    EMEDF.InstrDoc doc = docs.DOC[ins.Bank]?[ins.ID];
                    if (doc == null)
                    {
                        throw new Exception($"Unknown instruction in event {id}: {ins.Bank}[{ins.ID}] {string.Join(" ", ins.ArgData.Select(b => $"{b:x2}"))}");
                    }
                    string funcName = doc.DisplayName;

                    IEnumerable <ArgType> argStruct = doc.Arguments.Select(arg => arg.Type == 8 ? ArgType.UInt32 : (ArgType)arg.Type);

                    Layers layers = ins.Layer is uint l ? new Layers {
                        Mask = l
                    } : null;
                    Instr instr = new Instr {
                        Inner = ins, Cmd = InstructionID(ins.Bank, ins.ID), Name = funcName, Layers = layers
                    };

                    try
                    {
                        instr.Args = docs.UnpackArgsWithParams(ins, insIndex, doc, paramArgs, (argDoc, val) =>
                        {
                            if (argDoc.GetDisplayValue(val) is string displayStr)
                            {
                                return(new DisplayArg {
                                    DisplayValue = displayStr, Value = val
                                });
                            }
                            return(val);
                        });
                    }
                    catch (Exception ex)
                    {
                        var sb = new StringBuilder();
                        sb.AppendLine($@"Unable to unpack arguments for {funcName} at Event {evt.ID}[{insIndex}]");
                        sb.AppendLine($@"Instruction arg data: {InstructionDocs.InstrDebugString(ins)}");
                        sb.AppendLine(ex.Message);
                        throw new Exception(sb.ToString());
                    }
                    func.Body.Add(instr);
                }
                EventCFG f = new EventCFG((int)evt.ID, options);
                try
                {
                    // This returns warnings, many of which exist in vanilla emevd.
                    // Ignored until we have a nice way to show them.
                    f.Decompile(func, info);
                }
                catch (FancyNotSupportedException)
                {
                    // For the moment, swallow this.
                    // Can find a way to expose the error, but these are basically intentional bail outs, also existing in vanilla emevd.
                    StringBuilder code = new StringBuilder();
                    scripter.UnpackEvent(evt, code);
                    writer.Write(code.ToString());
                    continue;
                }
                catch (Exception ex)
                {
                    var sb = new StringBuilder();
                    sb.AppendLine($@"Error decompiling Event {evt.ID}");
                    sb.AppendLine(ex.ToString());
                    throw new Exception(sb.ToString());
                }
                func.Print(writer);
                writer.WriteLine();
            }
        }