[2.0.19] Mod using get_blueprint_entities fails when building directly from blueprint library
Posted: Mon Nov 18, 2024 1:09 am
1. What did you do?
I am working to update a mod for 2.0 that intercepts blueprint construction requests in the on_pre_build() event. It searches the get_blueprint_entities() list for instances the modded entities to do some additional setup.
Specifically, it adds a hook to on_pre_build() that executes the following code snippet:
if player.is_cursor_blueprint() then
local entities = nil
if player.cursor_stack and player.cursor_stack.is_blueprint_book then
local bp = player.cursor_stack.get_inventory(defines.inventory.item_main)[player.cursor_stack.active_index]
entities = bp.get_blueprint_entities()
elseif player.cursor_stack and player.cursor_stack.is_blueprint then
local bp = player.cursor_stack.item
entities = bp.get_blueprint_entities()
elseif player.cursor_record and (player.cursor_record.type == "blueprint-book" or player.cursor_record.type == "blueprint") then
entities = player.cursor_record.get_blueprint_entities()
end
... continues
2. What happens?
In the examples below blueprints of a single entity are sufficient (no modded content required). Starting a new freeplay game and placing the stone furnace is enough as long as you have preexisting blueprints and blueprint books in your blueprint library.
[works] Copy/paste (ctrl-c, ctrl-v) works via player.cursor_stack.is_blueprint
[works] Copying, placing the result into the inventory (or directly on the quickbar), then selecting and placing the blueprint via player.cursor_stack.is_blueprint
[works] Selecting a blueprint book from inventory, scroll-selecting a blueprint, and placing it via player.cursor_stack.is_blueprint_book
[works] Opening the blueprint library, selecting a blueprint, and placing it via blueprint.cursor_record
[crash] Opening the blueprint library, selecting a blueprint book, scroll-selecting a blueprint, and placing it
The failure when sourcing from the library occurs as the player.cursor_stack == nil. Then, although player.cursor_record is a LuaRecord and player.cursor_record.type == "blueprint-book", the call to player.cursor_record.get_blueprint_entities() crashes with "Record is not a BlueprintRecord."
When player.cursor_record.type == "blueprint" (i.e., the fourth scenario) the call to player.cursor_record.get_blueprint_entities() works as expected.
3. What did you expect to happen?
From the LuaRecord API page, I expected player.cursor_record to properly be a BlueprintBookRecord when it's type was "blueprint-book."
Access to the currently-selected blueprint in the cursor should behave correctly regardless of the source of a blueprint (and blueprint-book). At minimum, I would expect read-only access to the selected blueprint through the player.cursor_stack (as an item) or player.cursor_record (as a library entry).
Tangentially: When selecting a blueprint directly from the Blueprint Library, player.cursor_record does populate with data but there is nothing like an active_index into player.cursor_record.contents[???] or player.cursor_record.get_active_blueprint(). Perhaps there is some complication with nested blueprints.
References: viewtopic.php?p=597386
4. Does it happen always, once, or sometimes?
Consistently replicated from a new game.
I am working to update a mod for 2.0 that intercepts blueprint construction requests in the on_pre_build() event. It searches the get_blueprint_entities() list for instances the modded entities to do some additional setup.
Specifically, it adds a hook to on_pre_build() that executes the following code snippet:
if player.is_cursor_blueprint() then
local entities = nil
if player.cursor_stack and player.cursor_stack.is_blueprint_book then
local bp = player.cursor_stack.get_inventory(defines.inventory.item_main)[player.cursor_stack.active_index]
entities = bp.get_blueprint_entities()
elseif player.cursor_stack and player.cursor_stack.is_blueprint then
local bp = player.cursor_stack.item
entities = bp.get_blueprint_entities()
elseif player.cursor_record and (player.cursor_record.type == "blueprint-book" or player.cursor_record.type == "blueprint") then
entities = player.cursor_record.get_blueprint_entities()
end
... continues
2. What happens?
In the examples below blueprints of a single entity are sufficient (no modded content required). Starting a new freeplay game and placing the stone furnace is enough as long as you have preexisting blueprints and blueprint books in your blueprint library.
[works] Copy/paste (ctrl-c, ctrl-v) works via player.cursor_stack.is_blueprint
[works] Copying, placing the result into the inventory (or directly on the quickbar), then selecting and placing the blueprint via player.cursor_stack.is_blueprint
[works] Selecting a blueprint book from inventory, scroll-selecting a blueprint, and placing it via player.cursor_stack.is_blueprint_book
[works] Opening the blueprint library, selecting a blueprint, and placing it via blueprint.cursor_record
[crash] Opening the blueprint library, selecting a blueprint book, scroll-selecting a blueprint, and placing it
The failure when sourcing from the library occurs as the player.cursor_stack == nil. Then, although player.cursor_record is a LuaRecord and player.cursor_record.type == "blueprint-book", the call to player.cursor_record.get_blueprint_entities() crashes with "Record is not a BlueprintRecord."
When player.cursor_record.type == "blueprint" (i.e., the fourth scenario) the call to player.cursor_record.get_blueprint_entities() works as expected.
3. What did you expect to happen?
From the LuaRecord API page, I expected player.cursor_record to properly be a BlueprintBookRecord when it's type was "blueprint-book."
Access to the currently-selected blueprint in the cursor should behave correctly regardless of the source of a blueprint (and blueprint-book). At minimum, I would expect read-only access to the selected blueprint through the player.cursor_stack (as an item) or player.cursor_record (as a library entry).
Tangentially: When selecting a blueprint directly from the Blueprint Library, player.cursor_record does populate with data but there is nothing like an active_index into player.cursor_record.contents[???] or player.cursor_record.get_active_blueprint(). Perhaps there is some complication with nested blueprints.
References: viewtopic.php?p=597386
4. Does it happen always, once, or sometimes?
Consistently replicated from a new game.