Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about execution scopes #495

Open
FelipeVieiraVendramini opened this issue Jun 21, 2023 · 1 comment
Open

Question about execution scopes #495

FelipeVieiraVendramini opened this issue Jun 21, 2023 · 1 comment

Comments

@FelipeVieiraVendramini
Copy link

FelipeVieiraVendramini commented Jun 21, 2023

I'm working on a project and we have a lot of .lua scripts already done, hundred scripts. Loading them takes a few seconds (2-4 seconds) which is actually a little bit overkill. Of course I could just load the scripts only once and it would work, except for only one thing, only the scripts that call static C# functions would work.

This works until I need to call the functions that need an actor to work. They do not need an actor in the LUA context, but I need LUA to execute the methods from the actor.

public class LuaMgr
{
	private static Lua lua;

	public static void Initialize()
	{
		lua = new Lua();
		
		logger.LogInformation("Loading LUA scripts...");

		foreach (var item in LuaScriptsSettings.Scripts)
		{
			string[] splitPath = item.Value.Split('\\');
			string realPath = Path.Combine(splitPath);
			realPath = Path.Combine(Environment.CurrentDirectory, "lua", realPath);

			if (!File.Exists(realPath))
			{
				logger.LogWarning("Script file \"{path}\" not found!", item.Value);
				continue;
			}

#if DEBUG
			logger.LogDebug("Loading script file \"{path}\"", item.Value);
#endif

			lua.DoFile(realPath);
		}

		logger.LogInformation("LUA Scripts loaded");

		logger.LogInformation("Registering LUA functions");

		lua.RegisterFunction("SysCheckTime", typeof(SystemScript).GetMethod("SysCheckTime", new Type[]
		{
			typeof(int), typeof(string)
		}));

		logger.LogInformation("LUA functions registered!");
	}

	public static void Run(string script, Actor actor)
	{
		using var luaScoped = lua.State.NewThread();
		var runner = new LuaRunner(luaScoped, actor);
		runner.Run(script);
	}
}

I know that if I do lua.RegisterFunction("ActorFunction", actor, typeof(Actor).GetMethod("MethodName")) this will register the actor within the method, but my actor is dynamic and I cannot be loading the Lua files every for every actor (not only because of the time and the delay caused in the application, but ONE instance of Lua with all scripts loaded takes up to 800MB in memory).

The .lua files has a lot of scripts ready to be run by the application, calling LuaMgr.Run won't add new scripts, it will just execute the currently loaded ones (Example: LuaMgr.Run("UpdateWindow(1,2,3)", actor)).

Is there any way to clone the main Lua instance and register the functions within the actor only to the current context? There's anyway I can do it without editing every single file to pass the actor back to C#?

The LuaRunner class

public class LuaRunner
{
	private readonly Lua lua;
	private readonly Actor actor;
	
	public LuaRunner(Lua lua, Actor actor)
	{
		this.lua = lua;
		this.actor = actor;
	}
	
	public void Run(string script)
	{
		this.lua.DoString(script);
	}
	
	#region LUA Callbacks
	
	public int GetActorData(int actorId, int index)
	{
		Actor currentActor;
		if (actorId <= 0)
		{
			currentActor = this.actor;
		}
		else
		{
			currentActor = ActorManager.FindActor(actorId);
		}
		
		if (currentActor == null)
		{
			return 0;
		}
		
		switch (index)
		{
			case 0: return currentActor.Property1;
			case 1: return currentActor.Property2;
			case 2: return currentActor.Property3;
			default: return 0;
		}
	}
	
	#endregion
}

The LuaRunner is planned to be registered with the function. Basically most function calls will be to static functions, but few ones will ask for information about the actor who is executing the action.

I thought about making it register the methods every time I create a new LuaRunner instance, but the NewThread which I was thinking that would fit my needs returns an instance of KeraLua.Lua, which I couldn't find anything about how to register a C# function to it.

It would be something like this

private void RegisterMethods()
{
	lua.RegisterFunction("GetActorData", this, typeof(LuaRunner).GetMethod("GetActorData", new Type[] { typeof(int), typeof(int) }));
	/// ... etc
}

I'm stuck with this, been researching with NLua, KeraLua, MoonSharp and others but couldn't find anything like this. The closest issue that I found about this subject was about AI (check here), and it's almost my problem.
Except that it's not for AI, but for game events (like killing a monster, clicking a NPC or an item etc).

There's any way to achieve what I'm trying to? Can I get any direction?

@noncom
Copy link

noncom commented Aug 4, 2023

I'm sorry if I misunderstand something, but why can't you just create a single Lua environment with all the scripts, and pass the "actor" to the Lua methods you're calling, so that they know what actor to work on? Isn't it just the same as passing a variable?

Or build and maintain a table with your actors within the Lua environemnt so that it has some kind of access to them?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants