Hi there ! As I said in the title, I want to know if this is possible to create an Array (or List) with Actions that have different parameters or if there’s another way to do something like this ^^’
Plus, I need too to enter in my function a string, and then creating an Action with this string as the function name… Is this possible in some way ?
If you don’t know what I mean, here’s an example :
List<Action> toDoList = null;
private void AddToDoList(string actionName, DynValue[] parameters) {
Action action = null;
switch (parameters.Length()) {
case 1:
action = new Action<parameters[0].Type>(actionName);
break;
case 2:
action = new Action<parameters[0].Type, parameters[1].Type>(actionName);
break;
case 3:
action = new Action<parameters[0].Type, parameters[1].Type, parameters[2].Type>(actionName);
break;
case 4:
action = new Action<parameters[0].Type, parameters[1].Type, parameters[2].Type, parameters[3].Type>(actionName);
break;
default:
action = new Action(actionName);
break;
}
toDoList.Add(action);
}
PS : I’m using MoonSharp ^^ Dynvalues are values that can have every type you want, and DynValue.Type gives the type of the value.
Generic parameters has to be compile-time constants, so that won’t work. You also can’t generate named methods in this way - method names must be known compile-time.
You can create some kind of string-to-action dictionary, and fill it with actions where you have pre-defined the parameters:
//assuming these methods:
public void Foo() { }
public void Bar(string s) { }
public void FooBar(string s, int i) { }
private Dictionary<string, Action> namedActions = new Dictionary<string, Action>();
public void SetAction(string name, Action a) {
namedActions[name] = a;
}
public void InvokeAction(string name) {
namedActions[name]();
}
public void UsageExample() {
SetAction("CallFoo", Foo);
SetAction("CallBarWithHello", () => Bar("Hello"));
SetAction("CallBarWithGoodbye", () => Bar("Goodbye"));
SetAction("FooBar", () => FooBar("Foo", 156));
InvokeAction("CallFoo");
InvokeAction("CallBarWithHello");
InvokeAction("CallBarWithGoodbye");
InvokeAction("FooBar");
SetAction("CallFoo", () => Debug.Log("Not foo anymore!"));
InvokeAction("CallFoo");
}
I can only really see this relevant if you want to link user input strings to behaviour in some way - this is generally better solved though using actual methods as they were meant to be used.
Oh, so this isn’t possible to do what I wanted to do… Too bad
Your answer may be correct Baste, but I’m actually creating some sort of “starter kit” to create an Undertale’s fangame, and using a Dictinnary like this, if I assume that using a function with different parameters will be one entry of this Dictionnary, it’ll be huge very quickly. Maybe if I just tell you the real problem you’ll be able to help me better ^^’
Here’s the real problem :
In MoonSharp, lua scripts are read then they are executed : the problem with this is that in some cases, the function that I’m using, if it is called several times, will only execute the last call of this function.
For example (in lua) :
function EventPage3()
SetDialog({"This will not appear", "This one too"})
Wait(2)
SetDialog({"Only this will appear"})
end
Only the text “Only this will appear” will appear
And I really want an execution line-per-line, and to do this I need to call a function that binds the lua functions to c# functions, so that binds the lua function’s name and an Action.
I thought that putting these actions in an array would work, but now I know that it’ll won’t
So now I’m asking you if there’s another way to do what I want to do, because I thought about it for some days an I couldn’t find any solution
you’ll need one more parameter, and that’s the object on which the function you’re attempting to create an Action of actually exists. You can’t just create an Action out of thin air by a string name. There could be any number of functions with the name ‘Foo’ in any number of classes/structs/etc. So you need the target (the type if static, or the object itself if instance level)
you’ll need to reflect the MethodInfo for a method with the name and parameter list of types that you received from the array of DynValues. Use this method (or any of its overloads if you need private/protected methods): Type.GetMethod Method (System) | Microsoft Learn
@Baste : All I want to do is to wait until the end of the current function to continue to execute the Lua code : MoonSharp creates, in the function “SetDialog”, a text box, and I want to make the program continue when this text box will be closed : this is all that I want to do, only wait until the end of the actual dialogue.
All the function that I’m using are in the same class as the code I posted here. I created in the script an array of GameObjects with the events that’ll need. On the scripts that I’m binding, there’s a test if a string parameter, the event’s name, is the name of one of the events in the array I created, so I think I don’t need this.
Example (as always) :
private void TeleportEvent(string goName, float dirX, float dirY) {
if (dirX == 0 && dirY == 0)
return;
foreach (GameObject go in events)
if (goName == go.name) {
go.transform.position = new Vector3(dirX, dirY, go.transform.position.z);
return;
}
Debug.Log("The name you entered into the function doesn't exists. Did you forget to add the 'Event' tag ?");
}
(But I may have misunderstood, sorry, I’m French :P)
2)3)4) I tried this, but I have another problem : how do I convert MoonSharp.Interpreter.DataType into Type ? I tried something like this, but it’ll won’t work with an array as parameter (which I need for SetDialog):
private void AddToDoList(string actionName, DynValue[] parameters) {
Type[] types = new Type[parameters.Length];
Type actionType;
for (int i = 0; i < parameters.Length; i++)
switch ((int)parameters[i].Type) {
case 2:
types[i] = typeof(bool);
break;
case 3:
types[i] = typeof(float);
break;
case 4:
types[i] = typeof(string);
break;
}
MethodInfo mInfo = typeof(EventManager).GetMethod(actionName, types);
actionType = Expression.GetActionType(types);
Delegate del = Delegate.CreateDelegate(actionType, mInfo);
}
Plus, if I understand this, I would be able to store these actions in a Delegate array, and then use them by casting them into Action<the arguments that I’ll need> ?
var tp = this.GetType();
//assuming method 'actionName' is public and instance level, and that you have linq
var methInfo = tp.GetMethod(actionName, (from v in parameters select v.Type).ToArray());
Yeah, I know this, but I was saying that DynValue.Type returns a MoonSharp.Interpreter.DataType value, not a Type value…and I was asking if this is possible to convert this returned value into a Type value… This is why I made a switch in my last code snippet, to translate the values given by MoonSharp.Interpreter.DataType into Type values.
But there’s a value “Table” in this enumeration, and it counts all types of arrays without distinction…so I can’t translate arrays from DataType to Type…
oh… Umm, not sure, I don’t use MoonSharp ever. Where’s the documentation on this type?
If this is it:
Then you could write a simple conversion, just a simple switch table, not too difficult. A couple of those types on their I won’t know what the .Net side equivalent is… so either you’ll have to find out, or just not support them (like what is TailCallRequest?).
Ok, so after studying a little more MoonSharp, here’s what I have :
private void AddToDoList(string actionName, DynValue[] parameters) {
Type[] types = new Type[parameters.Length];
for (int i = 0; i < parameters.Length; i++) {
switch ((int)parameters[i].Type) {
case 2:
types[i] = typeof(bool);
break;
case 3:
types[i] = typeof(float);
break;
case 4:
types[i] = typeof(string);
break;
case 6:
DynValue[] arrayVal = TableToList<DynValue>(parameters[i].Table, v => v).ToArray();
switch ((int)arrayVal[0].Type) {
case 2:
types[i] = typeof(bool[]);
break;
case 3:
types[i] = typeof(float[]);
break;
case 4:
types[i] = typeof(string[]);
break;
}
print(types[i]);
break;
}
}
Type actionType = Expression.GetActionType(types);
MethodInfo methInfo = this.GetType().GetMethod(actionName, types);
print(methInfo.Name);
print(actionType.FullName);
Delegate del = Delegate.CreateDelegate(actionType, methInfo);
toDoList.Add(del);
}
Here, at the print of the line 36, for testing with SetDialog and its parameters, I get “SetDialog” as I wanted it, and at the print of the line 37, where I have to get the Action type, I have Action `3[String[ ], Boolean, String[ ]] (as I requested too) but the function CreateDelegate doesn’t work… I get this error :