lorddarkar3 Posted May 30, 2021 Share Posted May 30, 2021 First off, I'm hoping I'm posting this correctly Second, I have two resolutions I'm willing to accept from this: I want to be able to modify the recipe tab in the same way Craft Tab Enabler did, but for a specific character (My functional modded character) This is the most important thing I want to solve here. My other resolution, that is not required, is having this constantly update to better fit the currently visible tabs (basically remove the giant gap that is visible when most tabs are hidden) And before you ask "Why do you need to do this?" Well, for the same reason Craft Tab Enabler was created (Mostly). I'm wanting to use this concept to solve the issue of tabs being hidden behind other tabs. My character uses a type of "level system" allowing it to unlock different levels of the "Bonus Tech" which the ancient tab ends up covering tabs such as the Celestial tab when you approach the Celestial Orb. I've spent hours searching DST's scripts trying to find something that might help me solve this on my own, but nothing I've done has gotten me the results I'm looking for. Searching online I couldn't find anything that would help me in this situation either. So to sum up my question: How do I remake Craft Tab Enabler but have it only apply to a single character? For a reference with Craft Tab Enabler's code: local RECIPETABS = GLOBAL.RECIPETABS local sorttabs = {} for _,v in pairs(RECIPETABS) do table.insert(sorttabs, v) end table.sort( sorttabs, function(a, b) return (a.sort == b.sort) and (a.str < b.str) or (a.sort < b.sort) end ) for i,v in ipairs(sorttabs) do v.sort = i v.crafting_station = nil end Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/ Share on other sites More sharing options...
Monti18 Posted May 31, 2021 Share Posted May 31, 2021 The Craft Tab Enabler Mod just orders the recipetabs and deletes the crafting_station requirement. Did you add as your sixth argument for AddRecipeTab a true? If yes, try change it to a nil and see if it works. local numtabslots = 1 --reserver 1 slot for crafting station tabs for k, v in pairs(RECIPETABS) do table.insert(tabnames, v) if not v.crafting_station then numtabslots = numtabslots + 1 end end for k, v in pairs(CUSTOM_RECIPETABS) do if v.owner_tag == nil or owner:HasTag(v.owner_tag) then table.insert(tabnames, v) if not v.crafting_station then numtabslots = numtabslots + 1 end end end This is from the widget crafttabs, as you can see, it checks if crafting_station is true or not and if it's not true, the numtabslot is increased, which I think means an own slot for the crafting tab. For your second problem. I'm not sure how you can do this, perhaps you could try to change crafting_station to true or nil depending on if you want the tab to be put in the last space with all the other tabs with the crafting station requirement or not. 1 Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1464945 Share on other sites More sharing options...
lorddarkar3 Posted June 1, 2021 Author Share Posted June 1, 2021 Is my custom recipe tab relevant here? It's DST's vanilla tabs that are generating problems. The Ancient tab is hiding other vanilla tabs behind it. And either way, my recipe tab's sixth argument is already nil, you're meant to start with the tab available. Ultroman has said in a different topic "There seems to be a maximum number of tabs being visible at a time." Which is why I'm wanting to replicate Craft Tab Enablers recipe tab layout. I'm wanting it to only happen for my specific character as it would be annoying for other players who aren't playing as my character and don't need it. Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1465111 Share on other sites More sharing options...
Monti18 Posted June 1, 2021 Share Posted June 1, 2021 (edited) Ah sorry, I misunderstood your question, I thought you had multiple custom tabs that needed to be shown. Try if this will work: local function crafttabs(inst) if not GLOBAL.TheNet:GetIsClient() then return end local sorttabs = {} local RECIPETABS = GLOBAL.RECIPETABS for _,v in pairs(RECIPETABS) do table.insert(sorttabs, v) end table.sort( sorttabs, function(a, b) return (a.sort == b.sort) and (a.str < b.str) or (a.sort < b.sort) end ) for i,v in ipairs(sorttabs) do v.sort = i v.crafting_station = nil end end AddPrefabPostInit("yourcharacter", crafttabs) This should only change the crafting_station values on the clients of those that have your mod character. If it doesn't, you will perhaps need to make a check at the beginning that the instance is your character, something like: if inst.prefab == "yourcharacter" then .........code.... end Edited June 1, 2021 by Monti18 1 1 Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1465176 Share on other sites More sharing options...
lorddarkar3 Posted June 1, 2021 Author Share Posted June 1, 2021 Second method worked, thanks a lot! Only problem is using something to change characters in-game results in the effects staying, but I think I can solve this on my own. If anyone happens to come up with a solution for my second problem, (Removing gaps) I'd be glad if you shared! Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1465347 Share on other sites More sharing options...
CarlZalph Posted June 1, 2021 Share Posted June 1, 2021 It's been a while but I believe the builder_tag/owner_tag parts for recipes control the character-specific craft tabs. Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1465352 Share on other sites More sharing options...
lorddarkar3 Posted June 2, 2021 Author Share Posted June 2, 2021 Oh hi Carl! I'm not too sure how to use those. I also realized that it doesn't only apply to the character, when anyone picks my modded character, the change applies to all players, not being visible until they change characters or rejoin. I'm guessing this is because of "GLOBAL.RECIPETABS," is there a way for me to make this client-side? Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1465365 Share on other sites More sharing options...
Monti18 Posted June 2, 2021 Share Posted June 2, 2021 As your mod is all_clients_require_mod = true, the only way is with the checks to see if you are on the client, which we did. I had some time so I tried to get it working when changing the character and hopefully also for all players. This is the code that I have now: local RECIPETABS = GLOBAL.RECIPETABS local sorttabs = {} local RECIPETABS = GLOBAL.RECIPETABS for _,v in pairs(RECIPETABS) do table.insert(sorttabs, v) end table.sort(sorttabs, function(a, b) return (a.sort == b.sort) and (a.str < b.str) or (a.sort < b.sort) end) local sort_number = {} local crafting_station_bool = {} for i,v in pairs(sorttabs) do sort_number[i] = v.sort crafting_station_bool[i] = v.crafting_station end local function crafttabs(inst) if not GLOBAL.TheNet:GetIsClient() then return end if inst.prefab == "yourcharacter" then for i,v in ipairs(sorttabs) do v.sort = i v.crafting_station = nil end else for i,v in ipairs(sorttabs) do v.sort = sort_number[i] v.crafting_station = crafting_station_bool[i] end end end AddPlayerPostInit(crafttabs) When playtesting, I could change character and the change was reverted. I saved the sort values and the crafting station values in other tables and overrode the values that were changed with the original ones, when the character is not yourcharacter. I think like this it should also work for all players, but I have at the moment no means to test this, so try if it works. As for removing the gaps, I think that you will need to write something to change the widget crafttabs, especially the self.tabs.spacing, as this is the spacing of the tabs and done once at the beginning and then never again, so you would need to add an update function to this. 1 Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1465425 Share on other sites More sharing options...
Monti18 Posted June 2, 2021 Share Posted June 2, 2021 (edited) So I invested some more time for your second problem and I think I have the answer for it! I'm not sure if it will work with more players as I can't test that. First, add this to the common_postinit of your character: Spoiler --we need to make two net_strings to pass the information to the client inst.net_tab_craftingstation_false = net_string(inst.GUID,"tab_craftingstation_false", "tab_craftingstation_false_dirty") inst:ListenForEvent("tab_craftingstation_false_dirty", function(inst) if not TheNet:GetIsClient() then return end if inst.HUD and inst.HUD.controls.crafttabs then local str = inst.net_tab_craftingstation_false:value() inst.HUD.controls.crafttabs:UpdateTabSpacing(str, false) -- we call the updatetabspacing function with the string that we got from the net_string and the bool that is needed end end) inst.net_tab_craftingstation_true = net_string(inst.GUID,"tab_craftingstation_true", "tab_craftingstation_true_dirty") inst:ListenForEvent("tab_craftingstation_true_dirty", function(inst) if not TheNet:GetIsClient() then return end if inst.HUD and inst.HUD.controls.crafttabs then local str = inst.net_tab_craftingstation_true:value() inst.HUD.controls.crafttabs:UpdateTabSpacing(str, true) end end) These are net_strings so that the client knows which tabs are changed and to which boolean value. The rest is placed into the modmain: Spoiler AddPrefabPostInit("yourcharacter", function (inst) local function changetabs(inst,tab,bool) if tab ~= nil then if type(tab) == "string" then if bool == true then inst.net_tab_craftingstation_true:set(tab) --give the tab name to the client with wanted boolean value else inst.net_tab_craftingstation_false:set(tab) end elseif type(tab) == "table" then for k,v in ipairs(tab) do if bool == true then inst.net_tab_craftingstation_true:set(v) --give the tab name to the client with wanted boolean value else inst.net_tab_craftingstation_false:set(v) end end end end end inst.changetabs = changetabs --save the function under inst.changetabs so that the function can be called from anywhere end) This adds a function to your character that you can call with inst.changetabs. It has 3 argument, inst(like for most of them), tab and bool. Tab is the tabs that you want to change, you can either just give one tab as a string or a table of strings.The names of the tabs can be found in constants.lua in RECIPETABS. The bool is to determine if the tab should have an own place in the layout or not. True means it has no place in the layout, it will be placed in the last place and can be hidden behind other tabs. False means it has always a place in the layout. Now we only need to update the crafttab widget. The problem is that the tabs determined at the start of the game and they are not changed in between. So we are gonna delete all tabs, then make new ones with only the ones we want. Spoiler local TabGroup = require "widgets/tabgroup" local tab_bg = { atlas = "images/hud.xml", normal = "tab_normal.tex", selected = "tab_selected.tex", highlight = "tab_highlight.tex", bufferedhighlight = "tab_place.tex", overlay = "tab_researchable.tex", } AddClassPostConstruct("widgets/crafttabs", function(self,str,bool) -- we get a string and a bool with the function, the string is the tab and the bool is for the crafting_station self.UpdateTabSpacing = function(self) -- we add a new function to crafttabs that we can call when changing the amount of tabs self.tabs:Kill() --we delete all the tabs that were there --we change crafting_station on the client of the tab we want to change to the value we want to have for k,v in pairs(sorttabs) do if v.str == str then v.crafting_station = bool end end self.tabs = self:AddChild(TabGroup()) --we add our new tabs self.tabs:SetPosition(-16,0,0) local tabnames = {} local numtabslots = 1 --reserver 1 slot for crafting station tabs for k, v in pairs(sorttabs) do --we use our table with the modified values to get the tabs that we want table.insert(tabnames, v) if not v.crafting_station then numtabslots = numtabslots + 1 end end for k, v in pairs(GLOBAL.CUSTOM_RECIPETABS) do if v.owner_tag == nil or self.owner:HasTag(v.owner_tag) then table.insert(tabnames, v) if not v.crafting_station then numtabslots = numtabslots + 1 end end end self.tabs.spacing = 790 / numtabslots --this is only copy/paste of the crafttabs widget that make the tabs, so if Klei changes something here, you will also need to change it. self.tabbyfilter = {} local was_crafting_station = nil for k, v in ipairs(tabnames) do local tab = self.tabs:AddTab( STRINGS.TABS[v.str], GLOBAL.softresolvefilepath(tab_bg.atlas), v.icon_atlas or GLOBAL.softresolvefilepath("images/hud.xml"), v.icon, tab_bg.normal, tab_bg.selected, tab_bg.highlight, tab_bg.bufferedhighlight, tab_bg.overlay, function(widget) --select fn if not self.controllercraftingopen then if self.craft_idx_by_tab[k] then self.crafting.idx = self.craft_idx_by_tab[k] end local default_filter = function(recname) local recipe = GLOBAL.GetValidRecipe(recname) return recipe ~= nil and recipe.tab == v and (self.owner.replica.builder == nil or self.owner.replica.builder:CanLearn(recname)) end local advanced_filter = function(recname) local recipe = GLOBAL.GetValidRecipe(recname) return recipe ~= nil and recipe.tab == v and (self.owner.replica.builder == nil or self.owner.replica.builder:CanLearn(recname)) end self.crafting:SetFilter(advanced_filter) self.crafting:Open() self.preventautoclose = nil end end, function(widget) --deselect fn self.craft_idx_by_tab[k] = self.crafting.idx self.crafting:Close() self.preventautoclose = nil if self.isquagmire then widget.inst:DoTaskInTime(0, function() if widget.focus then widget.ongainfocusfn() end end) end end, was_crafting_station and v.crafting_station --collapsed ) was_crafting_station = v.crafting_station tab.filter = v tab.icon = v.icon tab.icon_atlas = v.icon_atlas or GLOBAL.softresolvefilepath("images/hud.xml") tab.tabname = STRINGS.TABS[v.str] if self.isquagmire then tab.disable_scaling = true tab.overlay_scaling = true end self.tabbyfilter[v] = tab end self:UpdateRecipes() --we update the recipes, otherwise all tabs can be seen, even if you can't produce anything there end end) Now if you want to change the amount of tabs shown, you need to call the function with the parameters you want and it should change. This methods changes some things for crafttabs, so I'm not sure how well compatible it's with mods that change the crafttabs, but I also don't know how else you couold change it. I commented the most important parts of the code, if you have questions, let me know. Edited June 2, 2021 by Monti18 forgot that changes are not propagated to client 1 Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1465439 Share on other sites More sharing options...
lorddarkar3 Posted June 2, 2021 Author Share Posted June 2, 2021 First script works, only my character has their tabs changed even after changing characters, but I'm not sure what you mean by Quote Now if you want to change the amount of tabs shown, you need to call the function with the parameters you want and it should change. Which function specifically and how would I get this to update when new tabs become available or old tabs become unavailable? Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1465598 Share on other sites More sharing options...
Monti18 Posted June 2, 2021 Share Posted June 2, 2021 (edited) I mean the function changetabs, specifically I saved the function in the variable inst.changetabs in your character. I don't know how your character gets new tabs or loses tabs, but lets say you have a level system, and you reach lvl 10 and want to add one new tab. The tab is "ANCIENT" for the ancient tab. You should have a function that runs when you level up and if your level is equal 10 then you run inst.changetabs(inst,"ANCIENT", false) This means that the ancient tabs crafting_station value is set to false, which means that the tab will have its own place. If you explain a bit when you wanted the tabs to update, I could try to help you. Edit: I just saw that my method was flawed, as the changes to sorttable are not propagated to the client, so there was no change there. I updated the functions in the post before to reflect the changes. If you want to test how it works, insert the spoiler into your modmain and press Left Alt to substract recipe tabs. Spoiler local recipetablist = { "CELESTIAL", "MOON_ALTAR", "CARTOGRAPHY", "SCULPTING", "ORPHANAGE", "PERDOFFERING", "MADSCIENCE", "FOODPROCESSING", "FISHING", "WINTERSFEASTCOOKING", "HERMITCRABSHOP", "TURFCRAFTING", } local function testfn(inst) if inst.changetabs ~= nil then local tab = recipetablist[math.random(1,12)] inst.changetabs(inst,tab,true) end end AddModRPCHandler("test","changetabs",testfn) GLOBAL.TheInput:AddControlHandler(38, function() SendModRPCToServer(MOD_RPC["test"]["changetabs"]) end) Edited June 2, 2021 by Monti18 changed method to work for client 1 Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1465603 Share on other sites More sharing options...
lorddarkar3 Posted June 3, 2021 Author Share Posted June 3, 2021 Ah, I see, that makes a lot more sense. Been trying for a while now, but can't seem to be getting it working, am I doing something wrong?In modmain.lua: Spoiler -- Reorder crafting tabs local RECIPETABS = GLOBAL.RECIPETABS local sorttabs = {} local RECIPETABS = GLOBAL.RECIPETABS for _,v in pairs(RECIPETABS) do table.insert(sorttabs, v) end table.sort(sorttabs, function(a, b) return (a.sort == b.sort) and (a.str < b.str) or (a.sort < b.sort) end) local sort_number = {} local crafting_station_bool = {} for i,v in pairs(sorttabs) do sort_number[i] = v.sort crafting_station_bool[i] = v.crafting_station end local function crafttabs(inst) if GLOBAL.TheNet:GetIsClient() then return end if inst.prefab == "rimuru" then for i,v in ipairs(sorttabs) do v.sort = i v.crafting_station = nil end else for i,v in ipairs(sorttabs) do v.sort = sort_number[i] v.crafting_station = crafting_station_bool[i] end end end AddPlayerPostInit(crafttabs) -- Extra data to keep crafting clean AddPrefabPostInit("rimuru", function (inst) local function changetabs(inst,tab,bool) if tab ~= nil then if type(tab) == "string" then if bool == true then inst.net_tab_craftingstation_true:set(tab) --give the tab name to the client with wanted boolean value else inst.net_tab_craftingstation_false:set(tab) end elseif type(tab) == "table" then for k,v in ipairs(tab) do if bool == true then inst.net_tab_craftingstation_true:set(v) --give the tab name to the client with wanted boolean value else inst.net_tab_craftingstation_false:set(v) end end end end end inst.changetabs = changetabs --save the function under inst.changetabs so that the function can be called from anywhere end) -- Even more data (This modifies recipe tabs so they can be changed in-game) local TabGroup = require "widgets/tabgroup" local tab_bg = { atlas = "images/hud.xml", normal = "tab_normal.tex", selected = "tab_selected.tex", highlight = "tab_highlight.tex", bufferedhighlight = "tab_place.tex", overlay = "tab_researchable.tex", } AddClassPostConstruct("widgets/crafttabs", function(self,str,bool) -- we get a string and a bool with the function, the string is the tab and the bool is for the crafting_station self.UpdateTabSpacing = function(self) -- we add a new function to crafttabs that we can call when changing the amount of tabs self.tabs:Kill() --we delete all the tabs that were there --we change crafting_station on the client of the tab we want to change to the value we want to have for k,v in pairs(sorttabs) do if v.str == str then v.crafting_station = bool end end self.tabs = self:AddChild(TabGroup()) --we add our new tabs self.tabs:SetPosition(-16,0,0) local tabnames = {} local numtabslots = 1 --reserver 1 slot for crafting station tabs for k, v in pairs(sorttabs) do --we use our table with the modified values to get the tabs that we want table.insert(tabnames, v) if not v.crafting_station then numtabslots = numtabslots + 1 end end for k, v in pairs(GLOBAL.CUSTOM_RECIPETABS) do if v.owner_tag == nil or self.owner:HasTag(v.owner_tag) then table.insert(tabnames, v) if not v.crafting_station then numtabslots = numtabslots + 1 end end end self.tabs.spacing = 790 / numtabslots --this is only copy/paste of the crafttabs widget that make the tabs, so if Klei changes something here, you will also need to change it. self.tabbyfilter = {} local was_crafting_station = nil for k, v in ipairs(tabnames) do local tab = self.tabs:AddTab( STRINGS.TABS[v.str], GLOBAL.softresolvefilepath(tab_bg.atlas), v.icon_atlas or GLOBAL.softresolvefilepath("images/hud.xml"), v.icon, tab_bg.normal, tab_bg.selected, tab_bg.highlight, tab_bg.bufferedhighlight, tab_bg.overlay, function(widget) --select fn if not self.controllercraftingopen then if self.craft_idx_by_tab[k] then self.crafting.idx = self.craft_idx_by_tab[k] end local default_filter = function(recname) local recipe = GLOBAL.GetValidRecipe(recname) return recipe ~= nil and recipe.tab == v and (self.owner.replica.builder == nil or self.owner.replica.builder:CanLearn(recname)) end local advanced_filter = function(recname) local recipe = GLOBAL.GetValidRecipe(recname) return recipe ~= nil and recipe.tab == v and (self.owner.replica.builder == nil or self.owner.replica.builder:CanLearn(recname)) end self.crafting:SetFilter(advanced_filter) self.crafting:Open() self.preventautoclose = nil end end, function(widget) --deselect fn self.craft_idx_by_tab[k] = self.crafting.idx self.crafting:Close() self.preventautoclose = nil if self.isquagmire then widget.inst:DoTaskInTime(0, function() if widget.focus then widget.ongainfocusfn() end end) end end, was_crafting_station and v.crafting_station --collapsed ) was_crafting_station = v.crafting_station tab.filter = v tab.icon = v.icon tab.icon_atlas = v.icon_atlas or GLOBAL.softresolvefilepath("images/hud.xml") tab.tabname = STRINGS.TABS[v.str] if self.isquagmire then tab.disable_scaling = true tab.overlay_scaling = true end self.tabbyfilter[v] = tab end self:UpdateRecipes() --we update the recipes, otherwise all tabs can be seen, even if you can't produce anything there end end) Inside character.lua (Cropped): Spoiler local common_postinit = function(inst) --we need to make two net_strings to pass the information to the client inst.net_tab_craftingstation_false = net_string(inst.GUID,"tab_craftingstation_false", "tab_craftingstation_false_dirty") inst:ListenForEvent("tab_craftingstation_false_dirty", function(inst) if not TheNet:GetIsClient() then return end if inst.HUD and inst.HUD.controls.crafttabs then local str = inst.net_tab_craftingstation_false:value() inst.HUD.controls.crafttabs:UpdateTabSpacing(str, false) -- we call the updatetabspacing function with the string that we got from the net_string and the bool that is needed end end) inst.net_tab_craftingstation_true = net_string(inst.GUID,"tab_craftingstation_true", "tab_craftingstation_true_dirty") inst:ListenForEvent("tab_craftingstation_true_dirty", function(inst) if not TheNet:GetIsClient() then return end if inst.HUD and inst.HUD.controls.crafttabs then local str = inst.net_tab_craftingstation_true:value() inst.HUD.controls.crafttabs:UpdateTabSpacing(str, true) end end) end -- Bunch of code local function great_sage(inst) -- Basically the level system if inst.components.sanity.current >= (TUNING.RIMURU_SANITY*8) then inst.components.builder.science_bonus = (3) inst.components.builder.magic_bonus = (3) inst.components.builder.ancient_bonus = (3) if inst.changetabs then inst.changetabs(inst,"SCIENCE", false) inst.changetabs(inst,"MAGIC", false) inst.changetabs(inst,"ANCIENT", false) end elseif inst.components.sanity.current >= (TUNING.RIMURU_SANITY*4) and inst.components.sanity.current < (TUNING.RIMURU_SANITY*8) then inst.components.builder.science_bonus = (2) inst.components.builder.magic_bonus = (2) inst.components.builder.ancient_bonus = (2) if inst.changetabs then inst.changetabs(inst,"SCIENCE", false) inst.changetabs(inst,"MAGIC", false) inst.changetabs(inst,"ANCIENT", false) end elseif inst.components.sanity.current >= (TUNING.RIMURU_SANITY*2) and inst.components.sanity.current < (TUNING.RIMURU_SANITY*4)then inst.components.builder.science_bonus = (1) inst.components.builder.magic_bonus = (1) inst.components.builder.ancient_bonus = (1) if inst.changetabs then inst.changetabs(inst,"SCIENCE", false) inst.changetabs(inst,"MAGIC", false) inst.changetabs(inst,"ANCIENT", false) end elseif inst.components.sanity.current > (0) and inst.components.sanity.current < (TUNING.RIMURU_SANITY*2) then inst.components.builder.science_bonus = (0) inst.components.builder.magic_bonus = (0) inst.components.builder.ancient_bonus = (0) if inst.changetabs then inst.changetabs(inst,"SCIENCE", true) inst.changetabs(inst,"MAGIC", true) inst.changetabs(inst,"ANCIENT", true) end end end local master_postinit = function(inst) inst.components.builder.science_bonus = (3) inst.components.builder.magic_bonus = (3) inst.components.builder.ancient_bonus = (3) if inst.changetabs then inst.changetabs(inst,"SCIENCE", false) inst.changetabs(inst,"MAGIC", false) inst.changetabs(inst,"ANCIENT", false) end inst:ListenForEvent("sanitydelta", function(inst) great_sage(inst) end) -- Actual system great_sage(inst) -- Make sure correct tabs are visible when starting FYI: I'm checking "if inst.changetabs then" because of the first run of "great_sage(inst)" which ends up crashing on the first run because inst.changetabs does not exist yet (afterwards it does) though it's completely possible that this is the problem and I need to change it. And just incase you want/need to see the oiriginal uncut files I'll attach a zip of both files. OG_Files.zip Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1465713 Share on other sites More sharing options...
Monti18 Posted June 3, 2021 Share Posted June 3, 2021 Yes the crash is happening as the function is added in PrefabPostInit, but since I changed the code you can now add the function to your character prefab, as it now doesn't depend on sorttable. When you have something like this where you don't know why it's not working, try adding print statements at multiple points in the function to see where the error is happening. What exactly is happening? Is it just that nothing changes? When I tried it with your mod, it worked, but the way you call the function just makes it unuseable, as it resets the tabs all the time. You need to make a function that only calls changetabs when there really is change of the recipetabs. Try to make such a function, if you don't have anything that works this evening I will write you one. 1 Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1465771 Share on other sites More sharing options...
lorddarkar3 Posted June 3, 2021 Author Share Posted June 3, 2021 Quote Yes the crash is happening as the function is added in PrefabPostInit, but since I changed the code you can now add the function to your character prefab, as it now doesn't depend on sorttable. Wouldn't that mean it would have worked when I did it? Or am I completely missing what you were trying to say? I definitely didn't take into consideration that I was constantly calling the function. Definitely should have tried using prints but that slipped my mind at the time. It also just rendered in my mind that you made it so I can use tables for multiple tabs instead of making a new line for every tab I want to enable/disable. Using your advice I made a new function that I can call whenever I want tabs enabled/disabled. I'm trying to make it check if the tab is already disabled/disabled and if so, not to call the changetabs function, is there a way to check if tabs are enabled or not? My current code: (tabenabled and tabdisabled are placeholders) local function tabsignal(inst,tab,toggle) if inst.changetabs then if type(tab) == "string" then if (not toggle and tabdisabled) or (toggle and tabenabled) then inst.changetabs(inst,tab,toggle) end elseif type(tab) == "table" then local enabletable = {} local disabletable = {} for k,v in ipairs(tab) do if toggle and tabdisabled then table.insert(enabletable,v) elseif toggle and tabenabled then table.insert(disabletable,v) end end if enabletable ~= nil then inst.changetabs(inst,enabletable,false) end if disabletable ~= nil then inst.changetabs(inst,disabletable,true) end end end end Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1465816 Share on other sites More sharing options...
Monti18 Posted June 3, 2021 Share Posted June 3, 2021 (edited) I meant that it would have worked if you added the function changetabs to your character prefab instead of adding it in a prefabpostinit, as great_sage is called before AddPrefabPostInit is run. If changetabs is in your character prefab, great_sage can call it when it is run, as the function can be referenced now. To check if tabs are enabled or not, you would need to make a list and save if a tab is enabled or not, or you would need to send an RPC and or netvar, as these values are saved on the client. I wouldn't make it so complicated, as then you have this function that is called a few times per second, which consumes quite a lot of computing power. I would change the way great_sage works, below is my idea: Spoiler --I used the tabs that you had in your example, you can change it however you want local rimurutabs = { "SCIENCE", "MAGIC", "ANCIENT", } --As you change the values of the bonus for each step of great sage to the same number, I made it into a function local function set_bonus(num) inst.components.builder.science_bonus = (num) inst.components.builder.magic_bonus = (num) inst.components.builder.ancient_bonus = (num) end local function great_sage(inst) local sanity_num -- we add a local number and give it a value depending on the value of rimurus sanity if inst.components.sanity.current >= (TUNING.RIMURU_SANITY*8) then sanity_num = 3 elseif inst.components.sanity.current >= (TUNING.RIMURU_SANITY*4) and inst.components.sanity.current < (TUNING.RIMURU_SANITY*8) then sanity_num = 2 elseif inst.components.sanity.current >= (TUNING.RIMURU_SANITY*2) and inst.components.sanity.current < (TUNING.RIMURU_SANITY*4) then sanity_num = 1 elseif inst.components.sanity.current > (0) and inst.components.sanity.current < (TUNING.RIMURU_SANITY*2) then sanity_num = 0 end --we check if great sage is still in the same "level" as the last time it was checked, --if yes, we stop the function here, so that there is no functions running that don't need to if sanity_num == inst.great_sage_num then return end if sanity_num ~= nil and inst.changetabs ~= nil then set_bonus(sanity_num) --we set the bonus depending on the sanity if sanity_num == 0 then -- we change the tabs, but this is only called if there was a change in "level" of great sage inst.changetabs(inst, rimurutabs, true) else inst.changetabs(inst, rimurutabs, false) end inst.great_sage_num = sanity_num -- we save the "level" value into a variable that will be called the next time great sage runs end end I just realised that at the moment, when you are changing multiple tabs at once, there is only one that as changed, as the dirty event is only fired once as the changes are too quick. I have an idea on how to do this, I will try to do it tomorrow. Edited June 3, 2021 by Monti18 1 Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1466055 Share on other sites More sharing options...
Monti18 Posted June 4, 2021 Share Posted June 4, 2021 (edited) I changed the functions a bit, that's why I will put all you need to use in your mod in this post. First, we start with the modmain: Spoiler local RECIPETABS = GLOBAL.RECIPETABS local sorttabs = {} local RECIPETABS = GLOBAL.RECIPETABS for _,v in pairs(RECIPETABS) do table.insert(sorttabs, v) end table.sort(sorttabs, function(a, b) return (a.sort == b.sort) and (a.str < b.str) or (a.sort < b.sort) end) local sort_number = {} local crafting_station_bool = {} for i,v in pairs(sorttabs) do sort_number[i] = v.sort crafting_station_bool[i] = v.crafting_station end local function crafttabs(inst) if GLOBAL.TheNet:GetIsClient() then return end if inst.prefab == "rimuru" then print("rimuru crafttabs") for i,v in ipairs(sorttabs) do print(v.str,i) v.sort = i end else for i,v in ipairs(sorttabs) do v.sort = sort_number[i] v.crafting_station = crafting_station_bool[i] end end end AddPlayerPostInit(crafttabs) local function OnChangeTabsTrue(inst,tab) if inst and inst.HUD and inst.HUD.controls.crafttabs then inst.HUD.controls.crafttabs:UpdateTabSpacing(tab,true) end end AddClientModRPCHandler("rimuru", "changetabstrue", OnChangeTabsTrue) local function OnChangeTabsFalse(inst,tab) if inst and inst.HUD and inst.HUD.controls.crafttabs then inst.HUD.controls.crafttabs:UpdateTabSpacing(tab,false) end end AddClientModRPCHandler("rimuru", "changetabsfalse", OnChangeTabsFalse) local TabGroup = require "widgets/tabgroup" local tab_bg = { atlas = "images/hud.xml", normal = "tab_normal.tex", selected = "tab_selected.tex", highlight = "tab_highlight.tex", bufferedhighlight = "tab_place.tex", overlay = "tab_researchable.tex", } AddClassPostConstruct("widgets/crafttabs", function(self) -- we get a string and a bool with the function, the string is the tab and the bool is for the crafting_station self.UpdateTabSpacing = function(self,str,bool) -- we add a new function to crafttabs that we can call when changing the amount of tabs self.tabs:Kill() --we delete all the tabs that were there print("UpdateTabSpacing", str,bool) --we change crafting_station on the client of the tab we want to change to the value we want to have if str ~= nil then for k,v in pairs(GLOBAL.RECIPETABS) do if v.str == str then v.crafting_station = bool end end end self.tabs = self:AddChild(TabGroup()) --we add our new tabs self.tabs:SetPosition(-16,0,0) local tabnames = {} local numtabslots = 1 --reserver 1 slot for crafting station tabs for k, v in pairs(sorttabs) do --we use our table with the modified values to get the tabs that we want table.insert(tabnames, v) if not v.crafting_station then numtabslots = numtabslots + 1 end end for k, v in pairs(GLOBAL.CUSTOM_RECIPETABS) do if v.owner_tag == nil or self.owner:HasTag(v.owner_tag) then table.insert(tabnames, v) if not v.crafting_station then numtabslots = numtabslots + 1 end end end self.tabs.spacing = 790 / numtabslots --this is only copy/paste of the crafttabs widget that make the tabs, so if Klei changes something here, you will also need to change it. self.tabbyfilter = {} local was_crafting_station = nil for k, v in ipairs(tabnames) do local tab = self.tabs:AddTab( STRINGS.TABS[v.str], GLOBAL.softresolvefilepath(tab_bg.atlas), v.icon_atlas or GLOBAL.softresolvefilepath("images/hud.xml"), v.icon, tab_bg.normal, tab_bg.selected, tab_bg.highlight, tab_bg.bufferedhighlight, tab_bg.overlay, function(widget) --select fn if not self.controllercraftingopen then if self.craft_idx_by_tab[k] then self.crafting.idx = self.craft_idx_by_tab[k] end local default_filter = function(recname) local recipe = GLOBAL.GetValidRecipe(recname) return recipe ~= nil and recipe.tab == v and (self.owner.replica.builder == nil or self.owner.replica.builder:CanLearn(recname)) end local advanced_filter = function(recname) local recipe = GLOBAL.GetValidRecipe(recname) return recipe ~= nil and recipe.tab == v and (self.owner.replica.builder == nil or self.owner.replica.builder:CanLearn(recname)) end self.crafting:SetFilter(advanced_filter) self.crafting:Open() self.preventautoclose = nil end end, function(widget) --deselect fn self.craft_idx_by_tab[k] = self.crafting.idx self.crafting:Close() self.preventautoclose = nil if self.isquagmire then widget.inst:DoTaskInTime(0, function() if widget.focus then widget.ongainfocusfn() end end) end end, was_crafting_station and v.crafting_station --collapsed ) was_crafting_station = v.crafting_station tab.filter = v tab.icon = v.icon tab.icon_atlas = v.icon_atlas or GLOBAL.softresolvefilepath("images/hud.xml") tab.tabname = STRINGS.TABS[v.str] if self.isquagmire then tab.disable_scaling = true tab.overlay_scaling = true end self.tabbyfilter[v] = tab end self:UpdateRecipes() --we update the recipes, otherwise all tabs can be seen, even if you can't produce anything there end end) If I understand your mod correctly, you will only need to change the tabs depending on the sanity, so you won't need to incorporate the function that works like craftabsenabler. This goes into your character prefab: Spoiler local function changetabs(inst,tab,bool) if tab ~= nil and bool ~= nil then if type(tab) == "string" then if bool == true then SendModRPCToClient(GetClientModRPC("rimuru","changetabstrue"),inst.userid,inst,tab) else SendModRPCToClient(GetClientModRPC("rimuru","changetabsfalse"),inst.userid,inst,tab) end elseif type(tab) == "table" then for k,v in ipairs(tab) do if bool == true then SendModRPCToClient(GetClientModRPC("rimuru","changetabstrue"),inst.userid,inst,v) else SendModRPCToClient(GetClientModRPC("rimuru","changetabsfalse"),inst.userid,inst,v) end end end end end --I used the tabs that you had in your example, you can change it however you want local rimurutabs = { --"SCIENCE", --If you try to make the base tabs disappear, the hud will look wonky. --"MAGIC", "ANCIENT", "CELESTIAL", } --As you change the values of the bonus for each step of great sage to the same number, I made it into a function local function set_bonus(inst,num) inst.components.builder.science_bonus = (num) inst.components.builder.magic_bonus = (num) inst.components.builder.ancient_bonus = (num) end local function great_sage(inst) local sanity_num -- we add a local number and give it a value depending on the value of rimurus sanity if inst.components.sanity.current >= (TUNING.RIMURU_SANITY*8) then sanity_num = 3 elseif inst.components.sanity.current >= (TUNING.RIMURU_SANITY*4) and inst.components.sanity.current < (TUNING.RIMURU_SANITY*8) then sanity_num = 2 elseif inst.components.sanity.current >= (TUNING.RIMURU_SANITY*2) and inst.components.sanity.current < (TUNING.RIMURU_SANITY*4) then sanity_num = 1 elseif inst.components.sanity.current > (0) and inst.components.sanity.current < (TUNING.RIMURU_SANITY*2) then sanity_num = 0 end --we check if great sage is still in the same "level" as the last time it was checked, if yes, we stop the function here, so that there is no functions running that don't need to if sanity_num == inst.great_sage_num then return end if sanity_num ~= nil then set_bonus(inst,sanity_num) --we set the bonus depending on the sanity if sanity_num == 0 then -- we change the tabs, but this is only called if there was a change in "level" of great sage changetabs(inst, rimurutabs, true) else changetabs(inst, rimurutabs, false) end inst.great_sage_num = sanity_num -- we save the "level" value into a variable that will be called the next time great sage runs end end --in master postinit (not necessary) inst.changetabs = changetabs We send a ClientModRPC to send the data to the client, as with netvars, these fast changes are not possible. You can change the great sage function as you want, this was just to show how I would to it. Edited June 6, 2021 by Monti18 some more changes... 1 Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1466277 Share on other sites More sharing options...
lorddarkar3 Posted June 4, 2021 Author Share Posted June 4, 2021 Whenever the script attempts to call the RPC, the console will print "Invalid RPC data type." I did some research online but didn't find anything that helped explain why this isn't working, it looks fine based off of what I learned. Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1466422 Share on other sites More sharing options...
Monti18 Posted June 5, 2021 Share Posted June 5, 2021 Oh sorry, stupid error from my side, I copied the wrong line in the function changetabs. It should be elseif type(tab) == "table" then for k,v in ipairs(tab) do if bool == true then SendModRPCToClient(GetClientModRPC("rimuru","changetabs"),inst.userid,inst,v,true) else SendModRPCToClient(GetClientModRPC("rimuru","changetabs"),inst.userid,inst,v,false) end end end as RPC are not able to send tables, and I forgot to change tab to v. 1 Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1466532 Share on other sites More sharing options...
lorddarkar3 Posted June 5, 2021 Author Share Posted June 5, 2021 Ah, the most relatable mistake in coding history. We got past that part but now I'm realizing that in the modmain "sorttabs" doesn't exist so "for k, v in pairs(sorttabs) do" can't do anything, obviously causing a crash. I don't have the slightest idea what table is meant to go here, clearly not an empty one, I know that much. Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1466716 Share on other sites More sharing options...
Monti18 Posted June 6, 2021 Share Posted June 6, 2021 You're right Yeah I forgot that this won't there anymore, you can just use GLOBAL.RECIPETABS, as we use these to see what recipetabs there are, but I changed the function a bit (again, I know) because I think there could be problems with the sort order, that's why I reimplemented the first function with sorttabs, but I only change the sort number. You can then leave sorttabs there. I also changed the ClientRPCs because they sometimes don't give the boolean argument to the client, which makes this unusuable. If you want to change the basic tabs, your hud will look wonky, when I tried it with science and magic, it looked strange, so perhaps leave them out. Take a look at the previous previous post, I updated it to reflect the changes (modmain and changetabs function). I hope it's working now, during my testing it worked, but perhaps I missed to add something. 1 Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1466778 Share on other sites More sharing options...
lorddarkar3 Posted June 6, 2021 Author Share Posted June 6, 2021 Well, it worked! However now it's also trying to add in the custom recipe tabs from other characters! (Not visible most of the time, just flashes on screen for a millisecond when the layout tries changing) But this results in icons going off the gui tab! (gif for visual explanation, I'm using the console to set my sanity) Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1466839 Share on other sites More sharing options...
Monti18 Posted June 6, 2021 Share Posted June 6, 2021 Do you mean other players that are playing at the same time or if you are changing character? I hate these interactions with the clients... You could try checking if it's your character with self.owner.prefab == "rimuru" at the start of the UpdateTabSpacing function and see if that works. 1 Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1466879 Share on other sites More sharing options...
lorddarkar3 Posted June 7, 2021 Author Share Posted June 7, 2021 No no, I mean when you have multiple character mods enabled, if that mod adds custom recipe tabs those tabs will flash on screen. (The purple blob with a halo is a recipe tab for a different modded character, Rimuru shouldn't ever be able to see it.) Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1466939 Share on other sites More sharing options...
Monti18 Posted June 7, 2021 Share Posted June 7, 2021 Ah now I understand! I'm not sure which recipe tab you mean, do you mean the celestial tab? Just the one below the carneval tab. Because this one is from the base game, I forgot to remove it from the rimurutabs table, this was purely for testing to see how it works with more tabs. Just remove it from rimirutasb and you shouldn't be able to see it. 1 Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1466967 Share on other sites More sharing options...
lorddarkar3 Posted June 7, 2021 Author Share Posted June 7, 2021 Noted. I'm talking about the tab between the Dress and Ancient tabs. It's from the Ninomae Ina'nis character mod, only Ina should be able to see it, but with the current scripts, it makes space for that tab for Rimuru as well. Link to comment https://forums.kleientertainment.com/forums/topic/130397-modifying-recipe-tabs-layout/#findComment-1467129 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