Page 1 of 1
Blueprint entity positioning
Posted: Tue May 23, 2017 9:13 pm
by SyncViews
Trying to work out how the game is positioning entities in blueprints to allow scripted edits, but I am finding the game seems to use 2 different coordinate systems and the blueprint wont build correctly if I position something wrongly.
Normally for entities/tiles on a surface tiles are at integer coordinates, and entities are positioned by their centre with the tile top-left being an integer. e.g. a tile may be at 10,12 and an inserter on it would be 10.5,12.5.
But in blueprints, most of the time it seems to me the entities are shifted by -0.5 compared to what I expect, except in some cases (I think if track is present).
Does anyone have any idea exactly what is going on here? Is it always shifted for some reason if a curved-rail or straight-rail is not present?
e.g. in these the belts are both in the same place relative to the hazard tiles. But when I create a blueprint with and without track, and look at the entities in the blueprint, they are positioned differently.
Without track:
Code: Select all
0eNqNkd1qwzAMhV8l07UNW2j346foRWEXYwwnEYmYYwdbKc1C3n1y2sFgGfRSsvSdo+MZKjfiEMkzmBmoDj6BeZshUeutyz2eBgQDxNiDAm/7XHG0Pg0hsq7QMSwKyDd4BvOwvCtAz8SEF9JaTB9+7CuMMvAfQ8EQkqwFn1UFpWV0ykQFDUWsL0/lov4wy5uZ99tI8czkroa3bWgR/lHp7JeNjZaw6oiMOlLb5RDmbbkbVsXAGrD59R8KnJUrpHd3xMSFLg5XOvlWqlfiLoxcHKOtP2X6hDGt0o+7XbkvX/bPT+WyfAOl66CW
Entities:
{entity_number=1,name="transport-belt",position={x=-1,y=1},direction=2}
{entity_number=2,name="transport-belt",position={x= 0,y=1},direction=2}
Tiles:
{position={x=-1,y=-2},name="hazard-concrete-right"}
{position={x= 0,y=-2},name="hazard-concrete-right"}
With track:
Code: Select all
0eNqNkt1ugzAMhV+F+TqpCiv74Sl2UWkX0zQFsMAaBJS40xji3eek3VR1P+1NJCc53zmxM0PZ7XB0ZBmKGagarIfiaQZPjTVd2ONpRCiAGHtQYE0fKmeog0UB2RrfoUgXdVbCzlg/Do51iR0fibPlWQFaJibcm8dierG7vkQn9G+GFwg1Levor2AcvKgGG0yFtFYwySromhxW+5MsZDshZn+l+oHU61UeqekqP8+9vpj7D1a6wdQdWnEaJ40qLeZfTq35MK7WMrnKIaN2oUEQwv3anQukEiCOrjj6HAo6Iy+Rvastek508nCgk22keiRuk60z1atcfUPno+/NZpPl2X1+d5styyf088yQ
Entities:
{entity_number=1,name="straight-rail", position={x= 0 ,y=0 },direction=2}
{entity_number=2,name="transport-belt",position={x=-0.5,y=1.5},direction=2}
{entity_number=3,name="transport-belt",position={x= 0.5,y=1.5},direction=2}
Tiles:
{position={x=-1,y=-2},name="hazard-concrete-right"}
{position={x= 0,y=-2},name="hazard-concrete-right"}
]
Re: Blueprint entity positioning
Posted: Wed May 24, 2017 1:40 am
by Rseding91
To get the actual location an entity will be built at in the world we do this logic:
Code: Select all
RealPosition Blueprint::getBuildingPosition(const RealPosition& position) const
{
if (this->isPlaceableOffGrid())
return position;
uint8_t buildingGridBitShift = this->getBuildingGridBitShift();
TilePosition tiledResult = position;
tiledResult.roundToGridBitShift(buildingGridBitShift);
RealPosition result(tiledResult.x, tiledResult.y);
result.x += (1 << buildingGridBitShift) * 0.5;
result.y += (1 << buildingGridBitShift) * 0.5;
return result;
}
void TilePosition::roundToGridBitShift(uint8_t shift)
{
this->x = (this->x >> shift) << shift;
this->y = (this->y >> shift) << shift;
}
Where
this->isPlaceableOffGrid() is true when all tiles and all entities in the blueprint have the prototype flag placeable off grid (
http://lua-api.factorio.com/latest/LuaE ... e.has_flag).
Where
uint8_t buildingGridBitShift = this->getBuildingGridBitShift(); is the max grid bit shift value of every entity prototype (
http://lua-api.factorio.com/latest/LuaE ... _bit_shift).
And then everything in the blueprint is shifted by that result and put in the world.
Re: Blueprint entity positioning
Posted: Wed May 24, 2017 9:44 am
by SyncViews
At least from the entities I tested, is 1 for train-stop, curved-rail and straight-rail and zero elsewhere, but is coded to the type, not the prototype data (e.g. I saw no property to allow a train stop which has shift=1 on any tile along a straight track like signals which have shift=0)?
Code: Select all
withoutTrack->getBuildingPosition({1,1})
buildingGridBitShift = 0
roundToGridBitShift = (1 >> 0) << 0 = 1
result.x = 1 + (1 << 0) * 0.5 = 0.5
return {1.5,1.5}
(0.5,0.5) extra shift
withTrack->getBuildingPosition({1,1})
buildingGridBitShift = 1
roundToGridBitShift = (1 >> 1) << 1 = 0
result.x = 0 + (1 << 1) * 0.5 = 0 + 1 = 1
return {1,1}
No extra shift
Which then looks to give me the same results for both blueprints if I adjust the entities by that, and I round the shift down to an integer for tiles (so both {0,0} in this case)? The tile thing still slightly confuses me, since in the two blueprints I looked at, the relative positions of tiles and belts changed.
There also seems to be some extra rounding of individual entities when placing a blueprint if I got it wrong. I think this is what I ran into before, entities jump or get skipped, but the pre-place outline and preview look right. Which would be what create_entity does on a per entity basis.
Then when creating (or updating/editing) a blueprint I can just use the inverse of those shifts for a {1,1} origin to adjust it (will test when home)?
Re: Blueprint entity positioning
Posted: Fri Jul 21, 2017 7:35 pm
by Reika
I realize this thread is a couple months inactive, but I find it relevant once again:
I am facing an issue due to item-in-blueprint placement, in my case involving walls and turrets (though I suspect other entities would end up being the same).
Basically, if I inject the items into the blueprint directly, using the above-supplied logic, then the blueprint "place preview"
looks correct, but the turrets are placed off-position (usually failing to place at all due to intersection):
If I manually adjust the positions, however, the
preview now breaks, but the placement is correct:
However, that latter case only works for one rotation; rotating the blueprint breaks placement as well:
Also, the blueprint needs to be saved and reopened for the turrets to display at all; the 'first preview' only shows the walls:
Relevant code:
Code: Select all
local function roundToGridBitShift(position, shift)
position.x = bit32.lshift(bit32.rshift(position.x, shift), shift)
position.y = bit32.lshift(bit32.rshift(position.y, shift), shift)
return position
end
local function getPositionForBPEntity(entity)
local position = entity.position
if (entity.has_flag("placeable-off-grid")) then
return position
end
local buildingGridBitShift = entity.building_grid_bit_shift
local tiledResult = position
tiledResult = roundToGridBitShift(tiledResult, buildingGridBitShift)
local result = {x=tiledResult.x, y=tiledResult.y}
result.x = result.x + bit32.lshift(1, buildingGridBitShift) * 0.5
result.y = result.y + bit32.lshift(1, buildingGridBitShift) * 0.5
return result
end
script.on_event(defines.events.on_player_setup_blueprint, function(event)
local player = game.players[event.player_index]
local surface = player.surface
local bp = player.cursor_stack
local flag = false
local entities = surface.find_entities_filtered({force = player.force, area = event.area})
local forbp = {}
local avgpos = {x=0, y=0}
for _,entity in pairs(entities) do
local ename = entity.name
local pos = entity.position
if string.find(entity.name, "rangeboost") then
flag = true
ename = getTurretBaseName(entity)
--pos.x = pos.x+1 --These are the lines that break/fix the preview and placement
--pos.y = pos.y+1
end
table.insert(forbp, {entity_number=#forbp, name=ename, position=pos, direction=entity.direction})
avgpos.x = avgpos.x+entity.position.x
avgpos.y = avgpos.y+entity.position.y
end
if not flag then return end
avgpos = {x=avgpos.x/#forbp, y=avgpos.y/#forbp}
for _,entry in pairs(forbp) do
entry.position.x = entry.position.x-avgpos.x
entry.position.y = entry.position.y-avgpos.y
end
bp.set_stack({name=event.item, count=1}) --since always invalid
game.print("BPing " .. #forbp .. " entities:")
for _,v in pairs(forbp) do game.print(v.name .. " @ " .. v.position.x .. ", " .. v.position.y) end
bp.clear_blueprint()
bp.set_blueprint_entities(forbp)
end)
Re: Blueprint entity positioning
Posted: Fri Jul 21, 2017 8:23 pm
by Reika
Two updates:
One, the broken offset seems to apply to all 2x2 entities, not just turrets (it also affects the logistics expander next to the coal belt).
Two, decimal "correction offsets" yield interesting results: 0.5 makes the "default" orientation work in both preview and place, but does not fix the rotated versions. Anything else (including 0.33, 0.25, 0.1875 and similar) act the same as zero.
Re: Blueprint entity positioning
Posted: Fri Jul 21, 2017 10:54 pm
by SyncViews
Would have to check turrets, but dont recall them being special, only rails. Because adding such an item might need to change the entire blueprint, I coded my logic to use "real coordinates" (as they would end up in the world if you placed the blueprint at 0,0), and applied the shift only on import/export. Worked for all the blueprints / placeable objects I tried allthough it is still really strange since it changes the relative coordinates of tiles and entities.
Factorio seems to generally snap invalid coordinates to grid, but does so differentlyvfor preview and actual placement. If some of these snapped positions cause collisions, those entities are not placed.
Re: Blueprint entity positioning
Posted: Sat Jul 22, 2017 3:32 am
by Reika
SyncViews wrote:I coded my logic to use "real coordinates" (as they would end up in the world if you placed the blueprint at 0,0), and applied the shift only on import/export.
Can you elaborate? I cannot find any hooks for
placing (ie exporting) blueprints and I followed the above post by Rseding exactly (as you presumably did) yet got poor results.
Re: Blueprint entity positioning
Posted: Sat Jul 22, 2017 1:25 pm
by SyncViews
So as in before I did any transforms/alterations, I took all the entities in the blueprint and adjusted them as described.
Then i added,removed,etc entities using those positions.
Then did the reverse transform to put them back in the blueprint.
To do stuff in mods the relevant methods are on the LuaItemStack object (where the stack contains a blueprint).
Re: Blueprint entity positioning
Posted: Sat Jul 22, 2017 5:53 pm
by Reika
SyncViews wrote:So as in before I did any transforms/alterations, I took all the entities in the blueprint and adjusted them as described.
Again, what do you mean
exactly? I "adjusted them as described" and it did not work.
SyncViews wrote:
Then i added,removed,etc entities using those positions. Then did the reverse transform to put them back in the blueprint.
....Wait, what?