Aquaterion Posted March 5, 2016 Share Posted March 5, 2016 As title stats, I'm finding this to be pretty much impossible to figure out.. did this to add the stat and image GLOBAL.CHARACTER_INGREDIENT["CUSTOMSTAT"] = "decrease_customstat" but sadly still gives the following error: WARNING! Could not find region 'FROMNUM' from atlas 'FROMNUM'. Is the region specified in the atlas? Looking for default texture '' from atlas 'FROMNUM'. images/inventoryimages.xml Usually I just add the atlasname but I'm not sure how I would go about doing this for stats. Now while I had this issue, I decided to explore where the default stats are being used, and in builder_replica I found out that it has an if for every stat, which I think, means that it doesn't support custom stats, unless I edit base files? Link to comment Share on other sites More sharing options...
RetroMike Posted March 5, 2016 Share Posted March 5, 2016 I hope someone is able to help you with this. I'd love to have a "Dream Energy" stat for my character that is used for crafting. Link to comment Share on other sites More sharing options...
Kzisor Posted March 6, 2016 Share Posted March 6, 2016 (edited) This is very easy to set up, you have to overload a few function in order to do it though. Here is a simple example you will have to modify it as needed for your own usage. EXAMPLE: Texture/Atlas Files: modmain.lua code: CHARACTER_INGREDIENT["LEVEL"] = "decrease_level" local recipe = AddRecipe( "soul_essence", { Ingredient( CHARACTER_INGREDIENT.LEVEL, 5, "images/decrease_level.xml") }, RECIPETABS.MAGIC, TECH.NONE, nil, nil, nil, nil, "wortox", "images/inventoryimages/soul_essence.xml", "soul_essence.tex" ) local builder_replica = GLOBAL.require("components/builder_replica") local function BuilderReplicaPostInit( inst ) local _RemoveIngredients = inst.RemoveIngredients function inst:RemoveIngredients( ingredients, recname ) local recipe = AllRecipes[recname] if recipe then for k,v in pairs(recipe.character_ingredients) do if v.type == CHARACTER_INGREDIENT.LEVEL then self.inst.replica.leveler:SetLevel( TUNING.WORTOX.LEVEL_SYSTEM, self.inst.components.leveler:GetLevel( TUNING.WORTOX.LEVEL_SYSTEM ) - v.amount ) end end end _RemoveIngredients( self, ingredients, recname ) end local _HasCharacterIngredient = inst.HasCharacterIngredient function inst:HasCharacterIngredient( ingredient ) local _ret = _HasCharacterIngredient( self, ingredient ) if not _ret then if ingredient.type == CHARACTER_INGREDIENT.LEVEL then if ingredient.level_tag ~= nil and self.inst.replica.leveler ~= nil then print( ingredient.level_tag ) return self.inst.replica.leveler:GetLevel( TUNING.WORTOX.LEVEL_SYSTEM ) >= ingredient.amount end end end return _ret end end BuilderReplicaPostInit( builder_replica ) Note: Take notice how I pushed an atlas file as the 3rd parameter of the Ingredient class. The atlas file and texture file must be named the same as you put in the custom character ingredient. character prefab.lua master_postinit function: local _RemoveIngredients = inst.components.builder.RemoveIngredients function inst.components.builder:RemoveIngredients( ingredients, recname ) local recipe = AllRecipes[recname] if recipe then for k,v in pairs(recipe.character_ingredients) do if v.type == CHARACTER_INGREDIENT.LEVEL then self.inst.components.leveler:SetLevel( TUNING.WORTOX.LEVEL_SYSTEM, self.inst.components.leveler:GetLevel( TUNING.WORTOX.LEVEL_SYSTEM ) - v.amount ) end end end _RemoveIngredients( self, ingredients, recname ) end local _HasCharacterIngredient = inst.components.builder.HasCharacterIngredient function inst.components.builder:HasCharacterIngredient( ingredient ) local _ret = _HasCharacterIngredient( self, ingredient ) if not _ret then if ingredient.type == CHARACTER_INGREDIENT.LEVEL then if self.inst.components.leveler ~= nil then return self.inst.components.leveler:GetLevel( TUNING.WORTOX.LEVEL_SYSTEM ) >= ingredient.amount end end end return _ret end Note: Modify the cost above as needed and put it at the very bottom of your master_postinit function, this only runs on the server. Conclusion: This can easily be modified to work with any custom stat, you should make a new icon for the stat unlike I, which was used the essence texture as the decrease_level texture file. Not ENOUGH Ingredients GOT INGREDIENTS Edited March 7, 2016 by Kzisor Updated the code to work with client side. Link to comment Share on other sites More sharing options...
Aquaterion Posted March 6, 2016 Author Share Posted March 6, 2016 Awesome, didn't know you can put the ingredient atlas as the 3rd parameter, since recipes that required my modded items were causing issue this fixes it too. Since the stat I made is a stat I give to all characters, I had to figure out where to put that code, which was in the same function in modmain that adds the customstat component to every character. I did have to change self.inst to inst in the functions but other than that so far its working perfectly, all I gotta do now is test it to make sure it works with other people online as I haven't tested anything yet. Thanks for your help ^^ Link to comment Share on other sites More sharing options...
Aquaterion Posted March 6, 2016 Author Share Posted March 6, 2016 (edited) Ok so I got my friend to try it out and he couldn't even join without crashing I was using this to give the custom stat and its also where i put this ingredient thing: for k,prefabname in ipairs(GLOBAL.DST_CHARACTERLIST) do AddPrefabPostInit(prefabname, AddStat) end the stat and character ingriedient were in AddStat but when ever he tries to join he gets this error: error calling PrefabPostInit: webber in mod workshop-637153586 (Mod): [string "../mods/workshop-637153586/modmain.lua"]:152: attempt to index field 'builder' (a nil value) LUA ERROR stack traceback: ../mods/workshop-637153586/modmain.lua(152,1) =(tail call) ? =[C] in function 'xpcall' scripts/mods.lua(123,1) in function 'mod' scripts/mainfunctions.lua(157,1) line 152 is this: local _RemoveIngredients = inst.components.builder.RemoveIngredients So to fix this, I added if GLOBAL.TheWorld.ismastersim to your code, but then later realised that this makes the recipes only work for the host So how am I to go about making these builder functions available to everyone? Edited March 6, 2016 by Aquaterion Link to comment Share on other sites More sharing options...
Kzisor Posted March 6, 2016 Share Posted March 6, 2016 (edited) 8 hours ago, Aquaterion said: So how am I to go about making these builder functions available to everyone? Well, I specifically wrote how to handle it from a custom character perspective because most mods do not add new stats to every character. In order to add a new custom character ingredient for all characters you must use the components code for the server and then use replica code for the client side (note: you simply replace components with replica and it should work for clients, but you must have both sets of code for it to work across the board). Edited March 7, 2016 by Kzisor Removed code as it did not work as intended. Link to comment Share on other sites More sharing options...
Aquaterion Posted March 6, 2016 Author Share Posted March 6, 2016 (edited) Damn I thought it was gonna be that easy.. error calling PrefabPostInit: wilson in mod workshop-637153586 (Mod): [string "../mods/workshop-637153586/modmain.lua"]:153: attempt to index field 'builder' (a nil value) LUA ERROR stack traceback: ../mods/workshop-637153586/modmain.lua(153,1) =(tail call) ? =[C] in function 'xpcall' scripts/mods.lua(123,1) in function 'mod' scripts/mainfunctions.lua(157,1) Same error I was having at the start, the 1 I had to do ismastersim to fix --- for k,prefabname in ipairs(GLOBAL.DST_CHARACTERLIST) do AddPrefabPostInit(prefabname, AddStat) end is this even a good way to put the code on all characters? Edited March 7, 2016 by Aquaterion Link to comment Share on other sites More sharing options...
Kzisor Posted March 7, 2016 Share Posted March 7, 2016 (edited) 5 hours ago, Aquaterion said: is this even a good way to put the code on all characters? To answer this question, no that is a bad way of handling that. You should use 'AddPlayerPostInit' it accepts 1 argument which is a function. To answer how to make this work with clients, use the following code and alter it as needed. local builder_replica = GLOBAL.require("components/builder_replica") local function BuilderReplicaPostInit( inst ) local _RemoveIngredients = inst.RemoveIngredients function inst:RemoveIngredients( ingredients, recname ) local recipe = AllRecipes[recname] if recipe then for k,v in pairs(recipe.character_ingredients) do if v.type == CHARACTER_INGREDIENT.LEVEL then self.inst.replica.leveler:SetLevel( TUNING.WORTOX.LEVEL_SYSTEM, self.inst.components.leveler:GetLevel( TUNING.WORTOX.LEVEL_SYSTEM ) - v.amount ) end end end _RemoveIngredients( self, ingredients, recname ) end local _HasCharacterIngredient = inst.HasCharacterIngredient function inst:HasCharacterIngredient( ingredient ) local _ret = _HasCharacterIngredient( self, ingredient ) if not _ret then if ingredient.type == CHARACTER_INGREDIENT.LEVEL then if ingredient.level_tag ~= nil and self.inst.replica.leveler ~= nil then print( ingredient.level_tag ) return self.inst.replica.leveler:GetLevel( TUNING.WORTOX.LEVEL_SYSTEM ) >= ingredient.amount end end end return _ret end end BuilderReplicaPostInit( builder_replica ) Edit: I've updated the original code I posted so if you are viewing this post after 03/06/2016 use the code in the original post I made as it will work perfectly. Edited March 7, 2016 by Kzisor Added a tidbit of information about an update on the original post I made. Link to comment Share on other sites More sharing options...
Aquaterion Posted March 7, 2016 Author Share Posted March 7, 2016 Do I remove everything you told me to put before or just the one with the replicas?I can't test it right now as I'm bout to go to bed. Thanks for the help so far ^^ Link to comment Share on other sites More sharing options...
Kzisor Posted March 7, 2016 Share Posted March 7, 2016 Just now, Aquaterion said: Do I remove everything you told me to put before or just the one with the replicas?I can't test it right now as I'm bout to go to bed. Thanks for the help so far ^^ Delete everything you've added thus far and use the code from the original post I made. Link to comment Share on other sites More sharing options...
Aquaterion Posted March 7, 2016 Author Share Posted March 7, 2016 (edited) 23 hours ago, Kzisor said: Delete everything you've added thus far and use the code from the original post I made. I haven't been able to try it yet as the people I was testing with are both offline, but just to be clear, first put the new "replica" code, then the old "component" code right? Edited March 8, 2016 by Aquaterion Link to comment Share on other sites More sharing options...
Aquaterion Posted March 8, 2016 Author Share Posted March 8, 2016 Just tested it out, still other clients can't use the stat as a recipe, btw, their stat meters are also not working(this was happening before, i just wanted to point it out), but the stat should be working. If you want I can send you the files, maybe i've done something wrong Link to comment Share on other sites More sharing options...
Kzisor Posted March 8, 2016 Share Posted March 8, 2016 12 minutes ago, Aquaterion said: Just tested it out, still other clients can't use the stat as a recipe, btw, their stat meters are also not working(this was happening before, i just wanted to point it out), but the stat should be working. If you want I can send you the files, maybe i've done something wrong If it's not working on your end then you've did something in correct and you will need to debug it on your end. The code supplied works effectively across both my computers. Link to comment Share on other sites More sharing options...
Aquaterion Posted March 8, 2016 Author Share Posted March 8, 2016 (edited) 54 minutes ago, Kzisor said: If it's not working on your end then you've did something in correct and you will need to debug it on your end. The code supplied works effectively across both my computers. Hmm Maybe the issue is with using self.inst or inst, at first changing self.inst to inst helped, atleast in the host one, but this 1, didn't: Spoiler [string "../mods/workshop-637153586/modmain.lua"]:197: attempt to index field 'replica' (a nil value) LUA ERROR stack traceback: ../mods/workshop-637153586/modmain.lua:197 in (upvalue) _HasCharacterIngredient (Lua) <193-204> self = classified = 100745 - player_classified (valid:true) ondetachclassified = function - scripts/components/builder_replica.lua:28 inst = 100037 - wilson (valid:true) ingredient = table: 238DACC8 _ret = false ../mods/workshop-637153586/modmain.lua:194 in (method) HasCharacterIngredient (Lua) <193-204> self = classified = 100745 - player_classified (valid:true) ondetachclassified = function - scripts/components/builder_replica.lua:28 inst = 100037 - wilson (valid:true) ingredient = table: 238DACC8 scripts/components/builder_replica.lua:228 in (method) CanBuild (Lua) <212-236> self = classified = 100745 - player_classified (valid:true) ondetachclassified = function - scripts/components/builder_replica.lua:28 inst = 100037 - wilson (valid:true) recipename = rasengan recipe = table: 238DB768 i = 1 And this is what I have in modmain.lua Spoiler local function GiveStat(inst) if inst.components.stat == nil then inst:AddComponent("stat") inst.components.stat:StartCharge(1, 3) AddClassPostConstruct("widgets/controls", AddStatIndicator) local builder_replica = GLOBAL.require("components/builder_replica") local function BuilderReplicaPostInit( inst ) local _RemoveIngredients = inst.RemoveIngredients function inst:RemoveIngredients( ingredients, recname ) local recipe = AllRecipes[recname] if recipe then for k,v in pairs(recipe.character_ingredients) do if v.type == CHAR_ING.STAT then inst.components.stat:UseAmount(v.amount) end end end _RemoveIngredients( self, ingredients, recname ) end local _HasCharacterIngredient = inst.HasCharacterIngredient function inst:HasCharacterIngredient( ingredient ) local _ret = _HasCharacterIngredient( self, ingredient ) if not _ret then if ingredient.type == CHAR_ING.STAT then if inst.replica.stat~= nil then return inst.replica.stat:GetCurrent() >= ingredient.amount end end end return _ret end end BuilderReplicaPostInit( builder_replica ) Maybe I'm doing the stat_replica.lua wrong? Honestly I didn't have 1 before you mentioned it, as I didn't know what its used for. Edited March 8, 2016 by Aquaterion Link to comment Share on other sites More sharing options...
Kzisor Posted March 8, 2016 Share Posted March 8, 2016 47 minutes ago, Aquaterion said: Maybe I'm doing the stat_replica.lua wrong? Honestly I didn't have 1 before you mentioned it, as I didn't know what its used for. Replica's are kinda like components, but run on the clients. Are you using AddReplicaComponent to actually add the component replica? Example: AddReplicableComponent("leveler") Link to comment Share on other sites More sharing options...
Aquaterion Posted March 8, 2016 Author Share Posted March 8, 2016 (edited) Just now, Kzisor said: Replica's are kinda like components, but run on the clients. Are you using AddReplicaComponent to actually add the component replica? Example: AddReplicableComponent("leveler") where do i do that, cuz I surely didn't.. is that like "AddComponent("leveler") or? Edited March 8, 2016 by Aquaterion Link to comment Share on other sites More sharing options...
Kzisor Posted March 8, 2016 Share Posted March 8, 2016 Just now, Aquaterion said: where do i do that, cuz I surely didn't You add that in your modmain.lua file. That is more than likely why you don't have replica showing up. Link to comment Share on other sites More sharing options...
Aquaterion Posted March 9, 2016 Author Share Posted March 9, 2016 (edited) YES I GOT IT TO WORK, THANKS SO MUCH, NOW ALL I GOTTA FIX IS THE METER!! The problem is that it doesn't show the current number for clients. I tried replacing some things with replica but I don't believe it worked, any ideas? Spoiler local Badge = require "widgets/badge" local UIAnim = require "widgets/uianim" local Text = require "widgets/text" local StatBadge = Class(Badge, function(self, owner) self.owner = ThePlayer Badge._ctor(self, "stat", self.owner) self.statarrow = self.underNumber:AddChild(UIAnim()) self.statarrow:GetAnimState():SetBank("sanity_arrow") self.statarrow:GetAnimState():SetBuild("sanity_arrow") self.statarrow:GetAnimState():PlayAnimation("neutral") self.statarrow:SetClickable(false) if self.owner.components.stat then self.onstatdelta = function(owner, data) self:StatDelta(data) end self.owner:ListenForEvent("statdelta", self.onstatdelta, self.owner) self:SetStatPercent(self.owner.components.stat:GetPercent()) end self.num = self:AddChild(Text(BODYTEXTFONT, 33)) self.num:SetHAlign(ANCHOR_MIDDLE) self.num:SetPosition(3.5, 1, 0) self.num:Hide() self:StartUpdating() end) function StatBadge:StatDelta(data) self:SetStatPercent(data.newpercent) end function StatBadge:SetStatPercent(pct) Badge.SetPercent(self, pct, self.owner.components.stat.max) self.num:SetString(tostring(math.ceil(pct * self.owner.components.stat.max))) end function StatBadge:OnUpdate(dt) if self.owner:HasTag('playerghost') then self:Hide() else self:Show() end local up = self.owner ~= nil and self.owner.components.stat ~= nil and self.owner.components.stat:GetPercent() < 1 local anim = up and "arrow_loop_increase" or "neutral" if self.arrowdir ~= anim then self.arrowdir = anim self.statarrow:SetPosition(0, -4, 0) self.statarrow:GetAnimState():PlayAnimation(anim, true) end end return StatBadge Edited March 9, 2016 by Aquaterion Link to comment Share on other sites More sharing options...
Kzisor Posted March 9, 2016 Share Posted March 9, 2016 10 hours ago, Aquaterion said: YES I GOT IT TO WORK, THANKS SO MUCH, NOW ALL I GOTTA FIX IS THE METER!! The problem is that it doesn't show the current number for clients. I tried replacing some things with replica but I don't believe it worked, any ideas? You have to use net variables for widgets/replicas. You can learn about net variables in one of the stickied posts by @PeterA. Link to comment Share on other sites More sharing options...
Aquaterion Posted March 9, 2016 Author Share Posted March 9, 2016 8 minutes ago, Kzisor said: You have to use net variables for widgets/replicas. You can learn about net variables in one of the stickied posts by @PeterA. so i have to add these to the component or widget? Link to comment Share on other sites More sharing options...
Aquaterion Posted March 9, 2016 Author Share Posted March 9, 2016 (edited) 11 hours ago, Kzisor said: You have to use net variables for widgets/replicas. You can learn about net variables in one of the stickied posts by @PeterA. function Stat:GetPercent() if self.inst.components.stat ~= nil then return self.inst.components.stat:GetPercent() elseif self.classified ~= nil then return self.inst["current"]:value() / self.inst["max"]:value() else return 1 end end doing print(c_sel().replica.stat:GetPercent()) works in console when hosting a local dedicated server, so im not sure why the badge aint using it even tho I clearly am calling them: local Badge = require "widgets/badge" local UIAnim = require "widgets/uianim" local Text = require "widgets/text" local StatBadge= Class(Badge, function(self, owner) Badge._ctor(self, "stat", owner) self.statarrow = self.underNumber:AddChild(UIAnim()) self.statarrow:GetAnimState():SetBank("sanity_arrow") self.statarrow:GetAnimState():SetBuild("sanity_arrow") self.statarrow:GetAnimState():PlayAnimation("neutral") self.statarrow:SetClickable(false) self.num = self:AddChild(Text(BODYTEXTFONT, 33)) self.num:SetHAlign(ANCHOR_MIDDLE) self.num:SetPosition(3.5, 1, 0) self.num:Hide() self:StartUpdating() if self.owner.replica.statthen self.onstatdelta = function(owner, data) self:StatDelta(data) end self.owner:ListenForEvent("statdelta", self.onstatdelta, self.owner) self:SetStatPercent(self.owner.replica.stat:GetPercent()) end end) function StatBadge:StatDelta(data) self:SetStatPercent(data.newpercent) end function StatBadge:SetStatPercent(pct, current, max) current = current or 50 max = max or 100 pct = pct or (current / max) Badge.SetPercent(self, pct, max) self.anim:GetAnimState():SetPercent("anim", 1 - pct) if pct <= .2 then self:StartWarning() else self:StopWarning() end if pct > .2 and pct < 1 then self:StartWarning(0, 80/255, 1, 1) else self:StopWarning() end self.num:SetString(tostring(math.ceil(pct * max))) end function StatBadge:OnUpdate(dt) if self.owner:HasTag('playerghost') then self:Hide() else self:Show() end local up = self.owner ~= nil and self.owner.replica.stat ~= nil and self.owner.replica.stat:GetPercent() < 1 local anim = up and "arrow_loop_increase" or "neutral" if self.arrowdir ~= anim then self.arrowdir = anim self.statarrow:SetPosition(0, -4, 0) self.statarrow:GetAnimState():PlayAnimation(anim, true) end if self.owner.replica.stat ~= nil then self:SetStatPercent( self.owner.replica.stat:GetPercent(), self.owner.replica.stat:GetCurrent(), self.owner.replica.stat:Max()) end end return StatBadge Edited March 9, 2016 by Aquaterion Link to comment Share on other sites More sharing options...
Kzisor Posted March 10, 2016 Share Posted March 10, 2016 12 hours ago, Aquaterion said: so i have to add these to the component or widget? Take a look at the following topic's attachments, I posted. Link to comment Share on other sites More sharing options...
Aquaterion Posted March 10, 2016 Author Share Posted March 10, 2016 (edited) 22 hours ago, Kzisor said: Take a look at the following topic's attachments, I posted. Ok so like after 6 hours of changing things, I managed to get the netvar thing to not crash the game.. I went to a local dedicated server to try it... andd badge still doesn't change.. Weird thing is, I made the console print the value when it changes, and it does print the value changing but the client side always shows 100/100 local function Set( netvar, value ) print("Set:value:" .. value) -- * netvar:set(value) end --* This prints correctly on server console, and incorrectly on client console, always printing 100 function Stat:SetCurrent(current) Set(self.inst["current"], current) end I really don't wanna give up as I did implement a good amount of features into this mod.. I don't get why a damn number is so hard to display for clients.. It seems client --> server works, but server --> client doesn't, from what I understood I think its because I don't explain how statdirty works exactly.. --- Edit: So I changed some things and now my stat meter is blinking, and when i hover on it it shows -1.IND It's blinking depending on the DoDelta, so progress or what? Edited March 10, 2016 by Aquaterion Link to comment Share on other sites More sharing options...
Kzisor Posted March 11, 2016 Share Posted March 11, 2016 11 hours ago, Aquaterion said: Ok so like after 6 hours of changing things, I managed to get the netvar thing to not crash the game.. I went to a local dedicated server to try it... andd badge still doesn't change.. Weird thing is, I made the console print the value when it changes, and it does print the value changing but the client side always shows 100/100 local function Set( netvar, value ) print("Set:value:" .. value) -- * netvar:set(value) end --* This prints correctly on server console, and incorrectly on client console, always printing 100 function Stat:SetCurrent(current) Set(self.inst["current"], current) end I really don't wanna give up as I did implement a good amount of features into this mod.. I don't get why a damn number is so hard to display for clients.. It seems client --> server works, but server --> client doesn't, from what I understood I think its because I don't explain how statdirty works exactly.. --- Edit: So I changed some things and now my stat meter is blinking, and when i hover on it it shows -1.IND It's blinking depending on the DoDelta, so progress or what? Make sure you're listening for the event which is suppose to be sent across the network (the "netvardirty" when you create the net variable) on the client also make sure the net variable is on the client not only on the server. Link to comment Share on other sites More sharing options...
Aquaterion Posted March 11, 2016 Author Share Posted March 11, 2016 (edited) 14 minutes ago, Kzisor said: Make sure you're listening for the event which is suppose to be sent across the network (the "netvardirty" when you create the net variable) on the client also make sure the net variable is on the client not only on the server. Hmm actually, I think the "current" value is working fine, but "max" isn't.. not sure why.. nevermind.. still not working I do have this in modmain.lua in the PlayerPostInit: if not TheWorld.ismastersim then inst:ListenForEvent("currentdirty", OnStatDirty) end I THINK ITS FINALLY WORKING OMG Edited March 11, 2016 by Aquaterion 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