Page 1 of 1
[1.1.70] Crash when after mining other-force entity and then deleting other force
Posted: Mon Oct 31, 2022 10:14 pm
by Gerkiz
Hello,
We hosted our scenario Towny. Everything was all good and dandy - some players were playing and all of a sudden new players tried to join but couldn't.
Their client crashed to desktop.
I tried myself to join the server, but received the same error along with crash to desktop.
Attached is save and log.
Steps to reproduce hard crash:
1. Load save while holding CTRL
2. Crash
Steps to reproduce normal crash to menu:
1. Load save
2. Receive the following error:
Code: Select all
Entity [name=oil-refinery, type=assembling-machine, position={803.5000000000, -537.5000000000}, setup=false, owned-by-ghost=false, to-be-deconstructed=false, to-be-upgraded=false, simulation=true] belongs to invalid force index=6
/Gerkiz
Re: [1.1.70] Crash CraftingMachine::getRecipe()
Posted: Mon Oct 31, 2022 10:34 pm
by Hanakocz
It is very possible that this is caused by force being removed, e.q. when one team loses their base, some entities get destroyed via entity.die(), then
Code: Select all
game.merge_forces(force_name, 'neutral')
is called. That removes the force from the game, and should also get rid of all remaining entities by converting them into neutral force.
Previously, it wasn't producing a crash, just error on load (one example):
Code: Select all
21.711 Warning Map.cpp:347: Map loading failed: Entity [name=transport-belt, type=transport-belt, position={48.5000000000, 228.5000000000}, setup=false, owned-by-ghost=false, to-be-deconstructed=false, to-be-upgraded=false, simulation=true] belongs to invalid force index=7
22.086 Error AppManagerStates.cpp:1566: Entity [name=transport-belt, type=transport-belt, position={48.5000000000, 228.5000000000}, setup=false, owned-by-ghost=false, to-be-deconstructed=false, to-be-upgraded=false, simulation=true] belongs to invalid force index=7
I attach savefile that produces this error (was played on 1.1.69, produces the same error still even if loaded in 1.1.70), and I think the scenario's code didn't changed since then, and server was even running continuously just with quick restart to update the game version in between those two examples.
Re: [1.1.70] Crash CraftingMachine::getRecipe()
Posted: Mon Oct 31, 2022 10:36 pm
by Loewchen
Can you provide a set of commands that corrupts the save?
Re: [1.1.70] Crash CraftingMachine::getRecipe()
Posted: Mon Oct 31, 2022 10:42 pm
by Hanakocz
This is the function that is called when the team loses:
It is just our assumption that the cause of problem comes from that, as that's what is removing the forces (and it can go for days and plenty of teams being removed before it happens to get corrupted)
https://github.com/ComfyFactory/ComfyFa ... m.lua#L752
Code: Select all
local function kill_force(force_name, cause)
local this = ScenarioTable.get_table()
local force = game.forces[force_name]
local town_center = this.town_centers[force_name]
local market = town_center.market
local position = market.position
local surface = market.surface
local balance = town_center.coin_balance
local town_name = town_center.town_name
surface.create_entity({name = 'big-artillery-explosion', position = position})
local is_suicide = cause and force_name == cause.force.name
for _, player in pairs(force.players) do
this.spawn_point[player.index] = nil
this.cooldowns_town_placement[player.index] = game.tick + 3600 * 5
this.buffs[player.index] = {}
if player.character then
player.character.die()
else
this.requests[player.index] = 'kill-character'
end
player.force = game.forces.player
Map.disable_world_map(player)
Public.set_player_color(player)
Public.give_key(player.index)
end
for _, e in pairs(surface.find_entities_filtered({force = force_name})) do
if e.valid then
if destroy_military_types[e.type] == true then
surface.create_entity({name = 'big-artillery-explosion', position = position})
e.die()
elseif destroy_robot_types[e.type] == true then
surface.create_entity({name = 'explosion', position = position})
e.die()
elseif destroy_wall_types[e.type] == true then
e.die()
elseif storage_types[e.type] ~= true then -- spare chests
local random = math_random()
if random > 0.5 or e.health == nil then
e.die()
elseif random < 0.25 then
e.health = e.health * math_random()
end
end
end
end
local r = 27
for _, e in pairs(surface.find_entities_filtered({area = {{position.x - r, position.y - r}, {position.x + r, position.y + r}}, force = 'neutral', type = 'resource'})) do
if e.name ~= 'crude-oil' then
e.destroy()
end
end
game.merge_forces(force_name, 'neutral')
this.town_centers[force_name] = nil
delete_chart_tag_for_all_forces(market)
-- reward the killer
local message
if is_suicide then
message = town_name .. ' has given up'
elseif cause == nil or not cause.valid or cause.force == nil then
message = town_name .. ' has fallen to an unknown entity (DEBUG ID 0)!' -- TODO: remove after some testing
elseif cause.force.name == 'player' or cause.force.name == 'rogue' then
local items = {name = 'coin', count = balance}
town_center.coin_balance = 0
if balance > 0 then
if cause.can_insert(items) then
cause.insert(items)
else
local chest = surface.create_entity({name = 'steel-chest', position = position, force = 'neutral'})
chest.insert(items)
end
end
if cause.name == 'character' then
message = town_name .. ' has fallen to ' .. cause.player.name .. '!'
elseif cause.force.name == 'player' then
message = town_name .. ' has fallen to outlanders!'
elseif cause.force.name == 'rogue' then
message = town_name .. ' has fallen to rogues!'
else
message = town_name .. ' has fallen to an unknown entity (DEBUG ID 1)!' -- TODO: remove after some testing
end
elseif cause.force.name ~= 'enemy' then
if this.town_centers[cause.force.name] ~= nil then
local killer_town_center = this.town_centers[cause.force.name]
if balance > 0 then
killer_town_center.coin_balance = killer_town_center.coin_balance + balance
cause.force.print(balance .. ' coins have been transferred to your town')
end
if cause.name == 'character' then
message = town_name .. ' has fallen to ' .. cause.player.name .. ' from ' .. killer_town_center.town_name .. '!'
else
message = town_name .. ' has fallen to ' .. killer_town_center.town_name .. '!'
end
else
message = town_name .. ' has fallen to an unknown entity (DEBUG ID 2)!' -- TODO: remove after some testing
log('cause.force.name=' .. cause.force.name)
end
else
message = town_name .. ' has fallen to the biters!'
end
Server.to_discord_embed(message)
game.print('>> ' .. message, {255, 255, 0})
end
local function on_forces_merged()
-- Remove any ghosts that have been moved into neutral after a town is destroyed. This caused desyncs before.
for _, e in pairs(game.surfaces.nauvis.find_entities_filtered({force = 'neutral', type = 'entity-ghost'})) do
if e.valid then
e.destroy()
end
end
end
Re: [1.1.70] Crash when after mining other-force entity and then deleting other force
Posted: Tue Nov 01, 2022 4:56 pm
by Rseding91
OK I figured out what went wrong:
* Player on force A mines friendly entity on force B
* Force B is deleted
* Entity from force B exists in payer A's undo queue
When deleing forces entities on that force in other players undo queues are not properly transferred.
Re: [1.1.70] Crash when after mining other-force entity and then deleting other force
Posted: Tue Nov 01, 2022 8:47 pm
by Rseding91
Thanks for the report and the additional information. The underlying issue is now fixed for the next release. The save file is in a broken state so it won't be usable.
Re: [1.1.70] Crash when after mining other-force entity and then deleting other force
Posted: Fri Nov 04, 2022 9:44 pm
by blubFisch
Great, thanks!
I don't know if it's relevant, but for me, this bug was triggered only sometimes. If I load the same save 5 times, 3 times it fails while 2 times it loads fine.