Simple Mod Framework (lua)

SewlekSewlek The programmer previously known as Schimmel Join Date: 2003-05-13 Member: 16247Members, NS2 Developer, NS2 Playtester, Squad Five Gold, Subnautica Developer
edited April 2013 in Modding
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/
«1

Comments

  • FehaFeha Join Date: 2006-11-16 Member: 58633Members
    Sounds like it might be useful. :)
    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 :)
  • SewlekSewlek The programmer previously known as Schimmel Join Date: 2003-05-13 Member: 16247Members, NS2 Developer, NS2 Playtester, Squad Five Gold, Subnautica Developer
    edited January 2013
    yeah i know gmod.

    "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).
  • FehaFeha Join Date: 2006-11-16 Member: 58633Members
    I didnt mean Player.OverrideInput specifically.
    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
  • SewlekSewlek The programmer previously known as Schimmel Join Date: 2003-05-13 Member: 16247Members, NS2 Developer, NS2 Playtester, Squad Five Gold, Subnautica Developer
    yes, you would need to load Button.lua before ClassUtility.lua. i switched to that framework with the mod im working on and i had to edit Server_Modded.lua so those classes would be available for overriding
  • CreelCreel Join Date: 2012-12-29 Member: 176639Members
    edited January 2013
    Oh god! The timing could not have been better. Just spent the last 3 hours bangin my head whilst trying to modify networkVars in a defined class. Futile attempts obviously as I was going about it completely wrong.. that's what you get for being a lua noob.

    Will re-write my mod asap!
  • CreelCreel Join Date: 2012-12-29 Member: 176639Members
    Converted part of my mod to use this framework and published it today '<a href="http://steamcommunity.com/sharedfiles/filedetails/?id=117563913" target="_blank">Stun Grenades</a>'.

    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.
  • jfmherokillerjfmherokiller Join Date: 2012-12-18 Member: 175408Members
    edited January 2013
    nice to find this little beauty. i incorporated it into DAK for my own purposes. Now i can modify classes while the server is running XD. Also I learned the hard way why you also hooked the prediction file its to stop the lag wasnt it?
  • CreelCreel Join Date: 2012-12-29 Member: 176639Members
    Sewlek, what about making this framework a mod in itself and have it search for files starting with 'smfClient_XXX','smfServer_XXX' etc and load them so mods can be used together?

    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.
  • SewlekSewlek The programmer previously known as Schimmel Join Date: 2003-05-13 Member: 16247Members, NS2 Developer, NS2 Playtester, Squad Five Gold, Subnautica Developer
    the problem is that you can never guarantee compatibility between mods. i would prefer to introduce a naming convention, something like "Shared_<ModName>.lua" so the framework has more control of what is going on. i will experiment a bit when i have time again. it would be pretty cool to have for example the combat mode loading the abilities from my strategics mod :D
  • SewlekSewlek The programmer previously known as Schimmel Join Date: 2003-05-13 Member: 16247Members, NS2 Developer, NS2 Playtester, Squad Five Gold, Subnautica Developer
  • WhosatWhosat Singapore Join Date: 2006-11-03 Member: 58301Members, Reinforced - Shadow
    <!--quoteo(post=2055320:date=Jan 3 2013, 10:04 PM:name=Sewlek)--><div class='quotetop'>QUOTE (Sewlek @ Jan 3 2013, 10:04 PM) <a href="index.php?act=findpost&pid=2055320"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->the problem is that you can never guarantee compatibility between mods. i would prefer to introduce a naming convention, something like "Shared_<ModName>.lua" so the framework has more control of what is going on. i will experiment a bit when i have time again. it would be pretty cool to have for example the combat mode loading the abilities from my strategics mod :D<!--QuoteEnd--></div><!--QuoteEEnd-->

    Or... ExtraLevels3?
  • InsaneInsane Anomaly Join Date: 2002-05-13 Member: 605Members, Super Administrators, Forum Admins, NS1 Playtester, Forum Moderators, NS2 Developer, Constellation, NS2 Playtester, Squad Five Blue, NS2 Map Tester, Subnautica Developer, Pistachionauts, Future Perfect Developer
  • JimWestJimWest Join Date: 2010-01-03 Member: 69865Members, Reinforced - Silver
    Can I hook the editor_setup.xml in any way, so that I don't have to copy the file all the time when it changed?
    (I have created some new entities and they need to be in there so the mappers can use them)
  • HuzeHuze Insightful Join Date: 2003-11-12 Member: 22724Members, NS1 Playtester, NS2 Playtester, Squad Five Blue, Reinforced - Shadow
    Link in OP is broken for me
  • SewlekSewlek The programmer previously known as Schimmel Join Date: 2003-05-13 Member: 16247Members, NS2 Developer, NS2 Playtester, Squad Five Gold, Subnautica Developer
    uploaded it to steam workshop
  • ShnagenburgShnagenburg Join Date: 2005-07-04 Member: 55235Members
    As silly as this sounds, where are the files downloaded to once subscribed? It isn't inherently obvious and there's no "mod" folder that jumps out at me in the ns2 directory.
  • RioRio Join Date: 2005-01-28 Member: 38716Members
    As silly as this sounds, where are the files downloaded to once subscribed? It isn't inherently obvious and there's no "mod" folder that jumps out at me in the ns2 directory.
    They are in one of the folders located here: %appdata%\Natural Selection 2\Workshop\ (for me this would be C:\Users\Rio\AppData\Roaming\Natural Selection 2\Workshop).
  • JimWestJimWest Join Date: 2010-01-03 Member: 69865Members, Reinforced - Silver
    edited March 2013
    Mhm it seems like the framework is breaking my mod cause It's breaking while loading the shared.lua?
    Script.Load("lua/PreLoadMod.lua")
    Script.Load("lua/Shared.lua")
    

    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).
  • MCMLXXXIVMCMLXXXIV Join Date: 2010-04-14 Member: 71400Members
    @Jim there are similar problems when editing files that only exist on the Server... Basically anything client or server specific (like ClientResources or PlayingTeam) should go in Client_Modded.lua or Server_Modded.lua, or you can wrap your affected code with 'if Server then' ... 'end' tags.
  • MyLilPwnyMyLilPwny Join Date: 2012-11-06 Member: 167812Members
    Can you add this to the github page please? Would be easier to use, and have updates from the community
  • SewlekSewlek The programmer previously known as Schimmel Join Date: 2003-05-13 Member: 16247Members, NS2 Developer, NS2 Playtester, Squad Five Gold, Subnautica Developer
    the mod will be integrated into default ns2 with next patch and will offer an alternative way to define entry points for mods. mods using the new entry point system will be able to use Class_Reload(className, networkVars).

    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.
    readme.txt
    All files with the ending ".entry" will be loaded.
    Priority defines the order of loading multiple mods. A mod of priority 10 will be
    loaded first, mods with priority 1 last.

    content for an example.entry file:

    modEntry = [[
    Client: lua/TestClient.lua,
    Server: lua/TestServer.lua,
    Predict: lua/TestPredict.lua,
    Shared: lua/TestShared.lua,
    Priority: 5
    ]]

    You can also write lua code in the entry files, but for increasing the likely hood of compatibility between mods,
    its strongly recommended to not do so and stick with the suggested convention.
  • MCMLXXXIVMCMLXXXIV Join Date: 2010-04-14 Member: 71400Members
    Wow Andi, this is a game changer and great news! I think this will really allow mods to play well together and should allow us to unbundle a lot of the duplicated code that we currently have between mods too.

    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!
  • SewlekSewlek The programmer previously known as Schimmel Join Date: 2003-05-13 Member: 16247Members, NS2 Developer, NS2 Playtester, Squad Five Gold, Subnautica Developer
    that doesnt work currently, im not sure if we will support that in future. you can however use ModLoader_GetLoadedModNames() in your Client_Modded.lua for example to check which other mods are loaded with an entry file, and the priority system provides enough control to allow your mod to work with or without another mod being loaded.

    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.
  • MCMLXXXIVMCMLXXXIV Join Date: 2010-04-14 Member: 71400Members
    That sounds fine to me. If we can give a hint to server operators about why their config isn't working and which mod IDs need to be added I think that'll be sufficient :)
  • SewlekSewlek The programmer previously known as Schimmel Join Date: 2003-05-13 Member: 16247Members, NS2 Developer, NS2 Playtester, Squad Five Gold, Subnautica Developer
    ok that new code is released, i hope it will make modding a bit easier in future
  • SewlekSewlek The programmer previously known as Schimmel Join Date: 2003-05-13 Member: 16247Members, NS2 Developer, NS2 Playtester, Squad Five Gold, Subnautica Developer
    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/
  • xDragonxDragon Join Date: 2012-04-04 Member: 149948Members, NS2 Playtester, Squad Five Gold, NS2 Map Tester, Reinforced - Shadow
    As a question/request, would it be possible to have the ability to load a script much earlier in the lua loading process (ie before any game logic is loaded?).
  • McGlaspieMcGlaspie www.team156.com Join Date: 2010-07-26 Member: 73044Members, Super Administrators, Forum Admins, NS2 Developer, NS2 Playtester, Squad Five Blue, Squad Five Silver, Squad Five Gold, Reinforced - Onos, WC 2013 - Gold, Subnautica Playtester
    Are there any plans to allow for overloading or overriding Mixin functions, just as Class overriding works now? Seems like this is a pretty big missing feature.
  • SewlekSewlek The programmer previously known as Schimmel Join Date: 2003-05-13 Member: 16247Members, NS2 Developer, NS2 Playtester, Squad Five Gold, Subnautica Developer
    to override a mixin function you can simply redefine the function, that doesnt require any more work
  • DarkOmenDarkOmen Join Date: 2002-11-05 Member: 7148Members
    Hello!

    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
    Script.Load("lua/Client.lua")
    Script.Load("lua/MyShared.lua")
    
    local newMarineCommanderVars =
    {
    
        [gMarineMenuButtons] =
        {
            [kTechId.BuildMenu] = { kTechId.CommandStation, kTechId.Extractor, kTechId.InfantryPortal, kTechId.None, kTechId.Armory,
                                    kTechId.RoboticsFactory, kTechId.ArmsLab, kTechId.None },
                                    
            [kTechId.AdvancedMenu] = { kTechId.Sentry, kTechId.Observatory, kTechId.PhaseGate, kTechId.PrototypeLab, 
                                       kTechId.SentryBattery, kTechId.None, kTechId.None, kTechId.None },
        
            [kTechId.AssistMenu] = { kTechId.AmmoPack, kTechId.MedPack, kTechId.NanoShield, kTechId.Scan,
                                     kTechId.PowerSurge, kTechId.CatPack, kTechId.WeaponsMenu, kTechId.None, },
                                     
            [kTechId.WeaponsMenu] = { kTechId.DropShotgun, kTechId.DropGrenadeLauncher, kTechId.DropFlamethrower, kTechId.DropWelder,
                                      kTechId.DropMines, kTechId.DropJetpack, kTechId.None, kTechId.AssistMenu}
        }
    
    }
    
    function MarineCommander:GetButtonTable()
        return gMarineMenuButtons
    end
    
    Class_Reload("MarineCommander", newMarineCommanderVars)
    
Sign In or Register to comment.