[MOD 0.14.x] Water maze

Topics and discussion about specific mods
JetFox
Burner Inserter
Burner Inserter
Posts: 16
Joined: Mon Jun 27, 2016 9:00 pm
Contact:

Re: [MOD 0.13.x] Water maze

Post by JetFox »

Quick updates... for most of the mods today :D
mraider94
Burner Inserter
Burner Inserter
Posts: 5
Joined: Sun Mar 20, 2016 6:03 am
Contact:

Re: [MOD 0.13.x] Water maze

Post by mraider94 »

Any chance of a 0.14 version?
swni
Long Handed Inserter
Long Handed Inserter
Posts: 91
Joined: Sat Mar 05, 2016 1:54 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by swni »

Done. I only tested it long enough to make sure it didn't crash or any obvious problems. Let me know if you encounter problems.
mraider94
Burner Inserter
Burner Inserter
Posts: 5
Joined: Sun Mar 20, 2016 6:03 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by mraider94 »

I am amazed how fast that was.

Oh on the mod portal page, why not set the homepage to the forum post?
swni
Long Handed Inserter
Long Handed Inserter
Posts: 91
Joined: Sat Mar 05, 2016 1:54 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by swni »

I've been playing with no mods for a while (trying to get all the achievements), and been busy with not-Factorio, so it hadn't occurred to me to update my mods for 0.14. (Although I am proud to say I updated to 0.13 within something like 30 minutes or an hour of its release, I was trying to be the first mod on the mod portal :) )
EldVarg
Burner Inserter
Burner Inserter
Posts: 15
Joined: Tue Nov 01, 2016 10:42 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by EldVarg »

Cool mod. How do you do the "Mandelbrot" from the screenshots?

Edit: Found it:
Mandelbrot(size)
EldVarg
Burner Inserter
Burner Inserter
Posts: 15
Joined: Tue Nov 01, 2016 10:42 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by EldVarg »

Added 2 new functions:

Added type to the Islandify, you can now have circles in addition to the squares.

Code: Select all

function Islandify(pattern, islandradius, bridgelength, bridgewidth, spawntype)
    local pattern_get = pattern.get
    local r = islandradius or 32
    local k = bridgelength or 48
    local w = bridgewidth or 2
    local t = spawntype or "square"
    local n = 2 * r + w + k

    local function create()
        return pattern.create()
    end

    local function reload(d)
        pattern.reload(d)
    end

    local function get(x, y)
        local px = math.floor((x + r) / n)
        local py = math.floor((y + r) / n)
        if not pattern_get(px, py) then
            return false
        end
        x = x % n
        y = y % n
        if (x < w and pattern_get(px, py + 1)) or (y < w and pattern_get(px + 1, py)) then
            return true
        else
            if t == "square" then
                x = (x + r) % n
                y = (y + r) % n
                return (x < 2 * r + w) and (y < 2 * r + w)
            elseif t == "circle" then
                x = (x + r) % n - r - (w / 2) + 0.5
                y = (y + r) % n - r - (w / 2) + 0.5
                return (x * x) + (y * y) < (r + (w / 2) + 1) * (r + (w / 2) + 1)
            end
        end
    end

    return {
        create = create,
        reload = reload,
        get = get,
        lua = 'Islandify(' .. pattern.lua .. ', ' .. r .. ', ' .. k .. ', ' .. w .. ', ' .. t .. ')'
    }
end
Add jitter to borders near water. - Note, this is randomized and will probably not be synced in multiplay.

Code: Select all

function JaggedBorder(pattern, chance, distance)
    local pattern_get = pattern.get
    local c = chance or 30
    local d = distance or 2

    local function create()
        return pattern.create()
    end

    local function reload(d)
        pattern.reload(d)
    end

    local function get(x, y)
        if math.random(100) < c and not pattern_get(x - d, y) then
            return false
        elseif math.random(100) < c and not pattern_get(x + d, y) then
            return false
        elseif math.random(100) < c and not pattern_get(x, y - d) then
            return false
        elseif math.random(100) < c and not pattern_get(x, y + d) then
            return false
        else
            return pattern_get(x, y)
        end
    end
    return {
        create = create,
        reload = reload,
        get = get,
        lua = 'JaggedBorder(' .. pattern.lua .. ', ' .. c .. ', ' .. d .. ')'
    }
end

Example of pattern in config.lua

Code: Select all

local pattern = JaggedBorder(Union(Islandify(Maze2(), 24, 8, 16, "circle"), Circle(80)), 30, 5) 
swini, feel free to add these to the mod if you wish.

Might release more in the future.

Edit: Random should be synced:
viewtopic.php?f=25&t=19353#p123629
Attachments
Round.png
Round.png (52.13 KiB) Viewed 8501 times
EldVarg
Burner Inserter
Burner Inserter
Posts: 15
Joined: Tue Nov 01, 2016 10:42 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by EldVarg »

Just found out that Water Maze is somewhat incompatible with Factorissimo.

Edit:
Made a fix: In control.lua:

Find function:

Code: Select all

local function make_chunk(event)
Insert in the beginning:

Code: Select all

if event.surface.name ~= "nauvis" then
	return
end
Attachments
incomp.jpg
incomp.jpg (504.94 KiB) Viewed 8493 times
User avatar
GeekinaCave
Inserter
Inserter
Posts: 39
Joined: Tue Jun 14, 2016 5:14 pm
Contact:

Re: [MOD 0.14.x] Water maze

Post by GeekinaCave »

Hi, does any know how create a pattern which make random craters with water using mandelbrot or something else?
swni
Long Handed Inserter
Long Handed Inserter
Posts: 91
Joined: Sat Mar 05, 2016 1:54 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by swni »

For some reason I stopped getting notifications (even though I am subscribed to this topic)....

EldVarg, thanks for the feedback and cool suggestions. I may include some of your ideas if I have time. Just a note, JaggedBorder as you wrote it might have interesting effects in some combinations that assume the pattern being combined returns the same value for get(x, y) every time (like Zoom).

GeekinaCave, not sure what you're looking for with random craters, do you want randomly scattered circular lakes? Currently there's no way to do that in the mod but I can add it fairly easily.
User avatar
GeekinaCave
Inserter
Inserter
Posts: 39
Joined: Tue Jun 14, 2016 5:14 pm
Contact:

Re: [MOD 0.14.x] Water maze

Post by GeekinaCave »

swni wrote:For some reason I stopped getting notifications (even though I am subscribed to this topic)....

EldVarg, thanks for the feedback and cool suggestions. I may include some of your ideas if I have time. Just a note, JaggedBorder as you wrote it might have interesting effects in some combinations that assume the pattern being combined returns the same value for get(x, y) every time (like Zoom).

GeekinaCave, not sure what you're looking for with random craters, do you want randomly scattered circular lakes? Currently there's no way to do that in the mod but I can add it fairly easily.
that will be great, since i want to play with several mods including angels ores and i want to give to all the crushed stone a reasonable use (filling the land for necessary expansion).
swni
Long Handed Inserter
Long Handed Inserter
Posts: 91
Joined: Sat Mar 05, 2016 1:54 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by swni »

New version 0.1.0 out with a ton of new patterns.

If you want regularly spaced circular lakes, you can try something like Invert(Tile(Translate(Circle(32), 32, 32), 64, 64)). Throw on some Jitter or Distort to make the lakes more irregularly shaped.
aaargha
Filter Inserter
Filter Inserter
Posts: 333
Joined: Wed Dec 07, 2016 8:35 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by aaargha »

Got to say, this mod is really neat. Currently trying to set up a train focused island map with RSO.

It seems some of the example patterns in config.lua are broken though? (Invalid argument to the Distort ones and Islandify not being included in the release?)

Anyway with regards to RSO integration (or any other resource/enemy spawn mod for that matter) I'd propose a simple callback system. Here is what I'm currently trying to make RSO play nice with (haven't had time to do the RSO part yet). in control.lua:

Code: Select all

local function make_chunk(event)
	--same as usual, cut to save post length
	--do renmote callbacks
	for k,v in pairs(global.saved_config.callback) do 
		remote.call(k, v, event)
	end
end

Code: Select all

local function on_init(event)
	global.saved_config     = config
	config.tp_data          = config.terrain_pattern.create()
	config.tp_lua           = config.terrain_pattern.lua
	terrain_pattern_get     = config.terrain_pattern.get
	config.terrain_pattern  = nil
	config.callback = {} --store registered callback functions
	on_load(nil)
end

--[[
	Add callback functionality.
	Callbacks will be made to registered remote functions after on_chunk_generated is finished.
	Use to replace on_chunk_generated callbacks in resource generation mods
	to ensure that terrain is generated before resources.

	Callbacks look like: 'remote.call(interface, name, event)' 
	where 'interface' is the interface exposed by the mod,
		'name' is the name of the function to call
		and 'event' is passed from on_chunk_generated
	Basically, expose the existing on_chunk_generated function
--]]
remote.add_interface("water_maze", {

	--[[
		Register or update callback. Only allows one registered functon per interface.
		remote.call("water_maze", "add_callback", interface, name)
	--]]
	add_callback = function(interface, name)
		global.saved_config.callback.interface = name
	end,

	--[[
		Remove callback from interface
		remote.call("water_maze", "remove_callback", interface)
	--]]
	remove_callback = function(interface)
		global.saved_config.callback.interface = nil
	end
})

script.on_init(on_init)
script.on_load(on_load)
This should allow other mods to instead of setting up a call back for on_chunk_generated do one for water maze instead:

Code: Select all

instread of:
script.on_event(defines.events.on_chunk_generated, some_function)
do:
remote.call("water_maze", "add_callback", "MYMOD", "CALLBACK")
and:
remote.add_interface("MYMOD", {
	CALLBACK = some_function
})
Haven't had a chance to test this properly yet, will probably get to do that tomorrow. However, feel free to add it if you like. Hopefully I'll manage to get it to run with RSO but at the moment I'm not really sure how to change it to not break if water maze is not installed.
orzelek
Smart Inserter
Smart Inserter
Posts: 3924
Joined: Fri Apr 03, 2015 10:20 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by orzelek »

From what devs said this should be much easier in 0.15 so I didn't try to do stuff like this in RSO.
They are planning to make sure that event calls are using mod load order if I recall Rsending91 correctly.

This would allow for water maze being always called before RSO for example to make sure terrain is ready before the ores are spawned.
There will be still some issues even with that approach - sometimes ores go out of the chunk that has been generated now and things will still break there. There are was to fix this but that would be for RSO and it's potentially a lot of work to do it properly.
swni
Long Handed Inserter
Long Handed Inserter
Posts: 91
Joined: Sat Mar 05, 2016 1:54 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by swni »

Oh, those weren't meant to be example patterns, they were leftover from testing. I'll clean up the examples and maybe make new screenshots at some point. Thanks for letting me know.

It would probably make more sense for my mod to call RSO than vice versa since RSO is the more popular, but either way can work. Also fine with waiting for 0.15, especially if things will just get easier :)

orzelek, to what extent does RSO care about what is land vs water? Presumably RSO only tries to place resources on land (with the effect that the density of resources / land square goes up as the amount of land goes down)? So in vanilla Factorio how does RSO handle placing resources on a chunk that hasn't been generated yet? I'm not sure why this interaction should be different in vanilla Factorio compared to with my mod active.
orzelek
Smart Inserter
Smart Inserter
Posts: 3924
Joined: Fri Apr 03, 2015 10:20 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by orzelek »

swni wrote:...
orzelek, to what extent does RSO care about what is land vs water? Presumably RSO only tries to place resources on land (with the effect that the density of resources / land square goes up as the amount of land goes down)? So in vanilla Factorio how does RSO handle placing resources on a chunk that hasn't been generated yet? I'm not sure why this interaction should be different in vanilla Factorio compared to with my mod active.
Tbh... I don't know for sure. It looks like base game method that checks for entity placement can work on not yet generated chunks since RSO uses can_place_entity to see if ore can be placed. It might be that it says that placement is forbidden there and it would cause the ore patch to move a bit to try and find better location - there is a +/- 1 chunk on patch placement to find better location (reduces ore/water overlaps). So presence/absence of water and/or other resources might have an actual influence on ore spawning.

It seems to work most of the time and writing delayed ore spawning was on my list of things nice to have but it adds a lot of complexity. It would be a proper solution for issues like this where different mods try to modify terrain.

From my point of view it would be better for RSO to provide the callback that other mods can register to if they update terrain. Then RSO would be able to call it before it's own handling of chunk generation event. If I understood changes for 0.15 correctly it might be enough to setup optional dependency there to guarantee the event order - currently it's alphabetical I think.
aaargha
Filter Inserter
Filter Inserter
Posts: 333
Joined: Wed Dec 07, 2016 8:35 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by aaargha »

orzelek and swni wrote:*reasonable arguments to wait for .15*
*Spoiled kid voice*: I don't care! I want to play now!

... and with that said here's what I have running at the moment. For those of us who can't wait, feel free to "steal" if you want to ;)

Firstly a minor bug on the water maze side of things. In the remote interface:

Code: Select all

global.saved_config.callback.interface = name
and
global.saved_config.callback.interface = nil
should be
global.saved_config.callback[interface] = name
and
global.saved_config.callback[interface] = nil
Now what to add for RSO, all in control.lua. At the tail end of init():

Code: Select all

... --rest of function	
checkForBobEnemies()
--new
--handle water mod chunk generation
if remote.interfaces["water_maze"] ~= nil then
	script.on_event(defines.events.on_chunk_generated, nil)
	remote.call("water_maze", "add_callback", "RSO", "chunk_generation_callback")
	local surface = game.surfaces['nauvis']
	regenerate_everything(surface)

end
--/new
initDone = true
... --rest of function	
Move the on_chunk_generated callback to its own function:

Code: Select all

local function gen_chunk(event)
	--lots of code
end

--script.on_init(delayedInit) - no longer required
script.on_load(delayedInit)

script.on_event(defines.events.on_chunk_generated, gen_chunk)

Create remote interface for callback:

Code: Select all

...--other remote interfaces
	saveLog = function()
		l:dump()
	end,

	--callback method for custom chunk generation
	chunk_generation_callback = gen_chunk
})
That should be it. If water maze is not installed it will behave as usual. If it is installed we remove the on_chunk_generated callback and add a callback from water maze. Then to be safe we regenerate any ores that may have been incorrectly placed outside the starting area. (probably not needed for the default settings, but I'm planning to mess some with the regions anyway, better safe than sorry)

Now I just need to mess a bit with the region and starting area settings in RSO and I'll soon be able to actually start playing on my hacky ribbon world (attached).

Anyways, these mods are awesome, keep up the good work people.

Cheers!
Attachments
water.png
water.png (149.19 KiB) Viewed 7969 times
swni
Long Handed Inserter
Long Handed Inserter
Posts: 91
Joined: Sat Mar 05, 2016 1:54 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by swni »

orzelek, did you have in mind something like the following: keep track of which chunks have been generated and only when a chunk and its 8 neighbors have all been generated do you then run the RSO generation code on it? If so, that sounds not too hard to patch up by recording a table which stores for each chunk the number of it and its neighbors that have been generated, and then call the appropriate code and drop it from the table when it hits 9. Something like

Code: Select all

function chunk_generated_callback(event)
    for k, v in global.chunk_generated_hooks_pre
        remote.call(k, v, event)
    end
    for i = -1, 2 do
        for j = -1, 2 do
            maybe_generate_chunk(event.area.left_top.x + i * CHUNK, event.area.left_top.y + j * CHUNK, event)
        end
    end
end

function maybe_generate_chunk(x, y, event)
    if x == 0 then x = 0 end    -- These checks are probably not necessary but I'm not sure
    if y == 0 then y = 0 end
    local key = x .. '#' .. y
    local c = global.chunks_seen
    if c[key] == nil then
        c[key] = 1
    else
        c[key] = c[key] + 1
        if c[key] == 9 then
            c[key] = nil
            do_actual_chunk_generation_code(event)
            for k, v in global.chunk_generated_hooks_post(event) do
                remote.call(k, v, event)
            end
        end
    end
end
Totally untested of course... and you would know better than I if that would work with the rest of your code.

aaargha, can I ask what happens if you combine the two mods out of the box? Is the problem that some resource patches get spawned in places that get turned into water, or something worse than that? Also did you manage to make that ribbon using the provided patterns or did you code it up yourself? And, did you manage to get Distort and Islandify to work (the README and mod info page should both show correct usage)?
aaargha
Filter Inserter
Filter Inserter
Posts: 333
Joined: Wed Dec 07, 2016 8:35 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by aaargha »

It was mostly just resource patches that got split in half, or just small patches next to the shores. Now that RSO can move the patches to avoid water there is a lot less of that, and a lot more usable resource fields (without plastering them everywhere). Didn't notice anything more problematic than that.

The ribbon world is made with the default patterns, just a lot of them.

Code: Select all

--"node" attributes
local half_square = 64
local bridge_l = 32
local bridge_w = 8 --comfortably fit two rails
local node_size = half_square * 2 + bridge_l

--"trunk" attributes
local trunk_w = 40

--generate
local node = SquaresAndBridges(half_square, bridge_l, bridge_w) --make base
node = Intersection(node, Translate(Cross(half_square * 2), half_square, node_size)) --strip side bridges
local side1 = Intersection(Tile(node, node_size, node_size), Translate(Strip(node_size), 0, -node_size / 2)) --bottom
local side2 = Intersection(Tile(Translate(node, 0, bridge_l), node_size, node_size), Translate(Strip(node_size), 0, node_size / 2)) --top
local pattern = Union(Translate(side1, -half_square, -trunk_w / 2), Union(Translate(side2, -half_square, trunk_w / 2), Strip(trunk_w))) --add sides to trunk
pattern = Union(pattern, Square(half_square)) --add a bit of starting area
pattern = Translate(pattern, 64, 0) --align to RSO regions
And that's why it's hacky :) If you know a more efficient way of doing this I'd appreciate it, this one is pretty slow. Also while I'm at it, feature request: a mirror transformation. Rotating 180 degrees does not really work as it introduces too many rounding errors meaning that straight edges do not stay straight. Also perhaps a cache for Tile would help performance wise for patterns like this.

Trying

Code: Select all

pattern = Islandify(Maze2)
results in
__water-maze__/control.lua:2: __water-maze__/config.lua:44: attempt to call global 'Islandify' (a nil value)
Haven't tried Distort as I've not really needed it, just noticed the broken patterns included in the config and I just figured that the examples weren't updated.
swni
Long Handed Inserter
Long Handed Inserter
Posts: 91
Joined: Sat Mar 05, 2016 1:54 am
Contact:

Re: [MOD 0.14.x] Water maze

Post by swni »

Bah, looks like I uploaded the wrong version. Islandify was called "ConvolveBridges" before I decided that that was misleading and confusing.

I considered providing a Memoize transformer that caches a given pattern, but I figured that all of the existing patterns are fast enough (some of them internally memoize) that wouldn't be necessary... however I did not anticipate that a sufficiently complicated and nested combination of patterns would be too slow even if all the parts are individually reasonable :) Memoizing adds significant overhead so I don't want to do it by default unless it is necessary.

I think I'll add a Rectangle(x1, y1, x2, y2) method and maybe let Circle take an optional center argument and let Union and Intersection have any number of arguments... that should help a bit with this sort of stuff. Then you can union together three rectangles, tile it, and union with a strip and starting area.

To do a 180 rotation you should be able to do Affine(pattern, -1, 0, 0, -1). It should keep everything as integers and therefore avoid rounding. Let me know if that doesn't work well. To do a mirror do Affine(pattern, -1, 0, 0, 1) or Affine(pattern, 1, 0, 0, -1) for x and y respectively. (Also, I'd be curious to know which pattern you tried that caused Rotate to round poorly so that I can fix that one.)
Post Reply

Return to “Mods”