private void ProcessNode(Class targetClass, Variable parent, string targetList, XmlNode xmlNode) { if (xmlNode == null) return; if (standalone == false) // generate GUID for each xmlnode if (nodeMap.ContainsKey(xmlNode) == false) nodeMap[xmlNode] = Guid.NewGuid().ToString(); //Console.WriteLine("Processing: {0}", xmlNode.Name); Variable obj = parent; string list = null; if (xmlNode.Name == "ZApplication") { if (fullBuild) ParseAttributes(ns.mainClass, parent, xmlNode); } else { // Check if this node is a List property of the parent //FieldInfo fi = parent.type.GetField(xmlNode.Name, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); FieldInfo fi = CodeGenerator.GetField(parent.type, xmlNode.Name); //if (pi != null) Console.WriteLine(" Parent property found: {0}", pi.PropertyType.Name); if (fi != null && typeof(IList).IsAssignableFrom(fi.FieldType)) { //Console.WriteLine("List found: {0}", xmlNode.Name); list = fi.Name; } // Check if this node is an event of the parent else if (fi != null && typeof(Delegate).IsAssignableFrom(fi.FieldType)) { Type type = fi.FieldType; string currentGuid = ""; if (standalone == false) nodeMap.TryGetValue(xmlNode, out currentGuid); string methodName = targetClass.GetNextMethodName(); //bool isStatic = targetClass.baseClass.StartsWith("Prototype"); string header = GetMethodHeader(methodName, type, false); Method met = new Method(header); targetClass.methods.Add(met); //if (isStatic) //{ //Automatically cast the caller to the type of the Model class //met.AddLine(String.Format("{0} model = caller as {0};", targetClass.name)); //} met.AddLine(xmlNode.InnerText); // BIND THE CALLBACK if (targetClass.type == typeof(Model)) targetClass.init.AddLine(String.Format("{0} += {1};", fi.Name, methodName)); // init method points to BindCallbacks() if (fullBuild) { // Add the generated method as an event handler if (targetClass.type == typeof(ZApplication)) ns.mainClass.init.AddLine(String.Format("{0}.{1} += {2};", parent.name, fi.Name, methodName)); if (standalone == false) // Create a ZEvent (always in CustomGame) { string varName = ns.mainClass.GetNextObjectName(); ns.mainClass.init.AddLine(""); ns.mainClass.init.AddLine(String.Format("var {0} = new ZEvent({1}, \"{2}\");", varName, parent.name, fi.Name)); // assign a GUID to the ZEvent ns.mainClass.init.AddLine(String.Format("{0}.GUID = \"{1}\";", varName, currentGuid)); // store the text of the method (for editing purposes) string escaped = xmlNode.InnerText.Replace("\"", "\"\""); // escape inner strings " -> "" ns.mainClass.init.AddLine(String.Format("{0}.Text = @\"{1}\";", varName, escaped)); } } else { if (targetClass.type != typeof(Model)) { string exprName = ns.mainClass.GetNextObjectName(); ns.mainClass.restore.AddLine(""); ns.mainClass.restore.AddLine(String.Format("ZEvent {0} = oldApp.FindEvent(\"{1}\");", exprName, currentGuid)); ns.mainClass.restore.AddLine(String.Format("CodeGenerator.RestoreEvent({0}, {1}, \"{2}\");", exprName, targetClass.variable, methodName)); } } return; //return here, so no TreeNode will be created for the CodeLike component } // Check if this node is a CodeLike property of the parent else if (fi != null && typeof(CodeLike).IsAssignableFrom(fi.FieldType)) { Type type = fi.FieldType; if (type == typeof(CustomCodeDefinition)) // handle custom code definitions { targetClass.definitions.Add(xmlNode.InnerText); } else if (type == typeof(VirtualMethod)) { string methodName = targetClass.GetNextMethodName(); object[] attributes = fi.GetCustomAttributes(typeof(MethodSignature), false); if (attributes.Length == 1 && attributes[0] is MethodSignature) { MethodSignature ms = attributes[0] as MethodSignature; Method met = new Method(ms.Signature); targetClass.methods.Add(met); met.AddLine(xmlNode.InnerText); } else { Console.WriteLine("Missing MethodSignature attribute on VirtualMethod: {0}.{0}", parent.name, xmlNode.Name); return; } } // if (standalone == false && fullBuild == true) // assign the GUIDs to the CodeLike components // { // ns.mainClass.init.AddLine(String.Format("{0}.{1}.GUID = \"{2}\";", parent.name, fi.Name, currentGuid)); // // } // if not shader if (standalone == false && fullBuild == true) // no need for the code text in a standalone build { string escaped = xmlNode.InnerText.Replace("\"", "\"\""); // escape inner strings " -> "" ns.mainClass.init.AddLine(String.Format("{0}.{1}.Text = @\"{2}\";", parent.name, fi.Name, escaped)); } //Console.WriteLine("Code Text:\n{0}", code.Text); return; //return here, so no TreeNode will be created for the CodeLike component } else { obj = InitComponent(ns.mainClass, xmlNode.Name, xmlNode, parent, targetList); if (obj == null) { Console.WriteLine("SKIPPING subtree - Cannot find type: {0}", xmlNode.Name); return; } if (xmlNode.Name == "Model") { string modelName = obj.name + "Model"; Class model = new Class(typeof(Model), modelName, "Model", obj.name, false); //String.Format("Prototype<{0}>", modelName) model.constructor = new Method("public " + modelName + "(ZComponent parent): base(parent)"); var staticApp = new StaticVariable(typeof(ZApplication), "CustomGame", "App", false); model.memberVars.Add(staticApp); ns.mainClass.staticRef.AddLine(String.Format("{0}.App = this;", modelName)); //model.constructor.AddLine("InitializeComponents();"); model.init = new Method("public override void BindCallbacks()"); //model.init.AddLine("CreateNamedComponents();"); //model.createNamed = new Method("public void CreateNamedComponents()"); ns.helperClasses.Add(model); targetClass = model; } } } foreach (XmlNode childNode in xmlNode.ChildNodes) { if (childNode.NodeType == XmlNodeType.Element) { ProcessNode(targetClass, obj, list, childNode); } } }
private void ParseAttributes(Class targetClass, Variable obj, XmlNode xmlNode) { if (xmlNode.Attributes != null) { foreach (XmlAttribute attribute in xmlNode.Attributes) { //if (attribute.Name == "Name") continue; if (xmlNode.Name == "GameObject" && attribute.Name == "Model") continue; string val = attribute.Value; FieldInfo fi = obj.type.GetField(attribute.Name, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance); if (fi != null) { Type type = fi.FieldType; if (xmlNode.Name == "ZApplication" && specialVars.Contains(attribute.Name)) SetAttribute(targetClass.constructor, type, val, obj.name, attribute.Name); else SetAttribute(targetClass.init, type, val, obj.name, attribute.Name); } else { // Also try a Property with a public setter PropertyInfo pi = obj.type.GetProperty(attribute.Name, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance); if (pi != null && pi.GetSetMethod() != null) { SetAttribute(targetClass.init, pi.PropertyType, val, obj.name, attribute.Name); } else { // These components might have custom fields (those will be resolved after compilation) if (xmlNode.Name == "ZApplication" || xmlNode.Name == "Model" || xmlNode.Name == "GameObject") { unresolved.Add(new UnresolvedField { targetClass = targetClass, objName = obj.name, objTypeName = obj.typeName, fieldName = attribute.Name, value = val }); } else Console.WriteLine(" Field not found: {0} - {1}", attribute.Name, val); } } } } }
private Variable InitComponent(Class targetClass, string typeName, XmlNode xmlNode, Variable parent, string targetList) { var type = types.Find(it => it.Name == typeName); Variable obj = null; string model = null; if (typeName == "GameObject") { XmlAttribute attribute = xmlNode.Attributes["Model"]; if (attribute != null) { model = attribute.Value; typeName = attribute.Value + "Model"; type = typeof(Model); } else { Console.WriteLine("Cannot instantiate GameObject without a Model!"); return null; } } if (type != null) { if (fullBuild) targetClass.init.AddLine(""); XmlAttribute attribute = xmlNode.Attributes["Name"]; if (attribute == null) { string objName = targetClass.GetNextObjectName(); obj = new Variable(type, typeName, objName, false); if (typeName == "Model") { Console.WriteLine("Cannot process Model without a name!"); return null; } if (fullBuild) { if (model != null) //GameObject without a name, it has to be CLONED { targetClass.init.AddLine(String.Format("var {0} = ({1}) {2}.Clone();", objName, typeName, model)); } else targetClass.init.AddLine(String.Format("var {0} = new {1}({2});", objName, typeName, parent.name)); } } else { string objName = attribute.Value; if (typeName == "Model") typeName = objName + "Model"; obj = new Variable(type, typeName, objName, false); targetClass.memberVars.Add(obj); if (fullBuild) { if (model != null) //GameObject with a name, it has to be CLONED { targetClass.init.AddLine(String.Format("{0} = ({1}) {2}.Clone();", objName, typeName, model)); } else { targetClass.createNamed.AddLine(String.Format("{0} = new {1}({2});", objName, typeName, parent.name)); } } else if (xmlNode.Name == "Model") { targetClass.restore.AddLine(""); targetClass.restore.AddLine(String.Format("{0} = new {1}({2});", objName, typeName, parent.name)); //targetClass.restore.AddLine(String.Format("{0} = {1}.CreatePrototype();", objName, typeName)); string currentGuid = ""; nodeMap.TryGetValue(xmlNode, out currentGuid); targetClass.restore.AddLine(String.Format("CodeGenerator.Restore({0}, oldApp.FindPrototype(\"{1}\"));", objName, currentGuid)); // Re-create all GameObjects in the scene by cloning the Model prototypes targetClass.restore.AddLine(String.Format("foreach (Model gameObj in oldApp.FindGameObjects(\"{0}\"))", currentGuid)); targetClass.restore.AddLine("{"); //targetClass.restore.AddLine("Console.WriteLine(\"GO found: {0} - {1}\", gameObj.GetType().Name, gameObj.Name);"); targetClass.restore.AddLine(String.Format(" var temp = {0}.Clone() as Model;", objName)); targetClass.restore.AddLine(String.Format(" CodeGenerator.Restore(temp, gameObj);")); targetClass.restore.AddLine(String.Format(" if (oldApp.SelectedObject == gameObj) this.SelectedObject = temp;")); targetClass.restore.AddLine("}"); } } if (fullBuild) { ParseAttributes(targetClass, obj, xmlNode); //targetClass.init.AddLine(String.Format("AddComponent({0});", obj.name)); if (standalone == false) // assign GUIDs to Model components { if (xmlNode.Name == "Model") { string currentGuid = ""; nodeMap.TryGetValue(xmlNode, out currentGuid); targetClass.createNamed.AddLine(String.Format("{0}.GUID = \"{1}\";", obj.name, currentGuid)); } } if (parent != null) { // We always need an Owner //targetClass.init.AddLine(String.Format("{0}.Owner = {1};", obj.name, parent.name)); if (targetList != null) // components in member lists are not considered children! { //Console.WriteLine("Adding to list: {0}", parent_list.GetType().Name); //targetClass.init.AddLine(String.Format("{0}.OwnerList = (IList) {1}.{2};", obj.name, parent.name, targetList)); //targetClass.init.AddLine(String.Format("{0}.{1}.Add({2});", parent.name, targetList, obj.name)); targetClass.init.AddLine(String.Format("{0}.SetOwner({1}, (IList) {1}.{2});", obj.name, parent.name, targetList)); } else { //targetClass.init.AddLine(String.Format("{0}.Children.Add({1});", parent.name, obj.name)); targetClass.init.AddLine(String.Format("{0}.SetOwner({1}, null);", obj.name, parent.name)); } } } } return obj; }
public string GenerateCodeFromXml(XmlDocument xml, bool standalone, bool fullBuild, Dictionary<XmlNode, string> nodeMap) { XmlNode rootElement = xml.DocumentElement; if (standalone && fullBuild == false) fullBuild = true; // no incremental build for standalone this.standalone = standalone; this.fullBuild = fullBuild; if (standalone == false) // no need for XmlNode->GUID mapping at standalone builds { if (nodeMap == null) this.nodeMap = new Dictionary<XmlNode, string>(); else this.nodeMap = nodeMap; } cu = new CompileUnit(); cu.AddUsing("using System;"); cu.AddUsing("using System.Collections;"); cu.AddUsing("using System.Collections.Generic;"); cu.AddUsing("using System.Text;"); cu.AddUsing("using System.Drawing;"); cu.AddUsing("using OpenTK;"); cu.AddUsing("using OpenTK.Graphics;"); cu.AddUsing("using OpenTK.Graphics.OpenGL;"); cu.AddUsing("using ZGE.Components;"); cu.AddUsing("using Gwen.Control;"); //if (standalone == false) // cu.AddUsing("using System.ComponentModel"); ns = new Namespace("ZGE"); cu.namespaces.Add(ns); Class main = new Class(typeof(ZApplication), "CustomGame", "ZApplication", "this", true); ns.mainClass = main; main.constructor = new Method("public CustomGame()"); main.staticRef = new Method("public override void SetStaticReferences()"); if (fullBuild) { //main.constructor.AddLine("if (createAll) InitializeComponents();"); main.init = new Method("public override void InitializeComponents()"); main.init.AddLine("CreateNamedComponents();"); main.createNamed = new Method("public override void CreateNamedComponents()"); } else { main.restore = new Method("public void RestoreComponents(ZApplication oldApp)"); main.restore.AddLine("CodeGenerator.Restore(this, oldApp);"); } types = Factory.GetTypesFromNamespace(Assembly.GetAssembly(typeof(ZApplication)), "ZGE.Components"); types.AddRange(Factory.GetTypesFromNamespace(Assembly.GetAssembly(typeof(ZApplication)), "Gwen.Control")); Variable dummy = new Variable(typeof(ZApplication), "CustomGame", "this", false); if (rootElement != null) ProcessNode(main, dummy, null, rootElement); if (standalone) { Method mm = new Method("[STAThread]\npublic static void Main()"); main.methods.Add(mm); mm.AddLine("ZApplication app = new CustomGame();"); mm.AddLine("using (Standalone game = new Standalone(app))"); mm.AddLine("{"); mm.AddLine(" game.Run(app.UpdateFrequency);"); mm.AddLine("}"); } string code = cu.GetFullCode(); // Save the file for debugging using (StreamWriter writer = new StreamWriter("DynamicGame.cs", false)) { writer.Write(code); } return code; }