Eneas


Above the clouds of Nauvis lies the ancient moon Eneas. Not only does it hold secrets concerning the history of this star system, it is also home to an enigmatic machine called unit-05. Eneas does not modify vanilla content, only adds new items and recipes. It also contains improvements to early game progression and a database for factorio lore enthusiasts. >0.6.11 should fix multiplayer issues but keep me updated

Content
3 months ago
2.0 - 2.1
9.40K
Planets

b Server crash: late_memory reward references Construction_Drone without checking Construction_Drones_Forked

7 days ago

Factorio 2.1.24 (build 87808), Eneas 1.0.10

Summary

The multiplayer server crashes with a non-recoverable error when a player
has researched friend-tech and the Eneas pollution check reaches the
medium level.

Error

Error while running event moon-eneas::on_nth_tick(60)
Unknown item name: Construction_Drone

stack traceback:
[C]: in function 'insert'
moon-eneas/prototypes/scripts/events.lua:825: in function 'deliver_supplies_to_lift'
moon-eneas/prototypes/scripts/events.lua:923: in function 'execute_pollution_check'
moon-eneas/prototypes/scripts/events.lua:1121: in function <events.lua:1100>

MultiplayerManager failed: "The mod moon-eneas (1.0.10) caused a non-recoverable error."
ServerMultiplayerManager.cpp:809: updateTick(...) changing state from(InGame) to(Failed)

Cause

SUPPLY_REWARDS.late_memory in prototypes/scripts/events.lua
(line 98-101) references Construction_Drone unconditionally:

late_memory = {
    tech_required = "friend-tech",
    items = {["Construction_Drone"] = {min = 1, max = 1}},
}

Construction_Drone is only provided by Construction_Drones_Forked.
The same file already guards other places correctly:

-- events.lua line 34-40
if script.active_mods["Construction_Drones_Forked"] then
    table.insert(DEBRIS_CONFIG.bonus_loot_table, {
        "Construction_Drone",
        1,
        1
    })
end

-- scripts/message.lua line 145
if script.active_mods["Construction_Drones_Forked"] then
    add_tech("lamp",{ ... supply_drop = {quality = "normal",
        items = {["Construction_Drone"] = 3}} })
end

Only late_memory is missing the check.

Why it does not always crash

create_scaled_rewards filters out zero amounts:

scaled_amount = math.floor(base_amount * pollution_multiplier * yield_multiplier)

With medium pollution (pollution_multiplier = 1.0) and servofish in
healthy state (servofish_multiplier = 1.5):

floor(1 * 1.0 * 1.5) = 1   -> item kept -> crash

With servofish in critical (0.25) or low / overpopulated (0.75):

floor(1 * 1.0 * 0.25) = 0  -> item skipped -> no crash

That is why the crash only appears when the fish population is healthy.

Reproduction

  1. Install Eneas 1.0.10 without Construction_Drones_Forked
  2. Build on the Eneas surface so that pollution rises above 500
  3. Keep the servofish population between 50 and 75 (healthy)
  4. Research friend-tech
  5. Wait for the next pollution check cycle (15 minutes)
  6. Server crashes

Suggested fix

late_memory = {
    tech_required = "friend-tech",
    items = script.active_mods["Construction_Drones_Forked"]
        and {["Construction_Drone"] = {min = 1, max = 1}}
        or {},
}

pairs({}) is a no-op in both build_reward_table (line 752)
and deliver_supplies_to_lift (line 816), so an empty table is safe.

If you prefer to always give something, an Eneas-native item works too:

items = script.active_mods["Construction_Drones_Forked"]
    and {["Construction_Drone"] = {min = 1, max = 1}}
    or {["eneas-artifact"] = {min = 20, max = 40}},

Related: a second missing nil check

prototypes/patches/construction-drones.lua line 15:

local Drone = data.raw.unit["normal-Construction_Drone"]
Drone.run_animation = { ... }

Drone can be nil if another mod removes that unit. Suggest:

local Drone = data.raw.unit["normal-Construction_Drone"]

if Drone then
    Drone.run_animation = { ... }
end

The file is already guarded by if mods["Construction_Drones_Forked"]
in data-final-fixes.lua:7, so this is defensive only.

New response