Jump to content

Recommended Posts

  • Developer

Hey everyone! For those who don't know me, I've been working on Don't Starve at Klei doing game design, world gen, adventure mode, and lots of other odds and ends, but:

For the next while I'm going to be dedicating myself to everything mods! Basically I'm going to be your advocate to the team at Klei, trying to make the process of modding as clear and clean as possible!

The main thing is, I don't know yet exactly how I'll be the most useful: My goal is to provide you with the tools and knowledge you need to mod unhindered! So expect to see me hanging around here, answering questions where I can and probably asking a bunch too, so we can figure out how I can be the most useful to everyone. :D

Yee-haw!

  • Like 9

Sweet! I can use all the help I can get, lol

Hey everyone! For those who don't know me, I've been working on Don't Starve at Klei doing game design, world gen, adventure mode, and lots of other odds and ends, but:

For the next while I'm going to be dedicating myself to everything mods! Basically I'm going to be your advocate to the team at Klei, trying to make the process of modding as clear and clean as possible!

The main thing is, I don't know yet exactly how I'll be the most useful: My goal is to provide you with the tools and knowledge you need to mod unhindered! So expect to see me hanging around here, answering questions where I can and probably asking a bunch too, so we can figure out how I can be the most useful to everyone. :D

Yee-haw!

  • Developer

Do you know about the anim tool and what I have to do in flash to get things to go all well and proper? I' don't wan't to just edit existing files, I wan't to make new animations for a different body type and new critters :3

I'm actually looking into that right now. The process we use for exporting is pretty gnarly, my first big task is to see if I can make this usable for modders, or to see if I can find a good alternative. I'll keep you posted! [MENTION=26201]no_signal[/MENTION] I'll have a look at that. I'm actually just wrapping up for the day, but if you've got any active threads on the problem let me know and I'll jump in in the morning.To everyone else, I'm still getting up to speed on all the work you've got going on here! This is gonna be fun. :D

[MENTION=26201]no_signal[/MENTION] I'll have a look at that. I'm actually just wrapping up for the day, but if you've got any active threads on the problem let me know and I'll jump in in the morning.

Edit:It works nowand I did not change any of the code.It must have been that Hotfix last night. Edited by no_signal

Hi Graham!I have a suggestion.Please consider changing the way the prefabs.xml file of mods gets parsed to interpret the path as relative to the container of the prefabs.xml file instead of relative to the game folder.IE: Currently a prefab asset is defined like:In mods/mymod/prefabs.xml:

<Asset  type='IMAGE' file='mods/mymod/images/mytexture.tex' flags='0' />
I would love to see it like:In mods/mymod/prefabs.xml
<Asset type='IMAGE' file='images/mytexture.tex' flags='0' />
The reason for requesting this change is the number of mod authors I've had to see explain to users that they can't just go and change the name of the mod folder. Right now I go GLOBAL.TheSim:LoadPrefabDefs( MODROOT.."prefabs.xml" ) to load my prefabs.xml. If there were a LoadPrefabDefs that took 2 arguments, like GLOBAL.TheSim:LoadPrefabDefs( "prefabs.xml", MODROOT) and inserted the second argument appropriately in the file values for Assets and Prefabs as it parsed the file then it wouldn't matter at all if users rename their mods. MODROOT will rename along with it, and the xml is not tied to the original mod path in any way.
  • Developer

I have a question.How come when i save component data it is different when I load it.It worked fine before the cave update.

[MENTION=8]Kevin[/MENTION] had changed the lua serialization code, but then reverted the changes in the hotfix as it was causing unforeseen consequences. This was likely why it broke your saving and then fixed it in the hotfix.

Is there a way to attach scenario to a wormhole? I would like some info how to use scenarios, its nice feature but can't read anything useful from code.World generation scripts files what the lockandkey.lua for, I see it used in tasks.lua but how it works. How wormholes are placed on archipelago adventure mode level?How to make static_layouts?How to make changes to tuning_override.lua from modmain.lua, I tired different ways and nothing worked.

[MENTION=8]Kevin[/MENTION] had changed the lua serialization code, but then reverted the changes in the hotfix as it was causing unforeseen consequences. This was likely why it broke your saving and then fixed it in the hotfix.

OKThanks for the info.
  • Developer

Please consider changing the way the prefabs.xml file of mods gets parsed to interpret the path as relative to the container of the prefabs.xml file instead of relative to the game folder.

Good call! I'm making up a list of improvements to investigate, just added this to it.

Is there a way to attach scenario to a wormhole? World generation scripts files what the lockandkey.lua...How to make static_layouts?How to make changes to tuning_override.lua from modmain.lua

Right now the world gen stuff is not very moddable, that's one of the larger improvements that needs to be made. The main consequence of this is that you can't affect any world-gen stuff from modmain.lua.As far as scenarios and static layouts, I will put together a simple tutorial in the near future, but it'll be tricky to get that stuff actually appearing in a map until the gen is moddable.Finally: LockandKey is used by the world layout algorithm to order the tasks. It tries to make sure that certain tasks won't appear until after certain other requirements have been met in the map, so that, for example, you won't meet any lvl 3 spider dens until you've had a chance to build a weapon.

Is it possible to get a mod system tutorial for dummies?I want to make my mods use the mod system but my lua skill level is that of a sack of potatoes.

Make sure you read the stickies in this forum, it will point you in the right places as far as tools and starting points. As far as learning Lua itself, I recommend trying to learn by example: Find a simple mod and dig into it and try figuring out how it works; find a mod that does something similar to what you want and try altering it or improving it.The best thing to do is just give it a go! When you run into specific problems, then you ask for specific help. :)

Will you add sockets to the game?

It's not part of the Lua runtime that we are using right now, and it's not in our plans to add that kind of feature to the engine.

It's not part of the Lua runtime that we are using right now, and it's not in our plans to add that kind of feature to the engine.

Just to follow up on this, you can include external modules anyway, just put them in the bin folder iirc.

[MENTION=55]Ipsquiggle[/MENTION] Hi !! You realize you're gonna suffer from sleep deprivation right ? :p

I have a question.How come when i save component data it is different when I load it.It worked fine before the cave update.

Exactly what I was going to ask ^^ But it seems to work fine now, just like before the cave update Edited by kiopho

I've been looking into loading custom stuff from /mod/ folder and I have ran into a hickup in your code. The following is from util.lua

-- look in package loaders to find the file from the root directories-- this will look first in the mods and then in the data directoryfunction resolvefilepath( filepath )    for path in string.gmatch(package.path, "([^;]+)") do        local filename = string.gsub(path, "scripts\\%?%.lua", filepath)        filename = string.gsub(filename, "\\", "/")        print("looking for: "..filename.." ("..filepath..")")        if kleifileexists(filename) then            print("found it! "..filename)            return filename        end    end    return nilend
Basically, it takes apart package.path and searches each directory for stuff (whatever is used by resolvefilepath).The purpose here appears to be that it should first search each mod directory and then proceed to the install directory. The hickup is this: the mod's addition to the package.path is misconstrued. In mods.lua we find
function ModWrangler:AddMod(modname)	print("enabling mod "..modname)	--add the file overwrite to this 	package.path = "mods/"..modname.."/scripts/?.lua;"..package.path	table.insert(self.modnames, modname)end
Note the forward-facing / there. So This would add for example mods/HF_summonbeard/scripts?.lua; to the package.path.HOWEVER, if we go back to the function in util.lua we have
local filename = string.gsub(path, "scripts\\%?%.lua", filepath)
which only replaces parts of package.path that include scripts\\%?%.lua (translated to scripts\?.lua) with "filepath" Therefore, when util.lua resolvefilepath() is executed, it will ignore the mod folder because it doesn't match up.This is what it looks like in the log.txt when I print package.path and un-comment the prints in the function above:
***util.lua(191,1)	Tell me what package.path is!mods/Potions/scripts/?.lua;mods/HF_unlockghostcaller/scripts/?.lua;mods/HF_unlockstickman/scripts/?.lua;mods/HF_unlockallchars/scripts/?.lua;mods/HF_summontreeguard/scripts/?.lua;mods/HF_summonmermplush/scripts/?.lua;mods/HF_summonknight/scripts/?.lua;mods/HF_summonhound/scripts/?.lua;mods/HF_summonfireling/scripts/?.lua;mods/HF_summonclone/scripts/?.lua;mods/HF_summonchaoticbuildablewormhole/scripts/?.lua;mods/HF_summonbeard/scripts/?.lua;mods/HF_followersitcommand/scripts/?.lua;mods/HF_dawnbreak_goldenbutterfly/scripts/?.lua;mods/HF_dawnbreak/scripts/?.lua;mods/Test Tools/scripts/?.lua;mods/CHARACTERLIB/scripts/?.lua;mods/ModLib/scripts/?.lua;data\scripts\?.lua;data\scriptlibs\?.lua***util.lua(195,1)	looking for: mods/Potions/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/HF_unlockghostcaller/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/HF_unlockstickman/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/HF_unlockallchars/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/HF_summontreeguard/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/HF_summonmermplush/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/HF_summonknight/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/HF_summonhound/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/HF_summonfireling/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/HF_summonclone/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/HF_summonchaoticbuildablewormhole/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/HF_summonbeard/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/HF_followersitcommand/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/HF_dawnbreak_goldenbutterfly/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/HF_dawnbreak/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/Test Tools/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/CHARACTERLIB/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: mods/ModLib/scripts/?.lua (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: data/inventoryimages/healthpotion.tex (inventoryimages/healthpotion.tex)***util.lua(195,1)	looking for: data/scriptlibs/?.lua (inventoryimages/healthpotion.tex)
Note the erroneous calls to HF_summonbeard (and others), searching for a "scripts/?.lua" file which will obviously never exist. All this because of the misconstrued addition to package.path from mods.lua.To fix this, mods.lua should instead of
package.path = "mods/"..modname.."/scripts/?.lua;"..package.path
have
package.path = "mods/"..modname.."\\scripts\\?.lua;"..package.path
resolvefilepath appears to have only two uses: in inventoryitem.lua and in recipe.lua to load textures for recipe tabs, and for items in our inventories. Both these have been causing direct issues for us because we have had to manipulate the variables using other methods when we shouldn't have had to.A current workaround for us is to add the proper path to package.path in our modmain.lua using
package = GLOBAL.packagepackage.path = MODROOT.."scripts\\?.lua;"..package.path
but this shouldn't be necessary. Edited by Heavenfall

Ipsquiggle, would you know if you guys are moving to a more normalized pub/sub type of setup for things?Example:components/equippable uses a single callback for when an item is equipped or unequipped. For my set framework, I need to wrap the existing equip/unequip callbacks and then insert my own logic. This is totally fine with me, but leads to a different hook than say something likecomponents/sanity is an event publisher, and I can add event listeners to the publisher for things like "goinsane" and "gosane" events without wrapping (and potentially screwing up) any function.As a modder, I'd like to hook things in as much possible and touch as little core code, which includes function wrapping, as possible. Allowing modders more hooks (and of course, making sure modders know what events to listen for) is probably one of the easier ways to build mods that don't collide with each other (or collide as much).

Edited by borrisb
  • Developer

I've been looking into loading custom stuff from /mod/ folder and I have ran into a hickup in your code.

Good catch! This is related to other things I'm working on right now so I'll have a look at it right away.

Ipsquiggle, would you know if you guys are moving to a more normalized pub/sub type of setup for things?

This is something we've discussed internally a bit... I'm a fan of the idea, but there's obviously quite a bit of work involved, figuring out the right system and getting everything changed over. I'll add it to my list-o-improvements and let you know what comes of that.

Hi Borrisb,I think that any instance of an object can listen for any events.If you say

self.inst:ListenForEvent("goinsane", function(inst, data) print(self.inst .. " noticed you went insane") end end)
And you can raise any events yourself too.
self.inst:ListenForEvent("goinsane", function(inst, data) print(self.inst .. " noticed you went insane and fired an object noted insanity event") self.inst:PushEvent("insanity2", {data1 = "some data", data2 = "more data"})end)
Please let me know if I'm wrong or misunderstanding what you're looking for. I'm trying to learn myself.[e] I re-read your post and I think I misunderstood. I thought you were suggesting that gosane/goinsane could push events you could listen for, and I was confused because you can. In the case of equip/unequip, there are events fired at that point as well. Equipping an item will fire the "equip" event, and unequipping will fire an "unequip" event. This is actually done through the inventory system though, which I guess makes sense. You can listen for the equip/unequip events instead of changing onequipfn and onunequipfn. As for documentation, that's always nice. Here's a quick list of the events I see
actionfailedaddfuelarmorbrokeattackedattackedbygrueblockedbuilditembuildstructurecatchcaughtchangeareachildgoinghomeclocktickcontainergotitemcoveredinbeescreepactivatedaycompletedaysegschangeddaytimedeathdoattackdonetalkingdropitemdusktimeenterlimboentermoodequipexitlimbofadecompletefishingcancelfishingcatchfishingcollectfishingloserodfishingnibblefishingstrainflyawayfreezefueltakengiveuptargetgohomegoinghomegoinsanegosanegotnewitemgotosleepgrowfrombutterflygrowfromseedharvestsomethingharvesttraphealthdeltaheardhornheargruehungerdeltahuntbeastnearbyhuntlosttrailimagechangeinventoryfullitemgetitemlosekeydownkeyupkilledleavemoodleftmousedownlightningstrikelocomoteloseloyaltyMaxwellThreatmouseoutmouseovernewactiveitemnewcombattargetnighttimenotfreeonareaattackotheronattackotheronbuiltondroppedoneatoneatenoneatsomethingonextinguishonfoundfireonhitotheronigniteonmissotheronopenonpickuponputininventoryonreachdestinationonremoveonsetprofileontalkonthawonthrownontrappedontriggersaveonwakeuponwenthomepercentusedchangeperishchangepicksomethingpowerupquitrainstartrainstopreadyreadytocatchrespawnresurrectrightmousedownsanitydeltaseasonChangesnowcoverchangesnowstartsnowstopspentfuelspringtrapstacksizechangestartactionstartaurastartfiredamagestartfollowingstartstarvingstopaurastopfiredamagestopfollowingstopstarvingtalkedtotechlevelchangetemperaturedeltatextinputthornstoolbroketorchranouttransformnormaltransformweretrappedturnedoffturnedonunequipunfreezeunlockrecipeworkedworkfinishedworkingwormholespit
How to use them is trivial and is an exercise left to the reader. Edited by zeidrich

In the case of equip/unequip, there are events fired at that point as well. Equipping an item will fire the "equip" event, and unequipping will fire an "unequip" event. This is actually done through the inventory system though, which I guess makes sense.

Doh. you know, I got so fixated on equippable, I only gave the inventory component a glance through to make sure I wasn't missing anything, and well, I sure missed the equip and unequip events. Thanks :)

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
×
  • Create New...