Developer PeterA Posted October 10, 2015 Developer Share Posted October 10, 2015 The sun rises in the east, sets in the west, and @rezecib hands out solid programming advice. Two thumbs up in agreement from me about not polluting the global namespace. 2 Link to comment Share on other sites More sharing options...
Snowhusky5 Posted December 17, 2015 Share Posted December 17, 2015 (edited) local OldGetPosition = inst.GetPositioninst.GetPosition = function(thing) local pos = OldGetPosition(thing) pos.x = math.floor(pos.x+0.5) pos.y = math.floor(pos.y+0.5) pos.z = math.floor(pos.z+0.5) return posendIf we try to do something similar to this (replacing a function in the game with a modded one that calls the original and then does other stuff), where exactly would we put this in the mod files? modmain does not work since 'inst' is not defined when you copy the old function. I'm pretty sure that this would work in a prefab, but would it only work for that specific prefab or everywhere that this function is used? Edited December 17, 2015 by Snowhusky5 Link to comment Share on other sites More sharing options...
rezecib Posted December 17, 2015 Author Share Posted December 17, 2015 @Snowhusky5, Look at Always On Status (the DST version) for a bunch of examples. You use the AddPrefabPostInit, AddComponentPostInit, AddClassPostConstruct functions in the modmain to pass a function that takes inst, self, self as arguments (one for each, respectively), and then you can do it within those. Link to comment Share on other sites More sharing options...
Snowhusky5 Posted December 17, 2015 Share Posted December 17, 2015 @Snowhusky5, Look at Always On Status (the DST version) for a bunch of examples. You use the AddPrefabPostInit, AddComponentPostInit, AddClassPostConstruct functions in the modmain to pass a function that takes inst, self, self as arguments (one for each, respectively), and then you can do it within those.Thanks, AddComponentPostInit is exactly what I needed. Link to comment Share on other sites More sharing options...
Mr.Tarunio Posted January 2, 2016 Share Posted January 2, 2016 how do you make a wearable item, like tophat do more buffs. Link to comment Share on other sites More sharing options...
HomShaBom Posted June 10, 2016 Share Posted June 10, 2016 How come every single code block in this post has everything written out on a single line? Link to comment Share on other sites More sharing options...
Muche Posted June 10, 2016 Share Posted June 10, 2016 1 hour ago, HomShaBom said: How come every single code block in this post has everything written out on a single line? Because the guide was written a while ago and the forum upgrade, which was done in January, stripped all newline characters from code blocks. Link to comment Share on other sites More sharing options...
rezecib Posted June 13, 2016 Author Share Posted June 13, 2016 I would like to fix the formatting of the post, but unfortunately there's still no source editor in the current forum, which makes editing it very time-consuming. 1 Link to comment Share on other sites More sharing options...
Layarion Posted July 2, 2016 Share Posted July 2, 2016 (edited) On 12/22/2014 at 7:28 PM, rezecib said: Fix the single lined madness by taking pictures of the code instead. i CANNOT read this BS and take your guide seriously. Edited July 2, 2016 by Layarion Link to comment Share on other sites More sharing options...
IvanX Posted July 18, 2016 Share Posted July 18, 2016 (edited) Nice guide, it's missing a few very important points thou.. For example, you've mentioned that DST and DS have different initialization order, on top of that first world init has different initialization order than not first one. So looking at a couple of cases, we'll have the following for most common events DS, first launch: 1. AddPlayerPostInit 2. AddSimPostInit 3. AddClassPostInit 4. AddGamePostInit DS, sequential launch: 1. AddPlayerPostInit 2. AddGamePostInit 3. AddSimPostInit 4. AddClassPostInit DST has the same order in both first and any sequential launches, but I still would rather not trust the fixed ordering: 1. AddSimPostInit 2. AddGamePostInit 3. AddPlayerPostInit 4. AddClassPostInit What does all of this mean? Usually the correct order of the mod program code would be to 1. get all of the required data 2. launch our initialize using all of that data But the problem is, how do you determine when to launch that initialize? Simple, just add a global boolean variable for each of these post inits, aka local _GameAdded = false local _SimAdded = false local _ClassAdded = false local _PlayerAdded = false Inside of every function that you use to gather data, set up one of those variables to true. Then fire OnAfterLoad() on the last line of the function. ! Note that since AddClassPostInit is fired last, for example you manipulate player.HUD.controls class, you would not be able to call player.HUD.controls. inside of the OnAfterLoad, thus you must pass it as an argument to OnAfterLoad(self) Inside of the OnAfterLoad function, just check that all of those functions finished running aka Added, then launch your code. Final code looks like this, and it does the same in both DS and DST. local functon OnAfterLoad(ctrls) if not _SimAdded or not _GameAdded or not _PlayerAdded or not _ControlsAdded then return false end local controls = GetPlayer().HUD.controls or ctrls -- do stuff with all the gathered data ... end local function AddSimPostInit() -- do stuff with sim ... _SimAdded = true OnAfterLoad() end local function AddGamePostInit() -- do stuff with Game ... _GameAdded = true OnAfterLoad() end local function AddPlayerPostInit() -- do stuff with Player ... _PlayerAdded = true OnAfterLoad() end local function AddControlsPostInit(self) -- do stuff with controls ... _ControlsAdded = true OnAfterLoad(self) end Edited July 18, 2016 by IvanX Link to comment Share on other sites More sharing options...
IvanX Posted July 18, 2016 Share Posted July 18, 2016 Another Point is AddPlayerPostInit That does not work in DST anymore, because if you write a local mode, you definitely only want your very player, but the function fires for all of the players. Unfortunately for you ThePlayer is NOT YET DEFINED within AddPlayerPostInit, because that is how constructors work, until you finish running one, the class is not yet out in the globals. Thus local function AddPlayerPostInit(player) if GLOBALS.ThePlayer == player then ... WILL NOT WORK. The solution is rather complicated, I've ninjaed it from this thread, thanks to @Kam297 AddPrefabPostInit("world", function(wrld) wrld:ListenForEvent("playeractivated", function(wlrd, player) if player == GLOBAL.ThePlayer then player:AddComponent("myclientsidecomponentwhichdoesntequireanyserversidestuff") end end)end) So to make it both DS and DST compatible you use The AddPrefabPostInit+ListenForEvent in DST and simply use AddPlayerPostInit in DS if IsDST() then AddPrefabPostInit("world", ...) else AddPlayerPostInit(...) end Link to comment Share on other sites More sharing options...
Muche Posted July 18, 2016 Share Posted July 18, 2016 @IvanX, I've tried simple (DST) AddGamePostInit(function() print("[Test|GamePostInit]") end) AddSimPostInit(function() print("[Test|SimPostInit]") end) , started hosting a world (got SimPostInit, then GamePostInit); disconnected, started it again and the order didn't change (SimPostInit, then GamePostInit). Are there more conditions to what you describe as sequential launch? 1 Link to comment Share on other sites More sharing options...
IvanX Posted July 18, 2016 Share Posted July 18, 2016 Note thou, that this will, YET AGAIN, change the priority for launching, but the OnAfterLoad hack should work here as well. AddPrefabPostInit + ListenForEvent will fire last of all Link to comment Share on other sites More sharing options...
IvanX Posted July 18, 2016 Share Posted July 18, 2016 (edited) 10 minutes ago, Muche said: @IvanX, I've tried simple (DST) AddGamePostInit(function() print("[Test|GamePostInit]") end) AddSimPostInit(function() print("[Test|SimPostInit]") end) , started hosting a world (got SimPostInit, then GamePostInit); disconnected, started it again and the order didn't change (SimPostInit, then GamePostInit). Are there more conditions to what you describe as sequential launch? Hmm, guess I should test it again, could be that it's running in the fixed order in DST now, did not do sufficient testing, as it is completely different order in DS and for a joint mod I still need to determine which one is fired last. Thanks P.S. I would not trust them running in a fixed order anyways. The way I look at it, it's very simillar to expecting pairs to run in the given order. In some cases it may be true, in some, there's no really fixed order set. Edited July 18, 2016 by IvanX Link to comment Share on other sites More sharing options...
IvanX Posted July 22, 2016 Share Posted July 22, 2016 One more very important thing: AddGamePostInit, AddPlayerPostInit, AddSimPostInit, AddClassPostInit, AddPrefabPostInit For game host, all of those methods fire BEFORE OnLoad methods of components. While OnLoad method of component will NOT fire if the component is added for the first time. So the only way to execute some code after making sure the component has been loaded is by using the "playeractivated hack" AddPrefabPostInit("world", function(wrld) wrld:ListenForEvent("playeractivated", function(wlrd, player) if player == GLOBAL.ThePlayer then -- launch this code very very late, after everything's been initialized end end) end) Not too convenient tbh. Link to comment Share on other sites More sharing options...
IvanX Posted July 22, 2016 Share Posted July 22, 2016 Here's an extremely useful set of polyfills, that is a must have on any DS-DST client mod. Just put it at the top of modmain.lua: local function IsDST() return GLOBAL.TheSim:GetGameID() == "DST" end local function IsClientSim() return IsDST() and GLOBAL.TheNet:GetIsClient() end local function GetPlayer() if IsDST() then return GLOBAL.ThePlayer else return GLOBAL.GetPlayer() end end local function GetWorld() if IsDST() then return GLOBAL.TheWorld else return GLOBAL.GetWorld() end end local function AddPlayerPostInit(fn) if IsDST() then env.AddPrefabPostInit("world", function(wrld) wrld:ListenForEvent("playeractivated", function(wlrd, player) if player == GLOBAL.ThePlayer then fn(player) end end) end) else env.AddPlayerPostInit(function(player) fn(player) end) end end IsDST - true for DST, false for DS IsClientSim - true for DST client, false for DST mastersim, falst for DS GetPlayer,GetWorld and AddPlayerPostInit - are polyfills for simillar functions in DS. AddPlayerPostInit fires only once for your very player. Link to comment Share on other sites More sharing options...
IvanX Posted July 22, 2016 Share Posted July 22, 2016 (edited) And here's a code snippet on how to save component data in a DS-DST client mode: local function IsDST() return TheSim:GetGameID() == "DST" end local function IsClientSim() return IsDST() and TheNet:GetIsClient() end local MyComponent = Class(function(self) ... if IsClientSim() then self._filepath = "session/"..(TheNet:GetSessionIdentifier() or "INVALID_SESSION").."/"..(TheNet:GetUserID() or "INVALID_USERID").."_/MyComponent_data" self:OnLoad() end end) function KnownFoods:OnSave() local data = { -- assign data here ... } if IsClientSim() then local str = json.encode(data) TheSim:SetPersistentString(self._filepath, str, true) else return data end end function KnownFoods:OnLoad(data) if IsClientSim() then -- ClientSim load uses PersistentString data TheSim:GetPersistentString(self._filepath, function(success, strdata) if success then data = json.decode(strdata) end end) else -- MasterSim uses OnLoad data end if data then -- manipulate data here ... print('MyComponent ~~~ component loaded with ... data') else print('MyComponent ~~~ component loaded with no data') end end How does it work? For DS and DST MasterSim we use the common OnSave and OnLoad functions, as for the ClientSim: first of all we need to force launch OnLoad at the end of the component constructor, since OnLoad does not fire for client only mods. As for the data, instead of sending it to the server, we pack it up to json in OnSave and save it into client's documents folder, then we do the opposite for OnLoad. Hope somebody's going to find this useful. Edited July 22, 2016 by IvanX Link to comment Share on other sites More sharing options...
Joachim Posted July 28, 2016 Share Posted July 28, 2016 On 7/2/2016 at 10:31 PM, Layarion said: Fix the single lined madness by taking pictures of the code instead. i CANNOT read this BS and take your guide seriously. I don't see what's wrong with it, though? Taking pictures of code is even more inconvenient. 1 Link to comment Share on other sites More sharing options...
Layarion Posted August 9, 2016 Share Posted August 9, 2016 On 7/28/2016 at 5:18 AM, Joachim said: I don't see what's wrong with it, though? Taking pictures of code is even more inconvenient. it is very difficult to follow Link to comment Share on other sites More sharing options...
Serpens Posted September 30, 2016 Share Posted September 30, 2016 will link my post, cause it contains some useful information: 1 Link to comment Share on other sites More sharing options...
Tykvesh Posted March 7, 2017 Share Posted March 7, 2017 Does new ListenForEvent overwrites the old one if their trigger event is the same? Link to comment Share on other sites More sharing options...
PanAzej Posted March 7, 2017 Share Posted March 7, 2017 (edited) 44 minutes ago, Tykvesh said: Does new ListenForEvent overwrites the old one if their trigger event is the same? Nope. If you wanted to replace an eventlistener by making a new one, well, it's not really possible. You gotta make some workarounds. Eventlisteners are the most annoying thing you have to work around, tbh. Edited March 7, 2017 by PanAzej 2 Link to comment Share on other sites More sharing options...
Tykvesh Posted March 10, 2017 Share Posted March 10, 2017 (edited) On 08.03.2017 at 2:27 AM, PanAzej said: If you wanted to replace an eventlistener by making a new one, well, it's not really possible. You gotta make some workarounds. Eventlisteners are the most annoying thing you have to work around, tbh. Thanks for reply. Also, is it possible to get list of all possible events? I'm currently interested of event where spider got a leader. EDIT: Ouch. All this time the answer was in front of me. This is PushEvent - what i was looking for. Edited March 12, 2017 by Tykvesh Link to comment Share on other sites More sharing options...
Tykvesh Posted March 22, 2017 Share Posted March 22, 2017 Is there any guides about creating animbanks/builds? I have painted background for my container widget, but I have no idea how to export it into ui_blahblah_0x0.zip file. Link to comment Share on other sites More sharing options...
Lumina Posted April 8, 2017 Share Posted April 8, 2017 It's probably too late to answer, but just in case. You have two ways to create a animbanks/build. Either you are using another file as a template, and in this case you need a tool to change the build name (build renamer), and a tool to export your .png as a .tex file (but in this case, the .tex should be the same size than your template .tex size, or it will not works). Or using spriter (in don't starve mod tool), and create an entire new ui_blahblah.zip, but you'll need to export it to compile it in the right files. Either methods have advantage and inconvenients. Here you could find link to some of the tools. Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now