public ScriptWalker(ScriptTable orig, ScriptTable mod, IndentedTextWriter output, EngineDescription desc) { _orig = orig; _mod = mod; _output = output; _op = desc.ScriptInfo; }
private static void UpdateXshdWithScriptInfo(XDocument doc, OpcodeLookup opcodes) { XNamespace df = doc.Root.Name.Namespace; var keyWords = doc.Root.Descendants(df + "Keywords"); XElement scriptTypeElement = keyWords.Where(x => x.Attribute("color")?.Value == "ScriptType")?.First(); XElement valueTypeElement = keyWords.Where(x => x.Attribute("color")?.Value == "ValueType")?.First(); XElement functionElement = keyWords.Where(x => x.Attribute("color")?.Value == "Function")?.First(); foreach (string scriptType in opcodes.GetAllScriptTypeNames()) { XElement element = StringToWordElement(scriptType, df); scriptTypeElement.Add(element); } foreach (string type in opcodes.GetAllValueTypeNames()) { XElement element = StringToWordElement(type, df); valueTypeElement.Add(element); } foreach (string function in opcodes.GetAllUniqueFunctionNames()) { XElement element = StringToWordElement(function, df); functionElement.Add(element); } }
private void RegisterTypeCasts(XContainer root, OpcodeLookup lookup) { List <TempTypeCast> info = new List <TempTypeCast>(); Dictionary <string, string[]> casts = new Dictionary <string, string[]>(); // Load type casting information. foreach (XElement element in root.Element("typecasting").Elements("to")) { TempTypeCast temp = new TempTypeCast() { Name = XMLUtil.GetStringAttribute(element, "name"), CastOnly = XMLUtil.GetBoolAttribute(element, "castOnly", false), Types = element.Elements("from").Select(e => e.Value) }; info.Add(temp); casts[temp.Name] = temp.Types.ToArray(); } bool itemsAdded = true; while (itemsAdded) { itemsAdded = false; // Iterate over all casts. foreach (var i in info) { string[] newPredecessors = casts[i.Name]; // Iterate over all predecessors of the cast. foreach (string type in casts[i.Name]) { // Check if the predecessor supports casting. if (casts.TryGetValue(type, out string[] predecessors))
private void RegisterExecutionTypes(XContainer root, OpcodeLookup lookup) { foreach (XElement element in root.Element("scriptTypes").Descendants("type")) { var opcode = (ushort)XMLUtil.GetNumericAttribute(element, "opcode"); string name = XMLUtil.GetStringAttribute(element, "name"); lookup.RegisterScriptType(name, opcode); } }
public ScriptEditor(EngineDescription buildInfo, IScriptFile scriptFile, IStreamManager streamManager, ICacheFile casheFile, Endian endian) { _endian = endian; _buildInfo = buildInfo; _opcodes = _buildInfo.ScriptInfo; _scriptFile = scriptFile; _streamManager = streamManager; _cashefile = casheFile; // If a game contains hsdt tags, it uses a newer Blam Script syntax. Currently the compiler only supports the old syntax. _hasNewSyntax = _buildInfo.Layouts.HasLayout("hsdt"); InitializeComponent(); // Disable user input. Enable it again when all background tasks have been completed. txtScript.IsReadOnly = true; // Enable code completion only if the compiler supports this game. if (!_hasNewSyntax) { txtScript.TextArea.GotFocus += EditorGotFocus; txtScript.TextArea.LostFocus += EditorLostFocus; txtScript.TextArea.TextEntering += EditorTextEntering; txtScript.TextArea.TextEntered += EditorTextEntered; txtScript.TextArea.Document.Changed += EditorTextChanged; } App.AssemblyStorage.AssemblySettings.PropertyChanged += Settings_SettingsChanged; SetHighlightColor(); SearchPanel srch = SearchPanel.Install(txtScript); var bconv = new System.Windows.Media.BrushConverter(); var srchbrsh = (System.Windows.Media.Brush)bconv.ConvertFromString("#40F0F0F0"); srch.MarkerBrush = srchbrsh; txtScript.SyntaxHighlighting = LoadSyntaxHighlighting(); // With syntax highlighting and HTML formatting, copying text takes ages. Disable the HTML formatting for copied text. DataObject.AddSettingDataHandler(txtScript, onTextViewSettingDataHandler); _progress = new Progress <int>(i => { progressBar.Value = i; }); itemShowInformation.IsChecked = App.AssemblyStorage.AssemblySettings.ShowScriptInfo; itemDebugData.IsChecked = App.AssemblyStorage.AssemblySettings.OutputCompilerDebugData; // Enable compilation only for supported games. if (_buildInfo.Name.Contains("Reach") || _buildInfo.Name.Contains("Halo 3") && _buildInfo.HeaderSize != 0x800 && !_buildInfo.Name.Contains("ODST")) { compileButton.Visibility = Visibility.Visible; progressReporter.Visibility = Visibility.Visible; } }
/// <summary> /// Loads setting data from a path. /// </summary> /// <param name="path">The path to load from.</param> /// <returns> /// The loaded setting data. /// </returns> public object LoadSetting(string path) { XDocument document = XDocument.Load(path); var result = new OpcodeLookup(); XElement root = document.Element("BlamScript"); RegisterExecutionTypes(root, result); RegisterValueTypes(root, result); RegisterFunctions(root, result); return(result); }
public static bool IsObject(string type, OpcodeLookup op) { CastInfo info = op.GetTypeCast("object"); if (info is null) { return(false); } else { return(info.From.Contains(type)); } }
private void RegisterValueTypes(XContainer root, OpcodeLookup lookup) { foreach (XElement element in root.Element("valueTypes").Descendants("type")) { string name = XMLUtil.GetStringAttribute(element, "name"); var opcode = (ushort)XMLUtil.GetNumericAttribute(element, "opcode"); int size = XMLUtil.GetNumericAttribute(element, "size"); bool quoted = XMLUtil.GetBoolAttribute(element, "quoted", false); string tag = XMLUtil.GetStringAttribute(element, "tag", null); var valueType = new ScriptValueType(name, opcode, size, quoted, tag); lookup.RegisterValueType(valueType); } }
public ScriptCompiler(ICacheFile casheFile, EngineDescription buildInfo, OpcodeLookup opCodes, ScriptingContextCollection context, IProgress<int> progress, ScriptCompilerLogger logger, bool debug) { _buildInfo = buildInfo; _progress = progress; _cacheFile = casheFile; _scriptingContext = context; _opcodes = opCodes; _logger = logger; _debug = debug; _expectedTypes = new TypeStack(logger, _debug); ushort intialSalt = SaltGenerator.GetSalt("script node"); _currentIndex = new DatumIndex(intialSalt, 0); }
private string DecompileScnrScripts() { using (IReader reader = _streamManager.OpenRead()) { ScriptTable scripts = _scriptFile.LoadScripts(reader); if (scripts is null) { return(""); } OpcodeLookup opcodes = _buildInfo.ScriptInfo; var decompiler = new BlamScriptDecompiler(scripts, opcodes, _endian); return(decompiler.DecompileAll(_scriptFile.Name, App.AssemblyStorage.AssemblySettings.ShowScriptInfo, true)); } }
private void RegisterGlobals(XContainer root, OpcodeLookup lookup) { foreach (XElement element in root.Element("globals").Descendants("global")) { string name = XMLUtil.GetStringAttribute(element, "name"); if (name == "") { continue; } ushort opcode = (ushort)XMLUtil.GetNumericAttribute(element, "opcode"); string returnType = XMLUtil.GetStringAttribute(element, "type"); bool isNull = XMLUtil.GetBoolAttribute(element, "null", false); var info = new GlobalInfo(name, opcode, returnType, !isNull); lookup.RegisterGlobal(info); } }
//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 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); } }
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); }
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(); })); }
public static IHighlightingDefinition LoadEmbeddedBlamScriptDefinition(string filename, OpcodeLookup lookup) { // Embedded resources are prefixed with their namespace name string ns = typeof(HighlightLoader).Namespace; string resourcePath = ns + '.' + filename; // Read it from the assembly this class is embedded in. System.Reflection.Assembly assembly = typeof(HighlightLoader).Assembly; using (Stream s = assembly.GetManifestResourceStream(resourcePath)) { if (s != null) { XDocument doc = XDocument.Load(s); UpdateXshdWithScriptInfo(doc, lookup); // We can't write the updated definition to the resource stream. Therefore we have to create a new stream. using (var destinationStream = new MemoryStream()) { // Save and rewind the stream. doc.Save(destinationStream); destinationStream.Seek(0, SeekOrigin.Begin); using (var reader = new XmlTextReader(destinationStream)) { // Don't cache the definition, since keywords vary between games. return(HighlightingLoader.Load(reader, HighlightingManager.Instance)); } } } else { throw new FileNotFoundException($"An embedded highlighting definition file with the name {filename} could not be found."); } } }
/// <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); }