How to adapt Lua scripts? - EstevanTH/GMod_Momo_Encryption_Library GitHub Wiki
Adapting scripts requires some experience in Lua. This guide is not for beginners!
Having a good knowledge of the scope of variables in Lua is really important here, to properly split code into different Lua files.
The general rule is that anything that must be present during startup cannot be encrypted because of the delayed loading.
I only give advice about hooks that exist in the base
gamemode. They are inherited by all gamemodes.
Hooks / events that are shown here are for reference. There are cases where care is needed with other hooks / events.
Do not forget functions that are required by other scripts! They may become missing at the time they are called.
There is no point in keeping empty Lua files.
autorun
Lua script
Adapt an For autorun
scripts, I suggest you to split your code into the following files:
- For encrypt-able code:
lua/protected/myautorun.lua
- For code that cannot be delayed:
lua/autorun/myautorun.lua
The most noticeable pieces of code that cannot take place in an encrypted script are:
hook.Add( "EntityRemoved", ... )
hook.Add( "Initialize", ... )
hook.Add( "InitPostEntity", ... )
hook.Add( "OnEntityCreated", ... )
hook.Add( "OnGamemodeLoaded", ... )
hook.Add( "PlayerConnect", ... )
hook.Add( "PostGamemodeLoaded", ... )
hook.Add( "PreGamemodeLoaded", ... )
The rest of the code will probably have no trouble.
autorun/client
Lua script
Adapt an The exact same rule applies.
For autorun/client
scripts, I suggest you to split your code into the following files:
- For encrypt-able code:
lua/protected/client/myautorun.lua
- For code that cannot be delayed:
lua/autorun/client/myautorun.lua
Encrypted autorun/client
Lua files are not guaranteed to be loaded after encrypted autorun
ones, so be careful if your client protected Lua code requires a function from shared protected Lua code.
entities
Lua script
Adapt an Rules for autorun
scripts apply, although there also is ENT
code that also cannot be delayed:
- The hook
ENT:Initialize()
- The hook
ENT:OnRemove()
- The hook
ENT:SetupDataTables()
ENT
attributes that are parts of the ENT Structure
For entities
scripts, I suggest you to split your code into the following files:
- For shared encrypt-able code:
lua/entities/.../shared_protected.lua
- For shared code that cannot be delayed:
lua/entities/.../shared.lua
- For client encrypt-able code:
lua/entities/.../client_protected.lua
- For client code that cannot be delayed:
lua/entities/.../cl_init.lua
Because the execution context is unusual for encrypted entities
scripts, you need to adapt them by adding the following pieces of code.
Add the following header at the top of your script:
----- PROTECTED -----
local className = "my_entity"
local ENT_context = ENT
local ENT = SERVER and ENT_context or scripted_ents.GetStored( className ).t
----- END PROTECTED -----
where "my_entity"
is the entity class name.
Add the following at the end of your script:
----- PROTECTED -----
if not ENT_context then
scripted_ents.Register( ENT, className )
end
----- END PROTECTED -----
weapons
Lua script
Adapt a Rules for autorun
scripts apply, although there also is SWEP
code that also cannot be delayed (to be confirmed):
- The hook
SWEP:Initialize()
- The hook
SWEP:OnRemove()
- The hook
SWEP:OwnerChanged()
- The hook
SWEP:SetupDataTables()
- The hook
SWEP:SetDeploySpeed()
- The hook
SWEP:SetWeaponHoldType()
- The hook
SWEP:TranslateActivity()
SWEP
attributes that are parts of the SWEP Structure
For weapons
scripts, I suggest you to split your code into the following files:
- For shared encrypt-able code:
lua/weapons/.../shared_protected.lua
- For shared code that cannot be delayed:
lua/weapons/.../shared.lua
- For client encrypt-able code:
lua/weapons/.../client_protected.lua
- For client code that cannot be delayed:
lua/weapons/.../cl_init.lua
Because the execution context is unusual for encrypted weapons
scripts, you need to adapt them by adding the following pieces of code.
Add the following header at the top of your script:
----- PROTECTED -----
local className = "my_weapon"
local SWEP_context = SWEP
local SWEP = SERVER and SWEP_context or weapons.GetStored( className )
----- END PROTECTED -----
where "my_weapon"
is the entity class name.
Add the following at the end of your script:
----- PROTECTED -----
if not SWEP_context then
weapons.Register( SWEP, className )
end
----- END PROTECTED -----
gamemode
Lua script
Adapt a Rules for autorun
scripts apply, although there also is GM
code that also cannot be delayed:
GM:EntityRemoved()
GM:Initialize()
GM:InitPostEntity()
GM:OnEntityCreated()
GM:OnGamemodeLoaded()
GM:PlayerConnect()
GM:PostGamemodeLoaded()
GM:PreGamemodeLoaded()
GM
attributes that are parts of the GM StructureGM
attributes that are redefined in child gamemodes (see below)
For gamemode
scripts, I suggest you to split your code into the following files:
- For shared encrypt-able code:
gamemodes/.../gamemode/shared_protected.lua
- For shared code that cannot be delayed:
gamemodes/.../gamemode/shared.lua
- For client encrypt-able code:
gamemodes/.../gamemode/client_protected.lua
- For client code that cannot be delayed:
gamemodes/.../gamemode/cl_init.lua
There is a problem if a protected gamemode is not the active gamemode but is loaded by inheritance. This problem concerns the client, but also the server when an encrypted gamemode
script is not included by another script from the gamemode it belongs to. If an element from GM
is replaced / removed in a protected script while the value in GM
before its execution was identical to that in a child gamemode then the value will be mistakenly copied in child gamemodes (because it's impossible to know where a value was defined). Also remember that there is no guarantee in the loading order of protected scripts.
Because the execution context is unusual for encrypted gamemode
scripts, you need to adapt them by adding the following pieces of code.
Add the following header at the top of your script (to be reviewed):
----- PROTECTED -----
local gamemodeName = "my_gamemode"
local function loadGamemodeScript()
local GM_context = GM
local GM
local GM_inherit = {}
local GM_initial
do
local folder = "gamemodes/"..gamemodeName
if SERVER and GM_context then
if GM_context.Folder==folder then
GM = GM_context
end
end
if not GM then
local gm = gmod.GetGamemode()
if SERVER and not gm then
return true
end
local done = {}
while gm and not done[gm] do
done[gm] = true
if gm.Folder==folder then
GM = gm
break
end
table.insert( GM_inherit, 1, gm )
gm = gm.BaseClass
end
if not GM then
ErrorNoHalt( 'The current gamemode is not "'..gamemodeName..'" and it does not inherit from it.\n' )
return
end
GM_initial = {}
for k, v in pairs( GM ) do
GM_initial[k] = v
end
end
end
----- END PROTECTED -----
where "my_gamemode"
is the gamemode short name.
Add the following at the end of your script:
----- PROTECTED -----
if GM_initial then
for k, newVal in pairs( GM ) do
local oldVal = GM_initial[k]
if newVal~=oldVal then
for i, gm in ipairs( GM_inherit ) do
if gm[k]~=oldVal then
break
end
gm[k] = newVal
end
end
end
for k, oldVal in pairs( GM_initial ) do
if GM[k]==nil then
for i, gm in ipairs( GM_inherit ) do
if gm[k]~=oldVal then
break
end
gm[k] = nil
end
end
end
end
end
local retry = loadGamemodeScript()
if retry then
timer.Simple( 0, loadGamemodeScript )
end
----- END PROTECTED -----