rezecib

[Guide] Getting started with modding DST (and some general tips for DS as well)

84 posts in this topic

for i,v in ipairs(DST_CHARACTERLIST) do-- do stuff to the i (index) and v (value) pair that it got from the table-- the first loop has i == 1, v == "wilson"-- the first loop has i == 2, v == "willow"-- the first loop has i == 3, v == "wx78"-- the first loop has i == 4, v == "wickerbottom"end

for i=1,#DST_CHARACTERLIST do   local v=DST_CHARACTERLIST[i]   --- the same i and vend

Share this post


Link to post
Share on other sites

@simplex, Thanks for the very detailed input! I've been going through it and editing it into the post. I'm guessing it was pretty clear to you that most of my CS experience is pretty informal, so it's awesome to have input from someone with much better grounding in the field!

 

 

 

You use the term "lazy evaluation"

I wrote the rough draft calling it lazy evaluation, then decided to check that and got reminded it was called minimal/short-circuit evaluation. Looks like I missed the last case where I called it lazy evaluation, though xD. Fixed now!

 

 

 

It's usually equivalent, yes, but not if the if_true expression may be false or nil itself.

Oh, good point. I changed it to have "if condition and if_true then", and noted that if if_true is not nil or false, then it will work like the intuitive block I had before.

 

 

 

It actually does not. It goes through all the key/value pairs in an unspecified order (pairs uses next internally).

 I read that when I was looking it up, but when I tested it, it was always going through in the order added. I'll add a note on that, though. I also added a note on ipairs only going until a value is nil.

 

 

 

This is true for replicas, but not classifieds.

Oops. Fixed :grin:

 

 

 

There's a lot of overlap between replicas and classified

 I think I'll quote you on this in the main post for now, you've said it much better than I can. Hopefully I'll get some examples in there later, though.

 

 

 

Netvars in and of themselves can't replace RPCs because they're the dual form of communication. DST's RPCs are client -> server RPCs. Netvars, on the other hand, when set on a client don't get updated on the server, only the other way around (so they only allow server -> client communication).

Everything is illuminated! I incorporated this into the engine differences summary :grin:

 

 

 

The way I implemented custom RPCs in Up and Away

I added this under the note that custom RPCs can't be nicely implemented yet. Maybe your implementation will help get us a more integrated system for custom RPCs from Peter sooner :grin:

 

 

 

It's awful, yes, but not impossible.

Thanks, I noted the possibility. Although I think that anyone who could figure out how to do it probably doesn't need a guide :razz:

 

@Maris, It's nice to avoid typing DST_CHARACTERLIST twice if you don't have to :razz:

 

Edit: Argh, it ate my edits the first time because I submitted this response just before it. I think I got all of them back in now, though.

 

Edited by rezecib
1 person likes this

Share this post


Link to post
Share on other sites
Custom world gen presets. You can make them manually, but I don't think you can define new named presets with a mod at the moment (this may have changed, though?).

 

If I'm understanding you correctly, and correct me if I'm wrong, I believe this bit is nicely moddable. This is a quick example based on the "archipelago" map from adventure mode, and will show up as the last option on your preset selection list.

 

EDIT: my girlfriend said my link looked "shadey", uploaded to the downloads page.

Edited by tetrified
1 person likes this

Share this post


Link to post
Share on other sites

One big thing that significantly improves client performances is not adding code which does not need to be ran on their side. I know a lot of veteran modders will already know about this, however, since this is specifically geared toward new modders I think it needs to be said.

 

Before you add any component to whatever mod you are adding, always remember to add the following code to ensure that you are not running unnecessary code on the clients machine.

if not TheWorld.ismastersim then   return instend

Only the server needs to be running the components as any time a new component is add or created the client will send and receive the required functionality to and from the server. By initializing the code on the clients computer you are potentially creating unnecessary memory usage which could in the long term cause conflicts from multiple mods.

Edited by Kzisor
1 person likes this

Share this post


Link to post
Share on other sites

Hello there, I came across your forum and it seems quite useful, thank you for sharing it!

 

If it is not too much trouble, I'll like to ask for some help, I did post a forum my self stating my problems here: http://forums.kleientertainment.com/topic/48463-errors-in-creating-character-mod/#entry597289

 

I checked my log and paste it here. http://sta.sh/0v1xn613bom (I am sorry if other bits of other mods are pasted in there, I copy what I thought was related to my Character mod.)

I know you said a way to fix it, but I'm not 100% confident in myself, and I am afraid I'll mess it somehow, I was thinking someone as great as you can help me out and tell me what to do and such? But only if you have the time, I do thank you for spending your time to read this!

Share this post


Link to post
Share on other sites

Custom containers (there's a workaround possible for creating containers with the same layout as an existing game container, but making anything with custom slot sizes is pretty awful, but possible).

 

 

Did the most recent patch change this?

 

post-461118-0-45049000-1420743829_thumb.

 

I'm going to see if it's easy to edit the background to the chest tomorrow, I'm just to tired to change it right this second.

 

Or is it a problem with clients? I haven't tested that.

 

EDIT: added a new picture, because I got a custom texture working, I'm working right now on making it more 'nicely' moddable

 

To clarify: it's fairly nicely moddable as it is, but you have to replace the containers.lua with a mod. more "mildly annoying" than anything, and it means multiple mods that use containers.lua wouldn't work together.

 

This may be due to the way container_replica and container_classified work, but I'll keep looking in to it.

 

I'm not sure how much farther I can go with this, I keep getting frustrated. I've uploaded the rar here, in case someone wants to take it and run with it to try to make it more 'nicely' moddable.

 

The best solution I can think of is to get an "AddParams" function going, but I'm far too tired right now to even think about it.

Edited by tetrified

Share this post


Link to post
Share on other sites

Did the most recent patch change this?

 

attachicon.gifcustom slot sizes.JPG

 

I'm going to see if it's easy to edit the background to the chest tomorrow, I'm just to tired to change it right this second.

 

Or is it a problem with clients? I haven't tested that.

 

EDIT: added a new picture, because I got a custom texture working, I'm working right now on making it more 'nicely' moddable

 

To clarify: it's fairly nicely moddable as it is, but you have to replace the containers.lua with a mod. more "mildly annoying" than anything, and it means multiple mods that use containers.lua wouldn't work together.

 

This may be due to the way container_replica and container_classified work, but I'll keep looking in to it.

 

I'm not sure how much farther I can go with this, I keep getting frustrated. I've uploaded the rar here, in case someone wants to take it and run with it to try to make it more 'nicely' moddable.

 

The best solution I can think of is to get an "AddParams" function going, but I'm far too tired right now to even think about it.

 

The params may be local, but the function widgetsetup is Global.

local containers = require "containers"containers.old_widgetsetup=containers.widgetsetup--define params here for your prefab- mine is cookpot.local params = {}params.cookpot ={}function containers.widgetsetup(container, prefab)    target = prefab or container.inst.prefab    if target == "cookpot" then        local t = params.cookpot        if t ~= nil then            for k, v in pairs(t) do                container[k] = v            end            container:SetNumSlots(container.widget.slotpos ~= nil and #container.widget.slotpos or 0)        end    else        containers.old_widgetsetup(container,prefab)    endend

Share this post


Link to post
Share on other sites
you have to replace the containers.lua with a mod. more "mildly annoying" than anything, and it means multiple mods that use containers.lua wouldn't work together.

That's what I call "not nicely moddable" :razz:

 

So no, this was always possible with that method. But you can also override widgetsetup without replacing it, but that's still jankier than it should be. 

 

Edit: No worries, it happens :)

Edited by rezecib

Share this post


Link to post
Share on other sites

That's what I call "not nicely moddable" :razz:

 

So no, this was always possible with that method. But you can also override widgetsetup without replacing it, but that's still jankier than it should be. 

 

 

yeeeah, midway through that post, I thought I had hit something that made it really nicely moddable, but then I realized I was still replacing it. Guess that's what I get for jumping the gun there.

Share this post


Link to post
Share on other sites

One big thing that significantly improves client performances is not adding code which does not need to be ran on their side. I know a lot of veteran modders will already know about this, however, since this is specifically geared toward new modders I think it needs to be said.

 

Before you add any component to whatever mod you are adding, always remember to add the following code to ensure that you are not running unnecessary code on the clients machine.

if not TheWorld.ismastersim then   return instend

Only the server needs to be running the components as any time a new component is add or created the client will send and receive the required functionality to and from the server. By initializing the code on the clients computer you are potentially creating unnecessary memory usage which could in the long term cause conflicts from multiple mods.

 

Do you mean literally any time in (mod) code you see something added to inst.components, it should have made sure it's running on the mastersim first (and only) at some point beforehand, as above?

Edited by outseeker

Share this post


Link to post
Share on other sites

Do you mean literally any time in (mod) code you see something added to inst.components, it should have made sure it's running on the mastersim first (and only) at some point beforehand, as above?

 

Unless a component specifically needs to be ran on the clients machine, aka night vision or keyhandling components I've created in the past; components should only be ran on the server to ensure integrity and to reduce the ability to 'hack' a character.

1 person likes this

Share this post


Link to post
Share on other sites

@Kzisor, I am willing to bet the bulk of mods (not done by rezecib lol) have overlooked this point; perhaps it needs it's own sticky?

1 person likes this

Share this post


Link to post
Share on other sites
[00:00:08]: Mod downloads complete.

[00:00:08]: GetCachedUGCCount 0

[00:00:08]: SteamWorkshop::CompleteCallback (success, Mods were updated.) set

[00:00:08]: SimLuaProxy::OnUpdateWorkshopModsComplete(ok., Mods were updated.)

[00:00:08]: Reloading Mod Info Prefabs

[00:00:08]: Loading Mod Info Prefabs

[00:00:08]: Unloading Mod Info Prefabs

[00:00:13]: Unloading Mod Info Prefabs

[00:00:13]: Collecting garbage...

[00:00:13]: lua_gc took 0.01 seconds

[00:00:13]: ~NetworkLuaProxy()

[00:00:13]: ~SimLuaProxy()

[00:00:13]: lua_close took 0.01 seconds

[00:00:13]: ReleaseAll

[00:00:13]: ReleaseAll Finished

[00:00:13]: cGame::StartPlaying

[00:00:13]: LOADING LUA

[00:00:13]: DoLuaFile scripts/main.lua

[00:00:13]: DoLuaFile loading buffer scripts/main.lua

[00:00:13]: scripts/main.lua(167,1) running main.lua

 

[00:00:13]: loaded modindex

[00:00:13]: ModIndex: Beginning normal load sequence.

 

[00:00:13]: ModIndex:GetModsToLoad inserting moddir, Michael

[00:00:13]: Could not load mod_config_data/modconfiguration_Michael

[00:00:13]: Loading mod: Michael (MICHAEL)

[00:00:13]: Mod: Michael (MICHAEL) Loading modworldgenmain.lua

[00:00:13]: Mod: Michael (MICHAEL)  Mod had no modworldgenmain.lua. Skipping.

[00:00:13]: Mod: Michael (MICHAEL) Loading modmain.lua

[00:00:13]: Mod: Michael (MICHAEL)  Error loading mod!

[string "../mods/Michael/modmain.lua"]:59: attempt to index global 'AddModCharacter' (a function value)

LUA ERROR stack traceback:

        ../mods/Michael/modmain.lua(59,1) in main chunk

        =[C] in function 'xpcall'

        scripts/util.lua(455,1) in function 'RunInEnvironment'

        scripts/mods.lua(373,1) in function 'InitializeModMain'

        scripts/mods.lua(354,1) in function 'LoadMods'

        scripts/main.lua(244,1) in function 'ModSafeStartup'

        scripts/main.lua(292,1)

        =[C] in function 'SetPersistentString'

        scripts/mainfunctions.lua(24,1) in function 'SavePersistentString'

        scripts/modindex.lua(76,1)

        =[C] in function 'GetPersistentString'

        scripts/modindex.lua(63,1) in function 'BeginStartupSequence'

        scripts/main.lua(291,1) in function 'callback'

        scripts/modindex.lua(410,1)

        =[C] in function 'GetPersistentString'

        scripts/modindex.lua(390,1) in function 'Load'

        scripts/main.lua(290,1) in main chunk

 

[00:00:13]: [string "../mods/Michael/modmain.lua"]:59: attempt to index global 'AddModCharacter' (a function value)

LUA ERROR stack traceback:

        ../mods/Michael/modmain.lua(59,1) in main chunk

        =[C] in function 'xpcall'

        scripts/util.lua(455,1) in function 'RunInEnvironment'

        scripts/mods.lua(373,1) in function 'InitializeModMain'

        scripts/mods.lua(354,1) in function 'LoadMods'

        scripts/main.lua(244,1) in function 'ModSafeStartup'

        scripts/main.lua(292,1)

        =[C] in function 'SetPersistentString'

        scripts/mainfunctions.lua(24,1) in function 'SavePersistentString'

        scripts/modindex.lua(76,1)

        =[C] in function 'GetPersistentString'

        scripts/modindex.lua(63,1) in function 'BeginStartupSequence'

        scripts/main.lua(291,1) in function 'callback'

        scripts/modindex.lua(410,1)

        =[C] in function 'GetPersistentString'

        scripts/modindex.lua(390,1) in function 'Load'

        scripts/main.lua(290,1) in main chunk

[00:00:13]: Error error! We tried displaying an error but TheFrontEnd isn't ready yet...

[00:00:13]: LOADING LUA SUCCESS

[00:00:13]: PlayerDeaths loaded morgue 1936

[00:00:13]: loaded profile

[00:00:13]: bloom_enabled false

[00:00:13]: loaded saveindex

[00:00:13]: OnFilesLoaded()

[00:00:13]: OnUpdatePurchaseStateComplete

[00:00:13]: Unload BE

[00:00:13]: Unload BE done

[00:00:14]: Mod: Michael (MICHAEL) Registering prefabs

[00:00:14]: Mod: Michael (MICHAEL)  Registering prefab file: prefabs/michael

[00:00:14]: error calling LoadPrefabFile in mod Michael (MICHAEL): 

[string "scripts/util.lua"]:292: Could not find an asset matching anim/Michael.zip in any of the search paths.

LUA ERROR stack traceback:

        =[C] in function 'assert'

        scripts/util.lua(292,1) in function 'resolvefilepath'

        scripts/mainfunctions.lua(72,1) in function 'RegisterPrefabs'

        scripts/mainfunctions.lua(99,1)

        =(tail call) ?

        =[C] in function 'xpcall'

        scripts/mods.lua(165,1)

        scripts/mods.lua(460,1) in function 'RegisterPrefabs'

        scripts/gamelogic.lua(154,1) in function 'LoadAssets'

        scripts/gamelogic.lua(931,1) in function 'DoResetAction'

        scripts/gamelogic.lua(949,1) in function 'complete_callback'

...

        =[C] in function 'GetPersistentString'

        scripts/saveindex.lua(90,1) in function 'Load'

        scripts/gamelogic.lua(970,1) in function 'callback'

        scripts/playerprofile.lua(671,1) in function 'Set'

        scripts/playerprofile.lua(553,1)

        =[C] in function 'GetPersistentString'

        scripts/playerprofile.lua(551,1) in function 'Load'

        scripts/gamelogic.lua(969,1) in main chunk

        =[C] in function 'require'

        scripts/mainfunctions.lua(677,1)

[00:00:14]: Disabling Michael (MICHAEL) because it had an error.

[00:00:14]: Disabling Michael (MICHAEL) because it had an error.

[00:00:14]: SCRIPT ERROR! Showing error screen

[00:00:14]: Mod: Michael (MICHAEL)  Registering default mod prefab

[00:00:14]: ModIndex: Load sequence finished successfully.

 

[00:00:14]: Reset() returning

[00:00:14]: QueryServerComplete no callback

[00:00:15]: QueryServerComplete no callback

[00:00:16]: Force aborting...

 

 

 

 

 

PLEASE HELP! I HAVE CHECKED THAT ANIM IS SPELLED CORRECTLY AND THAT michael.zip IS INSIDE IT, PLEASE HELP!!!

 


Share this post


Link to post
Share on other sites
[string "../mods/Michael/modmain.lua"]:59: attempt to index global 'AddModCharacter' (a function value)
 The problem doesn't appear to be with your character, it's that you're not calling AddModCharacter as a function. "attempt to index" suggests that you're doing something like AddModCharacter.michael, when you should be doing AddModCharacter("michael")

 

But please make your own thread for these sorts of issues.

Share this post


Link to post
Share on other sites

 The problem doesn't appear to be with your character, it's that you're not calling AddModCharacter as a function. "attempt to index" suggests that you're doing something like AddModCharacter.michael, when you should be doing AddModCharacter("michael")

 

But please make your own thread for these sorts of issues.

 

 

ok, sorry but thankyou

Share this post


Link to post
Share on other sites

@rezecib, could you say more about RPCs? In my mod, clients need to send some data occasionally, and, unless there is another clever way, I think I have to use one. I've looked at the game's code but I can't seem to understand how they really work, and how I could hijack one.

Share this post


Link to post
Share on other sites

@Jjmarco, check out the following code, it does something very similar.

 

modmain.lua

local SETDOG = GLOBAL.Action()SETDOG.str = "SetDog"SETDOG.id = "SETDOG"SETDOG.fn = function(act)			local silent = true			if (act.target.strength=="normal" or act.target.strength=="mighty") then 				local damage_mult = 0.9				local health_max = 150				local hunger_rate = 1.7				local scale = 0.9				local speed = 1.1				act.target.AnimState:SetBuild("gir_dog")				act.target.strength="dog"				act.target.Transform:SetScale(scale,scale,scale)				act.target.components.hunger:SetRate(hunger_rate*TUNING.WILSON_HUNGER_RATE)				act.target.components.combat.damagemultiplier = damage_mult				act.target.components.locomotor.walkspeed = (TUNING.WILSON_WALK_SPEED * speed)				act.target.components.locomotor.runspeed = (TUNING.WILSON_RUN_SPEED * speed)				act.target.components.sanity.dapperness = 0				local health_percent = act.target.components.health:GetPercent()				act.target.components.health:SetMaxHealth(health_max)				act.target.components.health:SetPercent(health_percent, true)			elseif act.target.components.sanity.current < (85) then               act.target.strength="mighty"			elseif act.target.components.sanity.current > (85) then				act.target.strength="normal"			end            -- act.target.components.health:SetCurrentHealth(1)            -- act.target.components.health:DoDelta(0)            return trueend AddAction(SETDOG)  

 

other.lua

            if TheWorld.ismastersim then                BufferedAction(inst, inst, ACTIONS.SETDOG):Do()                -- Since we are the server, do the action on the server.            else                SendRPCToServer(RPC.DoWidgetButtonAction, ACTIONS.SETDOG.code, inst, ACTIONS.SETDOG.mod_name)            end 

 

I'm the one that helped Purswader get it working. If you have any questions let me know.

1 person likes this

Share this post


Link to post
Share on other sites

@Kzisor, hm, so I checked out the thread where you helped Purswader.

If I understand correctly, this code, as a client, will send a request for doing the SETDOG action on the server, right?

If so, I think that RPCs aren't actually the solution to what I want to do. I want clients to be able to send strings to the server, to then change the description of a sign, for instance. Essentially the opposite of a netvar.

Is that possible?

Share this post


Link to post
Share on other sites

@Kzisor, hm, so I checked out the thread where you helped Purswader.

If I understand correctly, this code, as a client, will send a request for doing the SETDOG action on the server, right?

If so, I think that RPCs aren't actually the solution to what I want to do. I want clients to be able to send strings to the server, to then change the description of a sign, for instance. Essentially the opposite of a netvar.

Is that possible?

 

Yes it's possible, you need to look into chat functionality. There is a mod on Steam which uses chat in order to set sign text. What you're wanting to do sounds like something I've asked for previously. I don't know if Klei is working on that though. Another thing you could look into is the console code as that sends commands to the server.

1 person likes this

Share this post


Link to post
Share on other sites

@Kzisor, of course, the chat! I'll look into the code for the chat (and that mod). Thank you.

I hope Klei will one day add support for sending data to the server the same way netvars do.

Share this post


Link to post
Share on other sites

@rezecib,

 

First of all - very great tutorial about mods! I guess I still don't get many things, but after reading all of these it sure did make some things clear.

 

I might have a request to you tho :/ I triple checked everything in my mod (character + weapon) with Your tutorial here.. It seems ok. Every additions for from DS to DST seems on the place.. But something doesn't work - no crash or thing, but just like character statistics, components, so all skills, HP, hunger, sanity, eater etc... All are broken - not working for CLIENT, while HOST is all fine...

 

*Custom item works fine tho. Just the character itself seems broken on DST, while working fine on DS and ROG...

 

Any idea what can be wrong there? :/

Attaching my lua and logs from last login as a client...

 

What stupid mistake did I make here? -.- I guess that might save others who does the same..

 

 

wakkari.lua

log.txt

Edited by Foxrai

Share this post


Link to post
Share on other sites

@Foxrai, Try to keep the "I have a problem with my mod" posts to their own threads. Don't worry, I read everything on this forum. But it's either that your missing parts of the networking (esp AddNetwork()), or that you're breaking player_classified, such as by adding a recipe in your character prefab.

 

Edit: Characters are indeed entities, but you don't need to do AddNetwork in them directly, because that's done by the MakePlayerCharacter function. You can look at player_common to see the MakePlayerCharacter function-- it's just an entity with a lot of stuff layered on top. When you call MakePlayerCharacter, you provide two main functions (common_ and master_postinit) that are then run partway through the MakePlayerCharacter function; that's where you customize your character, basically.

Edited by rezecib

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now