Milestones

by Wiwiweb

Keep track of your progress in a fun way by finding out how fast you created key items. Look back on your factory's history, compare with your friends, or challenge yourself. Supports any list of items and comes with presets for popular big mods. Can be added to existing games.

Utilities
5 days ago
1.1 - 2.0
261K

g Crash when playing with Brave New Oarc

5 months ago
(updated 5 months ago)

I'm dev for BNO, this is a mod that supports multiplayer. Milestones crashes in on_player_changed_force while updating the gui, since the global.player array is not updated, due to how BNO works.

I did some debugging and at on_init time no player has joined yet, so the game.players list is empty.

on_init:

     for _, player in pairs(game.players) do
        initialize_player(player)
    end

does nothing because the number of players is 0 at this point.

Then an event for on_player_changed_force triggers which initializes the force, but not the global.players array. The call to refresh_gui_for_player accesses global.players without initializing and results in a crash in gui.lua function get_frame, where it loads the global.players[player_index] - which is nil.

Easiest way to see this is just run brave new oarc with milestones and start a single player game in the debugger. Put a break in on_player_changed_force.

Maybe initialize_force_if_needed could also initialize players as you do in on_init.

Nice work !

5 months ago
(updated 5 months ago)

I did a bit more digging, MileStones expected on_player_created to be called first, but BNO forces on_player_changed_force to be called first since it removes a player and changes it's force if the host created the game from a single player save. Here is a fix that works:

This is a copy from your code - with initialize_player added for both events mentioned above:

script.on_event(defines.events.on_player_changed_force, function(event)
    local player = game.get_player(event.player_index)
    if not global.players[player.index] then           -- <- added block
        initialize_player(player)
    end
    initialize_force_if_needed(player.force)
    refresh_gui_for_player(player)
end)

script.on_event(defines.events.on_forces_merged, function(event)
    clear_force(event.source_name)
end)

script.on_event(defines.events.on_player_created, function(event)
    local player = game.players[event.player_index]
    if not global.players[player.index] then            -- <- added if 
        initialize_player(player)
    end
    if global.forces[player.force.name] == nil then -- Possible if new player is added to empty force e.g. vanilla freeplay
        initialize_force_if_needed(player.force)
    end
end)

New response