z_mirror/Krastorio2

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

Caleb HeuerAdd remote interface to control loader snapping5c23cc70

trunk
5.2 KiB189 linesraw
1local flib_direction = require("__flib__.direction")
2local flib_position = require("__flib__.position")
3
4local loader_snapping_enabled = true
5
6--- @type table<defines.direction, Vector>
7local offsets = {
8  [defines.direction.north] = { 0, -1 },
9  [defines.direction.east] = { 1, 0 },
10  [defines.direction.south] = { 0, 1 },
11  [defines.direction.west] = { -1, 0 },
12}
13
14local belt_types = {
15  "linked-belt",
16  "loader",
17  "loader-1x1",
18  "splitter",
19  "transport-belt",
20  "underground-belt",
21}
22
23local container_types = {
24  "assembling-machine",
25  "beacon",
26  "boiler",
27  "burner-generator",
28  "container",
29  "curved-rail",
30  "furnace",
31  "infinity-container",
32  "lab",
33  "linked-container",
34  "logistic-container",
35  "mining-drill",
36  "proxy-container",
37  "rail",
38  "reactor",
39  "rocket-silo",
40  "straight-rail",
41}
42
43--- @param entity LuaEntity
44local function flip_loader(entity)
45  entity.direction = flib_direction.opposite(entity.direction)
46  entity.loader_type = entity.loader_type == "output" and "input" or "output"
47end
48
49--- Find entities and entity ghosts of the corresponding types.
50--- @param surface LuaSurface
51--- @param position MapPosition
52--- @param force ForceID
53--- @param types string[]
54--- @return LuaEntity[]
55local function find_entities(surface, position, force, types)
56  local entities = surface.find_entities_filtered({
57    force = force,
58    position = position,
59    type = types,
60  })
61  local ghosts = surface.find_entities_filtered({
62    force = force,
63    ghost_type = types,
64    position = position,
65  })
66  for i = 1, #ghosts do
67    entities[#entities + 1] = ghosts[i]
68  end
69  return entities
70end
71
72--- Ensure that the loader has the belt on the correct side.
73--- @param entity LuaEntity
74local function snap_direction(entity)
75  local offset_direction = entity.direction
76  if entity.loader_type == "input" then
77    offset_direction = flib_direction.opposite(offset_direction)
78  end
79  local container_position = flib_position.add(entity.position, offsets[offset_direction])
80
81  -- Case 1: If a container is in front, then flip the loader
82  local containers = find_entities(entity.surface, container_position, entity.force, container_types)
83  if #containers > 0 then
84    -- Check that it's not a composite loader entity
85    local is_composite = entity.surface.count_entities_filtered({
86      force = entity.force,
87      position = container_position,
88      type = { "loader", "loader-1x1" },
89    }) > 0
90    if not is_composite then
91      flip_loader(entity)
92      return
93    end
94  end
95
96  -- Case 2: If a belt is behind, then flip the loader
97  offset_direction = flib_direction.opposite(offset_direction)
98  local belt_position = flib_position.add(entity.position, offsets[offset_direction])
99  local belt = find_entities(entity.surface, belt_position, entity.force, belt_types)[1]
100  if not belt then
101    return
102  end
103
104  local belt_type = belt.type
105  if belt_type == "entity-ghost" then
106    belt_type = belt.ghost_type
107  end
108  if
109    belt_type == "transport-belt"
110    or belt_type == "underground-belt"
111    or math.abs(offset_direction - belt.direction) % 4 == 0
112  then
113    flip_loader(entity)
114  end
115end
116
117--- @param entity LuaEntity
118local function snap_to_belt(entity)
119  local offset_direction = entity.direction
120  if entity.loader_type == "input" then
121    offset_direction = flib_direction.opposite(offset_direction)
122  end
123  local belt_position = flib_position.add(entity.position, offsets[offset_direction])
124
125  local belt = find_entities(entity.surface, belt_position, entity.force, belt_types)[1]
126  if not belt then
127    return
128  end
129
130  local belt_direction = belt.direction
131  local belt_type = belt.type
132  if belt_type == "entity-ghost" then
133    belt_type = belt.ghost_type
134  end
135  if entity.direction == belt_direction then
136    -- Pass
137  elseif entity.direction == flib_direction.opposite(belt_direction) then
138    entity.loader_type = "input"
139  elseif belt_type == "transport-belt" or belt_type == "underground-belt" then
140    -- Sideloading
141    entity.loader_type = "output"
142  end
143end
144
145--- @param e EntityBuiltEvent
146local function on_entity_built(e)
147  if not loader_snapping_enabled then
148    return
149  end
150
151  local entity = e.entity or e.destination
152  if not entity.valid or not string.match(entity.name, "^kr.*%-loader$") then
153    return
154  end
155
156  entity.update_connections()
157  if not entity.loader_container then
158    snap_direction(entity)
159  end
160
161  snap_to_belt(entity)
162end
163
164remote.add_interface("kr_loader_snapping", {
165  --- Sets whether or not loader snapping is enabled. Setting is not preserved across save/load.
166  --- @param value boolean
167  set_enabled = function(value)
168    assert(type(value) == "boolean", "`value` must be a boolean")
169    loader_snapping_enabled = value
170  end,
171  --- Returns whether or not loader snapping is currently enabled.
172  get_enabled = function()
173    return loader_snapping_enabled
174  end,
175})
176
177--- @class LoaderSnappingHandler : event_handler
178local snap_loader = {}
179
180snap_loader.events = {
181  [defines.events.on_built_entity] = on_entity_built,
182  [defines.events.on_entity_cloned] = on_entity_built,
183  [defines.events.on_robot_built_entity] = on_entity_built,
184  [defines.events.script_raised_built] = on_entity_built,
185  [defines.events.script_raised_revive] = on_entity_built,
186  [defines.events.on_space_platform_built_entity] = on_entity_built,
187}
188
189return snap_loader