zazabar Posted December 17, 2016 Share Posted December 17, 2016 (edited) EDIT: Replaced code with updated code. If conversations after this don't make sense, that is why. Hey dere fellow modders! I wrote a new mod recently and I decided to do a write up on it to help others who are still new to modding (like myself) try to navigate through the system. The mod in question isn't too complicated. It adds two pieces of functionality. The first is that it allows 1-5 harvests of a crop from a single seed. What I mean by this is after you harvest the crop, instead of disappearing, it returns to growth level 0 and starts anew until X harvests have been reached. The second bit of functionality is the ability to use the shovel to remove said crop if you don't like what crop is growing for you. So let's get into it. The start: modinfo.lua --- This is going to be where we add the configuration options for the mod to access. There are already guides on how to write the general documentation, so I'm just going to talk about the configuration options themselves. configuration_options = { { name = "YourVariableName", description = "Your Variable Description", default = 4, --A default option out of the list to use. This is referring to the "data" variable and not the "description" variable. options = { { description = "1", data = 1, }, { description = "2", data = 2, }, { description = "3", data = 3, }, { description = "4", data = 4, }, { description = "5", data = 5, }, }, }, } Adding additional options is as simple as adding an additional {}, after the one before the last. In the case of my mod, the entire file looks like this: name = "Multiple Harvest Farms" description = "Allows you to get multiple harvests from a single seed. After picking your crop, the plant will return to 0 growth and start anew until it hits the set number of rotations." author = "zazabar" version = "1.0" forumthread = "" api_version = 10 priority = 1 --This lets the clients know that they need to download the mod before they can join a server that is using it. all_clients_require_mod = true --This let's the game know that this mod doesn't need to be listed in the server's mod listing client_only_mod = false --Let the mod system know that this mod is functional with Don't Starve Together dont_starve_compatible = false reign_of_giants_compatible = false dst_compatible = true --These tags allow the server running this mod to be found with filters from the server listing screen server_filter_tags = {"farm","crop","plant"} icon_atlas = "preview.xml" icon = "preview.tex" configuration_options = { { name = "NumCropRotations", description = "Number of Crop Rotations", default = 4, options = { { description = "1", data = 1, }, { description = "2", data = 2, }, { description = "3", data = 3, }, { description = "4", data = 4, }, { description = "5", data = 5, }, }, }, } In order for your component to get the configuration data from the mod, you'll need to use the GetModConfigData" function, which will pull it based on the name you gave it in the modinfo.lua file. Now for the meat: modmain.lua --- local require = GLOBAL.require GLOBAL.TUNING.NUMCROPROTATIONS = GetModConfigData("NumCropRotations") local function shoveled(inst, worker) inst.components.crop.matured = false inst.components.crop.growthpercent = 0 inst.components.crop.product_prefab = nil if inst.components.crop.grower ~= nil and inst.components.crop.grower:IsValid() and inst.components.crop.grower.components.grower ~= nil then inst.components.crop.grower.components.grower:RemoveCrop(inst) end inst.components.crop.grower = nil end local function AddWorkable(grower, plant) if grower.components.inspectable.nameoverride == "FARMPLOT" then plant:AddComponent("workable") plant.components.workable:SetWorkAction(GLOBAL.ACTIONS.DIG) plant.components.workable:SetWorkLeft(1) plant.components.workable:SetOnFinishCallback(shoveled) end end local function RemoveWorkable(grower, plant) if grower.components.inspectable.nameoverride == "FARMPLOT" then plant.inst:RemoveComponent("workable") end end AddComponentPostInit("grower", function(self) local oldPlantItem = self.PlantItem function self:PlantItem(item) local functionBool = false if self.inst.components.inspectable.nameoverride == "FARMPLOT" and item.components.plantable ~= nil then functionBool = oldPlantItem(self, item) self.curRotations = 0 return functionBool else return oldPlantItem(self, item) end end local oldOnSave = self.OnSave function self:OnSave() local mainData = oldOnSave(self) if self.inst.components.inspectable.nameoverride == "FARMPLOT" and self.curRotations ~= nil then mainData.cropTimerCurRotations = self.curRotations else mainData.cropTimerCurRotations = 0 end return mainData end local oldOnLoad = self.OnLoad function self:OnLoad(data, newents) oldOnLoad(self, data, newents) if self.inst.components.inspectable.nameoverride == "FARMPLOT" then self.curRotations = data.cropTimerCurRotations end end end) AddComponentPostInit("crop", function(self) local oldStartGrowing = self.StartGrowing function self:StartGrowing(prod, grow_time, grower, percent) oldStartGrowing(self, prod, grow_time, grower, percent) AddWorkable(grower, self.inst) end local oldHarvest = self.Harvest function self:Harvest(harvester) if self.grower.components.inspectable.nameoverride ~= "FARMPLOT" then return oldHarvest(self, harvester) end local tempItemProduct = self.product_prefab local tempCurRotations = self.grower.components.grower.curRotations + 1 local tempGrower = self.grower.components.grower local tempBoolean, tempPostProduct = oldHarvest(self, harvester) if tempCurRotations < GLOBAL.TUNING.NUMCROPROTATIONS then local tempItemPrefab = GLOBAL.SpawnPrefab("seeds") tempItemPrefab.components.plantable.product = tempItemProduct tempGrower.PlantItem(tempGrower, tempItemPrefab) tempGrower.curRotations = tempCurRotations end return tempBoolean, tempPostProduct end local oldResume = self.Resume function self:Resume() oldResume(self) AddWorkable(self.inst.components.crop.grower, self.inst) end end) There's a lot here so let's step through it. First, we need global data so we do a local require which specifies the GLOBAL data. Next, we assign our variable to the GLOBAL.TUNING area so that it can be modified by outside processes if necessary and so we don't have to make multiple calls to find it. Function shoveled - This function is what decides what happens to our crop when we use the shovel on it. It's required to have a callback function whenever you have something workable. Functions AddWorkable and RemoveWorkable - These two functions are what we use to add and remove the workable status from our crop. We want to make sure that we don't apply this to non-farm crops, so we do a quick check to make sure they are a part of that. Grower PostInit Function PlantItem - Once again, we want to make sure this only applies to farms. If it doesn't, just return the old function. Whenever possible we want to use the old functions for maximum compatibility, so we run the old function then add our extra variable before returning. Grower PostInit Function OnSave and OnLoad - We want to keep our data for the farms when we close the game or reopen it, so we need to have these two functions. Once again, call old functions whenever possible and then add our data before returning. Make sure the main format of the data doesn't change or the game might crash. We have the addition of the workable part in the crop portion later. Crop PostInit Function StartGrowing - Very simple, call the old function then add our workable. Crop PostInit Function Harvest - This function was slightly trickier. We want to run the old function, but when we do so, we inadvertently clear out all of the information about the crop from the grower. So to get around this, we need to get a couple of variables first then run the original function. After, we generate a new seed with the same product to throw back into the farm. Since the PlantItem function cleans up the seed prefab we generated, we don't have to worry about doing anything with it. Crop PostInit Function Resume - This function just adds our workable function to the crop. The reason it is here and not in the grower function is because it's actually troublesome to pull crops directly from the farmplot. ----------- And that's everything. I hope it helps someone! Edited December 19, 2016 by zazabar Posting current code. Link to comment Share on other sites More sharing options...
Aquaterion Posted December 17, 2016 Share Posted December 17, 2016 a few things if you don't mind me to point out: You don't need a new AddComponentPostInit for each function you're changing, you can do them all in 1: AddComponentPostInit("grower", function(self) function self:Function1() end function self:Function2() end end) You declared variables with the old functions, but you didn't actually use them I'll take OnLoad as an example here: Your code: local old = self.OnLoad function self:OnLoad(data, newents) if data.crops ~= nil then for k, v in pairs(data.crops) do self.isempty = false self.inst:AddTag("NOCLICK") local child = GLOBAL.SpawnSaveRecord(v, newents) if child ~= nil then child.components.crop.grower = self.inst child.Transform:SetPosition(v.x or 0, v.y or 0, v.z or 0) child.persists = false self.crops[child] = true AddWorkable(self, child) child.components.crop:Resume() end end end self.cycles_left = data.cycles_left or self.cycles_left if self.setfertility ~= nil then self.setfertility(self.inst, self:GetFertilePercent()) end if data.cropTimerNumRotations ~= nil then self.inst:AddComponent("croptimer") self.inst.components.croptimer.numRotations = data.cropTimerNumRotations self.inst.components.croptimer.curRotations = data.cropTimerCurRotations end end And what you would ideally do: local old = self.OnLoad function self:OnLoad(data, newents) old(data, newents)--RUNS THE OLD OnLoad that we named 'old', so we don't have to rewrite it --and then runs our new code; if data.cropTimerNumRotations ~= nil then self.inst:AddComponent("croptimer") self.inst.components.croptimer.numRotations = data.cropTimerNumRotations self.inst.components.croptimer.curRotations = data.cropTimerCurRotations end end Of course this is situational, as it depends when you want to run your new code, if its before or after the existing code. If it was in the middle, then yea you'd probably have to overwrite the whole function. Link to comment Share on other sites More sharing options...
SrJardel Posted December 17, 2016 Share Posted December 17, 2016 Thank you guys. Content like this + reading through the game code + "Programming Lua" book+ patience is what help a clueless Lua user like me to achieve most of my ideas, even with the lack of decent internet connection on my end to execute real time research while trying to code. Thanks again. Link to comment Share on other sites More sharing options...
Serpens Posted December 17, 2016 Share Posted December 17, 2016 I like the idea I use a mod which gives you 1-3 harvests at once when harvesting. But making every single harvest need to grow again, is a nice alternative Link to comment Share on other sites More sharing options...
zazabar Posted December 17, 2016 Author Share Posted December 17, 2016 50 minutes ago, Aquaterion said: a few things if you don't mind me to point out: You don't need a new AddComponentPostInit for each function you're changing, you can do them all in 1: AddComponentPostInit("grower", function(self) function self:Function1() end function self:Function2() end end) You declared variables with the old functions, but you didn't actually use them I'll take OnLoad as an example here: Your code: local old = self.OnLoad function self:OnLoad(data, newents) if data.crops ~= nil then for k, v in pairs(data.crops) do self.isempty = false self.inst:AddTag("NOCLICK") local child = GLOBAL.SpawnSaveRecord(v, newents) if child ~= nil then child.components.crop.grower = self.inst child.Transform:SetPosition(v.x or 0, v.y or 0, v.z or 0) child.persists = false self.crops[child] = true AddWorkable(self, child) child.components.crop:Resume() end end end self.cycles_left = data.cycles_left or self.cycles_left if self.setfertility ~= nil then self.setfertility(self.inst, self:GetFertilePercent()) end if data.cropTimerNumRotations ~= nil then self.inst:AddComponent("croptimer") self.inst.components.croptimer.numRotations = data.cropTimerNumRotations self.inst.components.croptimer.curRotations = data.cropTimerCurRotations end end And what you would ideally do: local old = self.OnLoad function self:OnLoad(data, newents) old(data, newents)--RUNS THE OLD OnLoad that we named 'old', so we don't have to rewrite it --and then runs our new code; if data.cropTimerNumRotations ~= nil then self.inst:AddComponent("croptimer") self.inst.components.croptimer.numRotations = data.cropTimerNumRotations self.inst.components.croptimer.curRotations = data.cropTimerCurRotations end end Of course this is situational, as it depends when you want to run your new code, if its before or after the existing code. If it was in the middle, then yea you'd probably have to overwrite the whole function. Thanks for the information! Wasn't aware you could do multiple declarations in one PostInit. That is definitely good to know. For the functions, yeah, in this case I couldn't just run them before or after. The code had to be inserted in specific points so I had to copy over the old code. I added the local old declarations at the start and forgot to remove them later. Link to comment Share on other sites More sharing options...
Kzisor Posted December 17, 2016 Share Posted December 17, 2016 A few pointers from a veteran modder. 4 hours ago, zazabar said: And modifying the base classes is not a preferred method. This is inaccurate; more accurately "it's frowned upon to override the original files with modified files in your mod". By overriding the files you are creating a scenario where if the original files are updated by Klei then your files will be out of date which means they will most likely not work. It's preferred to use the API to modify any and all entities, components, etc. before trying to make your own component. What you've done could have easily been done in the grower component without the need to add a secondary component. Additionally, it's better to add your configuration settings to the GLOBAL.TUNING table so you don't need to use the "KnownModIndex:GetModActualName" function. This way you have a centralized location in order to get the data, rather than calling a process intensive function such as the KnownModIndex functions. Inside your own modmain.lua file you do not need to call those expensive functions because you have direct access to the configuration settings. A few things to consider: Adding new components for basic functionality adds a lot of additional overhead which isn't needed. If you are modifying something already in game, do it through one of the already available components. When working with configurations, always put them in the GLOBAL.TUNING table. This prevents additional processing cycles wasted to call a function which isn't required during game-play. As Aquaterion pointed out, ALWAYS call previously used functions when override functions. This way if another mod alters the component your mod won't break theirs if it loads last. This is non-negotiable, you MUST do this if you're using the API. If you don't know how to make your mod work by doing it, rework your code. Hopefully this didn't come across offensively; it's simply we don't need more broken mods cluttering the workshop. Link to comment Share on other sites More sharing options...
Aquaterion Posted December 17, 2016 Share Posted December 17, 2016 29 minutes ago, Kzisor said: As Aquaterion pointed out, ALWAYS call previously used functions when override functions. This way if another mod alters the component your mod won't break theirs if it loads last. This is non-negotiable, you MUST do this if you're using the API. If you don't know how to make your mod work by doing it, rework your code. How would you go on about following the api when you want to change some code in a function which is in the middle of the function? I'll use the fishable's HookFish function as an example again; function Fishable:HookFish() local fishprefab = GetRandomKey(self.fish) local fish = SpawnPrefab(fishprefab) if fish ~= nil then self.hookedfish[fish] = fish self.inst:AddChild(fish) fish.entity:Hide() fish.persists = false if fish.DynamicShadow ~= nil then fish.DynamicShadow:Enable(false) end if fish.Physics ~= nil then fish.Physics:SetActive(false) end if self.fishleft > 0 then self.fishleft = self.fishleft - 1 end end return fish end Say I want to change the fishprefab variable, how would i go about it without actually redoing the whole function? Link to comment Share on other sites More sharing options...
Kzisor Posted December 17, 2016 Share Posted December 17, 2016 (edited) 2 minutes ago, Aquaterion said: How would you go on about following the api when you want to change some code in a function which is in the middle of the function? I'll use the fishable's HookFish function as an example again; function Fishable:HookFish() local fishprefab = GetRandomKey(self.fish) local fish = SpawnPrefab(fishprefab) if fish ~= nil then self.hookedfish[fish] = fish self.inst:AddChild(fish) fish.entity:Hide() fish.persists = false if fish.DynamicShadow ~= nil then fish.DynamicShadow:Enable(false) end if fish.Physics ~= nil then fish.Physics:SetActive(false) end if self.fishleft > 0 then self.fishleft = self.fishleft - 1 end end return fish end Say I want to change the fishprefab variable, how would i go about it without actually redoing the whole function? Modify the self.fish variable. AddComponentPostInit('fishable', function(inst) local _HookFish = inst.HookFish function inst:HookFish() self.fish = {} return _HookFish(self) end end) Edited December 17, 2016 by Kzisor Added code... Link to comment Share on other sites More sharing options...
Serpens Posted December 17, 2016 Share Posted December 17, 2016 38 minutes ago, Kzisor said: When working with configurations, always put them in the GLOBAL.TUNING table. This prevents additional processing cycles wasted to call a function which isn't required during game-play Should it be always GLOBAL.TUNING? Or would it also be okay to make GLOBAL.MyModVariableXY Link to comment Share on other sites More sharing options...
Aquaterion Posted December 17, 2016 Share Posted December 17, 2016 2 minutes ago, Kzisor said: Modify the self.fish variable. huh.. could you give an example? Link to comment Share on other sites More sharing options...
Kzisor Posted December 17, 2016 Share Posted December 17, 2016 Just now, Serpens said: Should it be always GLOBAL.TUNING? Or would it also be okay to make GLOBAL.MyModVariableXY If it's a 'tuning' variable; it should be put in the GLOBAL.TUNING table; period. That is the central location where all 'settings' variables are placed. Inside the GLOBAL.TUNING table; you can easily add a new table for your specific mod if you wanted to do that. 1 minute ago, Aquaterion said: huh.. could you give an example? I edited the original reply and added code. Alternatively you could simply modify the prefab which has the 'fishable' component and modify the fishprefab that way. Link to comment Share on other sites More sharing options...
Aquaterion Posted December 17, 2016 Share Posted December 17, 2016 7 minutes ago, Kzisor said: edited the original reply and added code. Alternatively you could simply modify the prefab which has the 'fishable' component and modify the fishprefab that way. I don't think you understood what I exactly wanted, but I did manage to sort of implement your example in a way. Atm I can't test it out but i believe that it should work, so thank you for that knowledge. P.S where dat autocompiler fix tho xD Link to comment Share on other sites More sharing options...
Kzisor Posted December 17, 2016 Share Posted December 17, 2016 (edited) 8 minutes ago, Aquaterion said: I don't think you understood what I exactly wanted, but I did manage to sort of implement your example in a way. Atm I can't test it out but i believe that it should work, so thank you for that knowledge. I imagine you're wanting to change the fish prefab which people get from things like ponds, etc. This can be achieved in many manners, in fact the one I posted isn't the correct way; it follows suit of what your question asked pertaining to my original comment. The correct way is the following: AddPrefabPostInit('pond', function(inst) if not GLOBAL.TheWorld.ismastersim then return inst end inst.components.fishable.fish = {} inst.components.fishable:SetFish('tropical_fish') return inst end) AddPrefabPostInit('pond_cave', function(inst) if not GLOBAL.TheWorld.ismastersim then return inst end inst.components.fishable.fish = {} inst.components.fishable:SetFish('tropical_fish') return inst end) AddPrefabPostInit('pond_marsh', function(inst) if not GLOBAL.TheWorld.ismastersim then return inst end inst.components.fishable.fish = {} inst.components.fishable:SetFish('tropical_fish') return inst end) Edited December 17, 2016 by Kzisor Fixed code to remove the original fish added to ponds. Link to comment Share on other sites More sharing options...
SrJardel Posted December 17, 2016 Share Posted December 17, 2016 1 hour ago, Kzisor said: Spoiler A few pointers from a veteran modder... we don't need more broken mods cluttering the workshop. Yes, please... Link to comment Share on other sites More sharing options...
zazabar Posted December 17, 2016 Author Share Posted December 17, 2016 39 minutes ago, Kzisor said: I imagine you're wanting to change the fish prefab which people get from things like ponds, etc. This can be achieved in many manners, in fact the one I posted isn't the correct way; it follows suit of what your question asked pertaining to my original comment. The correct way is the following: AddPrefabPostInit('pond', function(inst) if not GLOBAL.TheWorld.ismastersim then return inst end inst.components.fishable.fish = {} inst.components.fishable:SetFish('tropical_fish') return inst end) AddPrefabPostInit('pond_cave', function(inst) if not GLOBAL.TheWorld.ismastersim then return inst end inst.components.fishable.fish = {} inst.components.fishable:SetFish('tropical_fish') return inst end) AddPrefabPostInit('pond_marsh', function(inst) if not GLOBAL.TheWorld.ismastersim then return inst end inst.components.fishable.fish = {} inst.components.fishable:SetFish('tropical_fish') return inst end) Quick question. Trying to redo some of the code but I'm running into a weird crash that I'm having trouble solving. AddComponentPostInit("grower", function(self) local _old = self.PlantItem function self:PlantItem(item) return _old(item) end end) This is causing the program to crash, as it states that item is undefined. This happens when I try to plant a seed. I removed everything else and left just this, and it still crashes. "Attempt to index local 'item' (a nil value)" Am I missing an include or something? Link to comment Share on other sites More sharing options...
Kzisor Posted December 17, 2016 Share Posted December 17, 2016 (edited) 1 minute ago, zazabar said: Quick question. Trying to redo some of the code but I'm running into a weird crash that I'm having trouble solving. AddComponentPostInit("grower", function(self) local _old = self.PlantItem function self:PlantItem(item) return _old(item) end end) This is causing the program to crash, as it states that item is undefined. This happens when I try to plant a seed. I removed everything else and left just this, and it still crashes. "Attempt to index local 'item' (a nil value)" Am I missing an include or something? You have to push the 'self' variable as the first parameter when calling old functions. Don't worry, you don't need to set it, it is automatically set. Edited December 17, 2016 by Kzisor Link to comment Share on other sites More sharing options...
Aquaterion Posted December 17, 2016 Share Posted December 17, 2016 45 minutes ago, Kzisor said: I imagine you're wanting to change the fish prefab which people get from things like ponds, etc. This can be achieved in many manners, in fact the one I posted isn't the correct way; it follows suit of what your question asked pertaining to my original comment. The correct way is the following: no no that I know how to do, I basically wanted to choose a fish from self.fish depending on a different way rather than the "GetRandomKey" function. But I tested it and it worked! ^^ again, thank you for this knowledge. I'm sure it will be helpful. Link to comment Share on other sites More sharing options...
zazabar Posted December 17, 2016 Author Share Posted December 17, 2016 1 hour ago, Kzisor said: You have to push the 'self' variable as the first parameter when calling old functions. Don't worry, you don't need to set it, it is automatically set. Thanks! I'm a developer in the real world, so hearing stuff from other developers is always nice as well when it comes to stuff in other applications I don't know. Link to comment Share on other sites More sharing options...
zazabar Posted December 18, 2016 Author Share Posted December 18, 2016 4 hours ago, Kzisor said: So I revamped the entire thing based on your feedback. I got rid of the extra component and included all of the main primary functions without editing them. If you could look over this and see if you can find any other major flaws, it would be much appreciated! local require = GLOBAL.require GLOBAL.TUNING.NUMCROPROTATIONS = GetModConfigData("NumCropRotations") local function shoveled(inst, worker) inst.components.crop.matured = false inst.components.crop.growthpercent = 0 inst.components.crop.product_prefab = nil if inst.components.crop.grower ~= nil and inst.components.crop.grower:IsValid() and inst.components.crop.grower.components.grower ~= nil then inst.components.crop.grower.components.grower:RemoveCrop(inst) end inst.components.crop.grower = nil end local function AddWorkable(grower, plant) if grower.components.inspectable.nameoverride == "FARMPLOT" then plant:AddComponent("workable") plant.components.workable:SetWorkAction(GLOBAL.ACTIONS.DIG) plant.components.workable:SetWorkLeft(1) plant.components.workable:SetOnFinishCallback(shoveled) end end local function RemoveWorkable(grower, plant) if grower.components.inspectable.nameoverride == "FARMPLOT" then plant.inst:RemoveComponent("workable") end end AddComponentPostInit("grower", function(self) local oldPlantItem = self.PlantItem function self:PlantItem(item) local functionBool = false if self.inst.components.inspectable.nameoverride == "FARMPLOT" and item.components.plantable ~= nil then functionBool = oldPlantItem(self, item) self.curRotations = 0 return functionBool else return oldPlantItem(self, item) end end local oldOnSave = self.OnSave function self:OnSave() local mainData = oldOnSave(self) if self.inst.components.inspectable.nameoverride == "FARMPLOT" and self.curRotations ~= nil then mainData.cropTimerCurRotations = self.curRotations else mainData.cropTimerCurRotations = 0 end return mainData end local oldOnLoad = self.OnLoad function self:OnLoad(data, newents) oldOnLoad(self, data, newents) if self.inst.components.inspectable.nameoverride == "FARMPLOT" then self.curRotations = data.cropTimerCurRotations end end end) AddComponentPostInit("crop", function(self) local oldStartGrowing = self.StartGrowing function self:StartGrowing(prod, grow_time, grower, percent) oldStartGrowing(self, prod, grow_time, grower, percent) if grower.components.inspectable.nameoverride == "FARMPLOT" then AddWorkable(grower, self.inst) end end local oldHarvest = self.Harvest function self:Harvest(harvester) if self.grower.components.inspectable.nameoverride ~= "FARMPLOT" then return oldHarvest(self, harvester) end local tempItemProduct = self.product_prefab local tempCurRotations = self.grower.components.grower.curRotations + 1 local tempGrower = self.grower.components.grower local tempBoolean, tempPostProduct = oldHarvest(self, harvester) if tempCurRotations < GLOBAL.TUNING.NUMCROPROTATIONS then local tempItemPrefab = GLOBAL.SpawnPrefab("seeds") tempItemPrefab.components.plantable.product = tempItemProduct tempGrower.PlantItem(tempGrower, tempItemPrefab) tempGrower.curRotations = tempCurRotations end return tempBoolean, tempPostProduct end local oldResume = self.Resume function self:Resume() oldResume(self) AddWorkable(self.inst.components.crop.grower, self.inst) end end) Link to comment Share on other sites More sharing options...
Kzisor Posted December 18, 2016 Share Posted December 18, 2016 42 minutes ago, zazabar said: So I revamped the entire thing based on your feedback. I got rid of the extra component and included all of the main primary functions without editing them. If you could look over this and see if you can find any other major flaws, it would be much appreciated! This is a very elegant solution, I would say that this solution is the most flexible that could be programmed. A few notes about your code so others can learn from it. The code uses the proper API, this means it won't break if Klei changes things. It should only break if they remove the function names. The new functions are calling the old functions so separate mods which modify the same entity/prefabs/components will still work. You're using the GLOBAL.TUNING which means separate mods may change your settings from their mod if they wish to have it set a specific way. This ultimately means we shouldn't see duplicates of your mod on the workshop. The biggest reason I advocate to use GLOBAL.TUNING for settings is so people who want to have "modifications" for certain mods can do so by creating a separate mod and uploading it. Because GLOBAL.TUNING only runs on the server, their mod can be Hidden or Friends Only which prevents it from being displayed on the workshop; which ultimately reduces clutter on the workshop. Link to comment Share on other sites More sharing options...
SrJardel Posted December 19, 2016 Share Posted December 19, 2016 (edited) Since you guys are into it, I assume it would mean no harm to ask a simple question. How could I get **.AnimState:function() to take effect on an equipped item, or any item in general? I tried ThePlayer.AnimState and the command took effect on my character, so I assume there is a way to do the same on an item. I looked at some scripts and it most likely says "inst.AnimState", but I can't figure out what "inst" means, since there is no "inst = something" like other stuff. Sorry for the messy aproach, I am just curious while I try to learn a bit here and there. Edited December 19, 2016 by SrJardel Typo Link to comment Share on other sites More sharing options...
Kzisor Posted December 19, 2016 Share Posted December 19, 2016 19 minutes ago, SrJardel said: Since you guys are into it, I assume it would mean no harm to ask a simple question. How could I get **.AnimState:function() to take effect on an equipped item, or any item in general? I tried ThePlayer.AnimState and the command took effect on my character, so I assume there is a way to do the same on an item. I looked at some scripts and it most likely says "inst.AnimState", but I can't figure out what "inst" means, since there is no "inst = something" like other stuff. Sorry for the messy aproach, I am just curious while I try to learn a bit here and there. inst is the instance of the item/entity. It's usually passed through, but is only created in the main function in the prefab file of the item/entity. You should be able to Ctrl + F, inst = CreateEntity() and it will show you where it is located in the file. 1 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