-
Notifications
You must be signed in to change notification settings - Fork 613
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
How to bind multiple lua scripts to the same blueprint class? #658
Comments
You cannot directly do it in UnLua, because a UClass should only bind to one lua module. But there's another way to do the same thing by duplicating a class from the source class and dynamicly bind it to the same lua file. Example function to duplicate from a BlueprintGeneratedClass void BeginGenerator(UClass* InClass, UClass* InParentClass)
{
InClass->PropertyLink = InParentClass->PropertyLink;
InClass->ClassWithin = InParentClass->ClassWithin;
InClass->ClassConfigName = InParentClass->ClassConfigName;
InClass->SetSuperStruct(InParentClass);
}
UClass* CreateBlueprintGeneratedClass(UClass* InClass)
{
const auto ClassNameString = FString::Printf(TEXT("LUA_GENERATED_%s"), *InClass->GetName());
const auto ClassName = MakeUniqueObjectName(GetTransientPackage(), InClass, FName(*ClassNameString));
UBlueprintGeneratedClass* Class = NewObject<UBlueprintGeneratedClass>(GetTransientPackage(), ClassName, RF_Public | RF_Transient);
Class->UpdateCustomPropertyListForPostConstruction();
const auto Blueprint = NewObject<UBlueprint>(Class);
Blueprint->AddToRoot();
Blueprint->SkeletonGeneratedClass = Class;
Blueprint->GeneratedClass = Class;
#if WITH_EDITOR
Class->ClassGeneratedBy = Blueprint;
#endif
BeginGenerator(Class, InClass);
EndGenerator(Class);
Class->ClassFlags |= InClass->ClassFlags & CLASS_NewerVersionExists;
Class->AddToRoot();
return Class;
} And then in lua: local Newclass1 = UE.YourLibrary.Createclass(YourBlueprintClass) -- duplicate from YourBlueprintClass
local Object1 = Newobject(Newclass1,GetCurrentWorld(),nil,"test1") -- bind to test1.lua
local Newclass2 = UE.YourLibrary.Createclass(YourBlueprintClass)
local Object2 = NewObject(Newclass2,GetcurrentWorld(),nil, "test2") Don't forget to remove the class from root when it's useless. |
Really appreciate your example which is pretty clear and straightforward! But I have another question here, let's say we have two lua scripts: local Screen = require "Tutorials.Screen"
local M = UnLua.Class()
function M:ReceiveBeginPlay()
local msg = self:SayHi("Hi from test1")
Screen.Print(msg)
end
return M test2.lua local Screen = require "Tutorials.Screen"
local M = UnLua.Class()
function M:ReceiveBeginPlay()
local msg = self:SayHi("Hi from test2")
Screen.Print(msg)
end
function M:SayHi(name)
local origin = self.Overridden.SayHi(self, name)
return "overridden:" .. origin
end
return M and blueprint BP_Test with function SayHi that just returns the name. now I want to 'merge' test1.lua and test2.lua at runtime based on the loading order (test1.lua comes from mod1, test2.lua comes from mod2 and player can decide to load the mod1 first and then the mod2) local Screen = require "Tutorials.Screen"
local M = UnLua.Class()
function M:ReceiveBeginPlay()
local msg = self:SayHi("Hi from test1")
Screen.Print(msg)
-- merged from test2.lua
local msg = self:SayHi("Hi from test2")
Screen.Print(msg)
--
end
-- merged from test2.lua
function M:SayHi(name)
local origin = self.Overridden.SayHi(self, name)
return "overridden:" .. origin
end
--
return M
and then bind this test_merged.lua to the blueprint. I'm not quite familiar with lua, maybe there is already an elegant solution to achieve this but what comes to my mind is to integrate a 'git' tool to our game and generate some intermediate files from users' mods and bind them like the traditional ways. Why do we need this?We are trying to make a mod system that allows the community to write third-party mods. And we want to make all of the loaded mods compatible. |
It's not easy to merge different lua files, because This approach may lead to timing issues. I think you may merge two lua files at runtime. Firstly, use a template lua file: local Screen = require "Tutorials.Screen"
local M = UnLua.Class()
function M:ReceiveBeginPlay()
end
return M then require the template file and merge two lua files to the template: -- you should empty the required template.lua first so that unlua can bind to the new module
if packege.loaded["template"] then
packege.loaded["template"] = nil
end
-- require template
local template = require("template")
local mod1 = require("test1")
local mod2 = require("test2")
-- merge functions to template
for k,v in pairs(mod1):
-- skip overrided function
if k ~= "ReceiveBeginPlay" then
template[k] = v
end
end
for k,v in pairs(mod2):
-- skip overrided function
if k ~= "ReceiveBeginPlay" then
template[k] = v
end
end
-- merge overrided function like ReceiveBeginPlay, don't forget to pass self and other params to functions
template.ReceiveBeginPlay = function(param_self)
if mod1.ReceiveBeginPlay then
mod1.ReceiveBeginPlay(param_self)
end
if mod2.ReceiveBeginPlay then
mod2.ReceiveBeginPlay(param_self)
end
end
-- dynamicly bind the merged lua to a new uobject
local MergedObject = Newobject(YourClass,GetCurrentWorld(),nil,"template") I still have to say it's not easy, because you cannot imagine what kind of codes the community could write. |
Thank you and this really helps me a lot! |
I'm trying to figure out a mod system solution for my game which requires to bind multiple lua scripts to the same blueprint at runtime.
I mean there will be many mods came from different authors who probably want to override the same class but they don't know each other in advance.
The text was updated successfully, but these errors were encountered: