Skip to content

[DO:CityBlocks] Playtest fixes, and fix build restrictions being bypassable by bots - #1580

Merged
grilledham merged 3 commits into
Refactorio:developfrom
lex:city-blocks-fixes-and-bot-restriction
Aug 14, 2026
Merged

[DO:CityBlocks] Playtest fixes, and fix build restrictions being bypassable by bots#1580
grilledham merged 3 commits into
Refactorio:developfrom
lex:city-blocks-fixes-and-bot-restriction

Conversation

@lex

@lex lex commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Playtest findings on DO/City-Blocks, plus one shared-module bug that turned out to sit behind two of them.

DO/City-Blocks

Ore density halved. A room is 4x4 chunks of solid single-ore field, so at canonical richness one room outlasts anything you can build in it and clearing ground stops being a decision. Uses the existing ore_configs:scale_richness(0.5).

Rooms now keep a 3 tile ore-free band along their edge with the rail corridor. Previously the ore ran flush to the corridor, so a train stop or inserter needed a bay hand-mined first — nothing in a fresh room could be automated until it had been cleared by hand. The band keeps the room's ore tiles, so it looks the same, it just places no ore entity there.

Roboports are now allowed on the rail corridors. The rule was only denying tidy placement, not capability: logistics_radius is 25 and roboports merge into one network when their logistic zones touch, so two placed inside adjacent rooms already reach across a 32 tile corridor without anything ever standing on the corridor. Trains still move the tonnage; belts still cannot cross.

Corridor naming is unified on "rail corridor" (was variously strip, wall, corridor).

map_gen/shared/entity_placement_restriction.lua

This is the part that affects other maps.

Refunds never worked. The module read the item from event.consumed_items.get_contents()[1], which in 2.0 returns plain ItemWithQualityCount tables ({name, quality, count}) with no valid field, then gated the refund on stack.valid — always nil. Every entity the module destroyed was silently deleted and the item lost. The refund item now comes from the entity prototype's items_to_place_this with quality preserved.

Rules were bypassable with construction robots. Only on_built_entity was hooked, so any rule built on this module could be sidestepped by placing a ghost and letting bots finish it. It now hooks on_robot_built_entity too and refunds to the robot, so the item returns to the network.

Both changes apply to every map using the module:

Map Rule
danger_ores/presets/danger_ore_safety.lua DO/Safety-Ores — build only on ore
shared/danger_ore_banned_entities.luatoxic_danger_ore_jungle.lua belts/drills/poles only on ore
concrete_jungle.lua entities need a ground tier under them
dino_island.lua bans non-burner entities
rail_grid/rail_grid_restrictions.lua rails only on green tiles
crash_site/presets/steam_all_the_way.lua bans solar panels + accumulators
crash_site/presets/raining_bullets.lua bans laser turrets

The refund fix is a straight improvement everywhere. The robot hook is a gameplay tightening: on Raining Bullets, for example, you can currently ghost a laser turret and let bots finish it, and after this you cannot. That is the intent, but it is a behaviour change on live maps and worth a second opinion.

Not affected: the danger-ore ore restriction is modules/allowed_entities.lua, which already hooked both build events and already refunded via items_to_place_this. (modules/banned_entities.lua is dead code — nothing requires it.)

Known follow-up: Concrete Jungle

Both events can now fire with player_index = nil for robot builds. Five of the seven handlers read event.player and nil-guard it correctly. concrete_jungle.lua:304 does not, and it also reads event.entity, a field this module has never set — it sends created_entity. Since stack is a plain table in 2.0, stack.valid_for_read is always nil, so that handler falls into entity.name on a nil value on every player build already, i.e. it is broken on develop today independently of this PR. This PR adds a second path into it via robot builds.

Left out deliberately, as a fix there is a judgement call about another map's UX (the blueprint-vs-ghost warning can no longer be identified from the item stack). Happy to do it here instead if a Concrete Jungle owner would rather see it in one PR.

Also note that spill and the anti-grief callback are skipped for robot builds, since both take a player. Concrete Jungle is the only map using spill, and it only matters if bots fast-replace an entity that has items in it onto unsupported ground.

Changelog

Entries added under 2026-07-29 in map_gen/maps/danger_ores/changelog.lua.

🤖 Generated with Claude Code

lex and others added 2 commits July 29, 2026 23:14
Playtest findings on DO/City-Blocks, and one shared bug behind two of them.

Ore density is halved. A room is 4x4 chunks of solid single-ore field, so
at canonical richness one room outlasts anything built in it and clearing
ground stops being a decision.

Rooms now keep a 3 tile ore-free band along their edge with the rail
corridor. Previously the ore ran flush to the corridor, so a train stop
or inserter needed a bay hand-mined first and nothing in a fresh room
could be automated until it had been cleared by hand.

entity_placement_restriction never refunded anything. It read the item
from event.consumed_items.get_contents()[1], which in 2.0 returns plain
ItemWithQualityCount tables ({name, quality, count}) with no `valid`
field, then gated the refund on `stack.valid` - always nil, so every
entity it destroyed was silently deleted and the item lost. The refund
item now comes from the entity prototype with quality preserved, which
also works for robot builds, whose event carries no consumed_items at
all.

The module also only hooked on_built_entity, so every rule built on it
was bypassable with construction robots: place a ghost, let the bots
finish it. It now hooks on_robot_built_entity too and refunds to the
robot so the item returns to the network. This closes the same hole on
DO/Safety-Ores, which uses the module for its inverse rule.

Note for anyone chasing the same suspicion on the ore restriction: the
live ore rule is modules/allowed_entities.lua, and it already hooks both
build events and already refunds via items_to_place_this. It was not
affected. modules/banned_entities.lua is dead code with no requires.

Corridor naming is unified on "rail corridor" (was variously strip, wall
and corridor).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Players want them there for the same reason they would on any map, and
refusing costs nothing to protect: a roboport's logistics_radius is 25
and roboports join into a single network when their logistic zones
touch, so two placed inside adjacent rooms already reach across a 32
tile corridor. Bots could ferry between rooms without anything ever
standing on a corridor, so the rule was only denying the tidy placement,
not the capability. Trains still move the tonnage; belts still cannot
cross.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@grilledham grilledham left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the entity_placement_restriction.lua fix. One minor comment.

I can't remember the last time we played concrete jungle so probably not a priority to fix, but a fix in another PR would be welcome.

Comment thread map_gen/shared/entity_placement_restriction.lua Outdated
Review feedback: the note about consumed_items.get_contents() returning tables
with no valid field described the old code, not this code.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@grilledham
grilledham merged commit 9bfa704 into Refactorio:develop Aug 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants