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:

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:

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):

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:

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