1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2025-01-08 00:39:30 +02:00

Merge pull request #114 from mattNeumayer/perf_fix

Biter Battle: Improve terrain generation performance
This commit is contained in:
MewMew 2020-01-07 01:52:49 +01:00 committed by GitHub
commit 3ec2142a47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 173 additions and 109 deletions

View File

@ -107,6 +107,22 @@ local function process_entity(surface, entity)
entity_copy_functions[entity.type](surface, entity, mirror_position)
end
local function mirror_tiles(surface, source_area)
mirrored = {}
local i = 0
for x = source_area.left_top.x, source_area.left_top.x+31 do
for y = source_area.left_top.y, source_area.left_top.y+31 do
local tile = surface.get_tile(x, y)
mirrored[i] = {name = tile.name, position = {-x, -y - 1}}
i = i + 1
end
end
surface.set_tiles(mirrored, true)
end
local function clear_chunk(surface, area)
surface.destroy_decoratives{area=area}
if area.left_top.y > 32 or area.left_top.x > 32 or area.left_top.x < -32 then
@ -163,6 +179,13 @@ local function on_chunk_generated(event)
global.chunks_to_mirror[game.tick + delay][#global.chunks_to_mirror[game.tick + delay] + 1] = {x = x / 32, y = y / 32}
end
local function add_work(work)
if not global.ctp then global.ctp = { continue = 1, last = 0 } end
local idx = global.ctp.last + 1
global.ctp[idx] = work
global.ctp.last = idx
end
local function ocg (event)
if event.area.left_top.y < 0 then return end
if event.surface.name ~= "biter_battles" then return end
@ -176,14 +199,10 @@ local function ocg (event)
local x = ((event.area.left_top.x + 16) * -1) - 16
local y = ((event.area.left_top.y + 16) * -1) - 16
add_work({x = x / 32, y = y / 32, state = 1})
if not global.ctp then global.ctp = { continue = 1, last = 0 } end
local idx = global.ctp.last + 1
global.ctp[idx] = {x = x / 32, y = y / 32, state = 1}
global.ctp.last = idx
end
local function ticking_work()
if not global.ctp then return end
local work = global.mws or 512 -- define the number of work per tick here (for copies, creations, deletions)
@ -204,8 +223,12 @@ local function ticking_work()
}
local surface = game.surfaces["biter_battles"]
if not surface.is_chunk_generated(c) then
-- game.print("Chunk not generated yet, requesting..")
surface.request_to_generate_chunks({x = area.left_top.x - 16, y = area.left_top.y - 16}, 1)
--game.print("Chunk not generated yet, requesting..")
surface.request_to_generate_chunks({x = area.left_top.x + 16, y = area.left_top.y + 16}, 0)
-- requeue
add_work(c)
global.ctp.continue = i+1
global.ctp[i] = nil
return
end
@ -215,16 +238,7 @@ local function ticking_work()
list = function () return surface.find_entities_filtered({area = inverted_area, name = "character", invert = true}) end,
action = function (e) e.destroy() end
},
[2] = {
name = "Tile copy",
list = function () return surface.find_tiles_filtered({area = area}) end,
action = function (tile)
surface.set_tiles({{
name = tile.name,
position = {x = tile.position.x * -1, y = (tile.position.y * -1) - 1}
}}, true)
end
},
[2] = {},
[3] = {
name = "Entity copy",
list = function () return surface.find_entities_filtered({area = area}) end,
@ -246,24 +260,31 @@ local function ticking_work()
}
}
local task = tasks[c.state]
-- game.print(task.name)
d = d or task.list()
local last_idx = nil
for k, v in pairs(d) do
task.action(v)
d[k] = nil
last_idx = k
w = w + 1
if w > work then break end
end
local next_idx, _ = next(d, last_idx)
if next_idx == nil then
c.state = c.state + 1
c.data = nil
else
c.data = d
if c.state == 2 then
mirror_tiles(surface, area)
c.state = c.state + 1
c.data = nil
else
local task = tasks[c.state]
-- game.print(task.name)
d = d or task.list()
local last_idx = nil
for k, v in pairs(d) do
task.action(v)
d[k] = nil
last_idx = k
w = w + 1
if w > work then break end
end
local next_idx, _ = next(d, last_idx)
if next_idx == nil then
c.state = c.state + 1
c.data = nil
else
c.data = d
end
end
if c.state == 5 then

View File

@ -22,29 +22,25 @@ local function get_noise(name, pos)
local seed = game.surfaces[1].map_gen_settings.seed
local noise_seed_add = 25000
if name == 1 then
local noise = {}
noise[1] = simplex_noise(pos.x * 0.0042, pos.y * 0.0042, seed)
local noise = simplex_noise(pos.x * 0.0042, pos.y * 0.0042, seed)
seed = seed + noise_seed_add
noise[2] = simplex_noise(pos.x * 0.031, pos.y * 0.031, seed)
seed = seed + noise_seed_add
noise[3] = simplex_noise(pos.x * 0.1, pos.y * 0.1, seed)
local noise = noise[1] + noise[2] * 0.08 + noise[3] * 0.025
noise = noise + simplex_noise(pos.x * 0.031, pos.y * 0.031, seed) * 0.08
seed = seed + noise_seed_add
noise = noise + simplex_noise(pos.x * 0.1, pos.y * 0.1, seed) * 0.025
return noise
end
if name == 2 then
local noise = {}
noise[1] = simplex_noise(pos.x * 0.011, pos.y * 0.011, seed)
local noise = simplex_noise(pos.x * 0.011, pos.y * 0.011, seed)
seed = seed + noise_seed_add
noise[2] = simplex_noise(pos.x * 0.08, pos.y * 0.08, seed)
local noise = noise[1] + noise[2] * 0.2
noise = noise + simplex_noise(pos.x * 0.08, pos.y * 0.08, seed) * 0.2
return noise
end
if name == 3 then
local noise = {}
noise[1] = simplex_noise(pos.x * 0.02, pos.y * 0.02, seed)
local noise = simplex_noise(pos.x * 0.02, pos.y * 0.02, seed)
seed = seed + noise_seed_add
noise[2] = simplex_noise(pos.x * 0.08, pos.y * 0.08, seed)
local noise = noise[1] + noise[2] * 0.1
noise = noise + simplex_noise(pos.x * 0.08, pos.y * 0.08, seed) * 0.1
return noise
end
end
@ -145,6 +141,92 @@ function is_horizontal_border_river(pos)
return false
end
local function generate_inner_spawn_circle(pos, distance_to_center, surface)
-- assert(distance_to_center < spawn_circle_size) == true
local tile = false
if distance_to_center < 7 then
tile = "sand-1"
elseif distance_to_center < 9.5 then
tile = "refined-concrete"
else
tile = "deepwater"
if math_random(1, 48) == 1 then surface.create_entity({name = "fish", position = pos}) end
end
surface.set_tiles({{name = tile, position = pos}}, true)
end
local function generate_starting_area(pos, distance_to_center, surface)
-- assert(distance_to_center >= spawn_circle_size) == true
local spawn_wall_radius = 116
local noise_multiplier = 15
local min_noise = -noise_multiplier * 1.25
-- Avoid calculating noise, see comment below
if (distance_to_center + min_noise - spawn_wall_radius) > 4.5 then
return
end
local noise = get_noise(2, pos) * noise_multiplier
local distance_from_spawn_wall = distance_to_center + noise - spawn_wall_radius
-- distance_from_spawn_wall is the difference between the distance_to_center (with added noise)
-- and our spawn_wall radius (spawn_wall_radius=116), i.e. how far are we from the ring with radius spawn_wall_radius.
-- The following shows what happens depending on distance_from_spawn_wall:
-- min max
-- N/A -10 => replace water
-- if noise_2 > -0.5:
-- -1.75 0 => wall
-- else:
-- -6 -3 => 1/16 chance of turrent or turret-remnants
-- -1.95 0 => wall
-- 0 4.5 => chest-remnants with 1/3, chest with 1/(distance_from_spawn_wall+2)
--
-- => We never do anything for (distance_to_center + min_noise - spawn_wall_radius) > 4.5
if distance_from_spawn_wall < -10 and not is_horizontal_border_river(pos) then
local tile_name = surface.get_tile(pos).name
if tile_name == "water" or tile_name == "deepwater" then
surface.set_tiles({{name = get_replacement_tile(surface, pos), position = pos}}, true)
end
return
end
if surface.can_place_entity({name = "wooden-chest", position = pos}) and surface.can_place_entity({name = "coal", position = pos}) then
local noise_2 = get_noise(3, pos)
if noise_2 < 0.25 then
if noise_2 > -0.5 then
if distance_from_spawn_wall > -1.75 and distance_from_spawn_wall < 0 then
surface.create_entity({name = "stone-wall", position = pos, force = "north"})
end
else
if distance_from_spawn_wall > -1.95 and distance_from_spawn_wall < 0 then
surface.create_entity({name = "stone-wall", position = pos, force = "north"})
elseif distance_from_spawn_wall > 0 and distance_from_spawn_wall < 4.5 then
local name = "wooden-chest"
local r_max = math.floor(math.abs(distance_from_spawn_wall)) + 2
if math_random(1,3) == 1 then name = name .. "-remnants" end
if math_random(1,r_max) == 1 then surface.create_entity({name = name, position = pos, force = "north"}) end
elseif distance_from_spawn_wall > -6 and distance_from_spawn_wall < -3 then
if math_random(1, 16) == 1 then
if surface.can_place_entity({name = "gun-turret", position = pos}) then
local t = surface.create_entity({name = "gun-turret", position = pos, force = "north"})
t.insert({name = "firearm-magazine", count = math_random(6,12)})
end
else
if math_random(1, 16) == 1 then
if surface.can_place_entity({name = "gun-turret", position = pos}) then
surface.create_entity({name = "gun-turret-remnants", position = pos, force = "north"})
end
end
end
end
end
end
end
end
local function generate_circle_spawn(event)
if global.bb_spawn_generated then return end
@ -153,69 +235,19 @@ local function generate_circle_spawn(event)
local left_top_x = event.area.left_top.x
local left_top_y = event.area.left_top.y
if left_top_x < -320 then return end
if left_top_x > 320 then return end
if left_top_y < -320 then return end
if left_top_x < -160 then return end
if left_top_x > 160 then return end
if left_top_y < -160 then return end
local r = 116
for x = 0, 31, 1 do
for y = 0, 31, 1 do
local pos = {x = left_top_x + x, y = left_top_y + y}
local distance_to_center = math.sqrt(pos.x ^ 2 + pos.y ^ 2)
local noise = get_noise(2, pos) * 15
local tile = false
if distance_to_center < spawn_circle_size then
tile = "deepwater"
if math_random(1, 48) == 1 then surface.create_entity({name = "fish", position = pos}) end
end
if distance_to_center < 9.5 then tile = "refined-concrete" end
if distance_to_center < 7 then tile = "sand-1" end
if distance_to_center + noise < r - 10 and distance_to_center > spawn_circle_size and not is_horizontal_border_river(pos) then
local tile_name = surface.get_tile(pos).name
if tile_name == "water" or tile_name == "deepwater" then
surface.set_tiles({{name = get_replacement_tile(surface, pos), position = pos}}, true)
end
end
if tile then surface.set_tiles({{name = tile, position = pos}}, true) end
if surface.can_place_entity({name = "wooden-chest", position = pos}) and surface.can_place_entity({name = "coal", position = pos}) then
local noise_2 = get_noise(3, pos)
if noise_2 < 0.25 then
local spawn_wall_r = distance_to_center + noise
if noise_2 > -0.5 then
if spawn_wall_r < r and spawn_wall_r > r - 1.75 then
surface.create_entity({name = "stone-wall", position = pos, force = "north"})
end
else
if spawn_wall_r < r and spawn_wall_r > r - 1.95 then
surface.create_entity({name = "stone-wall", position = pos, force = "north"})
else
if spawn_wall_r < r + 4.5 and spawn_wall_r > r then
local name = "wooden-chest"
local r_max = math.floor(math.abs(spawn_wall_r - r)) + 2
if math_random(1,3) == 1 then name = name .. "-remnants" end
if math_random(1,r_max) == 1 then surface.create_entity({name = name, position = pos, force = "north"}) end
end
end
if spawn_wall_r < r - 3 and spawn_wall_r > r - 6 then
if math_random(1, 16) == 1 then
if surface.can_place_entity({name = "gun-turret", position = pos}) then
local t = surface.create_entity({name = "gun-turret", position = pos, force = "north"})
t.insert({name = "firearm-magazine", count = math_random(6,12)})
end
else
if math_random(1, 16) == 1 then
if surface.can_place_entity({name = "gun-turret", position = pos}) then
surface.create_entity({name = "gun-turret-remnants", position = pos, force = "north"})
end
end
end
end
end
end
generate_inner_spawn_circle(pos, distance_to_center, surface)
else
generate_starting_area(pos, distance_to_center, surface)
end
end
end

View File

@ -29,6 +29,11 @@ for i=0,511 do
perm[i+1] = p[bit32.band(i, 255) + 1]
end
-- special case of dot with 3 inputs
local function dot2(g, x, y)
return x * g[1] + y *g[2]
end
local function dot(g, ...)
local v = {...}
local sum = 0
@ -38,16 +43,17 @@ local function dot(g, ...)
return sum
end
local F2 = 0.5*(math.sqrt(3.0)-1.0)
local G2 = (3.0-math.sqrt(3.0))/6.0
function Simplex.d2(xin, yin,seed)
xin = xin + seed
yin = yin + seed
local n0, n1, n2 -- Noise contributions from the three corners
-- Skew the input space to determine which simplex cell we're in
local F2 = 0.5*(math.sqrt(3.0)-1.0)
local s = (xin+yin)*F2; -- Hairy factor for 2D
local i = math.floor(xin+s)
local j = math.floor(yin+s)
local G2 = (3.0-math.sqrt(3.0))/6.0
local t = (i+j)*G2
local X0 = i-t -- Unskew the cell origin back to (x,y) space
local Y0 = j-t
@ -70,34 +76,39 @@ function Simplex.d2(xin, yin,seed)
local y1 = y0 - j1 + G2
local x2 = x0 - 1 + 2 * G2 -- Offsets for last corner in (x,y) unskewed coords
local y2 = y0 - 1 + 2 * G2
-- Work out the hashed gradient indices of the three simplex corners
local ii = bit32.band(i, 255)
local jj = bit32.band(j, 255)
local gi0 = perm[ii + perm[jj+1]+1] % 12
local gi1 = perm[ii + i1 + perm[jj + j1+1]+1] % 12
local gi2 = perm[ii + 1 + perm[jj + 1+1]+1] % 12
-- Calculate the contribution from the three corners
local t0 = 0.5 - x0 * x0 - y0 * y0
if t0 < 0 then
n0 = 0.0
else
t0 = t0 * t0
n0 = t0 * t0 * dot(grad3[gi0+1], x0, y0) -- (x,y) of grad3 used for 2D gradient
n0 = t0 * t0 * dot2(grad3[gi0+1], x0, y0) -- (x,y) of grad3 used for 2D gradient
end
local t1 = 0.5 - x1 * x1 - y1 * y1
if t1 < 0 then
n1 = 0.0
else
t1 = t1 * t1
n1 = t1 * t1 * dot(grad3[gi1+1], x1, y1)
n1 = t1 * t1 * dot2(grad3[gi1+1], x1, y1)
end
local t2 = 0.5 - x2 * x2 - y2 * y2
if t2 < 0 then
n2 = 0.0
else
t2 = t2 * t2
n2 = t2 * t2 * dot(grad3[gi2+1], x2, y2)
n2 = t2 * t2 * dot2(grad3[gi2+1], x2, y2)
end
-- Add contributions from each corner to get the final noise value.
-- The result is scaled to return values in the interval [-1,1].
return 70.0 * (n0 + n1 + n2)