Page 1 of 1

Better quickbar support for ItemWithEntityData

Posted: Mon Aug 31, 2020 11:33 am
by Xorimuth
I've been trying to manipulate the quickbar, but it is quite hard to do with the current interface, which only has 4 functions related to it, of which only

Code: Select all

get_quick_bar_slot(index) → LuaItemPrototype 
and

Code: Select all

set_quick_bar_slot(index, filter)
are really useful to me.
Aim
I want to be able to swap out a vanilla spidertron remote for a modded one whilst it is in the player's hand. For this I have written the following code:

Code: Select all

local function get_previous_quickbar(player)
  local quickbar_slots = {}
  for i = 1, 100 do
    quickbar_slots[i] = player.get_quick_bar_slot(i)
  end
  return quickbar_slots
end

local function fill_in_quickbar(player, previous_quickbar, new_stack)
  for i = 1, 100 do
    if previous_quickbar[i] and not player.get_quick_bar_slot(i) then
      -- The quickbar filter has been lost since last check, therefore it contained the replaced item
      player.set_quick_bar_slot(i, new_stack)
    end
  end
end
]]

local function convert_remote(stack, old_name, new_name, player)
  if stack and stack.valid_for_read and stack.name == old_name then
    local connected_spidertron = stack.connected_entity
    local previous_quickbar = get_previous_quickbar(player)
    stack.set_stack{name=new_name, count=1}
    stack.connected_entity = connected_spidertron
    fill_in_quickbar(player, previous_quickbar, stack)
  end
end
`convert_remote` correctly replaces the remote with a new remote and transfers the `connected_entity`. Without `get_previous_quickbar` and `fill_in_quickbar`, if the old remote was in the player's quickbar, then it would just be removed.
Requested features
1. A way to get all quickbar slot indexes connected to a specific item, such as `LuaItemStack.get_quickbar_slots() -> array of numbers`
I've managed to get around this for my usecase by writing `get_previous_quickbar()` to store the contents of every quickbar slot, and then after the switch `fill_in_quickbar` iterates through the new quickbar contents, and any slots that are now empty and weren't previously are assumed to have been belonging to the old item.
Note that similar to point 2 below, this is made much harder by the fact that I cannot tell from get_quick_bar_slot() if that slot is connected to a specific spidertron remote, I can only tell if it is a spidertron remote. If I could tell which spidertron remote it was, then I wouldn't need this feature as much because I'd only have to iterate through the quickbar slot indexes once, which seems much more sensible.

2. `player.set_quick_bar_slot(i, new_stack)` does not work correctly for items such as spidertron remotes. Even though I am passing in a LuaItemStack instead of a LuaItemPrototype, it is only interpreted as a generic prototype, so it behaves really weirdly (because spidertron remotes don't really have a 'generic' state.
Related: 68374

For reference: my mod https://mods.factorio.com/mod/SpidertronWaypoints, specifically https://github.com/tburrows13/Spidertro ... lua#L1-L40

Re: Better quickbar support for ItemWithEntityData

Posted: Mon Aug 31, 2020 11:34 pm
by Xorimuth
On further investigation of point 2, it appears that LuaItemStack.item_number is the crucial thing that is not being passed into set_quick_bar_slot(). I'm inclined to say that this is actually a bug.

Re: Better quickbar support for ItemWithEntityData

Posted: Tue Sep 01, 2020 9:05 am
by Xorimuth
I've managed to solve this one for my usecase almost perfectly by storing the original item into a temporary inventory and then replacing the item in hand with the new item. This preserves the quickbar shortcut for the original item (it just becomes greyed out).

I'd still appreciate proper quickbar support for items with LuaItemStack.item_number.

Re: Better quickbar support for ItemWithEntityData

Posted: Tue Sep 01, 2020 3:42 pm
by Rseding91
I've fixed #2 for the next release. #1 I don't quite understand.

Re: Better quickbar support for ItemWithEntityData

Posted: Tue Sep 01, 2020 4:00 pm
by Xorimuth
Thanks for the reply, that is great to hear! With #2 implemented, I can cover my usecase perfectly, though it would still be a little hacky without #1. I'll try and explain #1 better:

I have an item in my cursor and I want to get all the quick bar slots that link to it. If my cursor item does not have item_number, this is simple: iterate from 1 to 100, call player.get_quick_bar_slot(i) and compare the cursor_stack.name with the returned LuaItemPrototype.name. Store the indexes that match.

The issue is when the item has the item_number property: unless you've changed it so that player.get_quick_bar_slot(i) returns the item_number of that item, there is no way of distinguishing between (e.g.) spidertron remotes on the quickbar. So, I cannot perfectly match the cursor_stack with the quickbar slots that are connected to it.

That's the problem. I have a solution for my usecase that I stated in the original post: I store every value from the quickbar in a table by iterating over it. Then I delete the item in the cursor, at which point all quickbar references to that item are deleted. I then iterate through every quickbar slot a second time, comparing it to table stored from the first time. If an item has disappeared, then I know that it was pointing to my specific spidertron remote. This actually works really well for me, but only because I do actually want to delete the item. If I just moved it to a different inventory, the quickbar connection would stay, and just be greyed out.

Adding `LuaItemStack.get_quickbar_slots() -> array of indexes corresponding to quickbar slots that point to the LuaItemStack (specifically adhering to item_number)` would make all this a lot easier.

As I said though, with #2 implemented, my personal needs are fulfilled. Thank you!