
Content Count
55 
Joined

Last visited
Posts posted by Clopen


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") inst:AddComponent("transformer") end if TheWorld.ismastersim then local tf = inst.components.transformer print("Server: tf = ", tostring(tf)) else local tf = inst.replica.transformer print("Client: tf = ", tostring(tf)) end
And I have this in master_postinit(inst):
if not (inst.components.transformer or inst.replica.transformer) then print("Adding in master_postinit") inst:AddComponent("transformer") end
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) <7484> [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:

Why can't I access a replica if it already exists?
 Actually, also why does it exist already if I haven't added it yet?
 And where do I put clientside initialization code for a player character?
Thanks in advance. =)

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? 
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:
 Is there ever a reason to use it directly?

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

I'm somewhat new to modding DST, and I haven't dealt much with hostclient 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. =)
P.S.
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. 
This is more of a consultation than a direct howto 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. =)

I see.
Well, alright then.
I'll give him a modified version of Wilson's stategraph.Thank you both. =)

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. 
Oh, you're right.
How lovely. =)
Thanks. ^_^ 
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. =)

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

Yeah, I did the same.
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. 
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")) end return false else return true end end 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) end end 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 rightclick to unequip it from its equip slot, yet I can place it in the equip slot without problem.However!
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 rightclick 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.
P.S.
The "restrictedtag" property is used in the game for the inactive Bernie. 
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.
I.e.: When rightclicking 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 currentlyequipped 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.

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. 
Thanks everyone.
When I saw that the timing was off I decided to just let the periodic task run whenever it wants to as long as it's fast enough (no problem there) and do the logic of progress and ending using starting time, total duration and current time, which is pretty much what @CarlZalph said.
I'll manage the rest around that.

Ugh, I don't know what's wrong with me lately. >_<
I went over all the code in armor.lua searching for a function to modify the armor durability and somehow I missed that one.
I only saw TakeDamage.Thanks. =\

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 end) 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 self:StopRecharging() end end function Rechargeable:GetPercent() return self.percent end function Rechargeable:GetRechargeTime() return self.recharge_time end function Rechargeable:SetPercent(percent) self.percent = percent self.inst:PushEvent("rechargechange", { percent = self.percent }) end function Rechargeable:SetInterval(interval) self.interval = interval end function Rechargeable:SetRechargeTime(recharge_time) self.recharge_time = recharge_time self.inst:PushEvent("rechargetimechange", { t = self.recharge_time }) end function Rechargeable:StartRecharging(starting_percentage) if starting_percentage then self:SetPercent(starting_percentage) end 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) end end function Rechargeable:StopRecharging() if self.recharge_task ~= nil then self.recharge_task:Cancel() self.recharge_task = nil end end return Rechargeable
And here is the relevant debug output:
Spoiler[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: 1Like 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.

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

Oh, you're right.
I just automatically assumed it was local because it's a "class" function.Thanks. =)

I'm trying to modify damage taken before armor checks and in a nonmultiplicative 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. 
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.
Hope this helps someone. =)

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

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

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.
IMPORTANT NOTE
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 doubleclick 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 CaseReplace.py help usage: CaseReplace.py [h] [f FIND] [r REPLACE] [m MIXED] [n] [v] [b] [p [PATH [PATH ...]]] [x [EXCLUDE [EXCLUDE ...]]] [version] 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 mixedcase 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: CaseReplace.py 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. Mixedcase will be replaced with the casing used in the replace argument.
I'm hoping that's selfexplanatory, 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 mixedcase findings with, for example: m SUPERDude
If at any point the search term is found where it isn't all lowercase and it isn't all uppercase (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.
Examples

python CaseReplace.py f ThisDude r ThatDude p **/*.scml
Replaces "ThisDude" with "ThatDude" with case preservation in every SCML (Spriter) file without changing any names.

python CaseReplace.py 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 CaseReplace.py 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 mixedcase 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
No Replica for Replicable Component?
in [Don't Starve Together] Mods and Tools
Posted
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. =)