Newbie Coding Error

Hey Gmod community, a beginner Gmod Lua scripter here with a somewhat stupid question.

I believe my problem lies somewhere within my understanding of the way that lua includes files, anyways let us get to the code and the problem it’s self.
So the problem is my gamemode file seems to not be visible. Whenever I try to call a function from it, I am told that the call failed.
Here is an example:



[ERROR] gamemodes/baby_snatcher/gamemode/shared.lua:18: attempt to call method '
GetGameState' (a nil value)
  1. unknown - gamemodes/baby_snatcher/gamemode/shared.lua:18


Here is the code for game mode and my shared file.

shared.lua




P.S: Excuse the crap code structure and all but I'm just mucking around to get a feel for things, I come from C++ so it's a bit strange to me the non OOP stuff.

include("gamemode.lua")
include("round.lua")
--------------------------
--- Gamemode constants ---
--------------------------

--Round States
WARMUP = 1
FIGHTING = 2 -- TODO: Think of a better round name.
FINISHED = 3
--Round time (time is in minutes)
WARMUP_TIME = 0.5
FIGHTING_TIME = 0.1--5
FINISHED_TIME = 0.25

function GM:Initialize()
	-- TODO:Before starting the round, check if there are at least 3 players.
	print(GAMEMODE:GetGameState())
	ROUND:RestartRound()
end

function GM:PlayerConnect(name, ip)
	--This does work
end





gamemode.lua



GAMEMODE = {}
--GAMEMODE.mt = {}
GAMEMODE.state = WARMUP

function GAMEMODE:SetGameState(state)

	self.state = state

end

function GAMEMODE:GetGameState()
	return self.state
end


Okay this is pretty fucking dumb, it turns out that ‘GAMEMODE’ is a reserved keyword or something.
Now my question is why isn’t this documented anywhere?? I’m pretty upset I spent a lot of time debugging my code…

Not a reserved keyword, just in use by another script. GM accesses the gamemode table inside the gamemodes folder and GAMEMODE accesses it everywhere else

Okay thanks for clarifying that for me! However, how have you figured this out? Where is it documented?

You would have to figure out what other script(s) are using GAMEMODE.

When a gamemode is being loaded the GM table is what you should be adding/editing. After that you should use GAMEMODE to call/get methods/variables.

Why is this?

Its how the GAMEMODE table gets populated. If I’m not mistaken the gamemode gets loaded like entities/weapons do. The loader creates a global GM/ENT/WEAPON table then includes the relevant lua files which then assign things to the corresponding global table. Then when that is done the loader will nil out the global table and assign the data to the GAMEMODE ect.

I think its expensive … but until you have finished your gamemode, you can return the valid one with gmod.GetGamemode().
When you finish your gamemode, I’ll recommend removing it.

What they mean is that GAMEMODE does not exist when your gamemode is originally loaded. You have to shove everything inside GM when your script loads.

This means:
Define everything inside GM and reference everything from GAMEMODE after initialization is complete:
[lua]
–GAMEMODE = {} --Get rid of this
–GAMEMODE.mt = {} --Not sure whether mt means metatable here, but I strongly advise against setting a metatable straight on GAMEMODE

–Define on GM during initialization
GM.state = WARMUP

–Define on GM during initialization
function GM:SetGameState(state)
self.state = state
end

function GM:GetGameState()
return self.state
end

–While your code is in the initialization stage, you can still reference things straight from the GM table
–But it is unconventional. Unless you really need to do it now, do it during the Initialize hook.
–If you really must, nothing is stopping you from doing this:
GM:SetGameState(SomeGenericGameStateIdentifier)
print(GM.GameState)

function GM:Initialize()
–This is called after the gamemode is done initializing everything.
–At this point, GM should be nil. To set the game state, you could either use:
GAMEMODE:SetGameState(SomeGenericGameStateIdentifier)
–Or, since this is a gamemode hook, the GAMEMODE table gets passed as the first argument (self)
self:SetGameState(SomeGenericGameStateIdentifier)
end

local function hook_Initialize()
–This hook will be called before the gamemode hook, as is true with all other hooks.
–The gamemode hook is always called last, and will not be called if you return anything other than nil
–In any of the other hooks. Keep this in mind. But at this point, the GM table is now gone and has been replaced by GAMEMODE.
–If you wish to set the game state, you will have to do:
GAMEMODE:SetGameState(SomeGenericGameStateIdentifier)
–GM:SetGameState() would throw an error.
end
hook.Add(“Initialize”, “hook_Initialize_name”, hook_Initialize())
[/lua]

Notice the pattern: The table GM gets destroyed after initialization and it then becomes GAMEMODE.
You do not need to (and should not) create neither GM or GAMEMODE.

When your gamemode gets autorefreshed, the GAMEMODE table will exist during initialization, containing everything that has been set in the previous initialization cycle as well as any entries added at run-time. You must still define your entries on GM at this point. However, the Initialize hook will not get called again, but using this information, you could write your own PostAutoRefresh hook. After your gamemode scripts are done being refreshed, the GM and GAMEMODE tables will be merged. This is something to keep in mind, as in tables that already exist inside GAMEMODE will also be merged with the one inside GM. For example:

Initial initialization:
[lua]
GM.SomeTable = {“a”, “b”, “c”}
[/lua]

If you change your mind and decide that SomeTable should only contain “d”, this won’t work:
[lua]
GM.SomeTable = {“d”}
[/lua]

You will end up with GM.SomeTable and GAMEMODE.SomeTable merging, giving you: {“a”, “b”, “c”, “d”}
This is something I often forget and it really bothers me.
If you wish to completely overwrite it without changing the map or restarting your server, you can simply do this:
[lua]
(GAMEMODE or GM).SomeTable = {“d”}
[/lua]

I hope this helps you understand a few of the basic concepts. I apologize if I repeated myself a lot at some points, I’m writing this slightly late.

Wow! You are amazing, thank you so much for your explanation. I think you have helped me avoid a lot of pitfalls and so thank you for taking your time to write this up. I will definitely rethink my coding style for Gmod. :slight_smile: