From ab8eb1cbe0ad329c0619c859577f5405a10b2d5b Mon Sep 17 00:00:00 2001 From: EgoMoose Date: Wed, 29 Mar 2023 10:53:51 -0400 Subject: [PATCH] Add modifiers module Runs when the PlayerModule is required thus allowing developers to inject custom code modules into the PlayerModule scripts before anything is initialized. This helps a fair bit when you want to make lasting changes that can build on top of each other. --- .../{Header.lua => CameraModuleHeader.lua} | 2 +- .../PlayerModule/Lua/Modifiers.lua | 35 +++++++++++++++++++ .../PlayerModule/Lua/PlayerModuleHeader.lua | 6 ++++ cli/PlayerScripts/PlayerModule/Lua/init.lua | 4 +-- cli/PlayerScripts/PlayerModule/Package.py | 25 ++++++++++++- cli/PlayerScripts/PlayerModule/README.md | 34 ++++++++++++++++-- 6 files changed, 99 insertions(+), 7 deletions(-) rename cli/PlayerScripts/PlayerModule/Lua/{Header.lua => CameraModuleHeader.lua} (77%) create mode 100644 cli/PlayerScripts/PlayerModule/Lua/Modifiers.lua create mode 100644 cli/PlayerScripts/PlayerModule/Lua/PlayerModuleHeader.lua diff --git a/cli/PlayerScripts/PlayerModule/Lua/Header.lua b/cli/PlayerScripts/PlayerModule/Lua/CameraModuleHeader.lua similarity index 77% rename from cli/PlayerScripts/PlayerModule/Lua/Header.lua rename to cli/PlayerScripts/PlayerModule/Lua/CameraModuleHeader.lua index a34ffcd..de12d95 100644 --- a/cli/PlayerScripts/PlayerModule/Lua/Header.lua +++ b/cli/PlayerScripts/PlayerModule/Lua/CameraModuleHeader.lua @@ -1,4 +1,4 @@ -local patchModule = script.Parent:WaitForChild("Patch") +local patchModule = script.Parent:FindFirstChild("Patch") local patch = patchModule and require(patchModule) local setmetatable = setmetatable diff --git a/cli/PlayerScripts/PlayerModule/Lua/Modifiers.lua b/cli/PlayerScripts/PlayerModule/Lua/Modifiers.lua new file mode 100644 index 0000000..3f00a78 --- /dev/null +++ b/cli/PlayerScripts/PlayerModule/Lua/Modifiers.lua @@ -0,0 +1,35 @@ +--!strict + +local PlayerModule = script.Parent + +local module = {} + +function module.add(modifier: ModuleScript, priority: number?) + local copy = modifier:Clone() + copy:SetAttribute("Priority", priority) + copy.Parent = script +end + +function module.apply() + local children = script:GetChildren() :: {ModuleScript} + + table.sort(children, function(a, b) + local pa = a:GetAttribute("Priority") :: number? + local pb = b:GetAttribute("Priority") :: number? + + if pa and pb then + return pa < pb + elseif pb then + return false + end + + return true + end) + + for _, child in children do + local callback = require(child) :: (ModuleScript) -> () + callback(PlayerModule) + end +end + +return module \ No newline at end of file diff --git a/cli/PlayerScripts/PlayerModule/Lua/PlayerModuleHeader.lua b/cli/PlayerScripts/PlayerModule/Lua/PlayerModuleHeader.lua new file mode 100644 index 0000000..8ee922e --- /dev/null +++ b/cli/PlayerScripts/PlayerModule/Lua/PlayerModuleHeader.lua @@ -0,0 +1,6 @@ +local modifiersModule = script:FindFirstChild("Modifiers") +local modifiers = modifiersModule and require(modifiersModule) + +if modifiers then + modifiers.apply() +end \ No newline at end of file diff --git a/cli/PlayerScripts/PlayerModule/Lua/init.lua b/cli/PlayerScripts/PlayerModule/Lua/init.lua index 257830c..fd3225c 100644 --- a/cli/PlayerScripts/PlayerModule/Lua/init.lua +++ b/cli/PlayerScripts/PlayerModule/Lua/init.lua @@ -24,15 +24,13 @@ function module.getCopy(patched: boolean): ModuleScript return module.get(patched):Clone() end -function module.replace(patched: boolean): ModuleScript +function module.replace(playerModule: ModuleScript) local existing = StarterPlayerScripts:FindFirstChild(MODULE_NAME) if existing then existing:Destroy() end - local playerModule = module.getCopy(patched) playerModule.Parent = StarterPlayerScripts - return playerModule end return module \ No newline at end of file diff --git a/cli/PlayerScripts/PlayerModule/Package.py b/cli/PlayerScripts/PlayerModule/Package.py index e7d8c5e..202d54b 100644 --- a/cli/PlayerScripts/PlayerModule/Package.py +++ b/cli/PlayerScripts/PlayerModule/Package.py @@ -9,6 +9,28 @@ def add_package_init(package_path): os.path.join(package_path, 'init.lua') ) +def patch_player_module(patched_player_module_path): + shutil.copy( + os.path.join(lua_folder, 'Modifiers.lua'), + os.path.join(patched_player_module_path, 'Modifiers.lua') + ) + + player_module_init_path = os.path.join( + patched_player_module_path, + 'init.lua' + ) + + header = None + with open(os.path.join(lua_folder, 'PlayerModuleHeader.lua'), 'r') as f: + header = f.read() + + existing = None + with open(player_module_init_path, 'r') as f: + existing = f.read() + + with open(player_module_init_path, 'w') as f: + f.write(header + '\n\n' + existing) + def patch_camera_module(patched_player_module_path): shutil.copy( os.path.join(lua_folder, 'Patch.lua'), @@ -22,7 +44,7 @@ def patch_camera_module(patched_player_module_path): ) header = None - with open(os.path.join(lua_folder, 'Header.lua'), 'r') as f: + with open(os.path.join(lua_folder, 'CameraModuleHeader.lua'), 'r') as f: header = f.read() existing = None @@ -45,6 +67,7 @@ def package(src_path): shutil.move(tmp_src_path, patched_player_module_path) add_package_init(src_path) + patch_player_module(patched_player_module_path) patch_camera_module(patched_player_module_path) if os.path.exists(tmp_src_path): diff --git a/cli/PlayerScripts/PlayerModule/README.md b/cli/PlayerScripts/PlayerModule/README.md index c9dd44e..a9cb85f 100644 --- a/cli/PlayerScripts/PlayerModule/README.md +++ b/cli/PlayerScripts/PlayerModule/README.md @@ -8,8 +8,8 @@ Package.get(patched: boolean): ModuleScript Package.getCopy(patched: boolean): ModuleScript -- replaces the PlayerModule under StarterPlayer.StarterPlayerScripts --- with a copy of the patched or unpatched version the PlayerModule and returns the copy -Package.replace(patched: boolean): ModuleScript +-- with the provided module script +Package.replace(playerModule: ModuleScript) ``` ## Patched CameraModule @@ -23,6 +23,7 @@ Package ... PlayerModulePatched Patch.lua (new file) + Modifiers.lua (new file) CameraModule init.lua (modified) ControlModule @@ -37,6 +38,35 @@ Since this is a open source project it's worth discussing how this module is "pa ### Patch Criteria +#### Modifiers.lua + +A submodule is added to the patched `PlayerModule` which provides the ability to write custom code additions/modifications to the `PlayerModule`. The interface of this module looks like this: + +```Lua +-- adds custom modifier module script to be run at a certain priority level +-- if no priority is specified then the code will be run at the end in no particular order +Modifiers.add(modifier: ModuleScript, priority: number?) +``` + +The modifier modules themselves are quite straightforward. They should return a function that accepts one argument: reference to the `PlayerModule` instance. For example a modifier might look like this: + +```Lua +-- some module in the game that handles player control +local controlBindings = require(...) + +return function (PlayerModule: ModuleScript) + local controlObject = require(PlayerModule.ControlModule) + + controlBindings.setEnableCallback(function(enabled) + if enabled then + controlObject:Enable() + else + controlObject:Disable() + end + end) +end +``` + #### Only header additions Your first thought if asked to make the CameraModule API public might be to write a regex replace or modify lines in the existing source string so that the module doesn't return an empty table.