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.
Adapt an autorun Lua script
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.
Adapt an autorun/client Lua script
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.
Adapt an entities Lua script
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() ENTattributes 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 -----
Adapt a weapons Lua script
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() SWEPattributes 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 -----
Adapt a gamemode Lua script
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()GMattributes that are parts of the GM StructureGMattributes 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 -----