public void Add(RuleEntry entry, RuleMetadata metadata, bool debug) { string className = "Rule_" + ruleClassCounter++; var unit = new RuleCompilationUnit() { ClassName = className, ClassFullName = string.Format("{0}.{1}", NamespaceName, className), IsDebugModeEnabled = debug, Rule = new CompiledRule(engine, metadata) { From = entry.From == null ? FormKind.Any : (FormKind)entry.From.FormKind }, }; string comment = string.Format("//\n// Source file for rule {0}\\{1}@{2} by {3}\n//\n", metadata.PluginFileName, metadata.RuleFileName, entry.Name, Program.GetProgramFullVersionInfo()); CodeBuilder builder = new CodeBuilder(NamespaceName, className, comment); builder.Usings.Add("Patcher.Rules.Compiled.Helpers"); builder.Usings.Add("Patcher.Rules.Compiled.Helpers." + engine.Context.GameTitle); builder.Usings.Add("Patcher.Rules.Compiled.Extensions"); builder.Usings.Add("Patcher.Rules.Compiled.Extensions." + engine.Context.GameTitle); builder.Usings.Add("Patcher.Rules.Compiled.Constants"); builder.Usings.Add("Patcher.Rules.Compiled.Constants." + engine.Context.GameTitle); Type sourceProxyType = entry.From != null ? engine.ProxyProvider.GetInterface((FormKind)entry.From.FormKind) : typeof(object); if (entry.Where != null) { string code = PreprocessCode(entry.Where.Code); if (StripComments(code).Length > 0) { // TODO: optimize HasTag() with index similarly var match = Regex.Match(code, @"^\s*Source\.EditorId\s*==\s*""([^""]*)""\s*$"); if (match.Success) { unit.Rule.WhereEditorId = match.Groups[1].Value; Log.Fine("Where criteria EditorID == '" + match.Groups[1].Value + "' will use an index."); } else { builder.BeginMethod("Where", sourceProxyType); builder.WriteCodeAsReturn(code); builder.EndMethod(); unit.Rule.Where = new WhereMethod(); } } } if (entry.Select != null) { string code = PreprocessCode(entry.Select.Code); if (StripComments(code).Length > 0) { builder.BeginMethod("Select", sourceProxyType); builder.WriteCode(code); builder.ReturnTrue(); builder.EndMethod(); unit.Rule.Select = new SelectMethod(); } } if (entry.Update != null) { string code = PreprocessCode(entry.Update.Code); if (StripComments(code).Length > 0) { builder.BeginMethod("Update", sourceProxyType, sourceProxyType); builder.WriteCode(code); builder.ReturnTrue(); builder.EndMethod(); unit.Rule.Update = new UpdateMethod(); } } if (entry.Inserts != null) { List<InsertMethod> methods = new List<InsertMethod>(); foreach (var insert in entry.Inserts) { string code = PreprocessCode(insert.Code); if (StripComments(code).Length > 0) { Type targetProxyType = engine.ProxyProvider.GetInterface((FormKind)insert.InsertedFormKind); builder.BeginMethod("Insert_" + methods.Count, sourceProxyType, targetProxyType); builder.WriteCode(code); builder.ReturnTrue(); builder.EndMethod(); } methods.Add(new InsertMethod() { InsertedFormId = insert.InsertedFormId, InsertedFormKind = (FormKind)insert.InsertedFormKind, Copy = insert.Copy }); } unit.Rule.Inserts = methods.ToArray(); } // Declare static helper fields foreach (var helper in engine.HelperProvider.Helpers) { // Skip declaration of helpers that are not used in debug mode if debug mode is disabled if (helper.DebugModeOnly && !debug) continue; builder.WriteCode(string.Format("static readonly {0} {1} = null;", helper.InterfaceType.FullName, helper.Name)); } string finalCode = builder.ToString(); if (!debug) { finalCode = StripDebug(finalCode); } // Write to memory stream using (var memoryStream = new MemoryStream(finalCode.Length)) { var writer = new StreamWriter(memoryStream); writer.Write(finalCode); writer.Flush(); memoryStream.Position = 0; // Find available file name for the new source file. int ruleNumber = 0; string sourceFilePath; do { sourceFilePath = string.Format("{0}@{1:00}.cs", Path.Combine(cachePath, unit.Rule.Metadata.RuleFileName), ruleNumber++); } while (units.Any(u => u.Source == sourceFilePath)); // Update source if necessary var sourceFile = engine.Context.DataFileProvider.GetDataFile(FileMode.Create, sourceFilePath); bool updated = sourceFile.CopyFrom(memoryStream, true); unit.Source = sourceFilePath; unit.Updated = updated; } units.Add(unit); }
public void Add(RuleEntry entry, RuleMetadata metadata, bool debug) { string className = "Rule_" + ruleClassCounter++; var unit = new RuleCompilationUnit() { ClassName = className, ClassFullName = string.Format("{0}.{1}", NamespaceName, className), IsDebugModeEnabled = debug, Rule = new CompiledRule(engine, metadata) { From = entry.From == null ? FormKind.Any : (FormKind)entry.From.FormKind }, }; string comment = string.Format("//\n// Source file for rule {0}\\{1}@{2} by {3}\n//\n", metadata.PluginFileName, metadata.RuleFileName, entry.Name, Program.GetProgramFullVersionInfo()); CodeBuilder builder = new CodeBuilder(NamespaceName, className, comment); builder.Usings.Add("Patcher.Rules.Compiled.Helpers"); builder.Usings.Add("Patcher.Rules.Compiled.Helpers." + engine.Context.GameTitle); builder.Usings.Add("Patcher.Rules.Compiled.Extensions"); builder.Usings.Add("Patcher.Rules.Compiled.Extensions." + engine.Context.GameTitle); builder.Usings.Add("Patcher.Rules.Compiled.Constants"); builder.Usings.Add("Patcher.Rules.Compiled.Constants." + engine.Context.GameTitle); Type sourceProxyType = entry.From != null?engine.ProxyProvider.GetInterface((FormKind)entry.From.FormKind) : typeof(object); if (entry.Where != null) { string code = PreprocessCode(entry.Where.Code); if (StripComments(code).Length > 0) { // TODO: optimize HasTag() with index similarly var match = Regex.Match(code, @"^\s*Source\.EditorId\s*==\s*""([^""]*)""\s*$"); if (match.Success) { unit.Rule.WhereEditorId = match.Groups[1].Value; Log.Fine("Where criteria EditorID == '" + match.Groups[1].Value + "' will use an index."); } else { builder.BeginMethod("Where", sourceProxyType); builder.WriteCodeAsReturn(code); builder.EndMethod(); unit.Rule.Where = new WhereMethod(); } } } if (entry.Select != null) { string code = PreprocessCode(entry.Select.Code); if (StripComments(code).Length > 0) { builder.BeginMethod("Select", sourceProxyType); builder.WriteCode(code); builder.ReturnTrue(); builder.EndMethod(); unit.Rule.Select = new SelectMethod(); } } if (entry.Update != null) { string code = PreprocessCode(entry.Update.Code); if (StripComments(code).Length > 0) { builder.BeginMethod("Update", sourceProxyType, sourceProxyType); builder.WriteCode(code); builder.ReturnTrue(); builder.EndMethod(); unit.Rule.Update = new UpdateMethod(); } } if (entry.Inserts != null) { List <InsertMethod> methods = new List <InsertMethod>(); foreach (var insert in entry.Inserts) { string code = PreprocessCode(insert.Code); if (StripComments(code).Length > 0) { Type targetProxyType = engine.ProxyProvider.GetInterface((FormKind)insert.InsertedFormKind); builder.BeginMethod("Insert_" + methods.Count, sourceProxyType, targetProxyType); builder.WriteCode(code); builder.ReturnTrue(); builder.EndMethod(); } methods.Add(new InsertMethod() { InsertedFormId = insert.InsertedFormId, InsertedFormKind = (FormKind)insert.InsertedFormKind, Copy = insert.Copy }); } unit.Rule.Inserts = methods.ToArray(); } // Declare static helper fields foreach (var helper in engine.HelperProvider.Helpers) { // Skip declaration of helpers that are not used in debug mode if debug mode is disabled if (helper.DebugModeOnly && !debug) { continue; } builder.WriteCode(string.Format("static readonly {0} {1} = null;", helper.InterfaceType.FullName, helper.Name)); } string finalCode = builder.ToString(); if (!debug) { finalCode = StripDebug(finalCode); } // Write to memory stream using (var memoryStream = new MemoryStream(finalCode.Length)) { var writer = new StreamWriter(memoryStream); writer.Write(finalCode); writer.Flush(); memoryStream.Position = 0; // Find available file name for the new source file. int ruleNumber = 0; string sourceFilePath; do { sourceFilePath = string.Format("{0}@{1:00}.cs", Path.Combine(cachePath, unit.Rule.Metadata.RuleFileName), ruleNumber++); } while (units.Any(u => u.Source == sourceFilePath)); // Update source if necessary var sourceFile = engine.Context.DataFileProvider.GetDataFile(FileMode.Create, sourceFilePath); bool updated = sourceFile.CopyFrom(memoryStream, true); unit.Source = sourceFilePath; unit.Updated = updated; } units.Add(unit); }