• Content Count

  • Joined

  • Last visited

 Content Type 




Klei Bug Tracker

Game Updates

Hot Lava Bug Reporter

Posts posted by Clopen

  1. Thank you, Zarklord! =D

    I've been kind of stuck with things and you really don't want to behold the hideous, unholy, unethical workaround I was making in order to circumvent the problem...

    I'm gonna try incorporating everything you said here and in the other thread in a bit and see if I can make it work.
    I think I have the necessary knowledge for it now, thanks to you, so hopefully I'll be able to manage. =)

  2. So this is what happened so far:

    • I created a replicable component.
    • Added it with AddReplicableComponent(). The game gave me some syntax errors in my _replica file so I know it loads it.
    • Added it as a component in a player character's master_postinit().
    • Tried to access either the component or its replica in common_postinit(), both were nil.
    • Moved the component to be added in common_postinit(), client now crashes silently, the word "error" does not show up in the log file for either the server or the client, but the client crashes due to a break in its C++ code and right before it there is a print warning that the replica already exists even though it was nil just before I added it.

    Right now I have this in common_postinit(inst):

    if not (inst.components.transformer or inst.replica.transformer) then
    	print("Adding in common_postinit")
    if TheWorld.ismastersim then
    	local tf = inst.components.transformer
    	print("Server: tf = ", tostring(tf))
    	local tf = inst.replica.transformer
    	print("Client: tf = ", tostring(tf))

    And I have this in master_postinit(inst):

    if not (inst.components.transformer or inst.replica.transformer) then
    	print("Adding in master_postinit")

    And the client log show this at the very end (with no other debug prints of mine anywhere):

    [00:01:02]: Adding in common_postinit	
    [00:01:02]: Client: tf = nil	
    [00:01:02]: Movement prediction enabled	
    [00:01:02]: Craft Pot ~~~ component loaded with no data	
    [00:01:02]: replica transformer already exists! 	scripts/entityreplica.lua:77 in (method) ReplicateEntity (Lua) <74-84>	
    [00:01:02]: Registering duplicate lua network variable 3646546233 in entity tee[100201]
    [00:01:02]: Break at: ..\source\simlib\Entity.cpp(347) :


    So I have two questions:

    1. Why can't I access a replica if it already exists?
      1. Actually, also why does it exist already if I haven't added it yet?
    2. And where do I put client-side initialization code for a player character?

    Thanks in advance. =)

  3. Actually, one more question...

    common_postinit() is called for an entity on both the server and client, right?
    And we basically look at TheWorld.ismastersim in order to determine whether we're on the client or the server - but how do we know if the player is remote or not?

    I have keyboard events I want to register to, and these need to be on the client only, but if someone is playing in a world without caves and they're the host then the value of TheWorld.ismastersim would still be true, no?
    So how do I know whether to register the key handler or not?

  4. First of all, thank you very much, Zarklord; what you wrote is really helpful. =)

    Ok, so I think I understand the concept of replicas (though I have a question pertaining to them which I'll write in a moment), and I think I understand more about classifieds now, but I didn't understand part of your explanation.

    I searched for "SetInLimbo" in the DST code (and my random collection of mods) and I only found it in entityscript.lua, in the functions RemoveFromScene() and ReturnToScene(). So regarding that:

    1. Is there ever a reason to use it directly?
    2. I looked for uses of RemoveFromScene() in the game code and found several, one of which is in inventoryitem.lua, inside OnPutInInventory().
      If I understand what you said correctly, this means that when an item is picked up, its entity is removed from all clients.
      However, I seem to remember reading at some point that all the items in all the containers everywhere are stored in memory for all the clients at all times.
      How do these two fit together - or, alternatively, is my memory and/or the information inaccurate?

    Now, about this:

    2 hours ago, Zarklord said:

    if the entity passed is a specific player, it will cause that classified entity to spawn for that specific client only, otherwise it will remove it from any existing player that it had as a classified target.

    I don't really get it.
    Let's try using concrete values, if that's OK.
    Say inst is some carrot and entity is Woodie.
    So if I invoke inst.Network:SetClassifiedTarget(entity), it will cause that entity, Woodie, to spawn only for the player playing that Woodie?
    I don't understand the meaning of that sentence.
    Does it need to be run before Woodie is spawned?
    If not, what happens if it's spawned already? Would Woodie disappear from everybody's clients except his own?

    I have similar comprehension issues with the out-of-limbo case, but clearing the above up will probably clear those up too.

    Now for a more specific question:
    How do I send information from the server to a specific client?
    Let's assume I have that client's player entity and/or I'm inside the scope of an RPC handler that was invoked by that client.

    I have a clear idea of what data I need to have where (server / client, who needs it, who doesn't) and what messages I want to send, when and between whom.
    I think I can implement all of the above with replicas, but if I set a netvar for a replica, won't it be sent to all the clients?
    In some cases that's just wasted network data since only one player will do something other than ignore it.

    Once again, I truly appreciate your assistance here, so thank you very much. :)

  5. I'm somewhat new to modding DST, and I haven't dealt much with host-client communications yet since I haven't needed to, but I do now so I've been looking at examples and searching through the forums but the way components and their replicas should be made is still not clear to me.

    I examined Kzisor's leveler component and its companion exp widget, as well as some standard game components and random things I found in the mods I have installed, but still.

    Some use classifieds, some use netvars, some reference the replica in the main component, some don't...I could really use a basic rundown of when you use replicable components as opposed to a regular component added in common_postinit(); when you should use player_classified (and what it even is to begin with); when to use netvars (are the instead of the classified thing?) - and if possible, seeing an example of a simple "Hello world" replicable component would be really great.

    Thanks in advance. =)

    If you're interested in the functional context here, I'm trying to create a "transformer" component to manage all character transformations in my mod.
    It's basically a state machine with forms and triggers that activate the transitions between them.
    I'd like to give it an AddTransformation() function that lets you define the transitions as well as the trigger, and, for example, I'd like key press to be one of the options.
    I really want to encapsulate the entirety of the functionality into the component and its replica.
    Ideally, the user would simply write something such as transformer:AddTransformation("justme", "superme", transformer.Triggers.OnKey(SOME_KEY)) where transformer is the component or its replica and it will simply work.
    For that end I made registered an RPC call for all transformations that passes along some transformation ID.
    Now I need to have the code that performs the transformation to be on the server and the code that listens for a key and invokes the RPC to be on the client, but I don't know what to put where, and how to raise an event on the client when the transformation is done.
    Thus I come seeking the wisdom of the forum elders.

  6. This is more of a consultation than a direct how-to question.

    I implemented a feature that temporarily adds a tag to a specific target (can be anything that can do combat), and now I'd like to give this effect some visual representation, but I don't know what.

    I tried tinting the target red (by setting AnimState:SetMultColour(1, 0.5, 0.5, 1)), and while it worked, I'm not sure it's a good idea - A. because it might not be too noticeable, especially for reddish entities; B. because I think it might clash with other places setting color multipliers; and C... pretty sure I had a C when I started typing this sentence but I forgot it already. O_o

    I thought maybe to put a ring on the ground around it, but I'm not sure how to do that and it would also need to be scaled based on the target's size.
    Also I think if I did that then I'd want the back of the ring to be hidden by the character, another something I don't know how to do.

    Another idea is an aura, but I think just adding a light source would make it difficult to see exactly which entity is the target when there are several around. Also it has gameplay ramifications at night which I'd rather not have. Would be easy to abuse.

    So any feasible ideas on how to mark the target (and if possible an ideas on how to implement them) would be appreciated.
    If it helps, it's possible that only specific players will be able to see this marking (I already know how to implement that part).

    Thanks in advance. =)

  7. Well, sure, I can do that, and yeah, it would work (thanks for the suggestion), but it doesn't feel like the right approach to me.

    What if I want to add other customization?
    Do I change Wilson's stategraph and test prefabs for everything?
    Every character has its own stategraph; there has to be a way to alter a specific state for a specific character.

  8. I made a new character and I'd like to override a specific state in its stategraph, but nobody else's (namely, I want to change its funnyidle animation to one of the emotes).

    I managed to override it for everyone,but I don't know how to override it just for him.

    I'd rather not copy Wilson's stategraph to a new file, make the modification and then assign that stategraph to him, since that would require updating when Wilson's stategraph changes.

    Thanks in advance. =)

  9. DST has a module called "util" in its scripts bundle which contains various scripting paraphernalia that one may find useful.

    I'd like to use the weighted_random_choice() function it has, but when I use require "util" to import the code (currently to my modmain file but I plan on moving it out of there shortly) and then use it, I get an error for invoking a nil value.

    I know I can copy the function, of course but since it's already there and various game scripts use it, I figure there should be a way to import it into a mod environment as well - or am I wrong?

    Assistance would be appreciated, like always. =)

  10. Yeah, I did the same. :D

    I actually found it by looking at Inventory:Equip().
    The first line there checks if the equippable item is restricted.

    Thanks a lot for all your help.
    I'm pretty sure I'll need it again (e.g. for making only specific entities attackable based on tags, a feature I'm not even close to starting work on yet and for which I'll start a separate topic if I need to).
    I'm making a pretty big mod with lots of new things and my knowledge of modding DST (and Lua in general, but that's less of a problem) is limited, so I'm bound to run into problems I'll need help with.

  11. Yeah, I saw the GiveItem() function. If you'd told me I had to override it to add something in the middle I'd have chosen to stay with what I have. -_-

    Regarding your second idea: Using OnPickup() seems like a good idea if I don't want them to be able to have the item at all - which may actually be what I decide eventually, but for now I just want the character to be unable to equip the item, but still have the ability to carry it.

    I do like your first idea though, of overriding CanTakeItemInSlot(), so I went ahead and tried it, but I've come across a big problem: it seems that CanTakeItemInSlot() is invoked for every inventory slot except equipment slots. I had my injected code accept/deny the item without any regard for the slot parameter and as a result the character is unwilling to put the item in his inventory, but he's willing to equip it.

    Here's the code, for reference:

    local function heavy_armor_check(item, slot, owner)
    	print("[Mod] given owner = " .. tostring(owner) .. " , item owner = " .. tostring(item.owner))
    	print("[Mod] owner.prefab = " .. tostring(owner.prefab) .. " , item.prefab = " .. tostring(item.prefab))
    	print("[Mod] slot = " .. tostring(slot))
    	if item == nil or owner == nil then return true end
    	if item:HasTag("heavyarmor") and not owner:HasTag("canequipheavy") then
    		if owner.components.talker then
    			owner.components.talker:Say(GetString(owner, "ARMORTOOHEAVY"))
    		return false
    		return true
    local function heavy_armor_check_wrapper(inventory)
    	local oldCanTakeItemInSlot = inventory.CanTakeItemInSlot
    	inventory.CanTakeItemInSlot = function(inv, item, slot)
    		return heavy_armor_check(item, slot, inv.inst) and oldCanTakeItemInSlot(inv, item, slot)
    AddComponentPostInit("inventory", heavy_armor_check_wrapper)

    If I pick up the tagged item from the ground with the equip slot empty, the character equips the item silently and no "[Mod]" print occurs at all.
    If I pick it up when I already have something equipped, the character says the ARMORTOOHEAVY line and the item is picked up to my cursor.
    Same thing happens if I try to place it in the inventory or right-click to unequip it from its equip slot, yet I can place it in the equip slot without problem.

    I have found a different, very simple solution which, in consistence with my recent "how the hell did I miss this" streak, I really should have noticed before.

    The equippable component has a "restrictedtag" property which only allows character with the specified tag to equip that item, which is precisely what I want. All I had to do was add this to my armor prefab's initialization function:

    inst.components.equippable.restrictedtag = "canequipheavy"

    And now only characters who are tagged with "canequipheavy" can equip it. Other characters don't even have "Equip" as a right-click action for it anymore; they can only examine it.

    Now, since my "heavy armor" thing is a component and not a specific prefab, I just need to add that line to my component's postinit function to apply it to every prefab that has that component and I'm done.

    Thanks for your help though, Ultroman; it did expose me to some useful things.

    The "restrictedtag" property is used in the game for the inactive Bernie.

  12. I'd like to find a way to make a character refuse to equip certain items (based on tags).

    I've found examples of this in other mods and posts but in all of them the item is equipped, checked and then unequipped if necessary.
    I got that working, and if I must then I'll keep that, but I would rather have the character refuse to equip it in the first place.

    • When right-clicking the equipment (armor) in the inventory, it will not be equipped at all and the character will say something about it - as opposed to what happens now, where it gets equipped, unequipped and then the characters says something about it.
    • When the equipment is picked up and the character's equip slot is empty, it should go into the inventory without being equipped - as opposed to what happens now, where... (same as above)
    • When equipping would cause a currently-equipped item to be unequipped, I'd like for the currently equipped item to remain equipped.

    In other words, as I said, the character should refuse to equip it, with the behavior you'd expect when that happens.

    Similarly, rather than using tags, I'd like to make specific items usable only by specific characters.
    I'm guessing that'll be similar though.

    Any ideas or leads would be appreciated. =)

    Edit: Problem solved; see the bottom part of my own reply below.

  13. On 2/8/2019 at 8:07 AM, Topaz_Chaz said:

    Hey, would someone be willing to help me? I'm modding for DST, but it crashes as it loads the world. I have no idea what to do. I'm stuck. Here's the client_log file. Thanks!


    "[00:04:46]: [string "scripts/util.lua"]:550: Could not find an asset matching images/avatars/avatar_phelps.tex in any of the search paths."

    You're missing that file.
    Check that you have an image called "avatar_phelps.png" in images\avatars and make sure you let the autocompiler run its course.
    You should be able to see it say that it's processing that file, I think.

    As a general tip, whenever you encounter a crash, search the log file for the first time the word "error" appears and look around there.
    The line I just copied appears one line above the first time "error" shows in the file.

  14. I have two different components that I activate one after the other.
    One uses DoTaskInTime to schedule a task for 30 seconds from now.
    The other uses DoPeriodicTask to schedule a task to run every 0.1 seconds over a total of 30 seconds.
    For some reason, the second task finishes all its iterations in 20 seconds instead of 30 like the first one.

    The periodic task increases a number value in every iteration, from 0 to 1, in increments of 0.1 / 30.
    When it reaches 1 it stops.
    This should take 300 iterations, so with an interval of 0.1 it should take 30 seconds in total.

    Even if the calculations in my code are wrong, it doesn't change the fact that the periodic task occurs too quickly.
    I put debug printouts right before starting the periodic task, printing the interval, and in the tick function printing the progress.
    The server log shows 15 prints per second, 1.5 times faster than it should be (which corresponds to the total time being 2/3 of what it should be).

    If I increase the interval to 0.5 the total time for the periodic task increases to about 27 seconds.
    I really have no idea what's going on here and how to fix it.

    Here's the code for the component (not much here, really):

    -- Fake component for enabling usage of the recharge
    -- item slot animation from The Forge
    local Rechargeable = Class(function(self, inst)
        self.inst = inst
    	self.percent = 1
    	self.recharge_time = 0
    	self.interval = 0
    local function do_recharge(inst, self)
    	self:SetPercent(math.min(1, self:GetPercent() + self.interval / self:GetRechargeTime()))
    	print("[Mod] Percentage: " .. tostring(self:GetPercent()))
    	if self:GetPercent() == 1 then
    function Rechargeable:GetPercent()
    	return self.percent
    function Rechargeable:GetRechargeTime()
    	return self.recharge_time
    function Rechargeable:SetPercent(percent)
    	self.percent = percent
    	self.inst:PushEvent("rechargechange", { percent = self.percent })
    function Rechargeable:SetInterval(interval)
    	self.interval = interval
    function Rechargeable:SetRechargeTime(recharge_time)
    	self.recharge_time = recharge_time
    	self.inst:PushEvent("rechargetimechange", { t = self.recharge_time })
    function Rechargeable:StartRecharging(starting_percentage)
    	if starting_percentage then
    	print("[Mod] Starting percentage: " .. tostring(self:GetPercent()) .. " ; Inteval: " .. tostring(self.interval))
    	if self.recharge_task == nil then
    		self.recharge_task = self.inst:DoPeriodicTask(self.interval, do_recharge, nil, self)
    function Rechargeable:StopRecharging()
    	if self.recharge_task ~= nil then
    		self.recharge_task = nil
    return Rechargeable


    And here is the relevant debug output:


    [00:38:00]: [Mod] Starting percentage: 0 ; Inteval: 0.1    
    [00:38:00]: [Mod] Percentage: 0.0033333333333333    
    [00:38:00]: [Mod] Percentage: 0.0066666666666667    
    [00:38:00]: [Mod] Percentage: 0.01    
    [00:38:00]: [Mod] Percentage: 0.013333333333333    
    [00:38:00]: [Mod] Percentage: 0.016666666666667    
    [00:38:00]: [Mod] Percentage: 0.02    
    [00:38:00]: [Mod] Percentage: 0.023333333333333    
    [00:38:00]: [Mod] Percentage: 0.026666666666667    
    [00:38:00]: [Mod] Percentage: 0.03    
    [00:38:00]: [Mod] Percentage: 0.033333333333333    
    [00:38:01]: [Mod] Percentage: 0.036666666666667    
    [00:38:01]: [Mod] Percentage: 0.04    
    [00:38:01]: [Mod] Percentage: 0.043333333333333    
    [00:38:01]: [Mod] Percentage: 0.046666666666667    
    [00:38:01]: [Mod] Percentage: 0.05    
    [00:38:01]: [Mod] Percentage: 0.053333333333333    
    [00:38:01]: [Mod] Percentage: 0.056666666666667    
    [00:38:01]: [Mod] Percentage: 0.06    
    [00:38:01]: [Mod] Percentage: 0.063333333333333    
    [00:38:01]: [Mod] Percentage: 0.066666666666667    
    [00:38:01]: [Mod] Percentage: 0.07    
    [00:38:01]: [Mod] Percentage: 0.073333333333333    
    [00:38:01]: [Mod] Percentage: 0.076666666666667    
    [00:38:01]: [Mod] Percentage: 0.08    
    [00:38:01]: [Mod] Percentage: 0.083333333333333    
    [00:38:02]: [Mod] Percentage: 0.086666666666667    
    [00:38:02]: [Mod] Percentage: 0.09    
    [00:38:02]: [Mod] Percentage: 0.093333333333333    
    [00:38:02]: [Mod] Percentage: 0.096666666666667    
    [00:38:02]: [Mod] Percentage: 0.1    
    [00:38:02]: [Mod] Percentage: 0.10333333333333    
    [00:38:02]: [Mod] Percentage: 0.10666666666667    
    [00:38:02]: [Mod] Percentage: 0.11    
    [00:38:02]: [Mod] Percentage: 0.11333333333333    
    [00:38:02]: [Mod] Percentage: 0.11666666666667    
    [00:38:02]: [Mod] Percentage: 0.12    
    [00:38:02]: [Mod] Percentage: 0.12333333333333    
    [00:38:02]: [Mod] Percentage: 0.12666666666667    
    [00:38:02]: [Mod] Percentage: 0.13    
    [00:38:02]: [Mod] Percentage: 0.13333333333333    
    [00:38:03]: [Mod] Percentage: 0.13666666666667    
    [00:38:03]: [Mod] Percentage: 0.14    
    [00:38:03]: [Mod] Percentage: 0.14333333333333    
    [00:38:03]: [Mod] Percentage: 0.14666666666667    
    [00:38:03]: [Mod] Percentage: 0.15    
    [00:38:03]: [Mod] Percentage: 0.15333333333333    
    [00:38:03]: [Mod] Percentage: 0.15666666666667    
    [00:38:03]: [Mod] Percentage: 0.16    
    [00:38:03]: [Mod] Percentage: 0.16333333333333    
    [00:38:03]: [Mod] Percentage: 0.16666666666667    
    [00:38:03]: [Mod] Percentage: 0.17    
    [00:38:03]: [Mod] Percentage: 0.17333333333333    
    [00:38:03]: [Mod] Percentage: 0.17666666666667    
    [00:38:03]: [Mod] Percentage: 0.18    
    [00:38:03]: [Mod] Percentage: 0.18333333333333    
    [00:38:04]: [Mod] Percentage: 0.18666666666667    
    [00:38:04]: [Mod] Percentage: 0.19    
    [00:38:04]: [Mod] Percentage: 0.19333333333333    
    [00:38:04]: [Mod] Percentage: 0.19666666666667    
    [00:38:04]: [Mod] Percentage: 0.2    
    [00:38:04]: [Mod] Percentage: 0.20333333333333    
    [00:38:04]: [Mod] Percentage: 0.20666666666667    
    [00:38:04]: [Mod] Percentage: 0.21    
    [00:38:04]: [Mod] Percentage: 0.21333333333333    
    [00:38:04]: [Mod] Percentage: 0.21666666666667    
    [00:38:04]: [Mod] Percentage: 0.22    
    [00:38:04]: [Mod] Percentage: 0.22333333333333    
    [00:38:04]: [Mod] Percentage: 0.22666666666667    
    [00:38:04]: [Mod] Percentage: 0.23    
    [00:38:04]: [Mod] Percentage: 0.23333333333333    
    [00:38:05]: [Mod] Percentage: 0.23666666666667    
    [00:38:05]: [Mod] Percentage: 0.24    
    [00:38:05]: [Mod] Percentage: 0.24333333333333    
    [00:38:05]: [Mod] Percentage: 0.24666666666667    
    [00:38:05]: [Mod] Percentage: 0.25    
    [00:38:05]: [Mod] Percentage: 0.25333333333333    
    [00:38:05]: [Mod] Percentage: 0.25666666666667    
    [00:38:05]: [Mod] Percentage: 0.26    
    [00:38:05]: [Mod] Percentage: 0.26333333333333    
    [00:38:05]: [Mod] Percentage: 0.26666666666667    
    [00:38:05]: [Mod] Percentage: 0.27    
    [00:38:05]: [Mod] Percentage: 0.27333333333333    
    [00:38:05]: [Mod] Percentage: 0.27666666666667    
    [00:38:05]: [Mod] Percentage: 0.28    
    [00:38:05]: [Mod] Percentage: 0.28333333333333    
    [00:38:06]: [Mod] Percentage: 0.28666666666667    
    [00:38:06]: [Mod] Percentage: 0.29    
    [00:38:06]: [Mod] Percentage: 0.29333333333333    
    [00:38:06]: [Mod] Percentage: 0.29666666666667    
    [00:38:06]: [Mod] Percentage: 0.3    
    [00:38:06]: [Mod] Percentage: 0.30333333333333    
    [00:38:06]: [Mod] Percentage: 0.30666666666667    
    [00:38:06]: [Mod] Percentage: 0.31    
    [00:38:06]: [Mod] Percentage: 0.31333333333333    
    [00:38:06]: [Mod] Percentage: 0.31666666666667    
    [00:38:06]: [Mod] Percentage: 0.32    
    [00:38:06]: [Mod] Percentage: 0.32333333333333    
    [00:38:06]: [Mod] Percentage: 0.32666666666667    
    [00:38:06]: [Mod] Percentage: 0.33    
    [00:38:06]: [Mod] Percentage: 0.33333333333333    
    [00:38:07]: [Mod] Percentage: 0.33666666666667    
    [00:38:07]: [Mod] Percentage: 0.34    
    [00:38:07]: [Mod] Percentage: 0.34333333333333    
    [00:38:07]: [Mod] Percentage: 0.34666666666667    
    [00:38:07]: [Mod] Percentage: 0.35    
    [00:38:07]: [Mod] Percentage: 0.35333333333333    
    [00:38:07]: [Mod] Percentage: 0.35666666666667    
    [00:38:07]: [Mod] Percentage: 0.36    
    [00:38:07]: [Mod] Percentage: 0.36333333333333    
    [00:38:07]: [Mod] Percentage: 0.36666666666667    
    [00:38:07]: [Mod] Percentage: 0.37    
    [00:38:07]: [Mod] Percentage: 0.37333333333333    
    [00:38:07]: [Mod] Percentage: 0.37666666666667    
    [00:38:07]: [Mod] Percentage: 0.38    
    [00:38:07]: [Mod] Percentage: 0.38333333333333    
    [00:38:08]: [Mod] Percentage: 0.38666666666667    
    [00:38:08]: [Mod] Percentage: 0.39    
    [00:38:08]: [Mod] Percentage: 0.39333333333333    
    [00:38:08]: [Mod] Percentage: 0.39666666666667    
    [00:38:08]: [Mod] Percentage: 0.4    
    [00:38:08]: [Mod] Percentage: 0.40333333333333    
    [00:38:08]: [Mod] Percentage: 0.40666666666667    
    [00:38:08]: [Mod] Percentage: 0.41    
    [00:38:08]: [Mod] Percentage: 0.41333333333333    
    [00:38:08]: [Mod] Percentage: 0.41666666666667    
    [00:38:08]: [Mod] Percentage: 0.42    
    [00:38:08]: [Mod] Percentage: 0.42333333333333    
    [00:38:08]: [Mod] Percentage: 0.42666666666667    
    [00:38:08]: [Mod] Percentage: 0.43    
    [00:38:08]: [Mod] Percentage: 0.43333333333333    
    [00:38:09]: [Mod] Percentage: 0.43666666666667    
    [00:38:09]: [Mod] Percentage: 0.44    
    [00:38:09]: [Mod] Percentage: 0.44333333333333    
    [00:38:09]: [Mod] Percentage: 0.44666666666667    
    [00:38:09]: [Mod] Percentage: 0.45    
    [00:38:09]: [Mod] Percentage: 0.45333333333333    
    [00:38:09]: [Mod] Percentage: 0.45666666666667    
    [00:38:09]: [Mod] Percentage: 0.46    
    [00:38:09]: [Mod] Percentage: 0.46333333333333    
    [00:38:09]: [Mod] Percentage: 0.46666666666667    
    [00:38:09]: [Mod] Percentage: 0.47    
    [00:38:09]: [Mod] Percentage: 0.47333333333333    
    [00:38:09]: [Mod] Percentage: 0.47666666666667    
    [00:38:09]: [Mod] Percentage: 0.48    
    [00:38:09]: [Mod] Percentage: 0.48333333333333    
    [00:38:10]: [Mod] Percentage: 0.48666666666667    
    [00:38:10]: [Mod] Percentage: 0.49    
    [00:38:10]: [Mod] Percentage: 0.49333333333333    
    [00:38:10]: [Mod] Percentage: 0.49666666666667    
    [00:38:10]: [Mod] Percentage: 0.5    
    [00:38:10]: [Mod] Percentage: 0.50333333333333    
    [00:38:10]: [Mod] Percentage: 0.50666666666667    
    [00:38:10]: [Mod] Percentage: 0.51    
    [00:38:10]: [Mod] Percentage: 0.51333333333333    
    [00:38:10]: [Mod] Percentage: 0.51666666666667    
    [00:38:10]: [Mod] Percentage: 0.52    
    [00:38:10]: [Mod] Percentage: 0.52333333333333    
    [00:38:10]: [Mod] Percentage: 0.52666666666667    
    [00:38:10]: [Mod] Percentage: 0.53    
    [00:38:10]: [Mod] Percentage: 0.53333333333333    
    [00:38:11]: [Mod] Percentage: 0.53666666666667    
    [00:38:11]: [Mod] Percentage: 0.54    
    [00:38:11]: [Mod] Percentage: 0.54333333333333    
    [00:38:11]: [Mod] Percentage: 0.54666666666667    
    [00:38:11]: [Mod] Percentage: 0.55    
    [00:38:11]: [Mod] Percentage: 0.55333333333333    
    [00:38:11]: [Mod] Percentage: 0.55666666666667    
    [00:38:11]: [Mod] Percentage: 0.56    
    [00:38:11]: [Mod] Percentage: 0.56333333333333    
    [00:38:11]: [Mod] Percentage: 0.56666666666667    
    [00:38:11]: [Mod] Percentage: 0.57    
    [00:38:11]: [Mod] Percentage: 0.57333333333333    
    [00:38:11]: [Mod] Percentage: 0.57666666666667    
    [00:38:11]: [Mod] Percentage: 0.58    
    [00:38:11]: [Mod] Percentage: 0.58333333333333    
    [00:38:12]: [Mod] Percentage: 0.58666666666667    
    [00:38:12]: [Mod] Percentage: 0.59    
    [00:38:12]: [Mod] Percentage: 0.59333333333333    
    [00:38:12]: [Mod] Percentage: 0.59666666666667    
    [00:38:12]: [Mod] Percentage: 0.6    
    [00:38:12]: [Mod] Percentage: 0.60333333333333    
    [00:38:12]: [Mod] Percentage: 0.60666666666667    
    [00:38:12]: [Mod] Percentage: 0.61    
    [00:38:12]: [Mod] Percentage: 0.61333333333333    
    [00:38:12]: [Mod] Percentage: 0.61666666666667    
    [00:38:12]: [Mod] Percentage: 0.62    
    [00:38:12]: [Mod] Percentage: 0.62333333333333    
    [00:38:12]: [Mod] Percentage: 0.62666666666667    
    [00:38:12]: [Mod] Percentage: 0.63    
    [00:38:12]: [Mod] Percentage: 0.63333333333333    
    [00:38:13]: [Mod] Percentage: 0.63666666666667    
    [00:38:13]: [Mod] Percentage: 0.64    
    [00:38:13]: [Mod] Percentage: 0.64333333333333    
    [00:38:13]: [Mod] Percentage: 0.64666666666667    
    [00:38:13]: [Mod] Percentage: 0.65    
    [00:38:13]: [Mod] Percentage: 0.65333333333333    
    [00:38:13]: [Mod] Percentage: 0.65666666666667    
    [00:38:13]: [Mod] Percentage: 0.66    
    [00:38:13]: [Mod] Percentage: 0.66333333333333    
    [00:38:13]: [Mod] Percentage: 0.66666666666667    
    [00:38:13]: [Mod] Percentage: 0.67    
    [00:38:13]: [Mod] Percentage: 0.67333333333333    
    [00:38:13]: [Mod] Percentage: 0.67666666666667    
    [00:38:13]: [Mod] Percentage: 0.68    
    [00:38:13]: [Mod] Percentage: 0.68333333333333    
    [00:38:14]: [Mod] Percentage: 0.68666666666667    
    [00:38:14]: [Mod] Percentage: 0.69    
    [00:38:14]: [Mod] Percentage: 0.69333333333333    
    [00:38:14]: [Mod] Percentage: 0.69666666666667    
    [00:38:14]: [Mod] Percentage: 0.7    
    [00:38:14]: [Mod] Percentage: 0.70333333333333    
    [00:38:14]: [Mod] Percentage: 0.70666666666667    
    [00:38:14]: [Mod] Percentage: 0.71    
    [00:38:14]: [Mod] Percentage: 0.71333333333333    
    [00:38:14]: [Mod] Percentage: 0.71666666666667    
    [00:38:14]: [Mod] Percentage: 0.72    
    [00:38:14]: [Mod] Percentage: 0.72333333333333    
    [00:38:14]: [Mod] Percentage: 0.72666666666667    
    [00:38:14]: [Mod] Percentage: 0.73    
    [00:38:14]: [Mod] Percentage: 0.73333333333333    
    [00:38:15]: [Mod] Percentage: 0.73666666666667    
    [00:38:15]: [Mod] Percentage: 0.74    
    [00:38:15]: [Mod] Percentage: 0.74333333333333    
    [00:38:15]: [Mod] Percentage: 0.74666666666667    
    [00:38:15]: [Mod] Percentage: 0.75    
    [00:38:15]: [Mod] Percentage: 0.75333333333333    
    [00:38:15]: [Mod] Percentage: 0.75666666666667    
    [00:38:15]: [Mod] Percentage: 0.76    
    [00:38:15]: [Mod] Percentage: 0.76333333333333    
    [00:38:15]: [Mod] Percentage: 0.76666666666667    
    [00:38:15]: [Mod] Percentage: 0.77    
    [00:38:15]: [Mod] Percentage: 0.77333333333333    
    [00:38:15]: [Mod] Percentage: 0.77666666666667    
    [00:38:15]: [Mod] Percentage: 0.78    
    [00:38:15]: [Mod] Percentage: 0.78333333333333    
    [00:38:16]: [Mod] Percentage: 0.78666666666666    
    [00:38:16]: [Mod] Percentage: 0.79    
    [00:38:16]: [Mod] Percentage: 0.79333333333333    
    [00:38:16]: [Mod] Percentage: 0.79666666666666    
    [00:38:16]: [Mod] Percentage: 0.8    
    [00:38:16]: [Mod] Percentage: 0.80333333333333    
    [00:38:16]: [Mod] Percentage: 0.80666666666666    
    [00:38:16]: [Mod] Percentage: 0.81    
    [00:38:16]: [Mod] Percentage: 0.81333333333333    
    [00:38:16]: [Mod] Percentage: 0.81666666666666    
    [00:38:16]: [Mod] Percentage: 0.82    
    [00:38:16]: [Mod] Percentage: 0.82333333333333    
    [00:38:16]: [Mod] Percentage: 0.82666666666666    
    [00:38:16]: [Mod] Percentage: 0.83    
    [00:38:16]: [Mod] Percentage: 0.83333333333333    
    [00:38:17]: [Mod] Percentage: 0.83666666666666    
    [00:38:17]: [Mod] Percentage: 0.84    
    [00:38:17]: [Mod] Percentage: 0.84333333333333    
    [00:38:17]: [Mod] Percentage: 0.84666666666666    
    [00:38:17]: [Mod] Percentage: 0.85    
    [00:38:17]: [Mod] Percentage: 0.85333333333333    
    [00:38:17]: [Mod] Percentage: 0.85666666666666    
    [00:38:17]: [Mod] Percentage: 0.86    
    [00:38:17]: [Mod] Percentage: 0.86333333333333    
    [00:38:17]: [Mod] Percentage: 0.86666666666666    
    [00:38:17]: [Mod] Percentage: 0.87    
    [00:38:17]: [Mod] Percentage: 0.87333333333333    
    [00:38:17]: [Mod] Percentage: 0.87666666666666    
    [00:38:17]: [Mod] Percentage: 0.88    
    [00:38:17]: [Mod] Percentage: 0.88333333333333    
    [00:38:18]: [Mod] Percentage: 0.88666666666666    
    [00:38:18]: [Mod] Percentage: 0.89    
    [00:38:18]: [Mod] Percentage: 0.89333333333333    
    [00:38:18]: [Mod] Percentage: 0.89666666666666    
    [00:38:18]: [Mod] Percentage: 0.9    
    [00:38:18]: [Mod] Percentage: 0.90333333333333    
    [00:38:18]: [Mod] Percentage: 0.90666666666666    
    [00:38:18]: [Mod] Percentage: 0.91    
    [00:38:18]: [Mod] Percentage: 0.91333333333333    
    [00:38:18]: [Mod] Percentage: 0.91666666666666    
    [00:38:18]: [Mod] Percentage: 0.92    
    [00:38:18]: [Mod] Percentage: 0.92333333333333    
    [00:38:18]: [Mod] Percentage: 0.92666666666666    
    [00:38:18]: [Mod] Percentage: 0.93    
    [00:38:18]: [Mod] Percentage: 0.93333333333333    
    [00:38:19]: [Mod] Percentage: 0.93666666666666    
    [00:38:19]: [Mod] Percentage: 0.94    
    [00:38:19]: [Mod] Percentage: 0.94333333333333    
    [00:38:19]: [Mod] Percentage: 0.94666666666666    
    [00:38:19]: [Mod] Percentage: 0.95    
    [00:38:19]: [Mod] Percentage: 0.95333333333333    
    [00:38:19]: [Mod] Percentage: 0.95666666666666    
    [00:38:19]: [Mod] Percentage: 0.96    
    [00:38:19]: [Mod] Percentage: 0.96333333333333    
    [00:38:19]: [Mod] Percentage: 0.96666666666666    
    [00:38:19]: [Mod] Percentage: 0.97    
    [00:38:19]: [Mod] Percentage: 0.97333333333333    
    [00:38:19]: [Mod] Percentage: 0.97666666666666    
    [00:38:19]: [Mod] Percentage: 0.98    
    [00:38:19]: [Mod] Percentage: 0.98333333333333    
    [00:38:20]: [Mod] Percentage: 0.98666666666666    
    [00:38:20]: [Mod] Percentage: 0.99    
    [00:38:20]: [Mod] Percentage: 0.99333333333333    
    [00:38:20]: [Mod] Percentage: 0.99666666666666    
    [00:38:20]: [Mod] Percentage: 1    
    [00:38:20]: [Mod] Percentage: 1    

    Like I said, 15 prints per second.

    What's the problem here and how do I make DoPeriodicTask work like I expect?
    I would have suspected server load but it's working faster than it should.

    Thanks in advance.

  15. I have some code that updates the durability of an armor (repairs it) in a timed task.
    It works, but the durability percentage only updates if I unequip it or equip it again.
    How do I get the item slot to refresh its state?

    ... Well, actually, I did get this to work by piggybacking on the "fueled" component's event:

    inst:PushEvent("percentusedchange", { percent = inst.components.armor:GetPercent() })

    But that looks like an underhanded trick that only works since the ItemTile widget calls the same SetPercent function for both and doesn't look very closely at the inventory item that pushed the event.
    I'd be happier if I could just call a "refresh inventory bar" function or something of the same ilk.

    Thanks in advance. =)

  16. I'm trying to modify damage taken before armor checks and in a non-multiplicative manner.

    Specifically, I'm making a "heavy armor" component which grants a fixed damage reduction that should go before everything else.
    For example, if the damage reduction is 10 then when a character wearing this armor is attacked, the damage should be reduced by 10 and then the entire combat mechanism should do its job.

    After the damage reduction takes place I want the normal armor damage reduction, so I can't make the armor component do this work.
    I also don't want any of the absorbed damage to affect the equipped armors and wear them down.

    Ideally I would wrap the function Inventory:ApplyDamage with my mechanism and alter the damage before the inventory does its work, but I can't do that since it's a local function.

    I looked at combat.lua to see if I could interject in the process somehow.
    I found Combat:GetAttacked and Combat:CalcDamage, but I didn't see any way for me to do what I want.
    The effects should occur after the damage calculation is performed but before the inventory applies the damage to the equipped armor.

    Any ideas on how I can do this?
    Of course, I could always replace inventory.lua or combat.lua, but that seems extremely intrusive and I imagine it would require constant updating with the game.

  17. In the two (well, one and a half) mods I've made so far, I was coding for functionality only ("just make it work.")
    I was on a deadline and I didn't know the environment (or Lua) very well, and I did get everything working, but the result was very messy code.
    I ended up with 1647 lines of code in my modmain file.

    Now I'm about to start working on a new mod, something bigger and possibly with other people too, so this style of work is not a good approach - and I don't like it either, coming from a background of coding with a strong emphasis on design, style and conventions.

    So what I'm looking for here is some advice from veteran Don't Starve script writers.
    What are some good practices and rules of thumb for coding in Lua for Don't Starve Together?
    Some design patterns would also be nice (for example, I always try to wrap an existing function with my extra code rather than replace it with a copy of the original that has my additions in it.)

    I know there's an option for importing modules which can help reduce the size of modmain and organize the code better, but I think that when I tried using it I had some trouble accessing the GLOBAL variable (my memory's kind of fuzzy on that part).

    Thanks in advance. =)

  18. I made a small utility script for renaming characters easily.

    It conserves case, so it should take care of both "esctemplate" and "ESCTEMPLATE" replacements at once.
    It also changes filenames accordingly.

    You can find it here, and a post I wrote with more details on how to use it here.

    The script itself is written in Python, so it should work on Mac systems too (untested), but there's a batch file I added to facilitate using it more easily, and that won't work on Macs (at least, not without conversion or some program to run batch files on Mac, if such a thing exists).
    Still, the batch file is very simple, and the explanations I wrote should make it clear how to use the script without relying on the batch file, so it should still be of use.

    If someone wants to write a Mac equivalent of the batch file I'll gladly add it to the archive for download.

    Hopes this helps someone. =)

  19. I usually use Dragon Wolf Leo's wonderful Extended Sample Character Template as a basis to a new character I make, or sometimes a character of my own that I'd already made, and I got tired of the search & replace and file renaming process, so I wrote a small utility to do it for me.

    It searches and replaces one string with another while preserving case, so if you rename esctemplate to SuperDude then everywhere you have esctemplate it will be changed to superdude and everywhere you have ESCTEMPLATE it will be changed to SUPERDUDE.

    It also renames all the files it finds accordingly, so esctemplate.lua will be renamed to superdude.lua and folders named esctemplate will be renamed to superdude.

    The tool is called CaseReplace and was written in Python 3 so you need to install that if you want to use it.


    This tool performs a simple search & replace operation. It doesn't know that you only want to change text when it's referring to a character name.
    Therefore the name you replace needs to be unique and only appear as the name of that character!
    If your character is named "e" and you run this tool to replace "e" with "a" you'll most certainly break your mod and nothing will work.
    Also, this tool has no undo option (replacing "a" with "e" again won't undo it), so it's highly recommended you back your files up before using it.
    I have tested it but not rigorously, so it's best to make a backup before running this.
    I will not be held responsible for the loss of your work or data as a result of using this tool.

    How to Use It

    First install Python 3.
    I used Python 3.6.6 but I think any version of Python 3 should work, or at least any that are after 3.6.6.

    Next, extract the contents of the ZIP file in the download link at the end of this post to your mod folder.

    You'll see two files: CaseReplace and RenameDSCharacter.

    Normally using RenameDSCharacter will be enough.
    Just double-click it, enter the current name of the character and then the new name you want to give it, and it'll do everything for you.

    That's it.


    Advanced Usage

    In case the normal way is not enough - for example if you want it to skip PNG files or something - you can use the CaseReplace script directly.
    If you run CaseReplace with the '--help' option you will see something like this:

    C:\MyModFolder>python --help
    usage: [-h] [-f FIND] [-r REPLACE] [-m MIXED] [-n] [-v] [-b]
                          [-p [PATH [PATH ...]]] [-x [EXCLUDE [EXCLUDE ...]]]
    CaseReplace script, by Tomer Godinger, May 2019.
    Search and replace utility that preserves case.
    optional arguments:
      -h, --help            show this help message and exit
      -f FIND               the string to find
      -r REPLACE            the string to replace with
      -m MIXED              what to use for mixed-case findings
      -n                    also rename files and directories
      -v                    verbose mode
      -b                    stop in case of an error
      -p [PATH [PATH ...]]  files to search in
      -x [EXCLUDE [EXCLUDE ...]]
                            files NOT to search in
      --version             show version
    Example usage: -f SomeString -r NewString C:\*.txt
            Will replace all occurrences of "SomeString" with "NewString" in all files that end with '.txt' under C:\.
            Case is preserved, so SOMESTRING will become NEWSTRING and somestring will become newstring.
            Mixed-case will be replaced with the casing used in the replace argument.

    I'm hoping that's self-explanatory, but I'll write a bit more anyway.
    Let's assume I want to rename esctemplate with SuperDude.

    When you run it you must provide:

    • The string to search for: -f esctemplate
    • The string to replace it with: -r SuperDude
    • At least one of these two (both is also fine):
      • Which files to look in - for example, to search only in Lua scripts: -p **/*.lua
      • Which files NOT to look in - for example, to skip ZIP files: -x **/*.zip

    If you only provide the -x option, the script will process every file except the ones who fit the -x pattern.

    This script uses the Python glob module, which uses Unix style pathname pattern expansion, so if you have trouble getting it to work only on the files you want then you may want to look into that.

    You also may provide:

    • What to replace mixed-case findings with, for example: -m SUPERDude
      If at any point the search term is found where it isn't all lower-case and it isn't all upper-case (e.g. "EscTemplate"), it will be replaced with what you provide here.
      If you do not provide it, the way you wrote the find name (with -f) will be used, so if you ran the batch file and wrote "SuperDude" then "EscTemplate" will be changed to "SuperDuide", as will "ESCtemplATE", "esctEmplate" and "ESCTEMPLATe".
    • Whether or not to rename files: -n
      If this option is provided, any file and directory in the search criteria (i.e. that fits the "-p" pattern (if given) and doesn't fit the "-x" pattern (if given)) will also have its name changed in the exact same manner (preserves case, though that has very little meaning on Windows).
    • A request to halt the process if an error occurs: -b
    • A request for the script to tell you what it's doing as it does it: -v
      This will show you which files are changed, how many replacements were made in them, which files were renamed, etc.


    • python -f ThisDude -r ThatDude -p **/*.scml
      Replaces "ThisDude" with "ThatDude" with case preservation in every SCML (Spriter) file without changing any names.
    • python -f wilson -r SpongeBob -n -p **/*.lua
      Replaces "wilson" with "spongebob" with case preservation in every Lua script file while also changing the names of the files (e.g. "SGwilson" will become "SGspongebob").
    • python -f superman -r clarkkent -m "Clark Kent" -n -p **/*.lua -x **metropolis**
      Replaces "superman" with "clarkkent" in all Lua script files that don't have the word "metropolis" in their name or path (so everything under a "metropolis" folder will also be skipped).
      This one will also change "Superman" to "Clark Kent" (with a space).
      Not something you usually want to do, but it can be useful, for example, if you only have "Superman" in mixed-case inside descriptions and speech lines, and there you would want to replace it with "Clark Kent" and not "clarkkent" or "ClarkKent".


    Where to Get It


    You're most welcome to ask any questions if you have them, and also tell me if you encounter a bug or have a suggestion.

    Happy modding! =D