Hi!
I must start with to say, thank you for a quick reply when I previously
E-Mailed you, JB Evains!
To make it easier, i will paste some of the mail I sent JB Evains earlier.
----
I'm trying to create an application to translate Bethesda's Skyrim Papyrus
script into CLR and back. Enabling people to write all scripts using C# or
any other .NET language; build it using visual studio and then
automatically converts the CIL from the built .dll into Papyrus Assembly
code. So far this works for very simple .NET applications. It even builds
the output Papyrus Assembly into a compiled script that works in Skyrim.
Now for my main issue. I'm also trying to do it the other way around. And
that is to read a Papyrus Assembly Code and generate a .NET library so that
the users can reference to any existing scripts from C#.
I'm able to generate a .dll after reading a Papyrus Assembly file but
having issues wheb it comes to the TypeReference object. Since Papyrus is
a Object Oriented Script Language it contains stuff as extending a script
from another (BaseTypes) using other scripts as variables, parameters and
ReturnTypes for methods.
But the issue is that when I'm trying to add a basetype to a defined
TypeDefinition using a TypeReference, or when trying to add a TypeReference
to a parameter or as a ReturnType of a method, i'm able to write the binary
but when i try to reference to the written binary from a new .NET project,
all the objects gives out weird information in the intellisense of visual
studio.
Looks like:
PapyrusDotNet.Core.Actor+ PapyrusDotNet.Core.ObjectReference/Form
And doesnt show any information about the parameters or the method name.
What would be the best way to define your own TypeReference when you are
trying to Reference to a Type that you have created inside the same Module.
Basically, best way to get a TypeReference from a TypeDefinition?
Now, for some code, this is how i create my TypeDefinitions (Remember, the
original scripts are referencing to eachother but at the same time i'm only
adding them one after another, which I know that right now gave me a small
headache as it may happen that one of the scripts parsed/ and added as a
TypeDefinition to my output .dll are referencing to other objects that not
yet have been added. I tried solving this by going through all those
references after all objects have been added and updating any references
that did not work during the parsing)
public static TypeDefinition TypeDefinitionFromPapyrus(PapyrusAsmObject
input)
{
var newType = new TypeDefinition("PapyrusDotNet.Core", input.Name,
TypeAttributes.Class);
newType.IsPublic = true;
if (!string.IsNullOrEmpty(input.ExtendsName))
{
newType.BaseType = new TypeReference("PapyrusDotNet.Core",
input.ExtendsName, MainModule, MainModule);
newType.DeclaringType = MainModule.Types.FirstOrDefault(t => t.FullName ==
newType.BaseType.FullName);
newType.Scope = MainModule;
}
foreach (var prop in input.PropertyTable)
{
var typeRef = GetTypeReference(null, prop.Type);
var pro = new PropertyDefinition(prop.Name, PropertyAttributes.HasDefault,
typeRef);
newType.Properties.Add(pro);
}
AddEmptyConstructor(newType);
foreach (var state in input.States)
{
TypeReference typeRef = GetTypeReference(newType);
// var typeRef = MainModule.TypeSystem.Void;
var function = new MethodDefinition(state.Name, MethodAttributes.Public,
typeRef);
function.IsStatic = state.IsStatic;
foreach (var par in state.Params)
{
TypeReference typeRefp = GetTypeReference(null, par.Type);
// var typeRefp = MainModule.TypeSystem.Object;
var nPar = new ParameterDefinition(par.Name, ParameterAttributes.None,
typeRefp);
function.Parameters.Add(nPar);
}
bool skipAdd = false;
foreach (var m in newType.Methods)
{
if (m.Name == function.Name)
{
if (m.Parameters.Count == function.Parameters.Count)
{
skipAdd = true;
for (int pi = 0; pi < m.Parameters.Count; pi++)
{
if (m.Parameters[pi].ParameterType.FullName !=
function.Parameters[pi].ParameterType.FullName) skipAdd = false;
}
break;
}
}
}
if (!skipAdd)
newType.Methods.Add(function);
}
return newType;
}
public static void AddEmptyConstructor(TypeDefinition type)
{
var methodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig
| MethodAttributes.SpecialName | MethodAttributes.RTSpecialName;
var method = new MethodDefinition(".ctor", methodAttributes,
MainModule.TypeSystem.Void);
/*method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Call,
baseEmptyConstructor));
*/
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
type.Methods.Add(method);
}
private static TypeReference GetTypeReference(TypeDefinition newType,
string fallback = null)
{
var typeName = "";
if (!string.IsNullOrEmpty(fallback))
typeName = fallback;
else
typeName = newType.FullName;
var ns = GetTypeNamespace(typeName);
var tn = GetTypeName(typeName);
if (ns == "System")
{
switch (tn.ToLower())
{
case "none":
case "void":
return MainModule.TypeSystem.Void;
case "int":
return MainModule.TypeSystem.Int32;
case "string":
return MainModule.TypeSystem.String;
case "float":
return MainModule.TypeSystem.Double;
case "bool":
case "boolean":
return MainModule.TypeSystem.Boolean;
default:
return MainModule.TypeSystem.Object;
}
}
var typeRef = new TypeReference(ns, tn, MainModule, MainModule);
typeRef.DeclaringType = MainModule.Types.FirstOrDefault(t => t.FullName ==
typeName);
typeRef.Scope = MainModule;
return typeRef;
}
private static string GetTypeName(string p)
{
if (p.Contains('.')) p = p.Split('.').LastOrDefault();
var pl = p.ToLower();
if (pl == "boolean")
return "bool";
if (pl == "none")
return "void";
if (pl == "float" || pl == "int" || pl == "bool" || pl == "string") return
pl;
return p;
}
private static string GetTypeNamespace(string p)
{
if (p.Contains('.')) p = p.Split('.').LastOrDefault();
var pl = p.ToLower();
/* have not added all possible types yet though.. might be a better way of
doing it. */
if (pl == "string" || pl == "int" || pl == "boolean" || pl == "bool" || pl
== "none"
|| pl == "void" || pl == "float" || pl == "short" || pl == "char" || pl
== "double"
|| pl == "int32" || pl == "integer32" || pl == "long" || pl == "uint")
{
return "System";
}
return "PapyrusDotNet.Core";
}
I'm sorry for the lack of comments in my code...
But as I said before, i'm able to build a .dll containing the classes that
I was looking for, except... When I'm opening up the .dll file in, lets say
.NET Reflector
The classes looks like following:
namespace PapyrusDotNet.Core
{
using System;
public class Action : Form
{
public Form.Action.Form/Action GetState();
public Form.Action.Form/Action GotoState(string newState);
}
}
Clicking on 'Form.Action.Form/Action' would give me an error as
'PapyrusDotNet.Core.Form+Action+Form/Action' is not loaded or may be hidden
due to your visbility settings.
And when referencing to this dll in visual studio, lets say I have a method
called:
public ObjectReference OnSell(Actor actor)
but in Intellisense i get something as following for it:
(PapyrusDotNet.Core.actor
akSeller):PapyrusDotNet.Core.Form+PapyrusDotNet.Core.ObjectReference+PapyrusDotNet.Core.Form/ObjectReference
When i'm expecting to see:
(Actor akSeller):ObjectReference
Once again, I have to apologize for this long post! I hope it made any
sense to you guys, in general what i'm trying to do is to create an
assembly using mono.cecil, within this assembly i define new Types and
those types may be extending some of eachother, so one type that ive
recently added to the assembly might be extending another/new type that is
being added later in the process. These types are in turn used as
parameters, method returnTypes and variables.
Best Regards,
Karl Johansson
--
--
--
mono-cecil
---
You received this message because you are subscribed to the Google Groups
"mono-cecil" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.