Jump to content

Recommended Posts

I'm not sure where to put this (the bug forum doesn't have anything for mod-related/non-gameplay bugs), but I've found some strange functionality/a possible bug related to events. In the workable component, the "workfinished" event gets pushed after it calls its onfinish callback. This means that for objects that get :Remove()'d in their onfinish callback (like anything that is dug), the "workfinished" event is never received. This seems like unintended behavior. At the very least it's inconsistent (and drove me crazy trying to figure it out).Here is the test code that I'm using:

function WorkableTestPostInit(inst)	inst:ListenForEvent("worked", function(inst) print("worked "..tostring(inst)) end)	inst:ListenForEvent("workfinished", function(inst) print("workfinished "..tostring(inst)) end)endonfinished_prefabs = { "evergreen", "grass" }for k,prefabname in ipairs(onfinished_prefabs) do	AddPrefabPostInit( prefabname, WorkableTestPostInit )end
On a related note, it seems like the "worked" event in the same function is oddly placed as well; it's placed before self.workleft is updated. This makes it awkward to get the updated workleft for anything listening for that event (you'd have to guess at the numworks decrement). Edited by squeek

I'm not sure where to put this (the bug forum doesn't have anything for mod-related/non-gameplay bugs), but I've found some strange functionality/a possible bug related to events. In the workable component, the "workfinished" event gets pushed after it calls its onfinish callback. This means that for objects that get :Remove()'d in their onfinish callback (like anything that is dug), the "workfinished" event is never received. This seems like unintended behavior. At the very least it's inconsistent (and drove me crazy trying to figure it out).Here is the test code that I'm using:

function WorkableTestPostInit(inst)	inst:ListenForEvent("worked", function(inst) print("worked "..tostring(inst)) end)	inst:ListenForEvent("workfinished", function(inst) print("workfinished "..tostring(inst)) end)endonfinished_prefabs = { "evergreen", "grass" }for k,prefabname in ipairs(onfinished_prefabs) do	AddPrefabPostInit( prefabname, WorkableTestPostInit )end
On a related note, it seems like the "worked" event in the same function is oddly placed as well; it's placed before self.workleft is updated. This makes it awkward to get the updated workleft for anything listening for that event (you'd have to guess at the numworks decrement).
You make very good points. I hope your suggestions will get incorporated into the game.

Is there any way to change local variables declared outside of component after game starts?

Well, there is a way. But it's a way that shouldn't be taken. Local variables are meant to be untouchable from outside their scope. Using debug.setlocal would make your code break even with the slightest change in the code that defines the local variable you're changing, since it relies on the order of declaration of local variables. And it would require injecting the code that calls debug.setlocal inside the loading of the component somehow. An alternative that circumvents that is debug.setupvalue (which is also quite breakable and should be avoided).Also note that Lua's upvalues are shared:
do	local upvalue = 1	function f()		return upvalue	end	function g()		upvalue = upvalue + 1	endendassert(upvalue == nil)g()assert(f() == 2)debug.setupvalue(g, 1, math.pi/2)assert(math.sin(f()) == 1)debug.setupvalue(g, 1, f)assert(f()()()() == f)
Edited by simplex

You make very good points. I hope your suggestions will get incorporated into the game.

Thinking about it a bit more, just moving PushEvent("workfinished") before the onfinished callback would actually create the same problem that the "worked" event currently has: the onfinished callback could update the entity in ways that the listener might care about. It'd probably be better to add a property to workable like self.shouldremoveonfinished and then in the workable component do:
    if self.workleft <= 0 then        if self.onfinish then self.onfinish(self.inst, worker) end        self.inst:PushEvent("workfinished")        if self.shouldremoveonfinished then self.inst:Remove() end    end
and remove the self:Remove() from all the dig_up callbacks and whatnot.One thing I don't understand is why inst:Remove() is called before the dug_ prefab is spawned in the dig_up callbacks:
local function dig_up(inst, chopper)	if inst.components.pickable and inst.components.pickable:CanBePicked() then		inst.components.lootdropper:SpawnLootPrefab("cutgrass")	end	inst:Remove()	local bush = inst.components.lootdropper:SpawnLootPrefab("dug_grass")end

[MENTION=56977]squeek[/MENTION]Yes, but calling inst:Remove() within the onSOMETHING callback is quite common in the DS code. For example, see the onpicked callback for flowers, or the default onburnt. Using a flag to indicate whether an entity should be removed is a good idea, but for consistency it would require a lot of refactoring of the current game code.

[MENTION=56977]squeek[/MENTION]Yes, but calling inst:Remove() within the onSOMETHING callback is quite common in the DS code. For example, see the onpicked callback for flowers, or the default onburnt. Using a flag to indicate whether an entity should be removed is a good idea, but for consistency it would require a lot of refactoring of the current game code.

Very true. It seems like there's some overlap in the intended function of events and callbacks. From a modding point-of-view, it seems like event listeners should be used when adding new/independent behavior and callbacks should only be overwritten when you are altering the original behavior. Because the event system is somewhat under-developed, though (for example, only the picker gets an event sent when they pick something, the picked thing doesn't get an event at all [and if there was a "picked" event, it'd have the same problems I outlined above]), it's a bit confusing. I might be wrong about the intended use of events, though. Edited by squeek

[MENTION=44092]simplex[/MENTION] Thanks for idea of upvalues. I just changed all functions that were using that local variables with component post init in mod main. If that local variables would be part of the component I wouldn't have to edit functions, and all I would have to do would be adding one function to edit those variables.

[MENTION=5551]_Q_[/MENTION]No problem, since I quite enjoy talking about this stuff. Function closures (functions with at least one upvalue) allow for such clever things. For example, here's a functional implementation of arrays (actually, of tables):

-- f = Set(f, i, v) means what f[i] = v would mean if f were a table.function Set(f, i, v)	return function(k)		if k == i then			return v		else			return f(k)		end	endend-- An empty function corresponds to an empty array.f = function() endfor i=1, 8 do	f = Set(f, i, 2^i)endassert(f(0) == nil)for i=1, 8 do	assert(f(i) == 2^i)endassert(f(9) == nil)
Moreover, the definition of Set (which is the entire implementation of tables) can be reduced to a single line:
function Set(f, i, v) return function(k) return k == i and v or f(k) end end
Edited by simplex

Hmkay, soo, character mod. Working on the files and I have very little clue on what I'm doingSo this is the character prefab

local MakePlayerCharacter = require "prefabs/player_common"local assets = {    Asset("data/scripts/speech_wilson.lua")    Asset("ANIM", "data/anim/wilson.zip"),       Asset("veggy-belly")}local prefabs = {}local fn = function(inst)	inst.components.hunger:SetMax(TUNING.WILSON_HUNGER * 1.25 )	inst.components.combat.damagemultiplier = 1.10	inst.components.hunger:SetRate(TUNING.WILSON_HUNGER_RATE*0.50)	inst.components.sanity:SetMax(TUNING.WILSON_SANITY*.75)	inst.AddTag("beefalo")endreturn MakePlayerCharacter("wellington", prefabs, assets, fn)
And this is the code I borrowed (with permission) from reinert's vegetarian mod to make wellington a vegetarian, but I can't quite figure out how to make it applicable to wellington only.
--Localize globals used from game environmentGetClock = GLOBAL.GetClockSpawnPrefab = GLOBAL.SpawnPrefabVector3 = GLOBAL.Vector3TheCamera = GLOBAL.TheCameraDEGREES = GLOBAL.DEGREES--Make cutgrass into a vegi food (substitute for lemon grass? )local function cutgrassPrefabPostInit(inst)	if inst then		--Make edible		if not inst.components.edible then inst:AddComponent("edible") end		inst.components.edible.foodtype = "VEGGIE"		inst.components.edible.healthvalue = TUNING.HEALING_TINY		inst.components.edible.hungervalue = TUNING.CALORIES_MED		inst.components.edible.sanityvalue = 0	end    endAddPrefabPostInit("cutgrass", cutgrassPrefabPostInit)--Make reeds into a vegi food (substitute for bamboo shoots? )local function reedsPrefabPostInit(inst)	if inst then		--Make edible		if not inst.components.edible then inst:AddComponent("edible") end		inst.components.edible.foodtype = "VEGGIE"		inst.components.edible.healthvalue = TUNING.HEALING_MED		inst.components.edible.hungervalue = TUNING.CALORIES_TINY		inst.components.edible.sanityvalue = 0	endendAddPrefabPostInit("reeds", reedsPrefabPostInit)local function modSimPostInit(player)
Also, will I need to make changes to the files that deal with experience & unlocking characters?

Umm, I dunno? It's [MENTION=6219]reinert[/MENTION] 's script, wrathof helped him a bit with it as well, as far as I can tell it's set to work regardless on all characters, what I want it to do is to work so that only Wellington is effected and as such can eat grass, however it seems redonkulously unlikely I'll get that much to work making wellington vegetarian is the primary goal, eating grass/reeds can stay or go.

Umm, I dunno? It's [MENTION=6219]reinert[/MENTION] 's script, wrathof helped him a bit with it as well, as far as I can tell it's set to work regardless on all characters, what I want it to do is to work so that only Wellington is effected and as such can eat grass, however it seems redonkulously unlikely I'll get that much to work making wellington vegetarian is the primary goal, eating grass/reeds can stay or go.

You need to add you're own food type that only he can eat.just add this in wellington's fn

inst.components.eater.foodprefs = {"VEGGIE", "SEEDS", "wellingtonfood"}

then put this in the modmain

----------------local function makeEdibleFn(healthvalue, hungervalue, sanityvalue)	return function (inst)		if not inst.components.edible then inst:AddComponent("edible") end		inst.components.edible.foodtype = "wellingtonfood"		inst.components.edible.healthvalue = healthvalue		inst.components.edible.hungervalue = hungervalue		inst.components.edible.sanityvalue = sanityvalue	end    endAddPrefabPostInit("cutgrass", makeEdibleFn(			TUNING.HEALING_TINY, 			TUNING.CALORIES_MED, 			0)		)AddPrefabPostInit("reeds", makeEdibleFn(			TUNING.HEALING_MED, 			TUNING.CALORIES_TINY, 			0)		)--------------------

Edited by no_signal

Hey Ipsquiggle, are socket DLLs confirmed to be deployed to the client on the next patch?I might already be able to do some testing :)

Please dont mind me, I'm retarded, hadn't updated.Edit: Oh boy, I AM SO HAPPY right now..... Edited by 0dark
  • Developer

<callback and event things>

The callbacks and events definitely fit into the "we did what worked at the time" kind of code, we haven't been methodical about their use or form. I'd say these kinds of things should be treated like "mod bugs" as you suggest: If you notice an obviously missing callbacks/events, or find that events or callbacks are poorly named or inappropriately fired, then let me know, and I'll put them on a buglist to fix. It won't be high priority most likely, but these are kind of the "best" way to mod so if they aren't being useful then that's a problem. :)

Edit: Oh boy, I AM SO HAPPY right now.....

:D

The callbacks and events definitely fit into the "we did what worked at the time" kind of code, we haven't been methodical about their use or form. I'd say these kinds of things should be treated like "mod bugs" as you suggest: If you notice an obviously missing callbacks/events, or find that events or callbacks are poorly named or inappropriately fired, then let me know, and I'll put them on a buglist to fix. It won't be high priority most likely, but these are kind of the "best" way to mod so if they aren't being useful then that's a problem. :)

Sounds good. I'll start compiling a list of things I come across.

Okay, so I've tweaked thing around following the suggestions I've gotten, and the game crashes w/o an error report.This is the Modmain

PrefabFiles = {	"wellington",}Assets = {    Asset( "IMAGE", "images/saveslot_portraits/wellington.tex" ),    Asset( "IMAGE", "images/selectscreen_portraits/wellington.tex" ),    Asset( "IMAGE", "images/selectscreen_portraits/welly_shilo.tex" ),    Asset( "IMAGE", "bigportraits/wellington.tex" ),}----------------local function makeEdibleFn(healthvalue, hungervalue, sanityvalue)	return function (inst)		if not inst.components.edible then inst:AddComponent("edible") end		inst.components.edible.foodtype = "GRASS"		inst.components.edible.healthvalue = 10		inst.components.edible.hungervalue = 10		inst.components.edible.sanityvalue = 10	end    endAddPrefabPostInit("cutgrass", makeEdibleFn(			TUNING.HEALING_TINY, 			TUNING.CALORIES_MED, 			0)		)AddPrefabPostInit("reeds", makeEdibleFn(			TUNING.HEALING_MED, 			TUNING.CALORIES_TINY, 			0)		)--------------------AddModCharacter("wellington")
And this is Wellingtons prefab

local MakePlayerCharacter = require "prefabs/player_common"local assets = {    Asset("data/scripts/speech_wilson.lua")    Asset("ANIM", "data/anim/wilson.zip"),   }local prefabs = {}local fn = function(inst)	inst.components.eater.foodprefs ={"VEGGIE", "SEEDS", "GRASS"	inst.components.hunger:SetMax(TUNING.WILSON_HUNGER * 1.25 )	inst.components.combat.damagemultiplier = 1.10	inst.components.hunger:SetRate(TUNING.WILSON_HUNGER_RATE*0.50)	inst.components.sanity:SetMax(TUNING.WILSON_SANITY*.75)	inst.AddTag("beefalo")endreturn MakePlayerCharacter("wellington", prefabs, assets, fn)

These are the only files I have other than the default anim/image files for the character sample mod. Which I've renamed and referenced.

Edited by Gotheran

hey guys, is there someone?i need some help here. i tried to load a custom texture for piglight mod. if i build the light ingame it dosen't appear, i mean you can see just fire on ground. in craftingtabmenu works the inventoryimages well. i think, i mistaken something in .zip file. and i got an error like this:-------------------------------------------------------------------------------------GUID 109205: Unknown animation idle for camplight_focus in cAnimStateComponent-------------------------------------------------------------------------------------i tried to using the nightmare_torch renamed the build.bin to camplight_focus and replaced the atlas-0.tex with texture of maxwelllight(atlasfile). same error. sounds like dontstarve does not find the "idle", "loop", "play".mod:http://www.sendspace.com/file/i8hqtxcan someone help me there.thank youregards

Okay, so I've tweaked thing around following the suggestions I've gotten, and the game crashes w/o an error report.This is the Modmain

PrefabFiles = {	"wellington",}Assets = {    Asset( "IMAGE", "images/saveslot_portraits/wellington.tex" ),    Asset( "IMAGE", "images/selectscreen_portraits/wellington.tex" ),    Asset( "IMAGE", "images/selectscreen_portraits/welly_shilo.tex" ),    Asset( "IMAGE", "bigportraits/wellington.tex" ),}----------------local function makeEdibleFn(healthvalue, hungervalue, sanityvalue)	return function (inst)		if not inst.components.edible then inst:AddComponent("edible") end		inst.components.edible.foodtype = "GRASS"		inst.components.edible.healthvalue = 10		inst.components.edible.hungervalue = 10		inst.components.edible.sanityvalue = 10	end    endAddPrefabPostInit("cutgrass", makeEdibleFn(			TUNING.HEALING_TINY, 			TUNING.CALORIES_MED, 			0)		)AddPrefabPostInit("reeds", makeEdibleFn(			TUNING.HEALING_MED, 			TUNING.CALORIES_TINY, 			0)		)--------------------AddModCharacter("wellington")
And this is Wellingtons prefab

local MakePlayerCharacter = require "prefabs/player_common"local assets = {    Asset("data/scripts/speech_wilson.lua")    Asset("ANIM", "data/anim/wilson.zip"),   }local prefabs = {}local fn = function(inst)	inst.components.eater.foodprefs ={"VEGGIE", "SEEDS", "GRASS"	inst.components.hunger:SetMax(TUNING.WILSON_HUNGER * 1.25 )	inst.components.combat.damagemultiplier = 1.10	inst.components.hunger:SetRate(TUNING.WILSON_HUNGER_RATE*0.50)	inst.components.sanity:SetMax(TUNING.WILSON_SANITY*.75)	inst.AddTag("beefalo")endreturn MakePlayerCharacter("wellington", prefabs, assets, fn)

These are the only files I have other than the default anim/image files for the character sample mod. Which I've renamed and referenced.

remove

Asset("data/scripts/speech_wilson.lua")

and add } too the end of

inst.components.eater.foodprefs ={"VEGGIE", "SEEDS", "GRASS"

-snip-

Still crashing, here's the updated prefab, it's almost a perfect copy of the sample character
local MakePlayerCharacter = require "prefabs/player_common"local assets = {        Asset( "ANIM", "anim/player_basic.zip" ),        Asset( "ANIM", "anim/player_idles_shiver.zip" ),        Asset( "ANIM", "anim/player_actions.zip" ),        Asset( "ANIM", "anim/player_actions_axe.zip" ),        Asset( "ANIM", "anim/player_actions_pickaxe.zip" ),        Asset( "ANIM", "anim/player_actions_shovel.zip" ),        Asset( "ANIM", "anim/player_actions_blowdart.zip" ),        Asset( "ANIM", "anim/player_actions_eat.zip" ),        Asset( "ANIM", "anim/player_actions_item.zip" ),        Asset( "ANIM", "anim/player_actions_uniqueitem.zip" ),        Asset( "ANIM", "anim/player_actions_bugnet.zip" ),        Asset( "ANIM", "anim/player_actions_fishing.zip" ),        Asset( "ANIM", "anim/player_actions_boomerang.zip" ),        Asset( "ANIM", "anim/player_bush_hat.zip" ),        Asset( "ANIM", "anim/player_attacks.zip" ),        Asset( "ANIM", "anim/player_idles.zip" ),        Asset( "ANIM", "anim/player_rebirth.zip" ),        Asset( "ANIM", "anim/player_jump.zip" ),        Asset( "ANIM", "anim/player_amulet_resurrect.zip" ),        Asset( "ANIM", "anim/player_teleport.zip" ),        Asset( "ANIM", "anim/player_one_man_band.zip" ),        Asset( "ANIM", "anim/shadow_hands.zip" ),        Asset( "SOUND", "sound/sfx.fsb" ),        Asset( "SOUND", "sound/wilson.fsb" ),-----------------------------------------------    Asset("ANIM", "anim/welly.zip"),   }local prefabs = {}local fn = function(inst)	inst.components.eater.foodprefs ={"VEGGIE", "SEEDS", "GRASS"}	inst.components.hunger:SetMax(TUNING.WILSON_HUNGER * 1.25 )	inst.components.combat.damagemultiplier = 1.10	inst.components.hunger:SetRate(TUNING.WILSON_HUNGER_RATE*0.50)	inst.components.sanity:SetMax(TUNING.WILSON_SANITY*.75)	inst.AddTag("beefalo")endSTRINGS.CHARACTER_TITLES.wellington = "The Beefalo"STRINGS.CHARACTER_NAMES.wellington = "Wellington"STRINGS.CHARACTER_DESCRIPTIONS.wellington = "* Is Testing"STRINGS.CHARACTER_QUOTES.wellington = "Moo Moo Ladies..."STRINGS.CHARACTERS.WELLINGTON = {}STRINGS.CHARACTERS.WELLINGTON.DESCRIBE = {}STRINGS.CHARACTERS.WELLINGTON.DESCRIBE.BEEFALO = "MooMoo Ladies"return MakePlayerCharacter("wellington", prefabs, assets, fn)

Still crashing, here's the updated prefab, it's almost a perfect copy of the sample character

local MakePlayerCharacter = require "prefabs/player_common"local assets = {        Asset( "ANIM", "anim/player_basic.zip" ),        Asset( "ANIM", "anim/player_idles_shiver.zip" ),        Asset( "ANIM", "anim/player_actions.zip" ),        Asset( "ANIM", "anim/player_actions_axe.zip" ),        Asset( "ANIM", "anim/player_actions_pickaxe.zip" ),        Asset( "ANIM", "anim/player_actions_shovel.zip" ),        Asset( "ANIM", "anim/player_actions_blowdart.zip" ),        Asset( "ANIM", "anim/player_actions_eat.zip" ),        Asset( "ANIM", "anim/player_actions_item.zip" ),        Asset( "ANIM", "anim/player_actions_uniqueitem.zip" ),        Asset( "ANIM", "anim/player_actions_bugnet.zip" ),        Asset( "ANIM", "anim/player_actions_fishing.zip" ),        Asset( "ANIM", "anim/player_actions_boomerang.zip" ),        Asset( "ANIM", "anim/player_bush_hat.zip" ),        Asset( "ANIM", "anim/player_attacks.zip" ),        Asset( "ANIM", "anim/player_idles.zip" ),        Asset( "ANIM", "anim/player_rebirth.zip" ),        Asset( "ANIM", "anim/player_jump.zip" ),        Asset( "ANIM", "anim/player_amulet_resurrect.zip" ),        Asset( "ANIM", "anim/player_teleport.zip" ),        Asset( "ANIM", "anim/player_one_man_band.zip" ),        Asset( "ANIM", "anim/shadow_hands.zip" ),        Asset( "SOUND", "sound/sfx.fsb" ),        Asset( "SOUND", "sound/wilson.fsb" ),-----------------------------------------------    Asset("ANIM", "anim/welly.zip"),   }local prefabs = {}local fn = function(inst)	inst.components.eater.foodprefs ={"VEGGIE", "SEEDS", "GRASS"}	inst.components.hunger:SetMax(TUNING.WILSON_HUNGER * 1.25 )	inst.components.combat.damagemultiplier = 1.10	inst.components.hunger:SetRate(TUNING.WILSON_HUNGER_RATE*0.50)	inst.components.sanity:SetMax(TUNING.WILSON_SANITY*.75)	inst.AddTag("beefalo")endSTRINGS.CHARACTER_TITLES.wellington = "The Beefalo"STRINGS.CHARACTER_NAMES.wellington = "Wellington"STRINGS.CHARACTER_DESCRIPTIONS.wellington = "* Is Testing"STRINGS.CHARACTER_QUOTES.wellington = "Moo Moo Ladies..."STRINGS.CHARACTERS.WELLINGTON = {}STRINGS.CHARACTERS.WELLINGTON.DESCRIBE = {}STRINGS.CHARACTERS.WELLINGTON.DESCRIBE.BEEFALO = "MooMoo Ladies"return MakePlayerCharacter("wellington", prefabs, assets, fn)
It looks like it is not finding "anim/welly.zip"

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...