z_mirror/EditorExtensions

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

Caleb HeuerFix crash when placing a super pump0ec1237

trunk
7.1 KiB272 linesraw
1local flib_gui = require("__flib__.gui")
2local flib_table = require("__flib__.table")
3
4--- @param entity LuaEntity
5--- @param speed double
6local function set_speed(entity, speed)
7  entity.set_fluid(2, {
8    name = "ee-super-pump-speed-fluid",
9    amount = 100000000000,
10    temperature = speed + 0.01, -- avoid floating point imprecision
11  })
12end
13
14--- @param entity LuaEntity
15local function get_speed(entity)
16  return math.floor(entity.get_fluid(2).temperature)
17end
18
19local slider_to_temperature = {
20  [0] = 0,
21  [1] = 100,
22  [2] = 200,
23  [3] = 300,
24  [4] = 400,
25  [5] = 500,
26  [6] = 600,
27  [7] = 700,
28  [8] = 800,
29  [9] = 900,
30  [10] = 1000,
31  [11] = 2000,
32  [12] = 3000,
33  [13] = 4000,
34  [14] = 5000,
35  [15] = 6000,
36  [16] = 7000,
37  [17] = 8000,
38  [18] = 9000,
39  [19] = 10000,
40  [20] = 15000,
41  [21] = 20000,
42  [22] = 25000,
43  [23] = 30000,
44}
45local temperature_to_slider = flib_table.inverted(slider_to_temperature)
46
47--- @param speed double
48--- @return double
49local function to_slider_value(speed)
50  local index
51  if speed == 0 then
52    index = 0
53  elseif speed < 1000 then
54    index = math.floor(speed / 100) * 100
55  elseif speed < 10000 then
56    index = math.floor(speed / 1000) * 1000
57  elseif speed < 30000 then
58    index = math.floor(speed / 5000) * 5000
59  else
60    index = 30000
61  end
62  return temperature_to_slider[index]
63end
64
65--- @param value double
66--- @return double
67local function from_slider_value(value)
68  return slider_to_temperature[value]
69end
70
71--- @param entity LuaEntity
72--- @param flow LuaGuiElement
73local function update_gui(entity, flow)
74  local speed = get_speed(entity)
75
76  local textfield = flow.speed_textfield --[[@as LuaGuiElement]]
77  textfield.style = "ee_slider_textfield"
78  textfield.text = tostring(speed)
79
80  local slider = flow.speed_slider --[[@as LuaGuiElement]]
81  slider.slider_value = to_slider_value(speed)
82end
83
84local handlers = {
85  --- @param entity LuaEntity
86  --- @param e EventData.on_gui_value_changed
87  on_pump_speed_slider_value_changed = function(entity, e)
88    local new_speed = from_slider_value(e.element.slider_value)
89    set_speed(entity, new_speed)
90    update_gui(entity, e.element.parent)
91  end,
92
93  --- @param entity LuaEntity
94  --- @param e EventData.on_gui_text_changed
95  on_pump_speed_textfield_changed = function(entity, e)
96    local textfield = e.element
97    local text = textfield.text
98    local speed = tonumber(text)
99
100    if not speed or speed > 600000 then
101      textfield.style = "ee_invalid_slider_textfield"
102      return
103    end
104
105    set_speed(entity, speed)
106    update_gui(entity, e.element.parent)
107  end,
108}
109
110flib_gui.add_handlers(handlers, function(e, handler)
111  local player = game.get_player(e.player_index)
112  if not player or player.opened_gui_type ~= defines.gui_type.entity then
113    return
114  end
115  local entity = player.opened
116  if not entity or not entity.valid then
117    return
118  end
119  if entity.name ~= "ee-super-pump" then
120    return
121  end
122  handler(entity, e)
123end)
124
125--- @param player LuaPlayer
126local function create_gui(player)
127  local existing = player.gui.relative.ee_super_pump_window
128  if existing then
129    existing.destroy()
130  end
131
132  flib_gui.add(player.gui.relative, {
133    type = "frame",
134    name = "ee_super_pump_window",
135    style = "frame_with_even_paddings",
136    style_mods = { width = 448 },
137    anchor = {
138      gui = defines.relative_gui_type.pump_gui,
139      position = defines.relative_gui_position.bottom,
140      name = "ee-super-pump",
141    },
142    {
143      type = "frame",
144      name = "inner_frame",
145      style = "inside_shallow_frame_with_padding",
146      {
147        type = "flow",
148        name = "inner_flow",
149        style_mods = { vertical_align = "center" },
150        { type = "label", caption = { "gui.ee-speed" }, tooltip = { "gui.ee-speed-tooltip" } },
151        {
152          type = "slider",
153          name = "speed_slider",
154          style_mods = { horizontally_stretchable = true, margin = { 0, 8, 0, 8 } },
155          minimum_value = 0,
156          maximum_value = 23,
157          value = 0,
158          handler = { [defines.events.on_gui_value_changed] = handlers.on_pump_speed_slider_value_changed },
159        },
160        {
161          type = "textfield",
162          name = "speed_textfield",
163          style = "ee_slider_textfield",
164          numeric = true,
165          clear_and_focus_on_right_click = true,
166          handler = { [defines.events.on_gui_text_changed] = handlers.on_pump_speed_textfield_changed },
167        },
168      },
169    },
170  })
171end
172
173--- @param e BuiltEvent
174local function on_entity_built(e)
175  local entity = e.entity or e.destination
176  if not entity or not entity.valid or entity.name ~= "ee-super-pump" then
177    return
178  end
179  local speed = 12000
180  local tags = e.tags
181  if tags and tags.EditorExtensions then
182    speed = tags.EditorExtensions.speed --[[@as double]]
183  end
184  set_speed(entity, speed)
185end
186
187--- @param e EventData.on_player_setup_blueprint
188local function on_player_setup_blueprint(e)
189  local blueprint = e.stack or e.record
190  if not blueprint then
191    return
192  end
193
194  local entities = blueprint.get_blueprint_entities()
195  if not entities then
196    return
197  end
198  for i, entity in pairs(entities) do
199    --- @cast i uint
200    if entity.name ~= "ee-super-pump" then
201      goto continue
202    end
203    local real_entity = e.surface.find_entity(entity.name, entity.position)
204    if not real_entity then
205      goto continue
206    end
207    blueprint.set_blueprint_entity_tag(i, "EditorExtensions", { speed = get_speed(real_entity) })
208    ::continue::
209  end
210end
211
212--- @param e EventData.on_entity_settings_pasted
213local function on_entity_settings_pasted(e)
214  local source, destination = e.source, e.destination
215  if not source.valid or not destination.valid then
216    return
217  end
218  if source.name ~= "ee-super-pump" or destination.name ~= "ee-super-pump" then
219    return
220  end
221  set_speed(destination, get_speed(source))
222end
223
224--- @param e EventData.on_gui_opened
225local function on_gui_opened(e)
226  local player = game.get_player(e.player_index)
227  if not player or player.opened_gui_type ~= defines.gui_type.entity then
228    return
229  end
230  local entity = e.entity
231  if not entity or not entity.valid then
232    return
233  end
234  if entity.name ~= "ee-super-pump" then
235    return
236  end
237
238  update_gui(entity, player.gui.relative.ee_super_pump_window.inner_frame.inner_flow)
239end
240
241--- @param e EventData.on_player_created
242local function on_player_created(e)
243  local player = game.get_player(e.player_index)
244  if not player then
245    return
246  end
247
248  create_gui(player)
249end
250
251local super_pump = {}
252
253super_pump.on_configuration_changed = function()
254  for _, player in pairs(game.players) do
255    create_gui(player)
256  end
257end
258
259super_pump.events = {
260  [defines.events.on_built_entity] = on_entity_built,
261  [defines.events.on_entity_cloned] = on_entity_built,
262  [defines.events.on_entity_settings_pasted] = on_entity_settings_pasted,
263  [defines.events.on_gui_opened] = on_gui_opened,
264  [defines.events.on_player_created] = on_player_created,
265  [defines.events.on_player_setup_blueprint] = on_player_setup_blueprint,
266  [defines.events.on_robot_built_entity] = on_entity_built,
267  [defines.events.script_raised_built] = on_entity_built,
268  [defines.events.script_raised_revive] = on_entity_built,
269  [defines.events.on_space_platform_built_entity] = on_entity_built,
270}
271
272return super_pump