public void RegisterFunction(ScriptFunctionInfo func) { _functionLookupByOpcode[func.Opcode] = func; List<ScriptFunctionInfo> functions; if (!_functionLookupByName.TryGetValue(func.Name, out functions)) { functions = new List<ScriptFunctionInfo>(); _functionLookupByName[func.Name] = functions; } functions.Add(func); }
public XMLOpcodeLookup(XDocument document) { XContainer root = document.Element("BlamScript"); // Script execution types var scriptTypes = from element in root.Element("scriptTypes").Descendants("type") select new { Opcode = (ushort)XMLUtil.GetNumericAttribute(element, "opcode"), Name = XMLUtil.GetStringAttribute(element, "name") }; _scriptTypeNameLookup = scriptTypes.ToDictionary(t => t.Opcode, t => t.Name); _scriptTypeOpcodeLookup = scriptTypes.ToDictionary(t => t.Name, t => t.Opcode); // Value types var valueTypes = new List<ScriptValueType>(); foreach (var element in root.Element("valueTypes").Descendants("type")) { var name = XMLUtil.GetStringAttribute(element, "name"); var opcode = (ushort)XMLUtil.GetNumericAttribute(element, "opcode"); var size = XMLUtil.GetNumericAttribute(element, "size"); var quoted = XMLUtil.GetBoolAttribute(element, "quoted", false); var tag = XMLUtil.GetStringAttribute(element, "tag", null); valueTypes.Add(new ScriptValueType(name, opcode, size, quoted, tag)); } _typeLookupByOpcode = valueTypes.ToDictionary(t => t.Opcode); _typeLookupByName = valueTypes.ToDictionary(t => t.Name); // Functions foreach (var element in root.Element("functions").Descendants("function")) { var name = XMLUtil.GetStringAttribute(element, "name"); if (name == "") continue; var opcode = (ushort)XMLUtil.GetNumericAttribute(element, "opcode"); var returnType = XMLUtil.GetStringAttribute(element, "returnType", "void"); var flags = (uint)XMLUtil.GetNumericAttribute(element, "flags", 0); var parameterTypes = element.Descendants("arg").Select(e => XMLUtil.GetStringAttribute(e, "type")).ToArray(); var info = new ScriptFunctionInfo(name, opcode, returnType, flags, parameterTypes); List<ScriptFunctionInfo> functions; if (!_functionLookupByName.TryGetValue(name, out functions)) { functions = new List<ScriptFunctionInfo>(); _functionLookupByName[name] = functions; } functions.Add(info); _functionLookupByOpcode[opcode] = info; } }
public void RegisterFunction(ScriptFunctionInfo func) { _functionLookupByOpcode[func.Opcode] = func; List <ScriptFunctionInfo> functions; if (!_functionLookupByName.TryGetValue(func.Name, out functions)) { functions = new List <ScriptFunctionInfo>(); _functionLookupByName[func.Name] = functions; } functions.Add(func); }
private void RegisterFunctions(XContainer root, OpcodeLookup lookup) { foreach (XElement element in root.Element("functions").Descendants("function")) { string name = XMLUtil.GetStringAttribute(element, "name"); if (name == "") continue; var opcode = (ushort) XMLUtil.GetNumericAttribute(element, "opcode"); string returnType = XMLUtil.GetStringAttribute(element, "returnType", "void"); var flags = (uint) XMLUtil.GetNumericAttribute(element, "flags", 0); string[] parameterTypes = element.Descendants("arg").Select(e => XMLUtil.GetStringAttribute(e, "type")).ToArray(); var info = new ScriptFunctionInfo(name, opcode, returnType, flags, parameterTypes); lookup.RegisterFunction(info); } }
private void GenerateCode(ScriptExpression expression, IndentedTextWriter output, bool firstrun = false) { int firstIndentedArg = int.MaxValue; bool isFunctionCall = false; if (expression.Type == ScriptExpressionType.Expression || expression.Type == ScriptExpressionType.Expression4) { ScriptValueType type = _opcodes.GetTypeInfo((ushort)expression.ReturnType); if (type.Name == "function_name") { isFunctionCall = true; if (!_nextFunctionIsScript) { ScriptFunctionInfo info = _opcodes.GetFunctionInfo(expression.Opcode); if (info != null) { if (info.Name.StartsWith("begin")) { firstIndentedArg = 0; if (expression.LineNumber > 0 && !_onNewLine) { output.Indent++; output.WriteLine(); } } else if (info.Name == "if") { firstIndentedArg = 1; } } } if (expression.LineNumber > 0) { output.Write("("); } } } bool wroteAnything = wroteAnything = HandleExpression(expression, output); int startIndent = output.Indent; int currentArg = 0; if (_h4 && firstrun) { firstIndentedArg = 0; currentArg = 1; _h4 = false; } ScriptExpression sibling = expression.Next; while (sibling != null) { if (wroteAnything && !_nextExpressionIsVar) { if (currentArg == firstIndentedArg) { output.Indent++; } if (currentArg >= firstIndentedArg) { output.WriteLine(); _onNewLine = true; } else if (output.Indent != startIndent) { output.WriteLine(); _onNewLine = true; } else { output.Write(" "); } } if (!_nextExpressionIsVar) { wroteAnything = HandleExpression(sibling, output); } else if ((_nextExpressionIsVar && sibling.Opcode != 0xFFFF)) { if (!_varTypeWritten) { ScriptValueType type = _opcodes.GetTypeInfo((ushort)sibling.ReturnType); output.Write(type.Name + " var_" + localVarCounter.ToString() + " "); _varTypeWritten = true; } wroteAnything = HandleExpression(sibling, output); } sibling = sibling.Next; currentArg++; } if (isFunctionCall && expression.LineNumber > 0) { if (output.Indent != startIndent) { output.Indent = startIndent; if (wroteAnything) { output.WriteLine(); } output.Write(")"); _onNewLine = true; } else { output.Write(")"); } } }
private bool GenerateExpressionCode(ScriptExpression expression, IndentedTextWriter output) { if (expression.LineNumber == 0) { return(false); } _onNewLine = false; ScriptValueType type = _opcodes.GetTypeInfo((ushort)expression.ReturnType); ScriptValueType actualType = type; if (type.Name != "function_name") { // Check if a typecast is occurring if (expression.Opcode != 0xFFFF) { actualType = _opcodes.GetTypeInfo(expression.Opcode); if (actualType.Quoted) { if (expression.Value != 0xFFFFFFFF) { output.Write("\"{0}\"", expression.StringValue); } else { output.Write("none"); } return(true); } } } uint value = GetValue(expression, type, _endian); byte[] val = BitConverter.GetBytes(value); switch (type.Name) { case "void": return(false); case "boolean": if (BitConverter.ToBoolean(val, 0)) { output.Write("true"); } else { output.Write("false"); } break; case "short": output.Write(BitConverter.ToInt16(val, 0)); break; case "long": // Signed integer output.Write((int)value); break; case "real": // Eww //var floatBytes = new byte[4]; //floatBytes[0] = (byte) (value & 0xFF); //floatBytes[1] = (byte) ((value >> 8) & 0xFF); //floatBytes[2] = (byte) ((value >> 16) & 0xFF); //floatBytes[3] = (byte) ((value >> 24) & 0xFF); output.Write(BitConverter.ToSingle(val, 0)); break; case "function_name": if (_nextFunctionIsScript) { if (expression.Opcode >= _scripts.Scripts.Count) { output.Write("import#" + expression.StringValue); } else { output.Write(expression.StringValue); // todo: there are cases (h3 xbox mainmenu's campaign_cam specifically) where the function_name expression's opcode value is +1 from what it should be, and the expression prior has the right index. } // the current state of this script code doesnt seem to be good enough to step back so here is the hacky fix implemented in the HO fork. //output.Write(_scripts.Scripts[expression.Opcode].Name); _nextFunctionIsScript = false; } else { ScriptFunctionInfo info = _opcodes.GetFunctionInfo(expression.Opcode); if (info == null) { output.Write("UNNAMED_OPCODE_" + expression.Opcode.ToString("X4") + "#" + expression.StringValue); } else { output.Write(info.Name); } //throw new InvalidOperationException("Unrecognized function opcode 0x" + expression.Opcode.ToString("X")); } break; case "unit_seat_mapping": // This isn't the technical way of doing this, // but since seat mapping names aren't stored anywhere, // it would be tricky to resolve them unless we just use an index for now if (expression.Value != 0xFFFFFFFF) { output.Write(expression.Value & 0xFFFF); } else { output.Write("none"); } break; case "unparsed": break; default: string enumValue = actualType.GetEnumValue(value); if (enumValue != null) { output.Write(enumValue); } else if (expression.Value == 0xFFFFFFFF) { output.Write("none"); } else { enumValue = expression.StringValue; if (enumValue != null) { output.Write(enumValue); } else { output.Write("0x{0:X}", value); } } break; } return(true); }
private void GenerateCode(ScriptExpression expression, IndentedTextWriter output) { int firstIndentedArg = int.MaxValue; bool isFunctionCall = false; if (expression.Type == ScriptExpressionType.Expression) { ScriptValueType type = _opcodes.GetTypeInfo((ushort)expression.ReturnType); if (type.Name == "function_name") { isFunctionCall = true; if (!_nextFunctionIsScript) { ScriptFunctionInfo info = _opcodes.GetFunctionInfo(expression.Opcode); if (info != null) { if (info.Name.StartsWith("begin")) { firstIndentedArg = 0; if (expression.LineNumber > 0 && !_onNewLine) { output.Indent++; output.WriteLine(); } } else if (info.Name == "if") { firstIndentedArg = 1; } } } if (expression.LineNumber > 0) { output.Write("("); } } } bool wroteAnything = HandleExpression(expression, output); int startIndent = output.Indent; int currentArg = 0; ScriptExpression sibling = expression.Next; while (sibling != null) { if (wroteAnything) { if (currentArg == firstIndentedArg) { output.Indent++; } if (currentArg >= firstIndentedArg || output.Indent != startIndent) { output.WriteLine(); _onNewLine = true; } else { output.Write(" "); } } wroteAnything = HandleExpression(sibling, output); sibling = sibling.Next; currentArg++; } if (isFunctionCall && expression.LineNumber > 0) { if (output.Indent != startIndent) { output.Indent = startIndent; if (wroteAnything) { output.WriteLine(); } output.Write(")"); _onNewLine = true; } else { output.Write(")"); } } }
private bool GenerateExpressionCode(ScriptExpression expression, IndentedTextWriter output) { if (expression.LineNumber == 0) { return(false); } _onNewLine = false; ScriptValueType type = _opcodes.GetTypeInfo((ushort)expression.ReturnType); ScriptValueType actualType = type; if (type.Name != "function_name") { // Check if a typecast is occurring actualType = _opcodes.GetTypeInfo(expression.Opcode); if (actualType.Quoted) { if (expression.Value != 0xFFFFFFFF) { output.Write("\"{0}\"", expression.StringValue); } else { output.Write("none"); } return(true); } } uint value = GetValue(expression, type); switch (type.Name) { case "void": return(false); case "boolean": if (value > 0) { output.Write("true"); } else { output.Write("false"); } break; case "short": case "long": // Signed integer output.Write((int)value); break; case "real": // Eww var floatBytes = new byte[4]; floatBytes[0] = (byte)(value & 0xFF); floatBytes[1] = (byte)((value >> 8) & 0xFF); floatBytes[2] = (byte)((value >> 16) & 0xFF); floatBytes[3] = (byte)((value >> 24) & 0xFF); output.Write(BitConverter.ToSingle(floatBytes, 0)); break; case "function_name": if (_nextFunctionIsScript) { output.Write(expression.StringValue); // halo online seems weird in that the "opcode" value that is actually a script index in this case is greater than the number of scripts //output.Write(_scripts.Scripts[expression.Opcode].Name); _nextFunctionIsScript = false; } else { ScriptFunctionInfo info = _opcodes.GetFunctionInfo(expression.Opcode); if (info == null) { output.Write("unknown_" + expression.Opcode.ToString("X") + "(" + expression.StringValue + ")"); //throw new InvalidOperationException("Unrecognized function opcode 0x" + expression.Opcode.ToString("X")); } else { output.Write(info.Name); } } break; case "unit_seat_mapping": // This isn't the technical way of doing this, // but since seat mapping names aren't stored anywhere, // it would be tricky to resolve them unless we just use an index for now if (expression.Value != 0xFFFFFFFF) { output.Write(expression.Value & 0xFFFF); } else { output.Write("none"); } break; default: string enumValue = actualType.GetEnumValue(value); if (enumValue != null) { output.Write(enumValue); } else if (expression.Value == 0xFFFFFFFF) { output.Write("none"); } else { enumValue = expression.StringValue; if (enumValue != null) { output.Write(enumValue); } else { output.Write("0x{0:X}", value); } } break; } return(true); }