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; }
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(); } }