[1.1.53] Map generation + chunk copying does not work correctly

Bugs that are actually features.
oof2win2
Long Handed Inserter
Long Handed Inserter
Posts: 56
Joined: Wed Nov 18, 2020 8:13 am
Contact:

[1.1.53] Map generation + chunk copying does not work correctly

Post by oof2win2 »

I am trying to create a surface "void" where chunks are generated. I then copy chunks from there onto the surface "battleground". The chunks are copied only from the bottom right quadrant (+x +y coordinates), with tiles being created by just multiplying the x and y values, which is much easier than performing any form of rotations etc. The issue is that a form of "lines" are created on battleground (the lines along the x and y axis are intended, please ignore those), where lab tiles are present, even though they should not be - see the attachment for an example. This must be an issue with map generation and the chunks being copied before Factorio generates the chunks itself, as there is no other rational explanation for this in my opinion.

If you run the code, you will need to teleport to battleground with /c game.player.teleport(game.player.position, "battleground"). Then you will need to generate chunks with /c local radius=400 game.player.force.chart(game.player.surface, {{x = -radius, y = -radius}, {x = radius, y = radius}}).

Code: Select all

script.on_init(function ()
    game.create_surface("void") -- origin surface of tiles + entities
	game.map_settings.pollution.enabled = false
	
    local battleground = game.create_surface("battleground")
	battleground.always_day = true
	battleground.generate_with_lab_tiles = true

	log("init done")
end)

---@param event EventData|on_player_created
script.on_event(defines.events.on_player_created, function (event)
	local player = game.get_player(event.player_index)
	local surface = game.get_surface("battleground")
	local position = surface.find_non_colliding_position_in_box("character", {{-2, -2}, {2, 2}}, 0.5, false)
	player.teleport(position or {0, 0}, "battleground")
end)

---Copy tiles across a surface. Copies tiles from the bottom right quadrant on originSurface
---@param originSurface LuaSurface
---@param targetSurface LuaSurface
---@param chunkPos ChunkPosition The position on the target surface that is meant to be copied to
---@param absPos ChunkPosition|nil Absolute position of the chunk - use {x=math.abs(x), y=math.abs(y)} to get this
local function copy_tiles(originSurface, targetSurface, chunkPos, absPos)
	if originSurface.name ~= "void" then log(originSurface.name) end
	local tiles = originSurface.find_tiles_filtered({
		area = {
			-- get the tile data from only one quadrant, positive positive (right bottom in factorio)
			left_top = {x = absPos.x * 32, y = absPos.y * 32},
			right_bottom = {x = (absPos.x + 1) * 32, y = (absPos.y + 1) * 32}
		}
	})

	-- multiplier for x and y values where tiles are to be set
	-- if they are less than 0 then they are flipped
	local yMultiplier = chunkPos.y >= 0 and 1 or -1
	local xMultiplier = chunkPos.x >= 0 and 1 or -1
	local toSetTiles = {}
	for _, tile in pairs(tiles) do
		table.insert(toSetTiles, {name = tile.name, position = {x = tile.position.x * xMultiplier, y = tile.position.y * yMultiplier}})
	end
	-- log(tostring(yMultiplier)  .. " " .. tostring(xMultiplier) .. " " .. serpent.line(chunkPos) .. serpent.line(absPos))
	if #toSetTiles == 0 then log("chunk not getting tiles set") end
	targetSurface.set_tiles(toSetTiles)
end

-- Handle chunks generateing
---@param event EventData|on_chunk_generated
script.on_event(defines.events.on_chunk_generated, function (event)
	local surface = event.surface
	local chunkPos = event.position

	-- we are not intersted in other surfaces
	if surface.name ~= "battleground" then return end

	-- this is so that the line in the middle is symetrical, it's intended to be a gap that is then filled with other stuff
	local tbl = { -- hashmap
			[0] = true
	}
    if tbl[chunkPos.x] or tbl[chunkPos.y] then return end -- there should be the river here

	-- FIXME: if the chunk is not generatd on_init then it doesnt work???
	-- if the chunk is generated on battleground, we want to copy the chunk from void
	local absPos = {x = math.abs(chunkPos.x), y = math.abs(chunkPos.y)}
	local void = game.get_surface("void")

	local alreadyGenerated = void.is_chunk_generated(absPos)
	if not alreadyGenerated then -- the chunk isnt present on void, so we need to request for generation
			-- the chunk is not generated so we tell factorio to generate it and let the handler below do the copy
			void.request_to_generate_chunks({
					-- * 32 because request_to_generate_chunks accepts Position but absPos is a ChunkPosition
					x = absPos.x * 32,
					y = absPos.y * 32,
			}, 1)
			void.force_generate_chunk_requests()
	end

	copy_tiles(void, surface, chunkPos, absPos)
end)
Attachments
Screenshot 2022-02-05 at 8.30.27.png
Screenshot 2022-02-05 at 8.30.27.png (285.85 KiB) Viewed 1271 times
User avatar
boskid
Factorio Staff
Factorio Staff
Posts: 3016
Joined: Thu Dec 14, 2017 6:56 pm
Contact:

Re: [1.1.53] Map generation + chunk copying does not work correctly

Post by boskid »

Thanks for the report, however there are no issues here in the game.

Your code is broken when it comes to handling of negative coordinates, it tries to set tiles on different chunk than what is reported by the event. Issues are mainly due to incorrect understanding the chunk coordinates system. In the center of the map where you have MapPosition of {0.0, 0.0}, there are 4 chunks that meet: chunks {0, 0}, {0, -1}, {-1, 0} and {-1, -1}. That means that your approach with the xMultiplier and yMultiplier is not working as it is supposed to.
Post Reply

Return to “Not a bug”