Skip to content

Commit ab8eb1c

Browse files
committed
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.
1 parent cb00c37 commit ab8eb1c

File tree

6 files changed

+99
-7
lines changed

6 files changed

+99
-7
lines changed

cli/PlayerScripts/PlayerModule/Lua/Header.lua renamed to cli/PlayerScripts/PlayerModule/Lua/CameraModuleHeader.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
local patchModule = script.Parent:WaitForChild("Patch")
1+
local patchModule = script.Parent:FindFirstChild("Patch")
22
local patch = patchModule and require(patchModule)
33

44
local setmetatable = setmetatable
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--!strict
2+
3+
local PlayerModule = script.Parent
4+
5+
local module = {}
6+
7+
function module.add(modifier: ModuleScript, priority: number?)
8+
local copy = modifier:Clone()
9+
copy:SetAttribute("Priority", priority)
10+
copy.Parent = script
11+
end
12+
13+
function module.apply()
14+
local children = script:GetChildren() :: {ModuleScript}
15+
16+
table.sort(children, function(a, b)
17+
local pa = a:GetAttribute("Priority") :: number?
18+
local pb = b:GetAttribute("Priority") :: number?
19+
20+
if pa and pb then
21+
return pa < pb
22+
elseif pb then
23+
return false
24+
end
25+
26+
return true
27+
end)
28+
29+
for _, child in children do
30+
local callback = require(child) :: (ModuleScript) -> ()
31+
callback(PlayerModule)
32+
end
33+
end
34+
35+
return module
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
local modifiersModule = script:FindFirstChild("Modifiers")
2+
local modifiers = modifiersModule and require(modifiersModule)
3+
4+
if modifiers then
5+
modifiers.apply()
6+
end

cli/PlayerScripts/PlayerModule/Lua/init.lua

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,13 @@ function module.getCopy(patched: boolean): ModuleScript
2424
return module.get(patched):Clone()
2525
end
2626

27-
function module.replace(patched: boolean): ModuleScript
27+
function module.replace(playerModule: ModuleScript)
2828
local existing = StarterPlayerScripts:FindFirstChild(MODULE_NAME)
2929
if existing then
3030
existing:Destroy()
3131
end
3232

33-
local playerModule = module.getCopy(patched)
3433
playerModule.Parent = StarterPlayerScripts
35-
return playerModule
3634
end
3735

3836
return module

cli/PlayerScripts/PlayerModule/Package.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,28 @@ def add_package_init(package_path):
99
os.path.join(package_path, 'init.lua')
1010
)
1111

12+
def patch_player_module(patched_player_module_path):
13+
shutil.copy(
14+
os.path.join(lua_folder, 'Modifiers.lua'),
15+
os.path.join(patched_player_module_path, 'Modifiers.lua')
16+
)
17+
18+
player_module_init_path = os.path.join(
19+
patched_player_module_path,
20+
'init.lua'
21+
)
22+
23+
header = None
24+
with open(os.path.join(lua_folder, 'PlayerModuleHeader.lua'), 'r') as f:
25+
header = f.read()
26+
27+
existing = None
28+
with open(player_module_init_path, 'r') as f:
29+
existing = f.read()
30+
31+
with open(player_module_init_path, 'w') as f:
32+
f.write(header + '\n\n' + existing)
33+
1234
def patch_camera_module(patched_player_module_path):
1335
shutil.copy(
1436
os.path.join(lua_folder, 'Patch.lua'),
@@ -22,7 +44,7 @@ def patch_camera_module(patched_player_module_path):
2244
)
2345

2446
header = None
25-
with open(os.path.join(lua_folder, 'Header.lua'), 'r') as f:
47+
with open(os.path.join(lua_folder, 'CameraModuleHeader.lua'), 'r') as f:
2648
header = f.read()
2749

2850
existing = None
@@ -45,6 +67,7 @@ def package(src_path):
4567
shutil.move(tmp_src_path, patched_player_module_path)
4668

4769
add_package_init(src_path)
70+
patch_player_module(patched_player_module_path)
4871
patch_camera_module(patched_player_module_path)
4972

5073
if os.path.exists(tmp_src_path):

cli/PlayerScripts/PlayerModule/README.md

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ Package.get(patched: boolean): ModuleScript
88
Package.getCopy(patched: boolean): ModuleScript
99

1010
-- replaces the PlayerModule under StarterPlayer.StarterPlayerScripts
11-
-- with a copy of the patched or unpatched version the PlayerModule and returns the copy
12-
Package.replace(patched: boolean): ModuleScript
11+
-- with the provided module script
12+
Package.replace(playerModule: ModuleScript)
1313
```
1414

1515
## Patched CameraModule
@@ -23,6 +23,7 @@ Package
2323
...
2424
PlayerModulePatched
2525
Patch.lua (new file)
26+
Modifiers.lua (new file)
2627
CameraModule
2728
init.lua (modified)
2829
ControlModule
@@ -37,6 +38,35 @@ Since this is a open source project it's worth discussing how this module is "pa
3738

3839
### Patch Criteria
3940

41+
#### Modifiers.lua
42+
43+
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:
44+
45+
```Lua
46+
-- adds custom modifier module script to be run at a certain priority level
47+
-- if no priority is specified then the code will be run at the end in no particular order
48+
Modifiers.add(modifier: ModuleScript, priority: number?)
49+
```
50+
51+
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:
52+
53+
```Lua
54+
-- some module in the game that handles player control
55+
local controlBindings = require(...)
56+
57+
return function (PlayerModule: ModuleScript)
58+
local controlObject = require(PlayerModule.ControlModule)
59+
60+
controlBindings.setEnableCallback(function(enabled)
61+
if enabled then
62+
controlObject:Enable()
63+
else
64+
controlObject:Disable()
65+
end
66+
end)
67+
end
68+
```
69+
4070
#### Only header additions
4171

4272
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.

0 commit comments

Comments
 (0)