Simple Mod Framework (lua)
Sewlek
The programmer previously known as Schimmel Join Date: 2003-05-13 Member: 16247Members, NS2 Developer, NS2 Playtester, Squad Five Gold, Subnautica Developer
hey guys,
I wrote a small framework which simplifies overriding class functions and changing / adding network variables.
how to use it:
create your mod folder and unpack the zip content there.
in lua/Shared_Modded.lua load all files which contain your mod funcitonality. there is an example for Player:OverrideInput. its pretty straight forward, the only important thing to mention is:
always call Class_Reload(<class name>, <network variables>) at the end of your files
http://steamcommunity.com/sharedfiles/filedetails/?id=137123467
example for usage of entry files and hooking into an excisting function / adding more network fields.
when subscribed and downloaded, you can find the mod in %appdata%/Natural Selection 2/Workshop/
I wrote a small framework which simplifies overriding class functions and changing / adding network variables.
how to use it:
create your mod folder and unpack the zip content there.
in lua/Shared_Modded.lua load all files which contain your mod funcitonality. there is an example for Player:OverrideInput. its pretty straight forward, the only important thing to mention is:
always call Class_Reload(<class name>, <network variables>) at the end of your files
http://steamcommunity.com/sharedfiles/filedetails/?id=137123467
example for usage of entry files and hooking into an excisting function / adding more network fields.
when subscribed and downloaded, you can find the mod in %appdata%/Natural Selection 2/Workshop/
Comments
Looking through it I got some questions though, in Server_Modded.lua (and client) you load both the standard Shared.lua and the standard Server.lua. But as far as I know, the standard Server.lua already loads Shared.lua, so it feels as if it might be a bit redundant :P
Or do you do this as you need methods the Shared.lua create, but also have to load Server.lua after the mod has loaded?
The way you do it, I suspect that a mod that changes a method in a purely serverside entity wont be able to reference the original. Please tell me if im wrong.
For example you refer like that in Player_Modded.lua. Although it is a shared entity, loaded by scripts that was loaded by Shared.lua so it should work fine.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->local overrideInput = Player.OverrideInput -- this value is nil if the script only loads by Server.lua?
function Player:OverrideInput(input)
-- code stuffz
return overrideInput(self, input)
end<!--c2--></div><!--ec2-->
Also, I chuckled when I read PreLoadMod, as you got some variables prefixed "gMod" there (the g probably stands for global). Made me think of garry's mod (gmod for short), which if you dont know what it is, is a source sandbox game you can mod using Lua :)
"g" here stand simply for "global", just a coincident :D
im including shared.lua first because it is needed for Shared_Modded.lua and i want that both are already available in Client.lua / Server.lua / Predict.lua. its a minor detail which caused me problems in the past when not doing it that way. i would not change it
oh and yes, Player.OverrideInput is nil server side, but that does not matter (its only called client side before the input is sent).
I meant that if your mod are supposed to override a method in an entity that isnt loaded by shared.lua, lets take Button as an example (loaded from server.lua), then you cant do something like:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->if (Server) then
// original network variables are not deleted
local networkVars =
{
}
// we dont simply copy and paste the old function. in case it changes in vanilla ns2 we automatically update it
local oldOnInitialized = Button.OnInitialized
function Button:OnInitialized()
Shared.Message("OnInitialized modded Button")
return oldOnInitialized(self)
end
Class_Reload("Button", networkVars)
end<!--c2--></div><!--ec2-->
As the original method wont have been created until after the mod loads, since Server.lua loads after it, you get an error because of var = nil.OnInitialized
I tried making mod load after the server does, but that just showed that it errors at line 88 in ClassUitlity. It is because it tries to get Button from _Gcopy, which returns nil as Button wasnt loaded at the time _Gcopy was made.
So the problem I am trying to show, is that this framework only works for entities that was loaded by shared.lua
Will re-write my mod asap!
During playtesting on a pubserver I had atleast 3 ppl experiencing 3rd person view when using modifier to run as a marine. I noticed it once when playing alien.. could this have something to do with the framework and how it juggles class methods around?
Never noticed it when the mod was using pure file replacements.
As it is only one mod can use the game_setup.xml file and I believe it is the last mod on command line that will get precedence.
Or... ExtraLevels3?
Sticky!
(I have created some new entities and they need to be in there so the mappers can use them)
Edit:
Yeah just activated the framework and getting an Error while loading the Game:
"attempt to index ClientResources (a nil value)"
Edit2:
Ok, how to fix this:
Script.Load("lua/ClientResources.lua") before shared then its OK (at client_modded).
In future all files with the ending "entry" placed in the folder lua/entry/ will be loaded, to allow multiple mods to specify and entry points without having to rely on the game_setup.xml.
One question, will we be able to specify dependencies somehow? e.g. Combat can depend on ExtraEntities, so I can mark that in the .entry file and when you start a server with Combat it automatically downloads and mounts extraentities too?
Looking forward to playing with the new system!
for example, you can make a "combatclassic" mod, which can resolve all conflicts those 2 mods would have with each other, but it would do nothing if one of those mods was not loaded.
example for usage of entry files and hooking into an excisting function / adding more network fields.
when subscribed and downloaded, you can find the mod in %appdata%/Natural Selection 2/Workshop/
What is the proper use of Class_Reload? The first parameter obviously enumerates which class is being modified, but how exactly is the second one used (newPlayerNetworkvars, for example)?
Should this array contain all the member vars within the class that I want overridden?
For example, does the following make any sense?
MyClient.lua