z_mirror/EditorExtensions

git clone https://git.raiguard.me/z_mirror/EditorExtensions

Caleb HeuerVersion 2.0f0478c9

hidden-items
4.6 KiB136 linesraw
1local table = require("__flib__/table")
2
3--- @class InventorySyncData
4--- @field filters table<integer, string?>
5--- @field hand_location uint?
6--- @field inventory LuaInventory
7
8--- @param player LuaPlayer
9local function pre_sync(player)
10  local prefix = table.find(defines.controllers, player.controller_type) .. "_"
11  local hand_location = player.hand_location or {}
12  --- @type table<string, InventorySyncData>
13  local sync_tables = {}
14  for _, name in ipairs({ "cursor", "main", "guns", "armor", "ammo" }) do
15    --- @type table<integer, string?>
16    local sync_filters = {}
17    local sync_inventory
18    local inventory_def = defines.inventory[prefix .. name]
19    if name == "cursor" then
20      sync_inventory = game.create_inventory(1)
21      local cursor_stack = player.cursor_stack
22      if cursor_stack and cursor_stack.valid_for_read then
23        sync_inventory[1].transfer_stack(cursor_stack)
24      end
25    elseif inventory_def then
26      local source_inventory = player.get_inventory(inventory_def) --[[@as LuaInventory]]
27      local get_filter = source_inventory.get_filter
28      local set_filter = source_inventory.set_filter
29      local supports_filters = source_inventory.supports_filters()
30      local source_inventory_len = #source_inventory --[[@as uint16]]
31      sync_inventory = game.create_inventory(source_inventory_len)
32      for i = 1, source_inventory_len do
33        --- @cast i uint
34        sync_inventory[i].transfer_stack(source_inventory[i])
35        if supports_filters then
36          sync_filters[i] = get_filter(i)
37          set_filter(i, nil)
38        end
39      end
40    end
41    if sync_inventory then
42      --- @type InventorySyncData
43      sync_tables[name] = {
44        filters = sync_filters,
45        hand_location = hand_location.inventory == inventory_def and hand_location.slot or nil,
46        inventory = sync_inventory,
47      }
48    end
49  end
50  global.inventory_sync[player.index] = sync_tables
51end
52
53--- @param player LuaPlayer
54local function post_sync(player)
55  -- determine prefix based on controller type
56  local prefix = table.find(defines.controllers, player.controller_type) .. "_"
57  -- iterate all inventories
58  local sync_data = global.inventory_sync[player.index]
59  if not sync_data then
60    return
61  end
62  global.inventory_sync[player.index] = nil
63  -- Cursor first to allow setting the hand, then armor to correct the inventory size
64  for _, name in ipairs({ "cursor", "armor", "main", "guns", "ammo" }) do
65    local sync_table = sync_data[name]
66    -- God mode doesn't have every inventory
67    if not sync_table then
68      goto continue
69    end
70    local sync_filters = sync_table.filters
71    local sync_inventory = sync_table.inventory
72    if name == "cursor" and player.cursor_stack then
73      player.cursor_stack.transfer_stack(sync_inventory[1])
74    else
75      local inventory_def = defines.inventory[prefix .. name]
76      if not inventory_def then
77        goto continue
78      end
79      local destination_inventory = player.get_inventory(inventory_def) --[[@as LuaInventory]]
80      local set_filter = destination_inventory.set_filter
81      local supports_filters = destination_inventory.supports_filters()
82      for i = 1, math.min(#destination_inventory, #sync_inventory) do
83        --- @cast i uint
84        if supports_filters then
85          set_filter(i, sync_filters[i])
86        end
87        destination_inventory[i].clear()
88        destination_inventory[i].transfer_stack(sync_inventory[i])
89      end
90      local hand_location = sync_table.hand_location
91      if hand_location and hand_location <= #destination_inventory then
92        player.hand_location = { inventory = inventory_def, slot = hand_location }
93      end
94    end
95    sync_inventory.destroy()
96    ::continue::
97  end
98end
99
100--- @param e EventData.on_pre_player_toggled_map_editor
101local function on_pre_player_toggled_map_editor(e)
102  local player = game.get_player(e.player_index)
103  if not player or not player.cheat_mode then
104    return
105  end
106  if not player.mod_settings["ee-inventory-sync"].value then
107    return
108  end
109  pre_sync(player)
110end
111
112--- @param e EventData.on_player_toggled_map_editor
113local function on_player_toggled_map_editor(e)
114  local player = game.get_player(e.player_index)
115  if not player or not player.cheat_mode then
116    return
117  end
118  if not player.mod_settings["ee-inventory-sync"].value then
119    return
120  end
121  post_sync(player)
122end
123
124local inventory_sync = {}
125
126inventory_sync.on_init = function()
127  --- @type table<uint, table<string, InventorySyncData?>>
128  global.inventory_sync = {}
129end
130
131inventory_sync.events = {
132  [defines.events.on_pre_player_toggled_map_editor] = on_pre_player_toggled_map_editor,
133  [defines.events.on_player_toggled_map_editor] = on_player_toggled_map_editor,
134}
135
136return inventory_sync