Entity Replacement System
PlanetsLib allows you to quickly generate planet-exclusive variants of entities. On placing an entity on a planet with a planet-exclusive variant, PlanetsLib will replace the original entity with your variant. The difference between entity variants and the original entity are invisible to the user, and variants can not be seen in the Factoriopedia. Every variant must be associated with a boolean startup setting that can be disabled to ease in uninstallation. Once an entity variant has been created, any attempt to create a variant for the same entity for the same planet will throw an error. This is a limitation of the current system that may change in the future. Currently, entity variants that are the same type as their origin entity are well-tested, but changing entity types is untested.
Known issues: Variant entities will be the same fast_replaceable_group as the entity they're based on. This makes it possible to place over the variant entity with the entity's item. This is an engine limitation.
PlanetsLib.create_planet_entity_variant(planet_names(table of strings or string),entity(table),new_properties(table),bound_setting(startup setting name),item_name(defaults to entity name))– Creates and adds to data.raw a variant ofentitywith a unique name, the same localized name/description, and new properties taken from new_properties. Whenentityis placed on planet during gameplay, PlanetsLib will replace entity with new_entity.bound_settingis a boolean startup setting. This entity variant is only placed when this startup setting is enabled. When disabling this startup setting on an existing save, variant entities are migrated back to their original entities when appropriate. When enabling this startup setting on an existing save, variant entities are migrated from their original entities when appropriate. To aid in mod uninstallation, expose this setting to users.PlanetsLib.assign_entity_replacement(planet,entity,new_entity,bound_setting)– Whenentityis placed on planet during gameplay, PlanetsLib will replace entity with new_entity. Due to current system limitations, assigning an entity replacement of the same entity onto the same planet will throw an error. Not recommended for regular use due to the lack of safety checks compared to PlanetsLib.create_planet_entity_variant().planet = "space-platform"causes this function to map a replacement to all space platforms.
Example
-- In settings.lua
data:extend{{
name = "enable-chemical-plant-replacement",
type = "bool-setting",
default_value=true,
setting_type="startup"
}}
-- In data-updates.lua
for _,planet in pairs(data.raw.planet) do
-- Create a chemical plant variant for each planet with a randomly chosen crafting speed.
PlanetsLib.create_planet_entity_variant(planet.name,data.raw["assembling-machine"]["chemical-plant"],{crafting_speed = math.random(1,50)},"enable-chemical-plant-replacement")
end
Example using existing entity
-- In settings.lua
data:extend{{
name = "enable-chemical-plant-replacement",
type = "bool-setting",
default_value=true,
setting_type="startup"
}}
-- In data.lua
local replacement_entity = data.raw["assembling-machine"]["replacement-entity"] --Entity already created by other means
--Create entity replacement rule from already existing entities
PlanetsLib.assign_entity_replacement("vulcanus","chemical-plant",replacement_entity.name,"enable-chemical-plant-replacement")
Entity variant migrations
On adding new entity replacement rules to an existing save or disabling old replacement rules, PlanetsLib will perform a runtime migration on all entities in violation of the current ruleset to comply with the new ruleset. This process includes copying the settings, wire connections, inventories, fluidbox contents, health, crafting progress, and a myriad of other settings associated with entities. This process is not perfect, so reports of incomplete migrations are welcome.
Safely disabling an entity replacement rule
Each entity replacement rule must be associated with a startup setting, defined with bound_setting. When this setting is enabled, entity replacements are active. When this setting is disabled, variant entities are generated in data, allowing saves with obsolete rules to load without deleting any entities. However, on loading a save, all variant entities that should not exist under the current ruleset are replaced with their original entity, reverting all replacements performed under that rule.
To safely remove an entity replacement from the game, disable the associated startup setting, load the save to allow the migration to occur, then remove the mod. When updating a mod to revert an entity replacement rule, apply a conventional migration to all affected entities, or if not possible, hide and force disable the associated setting, rather than deleting code adding the replacement rule. After you are ready to make old saves break their migration, you can delete the associated code.
Making your entity compatible with PlanetsLib's entity replacement script
If you have a script-augmented entity and a PlanetsLib entity replacement targets your entity, PlanetsLib.constants.entity_variants_list contains a list of entity variants for each entity. For scripted entity "scripted_entity", A list of variant entities will be found in PlanetsLib.constants.entity_variants_list["scripted_entity"] if any exist. To make your script-augmented entity compatible, add entities from this list to any entity name checks in your control stage. If PlanetsLib replaces an entity tracked in your mod's storage, remote.call("planetslib_entity_replacement","get_replacement",entity_unit_number) will return the LuaEntity that replaced your entity. Use this function to repair stale references.
- Custom event:
PlanetsLib.events.on_entity_replaced(event) - Runs when PlanetsLib replaces an entity. Use this event to change variables associated with script-augmented entities to refer to the new entity.
eventfields:entity(LuaEntity): The entity about to be deleted.new_entity(LuaEntity): The entity that has hadentity's settings and inventory transferred to.
Appendix
PlanetsLib.create_planet_entity_variant steps
PlanetsLib.create_planet_entity_variant(planet_names,entity,new_properties,bound_setting,item_name)
This section describes the steps taken by create_planet_entity_variant to help explain possible incompatibilities.
On calling function in data stage:
- Generate a deepcopy of
entity. This will be namednew_entity. - Append
"-PlanetsLib-{first_planet}"tonew_entity's name, giving it a unique name. Ifplanet_namesis a table,first_planetisplanet_names. If it's a table,first_planetisplanet_names[1]. - Set the fields of
new_entitysuch that the external appearance ofnew_entityis the same asentity. This includes copyingentity's localised_name and localised_description, redirecting Factoriopedia requests toentity, hidingnew_entityfrom Factoriopedia, adding entity flags hiding the entity from "made-in" and from the bonus gui, and overridingplaceable_byto beitem_name. If item_name is undefined anddata.raw["item"][entity.name]exists,item_namewill use this item. - While it's possible to almost fully hide the existence of variant entities, they will still appear in upgrade planners. To make variant entity icons visually distinct from their original, the sprite of the planet this variant entity is intended for will be added to the top right corner of the variant entity's icon.
- To allow additional customization,
new_entityandnew_propertieswill be merged into one table, with each top-level key innew_propertiesoverriding the value of the same top-level key. - Using
PlanetsLib.create_planet_entity_variant,new_entityis registered as a replacement forentityon each planet inplanet_namesif it's a list, or onplanet_namesif it is not a list. This tells PlanetsLib's control script "Ifentityplaced on this planet, delete it and replace it withnew_entity." Ifbound_settingis currently enabled by the user, continue to register the rule, but set itsenabledfield tofalse. new_entityis added todata.raw.
In control stage:
On configuration changed:
- If any entity replacement rules have changed since last save. Perform a migration.
- During a migration, each entity replacement rule is evaluated, and entities on each surface not matching the rule are replaced. If the rule is not enabled by the user, reverse replacements made by the rule. If the rule is enabled, perform replacements that should have been made by the rule.
On placing entity:
- On placing an
entityonplanet, if PlanetsLib.constants. on_entity_placed_on_planet_replacements[planet][entity] exists, this tells PlanetsLib thatentityis intended to be replaced onplanet. - If
enabled== true, execute the rule, replacingentitywithnew_entity. - Transfer settings, inventory, and other information from the old entity to the new entity.