z_mirror/EditorExtensions

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

Patrick 'Quezler' MounierMerge branch 'master' into patch-1e65a4b6

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