Well-met Posted May 28, 2021 Share Posted May 28, 2021 Hello Is there some easy way to make heavy ocean objects be picked up by players directly? I know it doesn't make sense but I'd need that for a mod. I've tried removing the NOBLOCK / NOCLICK / NOTARGET tags and such but it doesn't do anything. I'm not really a fan of the wincher claw mechanic especially when crabking respawns directly ontop of the celestial altar it dropped a couple days earlier. Link to comment Share on other sites More sharing options...
penguin0616 Posted May 29, 2021 Share Posted May 29, 2021 (edited) If I'm not mistaken, the salvageables are a sort of container for the actual item that gets fetched by the winch. In addition to removing the NOBLOCK, NOCLICK, NOTARGET, you still have to give it a reason to be picked up by the cursor. A rough and quick way of doing it could be giving it the "inventoryitem" component (might have some side effects, since the salvageables have an inventory component). Edited May 29, 2021 by penguin0616 2 Link to comment Share on other sites More sharing options...
Well-met Posted May 29, 2021 Author Share Posted May 29, 2021 (edited) Ah, that's closer to what is needed, but unfortunately that does not give the heavy object, only a blank empty fake item. thank you anyway Edited May 29, 2021 by Well-met Link to comment Share on other sites More sharing options...
Monti18 Posted May 31, 2021 Share Posted May 31, 2021 (edited) It gives you the correct item, it's just the underwater_salvageable prefab that you are getting, which has no inventoryitem image or strings. local function pickup(inst,pickupguy) local item = inst.components.inventory:GetItemInSlot(1) if item ~= nil then if item.components.equippable ~= nil then pickupguy.components.inventory:Equip(GLOBAL.SpawnPrefab(item.prefab)) else pickupguy.components.inventory:GiveItem(GLOBAL.SpawnPrefab(item.prefab)) end end inst:DoTaskInTime(0, inst.Remove) end local function underwater_salvageable(inst) inst:RemoveTag("notarget") inst:RemoveTag("NOCLICK") inst:RemoveTag("NOBLOCK") if not GLOBAL.TheWorld.ismastersim then return inst end if inst.components.inventoryitem == nil then inst:AddComponent("inventoryitem") end inst.components.inventoryitem:SetOnPickupFn(pickup) end AddPrefabPostInit("underwater_salvageable", underwater_salvageable) Adding something like this to your modmain will give you the item of the underwater_salvageable and remove it from your inventory after picking it up. Edited June 1, 2021 by Monti18 Applied changes to make the function work better 1 1 Link to comment Share on other sites More sharing options...
Well-met Posted May 31, 2021 Author Share Posted May 31, 2021 thank you! I will try this out soon Link to comment Share on other sites More sharing options...
Well-met Posted June 1, 2021 Author Share Posted June 1, 2021 16 hours ago, Monti18 said: It gives you the correct item, it's just the underwater_salvageable prefab that you are getting, which has no inventoryitem image or strings. local function pickup(inst,pickupguy) local item = inst.components.inventory:GetItemInSlot(1) if item ~= nil then pickupguy.components.inventory:GiveItem(GLOBAL.SpawnPrefab(item.prefab)) end inst:DoTaskInTime(0, inst.Remove) end local function underwater_salvageable(inst) inst:RemoveTag("notarget") inst:RemoveTag("NOCLICK") inst:RemoveTag("NOBLOCK") if not TheWorld.ismastersim then return inst end inst:AddComponent("inventoryitem") inst.components.inventoryitem:SetOnPickupFn(pickup) inst.components.inventory.ignorescangoincontainer = false end AddPrefabPostInit("underwater_salvageable", underwater_salvageable) Adding something like this to your modmain will give you the item of the underwater_salvageable and remove it from your inventory after picking it up. This code causes a crash on server load unfortunately Link to comment Share on other sites More sharing options...
Monti18 Posted June 1, 2021 Share Posted June 1, 2021 (edited) I think this is because I forgot to write there GLOBAL.TheWorld.ismastersim. You need to have a look at the server log to find the error, at least for me this exact piece of code is working when using GLOBAL.TheWorld.ismastersim . Edited June 1, 2021 by Monti18 2 Link to comment Share on other sites More sharing options...
Well-met Posted June 1, 2021 Author Share Posted June 1, 2021 11 hours ago, Monti18 said: I think this is because I forgot to write there GLOBAL.TheWorld.ismastersim. You need to have a look at the server log to find the error, at least for me this exact piece of code is working when using GLOBAL.TheWorld.ismastersim . Most of the mechanic seems to function however the item is teleported to the nearest shore and not put in the character's hands Link to comment Share on other sites More sharing options...
Monti18 Posted June 1, 2021 Share Posted June 1, 2021 (edited) Ah this seems to be because these are heavy objects, try this: local function pickup(inst,pickupguy) local item = inst.components.inventory:GetItemInSlot(1) if item ~= nil then pickupguy.components.inventory:Equip(GLOBAL.SpawnPrefab(item.prefab)) end inst:DoTaskInTime(0, inst.Remove) end I updated the function in my first post to reflect the changes, i also made a check for the component inventoryitem as I had problems with duplicate replicas and deleted the line with ignorescangoincontainer as it made no sense. When I tried it like this, I equipped the seashells upon picking it up. Edited June 1, 2021 by Monti18 1 1 Link to comment Share on other sites More sharing options...
Well-met Posted June 1, 2021 Author Share Posted June 1, 2021 works great now! now i'm just trying to figure out how to replace "MISSING NAME" with something more tangible. inst:SetPrefabNameOverride("Unidentified Depth") inst:AddComponent("inspectable") inst.components.inspectable.nameoverride = "Unidentified Depth" neither of these seem to work though hmm Link to comment Share on other sites More sharing options...
Monti18 Posted June 2, 2021 Share Posted June 2, 2021 Good to hear! You do it the same way as adding a name to a custom item: GLOBAL.STRINGS.NAMES.UNDERWATER_SALVAGEABLE = "Unidentified Depth" 2 Link to comment Share on other sites More sharing options...
Well-met Posted June 2, 2021 Author Share Posted June 2, 2021 5 hours ago, Monti18 said: Good to hear! You do it the same way as adding a name to a custom item: GLOBAL.STRINGS.NAMES.UNDERWATER_SALVAGEABLE = "Unidentified Depth" Thank you. Already I've been using your help as a base to do other things on my own I have one last problem with the underwater salvageable. Sea chests do not produce loot when picked up manually this way. Is there some obvious fix i'm missing? 1 Link to comment Share on other sites More sharing options...
Monti18 Posted June 2, 2021 Share Posted June 2, 2021 That's good, it's always the best to learn it to it yourself Are the chests also an underwater salvageable? I'm sorry, I haven't really played much of th sea part of the game But as far as I can see, these chests don't have an inventory component, that's why you won't get anything out of them. But they have the container component, you can just make a loop of all container slots and give yourself the item as I did it for the other salvageables. Try it and see if you can do it, otherwise let me know. 1 Link to comment Share on other sites More sharing options...
Well-met Posted June 2, 2021 Author Share Posted June 2, 2021 2 minutes ago, Monti18 said: That's good, it's always the best to learn it to it yourself Are the chests also an underwater salvageable? I'm sorry, I haven't really played much of th sea part of the game But as far as I can see, these chests don't have an inventory component, that's why you won't get anything out of them. But they have the container component, you can just make a loop of all container slots and give yourself the item as I did it for the other salvageables. Try it and see if you can do it, otherwise let me know. Sea chests roll a random set of various treasures, it's not really static https://dontstarve.fandom.com/wiki/Sunken_Chest If I had to take a guess, the loot is decided during the winch event which would be annoying considering we've bypassed exactly that Link to comment Share on other sites More sharing options...
Monti18 Posted June 2, 2021 Share Posted June 2, 2021 Ah ok, I had a quick look at them, the treasure is generated when the chest is generated by the message bottle. But that doesn't matter if it's then or with the winch, as we delete the chest and give ourselves a new one. You need to save the items of the previous chest and insert them into the new chest. From the function the variable item is your chest. You make a loop and save each item with and their stacksize if they have one in a table, and apply these items to the new item you spawn. You can do this by saving the new item as local new_item = GLOBAL.SpawnPrefab(item.prefab) and then apply the items to new_item. 1 Link to comment Share on other sites More sharing options...
Well-met Posted June 2, 2021 Author Share Posted June 2, 2021 a "loop"? Sorry I'm still not very good at lua Link to comment Share on other sites More sharing options...
Monti18 Posted June 2, 2021 Share Posted June 2, 2021 Oh sorry, it's a function that runs multiple times, see here from lua manual: https://www.lua.org/pil/4.3.4.html It's something like this: local items = {} for k,v in ipairs(item.components.container.slots) do items[k] = v end Here k is the key and v the value of the table. If you run this, you iterate through all slots of the container of your item, and each item is saved in the local table items. 1 Link to comment Share on other sites More sharing options...
Well-met Posted June 2, 2021 Author Share Posted June 2, 2021 Um alright, ill check this stuff out when I get home tonight what is "k" and "v" though? ipairs? Link to comment Share on other sites More sharing options...
Monti18 Posted June 2, 2021 Share Posted June 2, 2021 Tables and loops are very useful for modding, so try to get comfortable with them. i put a small explanation in the spoiler: Spoiler When you have a table, you can enter values into the table. These are v. v is just the variable name, you can call it whatever you want, but it gives back the value of the table. The key is the place where the value is stored in the table. If you don't choose a key, they start at 1 and go up by 1 for each next value. So for example: local table = { "first", "second", "third", } Here we have a table named "table". The first value is "first". As we chose no key, the key is 1. That means, table[1] = "first". The same goes for the other two, table[2] = "second" and table[3] = "third". local table2 = { one = "first", two = "second", three = "third", } Here we choose the key, that means that table["one"] = "first", whereas table[1] is nil, as there is no value for 1. When using pairs or ipairs, you cycle through each key of the table that is written in parentheses after pairs/ipairs. If you run this function: for k,v in ipairs(table) do print(k,v) end you will get this result: 1 first 2 second 3 third The differences between pairs/ipairs is can be seen here: https://stackoverflow.com/questions/55108794/what-is-the-difference-of-pairs-vs-ipairs-in-lua Try to get a feeling for it, it will make it much easier to write code as you don't need to write some things multiple times. 1 1 Link to comment Share on other sites More sharing options...
Well-met Posted June 3, 2021 Author Share Posted June 3, 2021 10 hours ago, Monti18 said: Tables and loops are very useful for modding, so try to get comfortable with them. i put a small explanation in the spoiler: Reveal hidden contents When you have a table, you can enter values into the table. These are v. v is just the variable name, you can call it whatever you want, but it gives back the value of the table. The key is the place where the value is stored in the table. If you don't choose a key, they start at 1 and go up by 1 for each next value. So for example: local table = { "first", "second", "third", } Here we have a table named "table". The first value is "first". As we chose no key, the key is 1. That means, table[1] = "first". The same goes for the other two, table[2] = "second" and table[3] = "third". local table2 = { one = "first", two = "second", three = "third", } Here we choose the key, that means that table["one"] = "first", whereas table[1] is nil, as there is no value for 1. When using pairs or ipairs, you cycle through each key of the table that is written in parentheses after pairs/ipairs. If you run this function: for k,v in ipairs(table) do print(k,v) end you will get this result: 1 first 2 second 3 third The differences between pairs/ipairs is can be seen here: https://stackoverflow.com/questions/55108794/what-is-the-difference-of-pairs-vs-ipairs-in-lua Try to get a feeling for it, it will make it much easier to write code as you don't need to write some things multiple times. well I've spent hours crashing over and over again and I'm no closer to retaining the loot and transferring it in the "new" chest. it's frustrating because it's probably simple Link to comment Share on other sites More sharing options...
Monti18 Posted June 3, 2021 Share Posted June 3, 2021 I know how you feel, I've been there often enough But don't worry, it's not the easiest, especialy if you don't have experience with loops. Here is the solution for you: local function pickup(inst,pickupguy) local item = inst.components.inventory:GetItemInSlot(1) if item ~= nil then if item.components.equippable ~= nil then local new_item = GLOBAL.SpawnPrefab(item.prefab) if item.components.container ~= nil and new_item.components.container ~= nil then --we check if the item is a container for k,v in ipairs(item.components.container.slots) do -- we do a loop through all slots of the old chest new_item.components.container.slots[k] = GLOBAL.SpawnPrefab(v.prefab) --we copy the items from the old chest to the new chest if v.components.stackable ~= nil then --we check if the item is stackable and if yes, we copy the stacksize of the old item to the new item local slot_item = new_item.components.container.slots[k] if slot_item and slot_item.components.stackable then slot_item.components.stackable.stacksize = v.components.stackable.stacksize end end end end pickupguy.components.inventory:Equip(new_item) else pickupguy.components.inventory:GiveItem(GLOBAL.SpawnPrefab(item.prefab)) end end inst:DoTaskInTime(0, inst.Remove) end When you copy item, it's important to use SpawnPrefab, as otherwise you just reference the old item and don't make a new one, I also always forget this. If you have problems to understand something in this code, let me know! 2 Link to comment Share on other sites More sharing options...
Well-met Posted June 3, 2021 Author Share Posted June 3, 2021 thank you for the code comments, very useful! i will test this tonight Link to comment Share on other sites More sharing options...
Well-met Posted June 4, 2021 Author Share Posted June 4, 2021 works great thank you so much Link to comment Share on other sites More sharing options...
Well-met Posted June 6, 2021 Author Share Posted June 6, 2021 On 6/3/2021 at 5:43 AM, Monti18 said: I know how you feel, I've been there often enough But don't worry, it's not the easiest, especialy if you don't have experience with loops. Here is the solution for you: local function pickup(inst,pickupguy) local item = inst.components.inventory:GetItemInSlot(1) if item ~= nil then if item.components.equippable ~= nil then local new_item = GLOBAL.SpawnPrefab(item.prefab) if item.components.container ~= nil and new_item.components.container ~= nil then --we check if the item is a container for k,v in ipairs(item.components.container.slots) do -- we do a loop through all slots of the old chest new_item.components.container.slots[k] = GLOBAL.SpawnPrefab(v.prefab) --we copy the items from the old chest to the new chest if v.components.stackable ~= nil then --we check if the item is stackable and if yes, we copy the stacksize of the old item to the new item local slot_item = new_item.components.container.slots[k] if slot_item and slot_item.components.stackable then slot_item.components.stackable.stacksize = v.components.stackable.stacksize end end end end pickupguy.components.inventory:Equip(new_item) else pickupguy.components.inventory:GiveItem(GLOBAL.SpawnPrefab(item.prefab)) end end inst:DoTaskInTime(0, inst.Remove) end When you copy item, it's important to use SpawnPrefab, as otherwise you just reference the old item and don't make a new one, I also always forget this. If you have problems to understand something in this code, let me know! The code crashes around 25% of the time when I hammer a "clone chest". it says [00:44:26]: [string "scripts/components/inventoryitem.lua"]:10: attempt to index field 'inventoryitem' (a nil value) this doesn't seem to be from my modmain so I don't know what to do Link to comment Share on other sites More sharing options...
Monti18 Posted June 7, 2021 Share Posted June 7, 2021 The game wants to index the owner of the item with the inventoryitem component, but on this item there is no iventoryitem component left. Could you post the entire log, I need to see for which item it happens and what the other variables are at the moment of the crash. 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