public static Script GetScriptFromContext(HS_Gen1Parser.ScriptDeclarationContext context, DatumIndex rootExpressionIndex, OpcodeLookup opcodes) { // Create a new Script. Script script = new Script { Name = context.scriptID().GetTextSanitized(), ExecutionType = (short)opcodes.GetScriptTypeOpcode(context.SCRIPTTYPE().GetTextSanitized()), ReturnType = (short)opcodes.GetTypeInfo(context.VALUETYPE().GetTextSanitized()).Opcode, RootExpressionIndex = rootExpressionIndex }; // Handle scripts with parameters. var parameterContext = context.scriptParameters(); if (parameterContext != null) { var parameters = parameterContext.parameter(); for (ushort i = 0; i < parameters.Length; i++) { string name = parameters[i].ID().GetTextSanitized(); var valueTypeNode = parameters[i].VALUETYPE(); string valueType = valueTypeNode is null ? "script" : valueTypeNode.GetTextSanitized(); // Add the parameter to the script object. ScriptParameter parameter = new ScriptParameter { Name = name, Type = opcodes.GetTypeInfo(valueType).Opcode }; script.Parameters.Add(parameter); } } return(script); }
/// <summary> /// Extracts all unique unit seat mappings from the script expressions of a scnr based script file. /// </summary> /// <param name="scnr">The scnr based script file.</param> /// <param name="reader">The stream to read from.</param> /// <param name="op">A lookup containing script type information.</param> /// <returns>All unique unit seat mappings contained in the script expressions.</returns> public static IEnumerable <UnitSeatMapping> ExtractScnrSeatMappings(ScnrScriptFile scnr, IReader reader, OpcodeLookup op) { ScriptTable scripts = scnr.LoadScripts(reader); ScriptValueType typeInfo = op.GetTypeInfo("unit_seat_mapping"); // find all unique mappings SortedDictionary <uint, UnitSeatMapping> uniqueMappings = new SortedDictionary <uint, UnitSeatMapping>(); foreach (var exp in scripts.Expressions) { if (exp.Opcode == typeInfo.Opcode && exp.ReturnType == typeInfo.Opcode && !exp.Value.IsNull) { // Calculate the index and only add it if it doesn't exist yet. uint index = exp.Value.UintValue & 0xFFFF; if (!uniqueMappings.ContainsKey(index)) { uint count = (exp.Value.UintValue & 0xFFFF0000) >> 16; string name = exp.StringValue; UnitSeatMapping mapping = new UnitSeatMapping((short)index, (short)count, name); uniqueMappings.Add(index, mapping); } } } return(uniqueMappings.Values); }
//public static bool CanBeCasted(string from, string to, OpcodeLookup op) //{ // if ((IsNumType(from) && IsNumType(to)) || (op.GetTypeInfo(from).IsObject && op.GetTypeInfo(to).IsObject)) // { // return true; // } // // Check if this type supports casting // CastInfo info = op.GetTypeCast(to); // if (info != null) // { // List<string> casts = new List<string>(); // List<string> processedTypes = new List<string>(); // int addedTypes = info.From.Count; // casts.AddRange(info.From); // // Generate a list of all possible casts. // while (addedTypes > 0) // { // int added = 0; // string[] difference = casts.Except(processedTypes).ToArray(); // foreach (string cast in difference) // { // info = op.GetTypeCast(cast); // if (info != null) // { // foreach (var type in info.From) // { // if (!casts.Contains(type)) // { // casts.Add(type); // added++; // } // } // } // processedTypes.Add(cast); // } // addedTypes = added; // } // // Check if this generated list contains this cast. // return casts.Contains(from); // } // else // { // return false; // } //} public static bool CanBeCasted(string from, string to, OpcodeLookup op) { if ((IsNumType(from) && IsNumType(to)) || (op.GetTypeInfo(from).IsObject&& op.GetTypeInfo(to).IsObject)) { return(true); } CastInfo info = op.GetTypeCast(to); if (info is null) { return(false); } else { return(info.From.Contains(from)); } }
private void DecompileScripts(object streamManager) { DateTime startTime = DateTime.Now; ScriptTable scripts; using (IReader reader = ((IStreamManager)streamManager).OpenRead()) { scripts = _scriptFile.LoadScripts(reader); if (scripts == null) { return; } } OpcodeLookup opcodes = _buildInfo.ScriptInfo; var generator = new BlamScriptGenerator(scripts, opcodes, _endian); var code = new IndentedTextWriter(new StringWriter()); generator.WriteComment("Decompiled with Assembly", code); generator.WriteComment("", code); generator.WriteComment("Source file: " + _scriptFile.Name, code); generator.WriteComment("Start time: " + startTime, code); generator.WriteComment("", code); generator.WriteComment("Remember that all script code is property of Bungie/343 Industries.", code); generator.WriteComment("You have no rights. Play nice.", code); code.WriteLine(); int counter = 0; if (scripts.Variables != null) { generator.WriteComment("VARIABLES", code); foreach (ScriptGlobal variable in scripts.Variables) { code.Write("(variable {0} {1} ", opcodes.GetTypeInfo((ushort)variable.Type).Name, variable.Name); generator.WriteExpression(variable.ExpressionIndex, code); if (_showInfo) { code.WriteLine(")\t\t; Index: {0}, Expression Index: {1}", counter.ToString(), variable.ExpressionIndex.Index.ToString()); } else { code.WriteLine(")"); } counter++; } code.WriteLine(); counter = 0; } generator.WriteComment("GLOBALS", code); foreach (ScriptGlobal global in scripts.Globals) { code.Write("(global {0} {1} ", opcodes.GetTypeInfo((ushort)global.Type).Name, global.Name); generator.WriteExpression(global.ExpressionIndex, code); if (_showInfo) { code.WriteLine(")\t\t; Index: {0}, Expression Index: {1}", counter.ToString(), global.ExpressionIndex.Index.ToString()); } else { code.WriteLine(")"); } counter++; } code.WriteLine(); counter = 0; generator.WriteComment("SCRIPTS", code); foreach (Script script in scripts.Scripts) { if (_showInfo) { generator.WriteComment(string.Format("Index: {0}, Expression Index: {1}", counter.ToString(), script.RootExpressionIndex.Index.ToString()), code); } code.Write("(script {0} {1} ", opcodes.GetScriptTypeName((ushort)script.ExecutionType), opcodes.GetTypeInfo((ushort)script.ReturnType).Name); if (script.Parameters != null && script.Parameters.Count > 0) { code.Write("({0} (", script.Name); bool firstParam = true; foreach (ScriptParameter param in script.Parameters) { if (!firstParam) { code.Write(", "); } code.Write("{1} {0}", param.Name, opcodes.GetTypeInfo((ushort)param.Type).Name); firstParam = false; } code.Write("))"); } else { code.Write(script.Name); } code.Indent++; code.WriteLine(); generator.WriteExpression(script.RootExpressionIndex, code, _buildInfo.HeaderSize == 0x1E000); code.Indent--; code.WriteLine(); code.WriteLine(")"); code.WriteLine(); counter++; } DateTime endTime = DateTime.Now; TimeSpan duration = endTime.Subtract(startTime); generator.WriteComment("Decompilation finished in ~" + duration.TotalSeconds + "s", code); Dispatcher.Invoke(new Action(delegate { txtScript.Text = code.InnerWriter.ToString(); })); }
private void CompareNormalExpressions(ScriptExpression origExp, ScriptExpression modExp) { ExpressionValueComparer valComparer = new ExpressionValueComparer(); bool areEqual = true; // the opcodes always have to match. areEqual = areEqual && (origExp.Opcode == modExp.Opcode); areEqual = areEqual && (origExp.ReturnType == modExp.ReturnType); // An expression's opcode determines its actual value type. The value type is used for casting. Function names are an exception. string valueType = _op.GetTypeInfo(origExp.ReturnType).Name == "function_name" ? "function_name" : _op.GetTypeInfo(origExp.Opcode).Name; switch (valueType) { case "void": case "boolean": case "long": case "short": // ignore random strings. areEqual = areEqual && valComparer.Equals(origExp.Value, modExp.Value); break; case "real": byte[] b1 = BitConverter.GetBytes(origExp.Value.UintValue); byte[] b2 = BitConverter.GetBytes(modExp.Value.UintValue); float fl1 = BitConverter.ToSingle(b1, 0); float fl2 = BitConverter.ToSingle(b2, 0); if ((fl1 != 0.0 || fl2 != -0.0) && (fl1 != -0.0 || fl2 != 0.0)) { areEqual = areEqual && valComparer.Equals(origExp.Value, modExp.Value); } break; case "string": case "string_id": case "function_name": areEqual = areEqual && (origExp.StringValue == modExp.StringValue); break; case "sound": case "effect": case "damage": case "looping_sound": case "animation_graph": case "damage_effect": case "object_definition": case "bitmap": case "shader": case "render_model": case "structure_definition": case "lightmap_definition": case "cinematic_definition": case "cinematic_scene_definition": case "cinematic_transition_definition": case "bink_definition": case "cui_screen_definition": case "any_tag": case "any_tag_not_resolving": case "ai_line": case "unit_seat_mapping": areEqual = areEqual && valComparer.Equals(origExp.Value, modExp.Value); // ignore missing tags, ai lines and unit seat mappings if (!origExp.Value.IsNull) { areEqual = areEqual && (origExp.StringValue == modExp.StringValue); } break; default: areEqual = areEqual && valComparer.Equals(origExp.Value, modExp.Value); // Ignore enum values, where a space char was replaced with an underscore. if (origExp.StringValue != modExp.StringValue && (!_op.GetTypeInfo(valueType).IsEnum || origExp.StringValue.Replace(' ', '_') != modExp.StringValue)) { areEqual = false; } break; } if (!areEqual) { WriteScriptObject(); _output.WriteLine("Unequal Expressions!"); _output.WriteLine("### Original ###"); _output.WriteLine(ExpressionToString(origExp)); _output.WriteLine("### Modified ###"); _output.WriteLine(ExpressionToString(modExp)); _output.WriteLine(); } }
/// <summary> /// Processes script declarations. Opens a datum. /// Creates the script node and the initial "begin" expression. /// Generates the variable lookup. Pushes return types. /// </summary> /// <param name="context"></param> public override void EnterScriptDeclaration(HS_Gen1Parser.ScriptDeclarationContext context) { if(_debug) { _logger.Script(context, CompilerContextAction.Enter); } // Create new script object and add it to the table. Script script = ScriptObjectCreation.GetScriptFromContext(context, _currentIndex, _opcodes); _scripts.Add(script); // Generate the parameter lookup. for(ushort i = 0; i < script.Parameters.Count; i++) { ScriptParameter parameter = script.Parameters[i]; var info = new ParameterInfo(parameter.Name, _opcodes.GetTypeInfo(parameter.Type).Name, i); _parameterLookup.Add(info.Name, info); } string returnType = context.VALUETYPE().GetTextSanitized(); int expressionCount = context.expression().Count(); // The final expression must match the return type of this script. _expectedTypes.PushType(returnType); // The other expressions can be of any type. if (expressionCount > 1) { _expectedTypes.PushTypes("void", expressionCount - 1); } CreateInitialBegin(returnType, context.GetCorrectTextPosition(_missingCarriageReturnPositions)); }