1
0
Fork 0

Mineclone compatibility (#8)

* splitting up and genericizing some code, localizing default-dependent stuff in one file

* make cooling lava an API as well

* split out spring code, start roughing in mineclone support

* ooh, at some point altitude checking was added to ABM definitions. Awesome.

* fix crash in flow through

* adding mapgen spring clay. Mineclone2 and Mineclone5 both need to accept pull requests fixing bugs before this will work
master v2.0
FaceDeer 2022-09-17 17:53:19 -06:00 committed by GitHub
parent cf67547455
commit 7bdc95c60a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 765 additions and 575 deletions

133
autotranslate.py Normal file
View File

@ -0,0 +1,133 @@
# A quick-and-dirty script to run untranslated text through Google Translate's API.
# The result will likely include comical errors a native speaker will laugh at you for
# or that will puzzle them, and some manual correction of escaped codes such as @1 and @= may be
# required, but hopefully it will serve as a start to something useful
# Copyright (C) 2020 FaceDeer
# LGPLv2.1+
# See https://github.com/minetest-tools/update_translations for
# potential future updates to this script.
from googletrans import Translator, LANGUAGES
import os, re, shutil
pattern_tr_filename = re.compile(r'\.tr$')
pattern_tr_id = re.compile(r'\.([^.]*)\.tr$')
pattern_line_to_translate = re.compile(r'^([^#].*[^@])=$') #finds lines that don't have a translation
translator = Translator()
def translate(tr_filename):
lang_id = pattern_tr_id.search(tr_filename)
if not lang_id:
print("Could not find language ID in tr filename " + tr_filename)
return
lang_id = lang_id.group(1)
if not lang_id in LANGUAGES:
print("language ID " + lang_id + " is not supported by Google Translate's API")
return
lines_to_translate = [] # this list of strings will ultimately be sent to Google for translation
with open(tr_filename, "r", encoding="utf-8") as tr_file_handle:
for line in tr_file_handle:
# Look for lines that end in "=", ie, that don't have a valid translation added to them
line_lacking_translation = pattern_line_to_translate.search(line)
if line_lacking_translation:
#break the line up at @n markers, this is not ideal for Google
#as it may remove some context but it's necessary to allow the
#@n markers to be preserved in the output later
lines_to_translate = lines_to_translate + line_lacking_translation.group(1).split("@n")
# Remove duplicates, and the empty string (a common artefact of splitting)
line_set = set(lines_to_translate)
line_set.discard("")
lines_to_translate = list(line_set)
# Only do more work if there are lines in need of translation
if lines_to_translate:
print("Calling Google API for " + tr_filename)
output = translator.translate(lines_to_translate, src="en", dest=lang_id)
#convert the output translations into a dictionary for easy substitution later
translation_dictionary = dict()
for out_line in output:
#Google's API sometimes seems to fail to translate a line for no apparent reason
#Don't put them in the dictionary, we can leave those untranslated and maybe try again
if out_line.origin != out_line.text:
translation_dictionary[out_line.origin] = out_line.text
translation_dictionary["@n"] = "@n" #These are to be left unchanged
tr_file_handle.seek(0)
with open(tr_filename + ".temp", "w", encoding="utf-8") as tr_file_new:
for line in tr_file_handle:
line_lacking_translation = pattern_line_to_translate.search(line)
if line_lacking_translation:
line = line.rstrip('\n') #remove trailing newline so we can add the translated string to the same line
line_split = re.split("(@n)", line[:-1]) #slice to leave off the "=" that's the last character of the line
translated_line = ""
#After splitting the line up on @n again, as was done before, we should have
#line segments that match the strings that were sent to Google.
for line_piece in line_split:
if line_piece in translation_dictionary:
translated_line = translated_line + translation_dictionary[line_piece]
else:
print("Google returned string unchanged in file " + tr_filename + ":")
print(line_piece)
translated_line = None
break
if translated_line:
tr_file_new.write("#WARNING: AUTOTRANSLATED BY GOOGLE TRANSLATE\n")
tr_file_new.write(line)
tr_file_new.write(translated_line)
tr_file_new.write("\n")
else:
tr_file_new.write(line)
tr_file_new.write("\n")
else:
tr_file_new.write(line)
shutil.move(tr_filename + ".temp", tr_filename) # Overwrite the original file with the new one
pattern_domain = re.compile(r'^# textdomain: (.+)$')
def create_tr_files_from_template(folder, lang_id):
if not lang_id in LANGUAGES:
print("language ID " + lang_id + " is not supported by Google Translate's API")
return
for root, dirs, files in os.walk(folder):
if root == "." or os.path.split(root)[1] == "locale":
for name in files:
if name == "template.txt":
template_filename = os.path.join(root,name)
with open(template_filename, "r", encoding="utf-8") as template_file:
first_line = template_file.readline()
domain = pattern_domain.search(first_line)
if domain:
translation_filename = domain.group(1) + "." + lang_id + ".tr"
translation_filename = os.path.join(root,translation_filename)
if not os.path.isfile(translation_filename):
print("Copying template.txt to " + translation_filename)
shutil.copy(template_filename, translation_filename)
else:
print(translation_filename + " already exists")
#If there are already .tr files in /locale, returns a list of their names
def get_existing_tr_files(folder):
out = []
for root, dirs, files in os.walk(folder):
for name in files:
if pattern_tr_filename.search(name):
out.append(os.path.join(root,name))
return out
#create_tr_files_from_template(".", "de")
#create_tr_files_from_template(".", "it")
tr_files = get_existing_tr_files(".")
for tr_file in tr_files:
translate(tr_file)

View File

@ -1,9 +1,14 @@
if not minetest.get_modpath("default") then return end
dynamic_liquid.cooling_lava = function(def)
local new_lava_cooling = minetest.settings:get_bool("dynamic_liquid_new_lava_cooling", true)
if not new_lava_cooling then return end
local lava_source = def.lava_source
local lava_flowing = def.lava_flowing
local obsidian = def.obsidian
local flowing_destroys = def.flowing_destroys or {}
local source_destroys = def.source_destroys or {}
local cooling_sound = def.cooling_sound
local falling_obsidian = dynamic_liquid.config.falling_obsidian
local falling_obsidian = minetest.settings:get_bool("dynamic_liquid_falling_obsidian", false)
-- The existing cool_lava ABM is hard-coded to respond to water nodes
-- and overriding node groups doesn't appear to work:
@ -20,7 +25,6 @@ local falling_obsidian = minetest.settings:get_bool("dynamic_liquid_falling_obsi
-- to nodes that should be destroyed by proximity to lava.
local particles = minetest.settings:get_bool("enable_particles", true)
local steam = function(pos)
if particles then
minetest.add_particlespawner({
@ -43,22 +47,19 @@ local steam = function(pos)
end
end
default.cool_lava = function(pos, node)
-- no-op disables default cooling ABM
end
-------------------------------------------------------------------------------------------------
local dynamic_cools_lava_flowing = {"group:dynamic_cools_lava_flowing", "group:cools_lava"}
-- Flowing lava will turn these blocks into steam.
local dynamic_lava_flowing_destroys = {
"group:dynamic_lava_flowing_destroys",
"default:water_flowing",
"default:river_water_flowing",
"default:snow",
"default:snowblock"
}
for _, node_name in pairs(flowing_destroys) do
table.insert(dynamic_lava_flowing_destroys, node_name)
end
local all_flowing_nodes = {unpack(dynamic_cools_lava_flowing)}
for i = 1, #dynamic_lava_flowing_destroys do
@ -71,9 +72,9 @@ local cool_lava_flowing = function(pos, node)
if cooler_adjacent ~= nil then
-- pulling nearby sources into position is necessary to break certain classes of
-- flow "deadlock". Weird, but what're you gonna do.
local nearby_source = minetest.find_node_near(pos, 1, "default:lava_source")
local nearby_source = minetest.find_node_near(pos, 1, lava_source)
if nearby_source then
minetest.set_node(pos, {name="default:lava_source"})
minetest.set_node(pos, {name=lava_source})
minetest.set_node(nearby_source, {name="air"})
steam(nearby_source)
else
@ -92,13 +93,13 @@ local cool_lava_flowing = function(pos, node)
steam(loc)
end
minetest.sound_play("default_cool_lava",
minetest.sound_play(cooling_sound,
{pos = pos, max_hear_distance = 16, gain = 0.25})
end
minetest.register_abm({
label = "Lava flowing cooling",
nodenames = {"default:lava_flowing"},
nodenames = {lava_flowing},
neighbors = all_flowing_nodes,
interval = 1,
chance = 1,
@ -122,14 +123,11 @@ end
-- lava source blocks will turn these blocks into steam.
local dynamic_lava_source_destroys = {
"group:dynamic_lava_source_destroys",
"default:water_source",
"default:river_water_source",
"default:water_flowing",
"default:river_water_flowing",
"default:ice",
"default:snow",
"default:snowblock"
}
for _, node_name in pairs(source_destroys) do
table.insert(dynamic_lava_source_destroys, node_name)
end
local all_source_nodes = {unpack(dynamic_cools_lava_source)}
for i = 1, #dynamic_lava_source_destroys do
@ -193,8 +191,8 @@ local cool_lava_source = function(pos, node)
if obsidian_location ~= nil then
minetest.set_node(pos, {name = "air"})
minetest.set_node(obsidian_location, {name = "default:obsidian"})
if minetest.spawn_falling_node and falling_obsidian then -- TODO cutting-edge dev function, so check if it exists for the time being. Remove check when 0.4.16 is released.
minetest.set_node(obsidian_location, {name = obsidian})
if falling_obsidian then
minetest.spawn_falling_node(obsidian_location)
end
elseif #evaporate_list > 0 then
@ -202,18 +200,18 @@ local cool_lava_source = function(pos, node)
local loc = evaporate_list[math.random(1,#evaporate_list)]
if loc.y <= pos.y then
minetest.set_node(pos, {name = "air"})
minetest.set_node(loc, {name = "default:lava_source"})
minetest.set_node(loc, {name = lava_source})
end
end
minetest.sound_play("default_cool_lava",
minetest.sound_play(cooling_sound,
{pos = pos, max_hear_distance = 16, gain = 0.25})
end
minetest.register_abm({
label = "Lava source cooling",
nodenames = {"default:lava_source"},
nodenames = {lava_source},
neighbors = all_source_nodes,
interval = 1,
chance = 1,
@ -221,4 +219,7 @@ minetest.register_abm({
action = function(...)
cool_lava_source(...)
end,
})
})
end

154
default.lua Normal file
View File

@ -0,0 +1,154 @@
local S = minetest.get_translator(minetest.get_current_modname())
local water_probability = dynamic_liquid.config.water_probability
local river_water_probability = dynamic_liquid.config.river_water_probability
local lava_probability = dynamic_liquid.config.lava_probability
local water_level = dynamic_liquid.config.water_level
local springs = dynamic_liquid.config.springs
if dynamic_liquid.config.lava then
dynamic_liquid.liquid_abm("default:lava_source", "default:lava_flowing", lava_probability)
end
if dynamic_liquid.config.water then
-- override water_source and water_flowing with liquid_renewable set to false
local override_def = {liquid_renewable = false}
minetest.override_item("default:water_source", override_def)
minetest.override_item("default:water_flowing", override_def)
dynamic_liquid.liquid_abm("default:water_source", "default:water_flowing", water_probability)
end
if dynamic_liquid.config.river_water then
dynamic_liquid.liquid_abm("default:river_water_source", "default:river_water_flowing", river_water_probability)
end
-- Flow-through nodes
-----------------------------------------------------------------------------------------------------------------------
if dynamic_liquid.config.flow_through then
local flow_through_nodes = {"group:flow_through", "group:leaves", "group:sapling", "group:grass", "group:dry_grass", "group:flora", "groups:rail", "groups:flower",
"default:apple", "default:papyrus", "default:dry_shrub", "default:bush_stem", "default:acacia_bush_stem","default:sign_wall_wood", "default:sign_wall_steel", "default:ladder_wood", "default:ladder_steel", "default:fence_wood", "default:fence_acacia_wood", "default:fence_junglewood", "default:fence_pine_wood","default:fence_aspen_wood"}
if minetest.get_modpath("xpanes") then
table.insert(flow_through_nodes, "xpanes:bar")
table.insert(flow_through_nodes, "xpanes:bar_flat")
end
if minetest.get_modpath("carts") then
table.insert(flow_through_nodes, "carts:rail")
table.insert(flow_through_nodes, "carts:powerrail")
table.insert(flow_through_nodes, "carts:brakerail")
end
dynamic_liquid.flow_through_abm({nodenames = flow_through_nodes})
end
if dynamic_liquid.config.mapgen_prefill then
dynamic_liquid.mapgen_prefill({liquid="default:water_source", liquid_level=water_level})
end
-- Springs
-----------------------------------------------------------------------------------------------------------------------
-- register damp clay whether we're going to set the ABM or not, if the user disables this feature we don't want existing
-- spring clay to turn into unknown nodes.
local clay_def = dynamic_liquid.duplicate_def("default:clay")
clay_def.description = S("Damp Clay")
if not springs then
clay_def.groups.not_in_creative_inventory = 1 -- take it out of creative inventory though
end
minetest.register_node("dynamic_liquid:clay", clay_def)
local data = dynamic_liquid.mapgen_data
if springs then
local c_clay = minetest.get_content_id("default:clay")
local c_spring_clay = minetest.get_content_id("dynamic_liquid:clay")
-- Turn mapgen clay into spring clay
minetest.register_on_generated(function(minp, maxp, seed)
if minp.y >= water_level or maxp.y <= -15 then
return
end
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
vm:get_data(data)
for voxelpos, voxeldata in pairs(data) do
if voxeldata == c_clay then
data[voxelpos] = c_spring_clay
end
end
vm:set_data(data)
vm:write_to_map()
end)
dynamic_liquid.spring({
nodenames = {"dynamic_liquid:clay"},
water_source = "default:water_source",
water_flowing = "default:water_flowing",
y_max = water_level,
y_min = -15,
pressure = 15,
})
local spring_sounds = nil
if default.node_sound_gravel_defaults ~= nil then
spring_sounds = default.node_sound_gravel_defaults()
elseif default.node_sound_sand_defaults ~= nil then
spring_sounds = default.node_sound_dirt_defaults()
end
-- This is a creative-mode only node that produces a modest amount of water continuously no matter where it is.
-- Allow this one to turn into "unknown node" when this feature is disabled, since players had to explicitly place it.
minetest.register_node("dynamic_liquid:spring", {
description = S("Spring"),
_doc_items_longdesc = S("A natural spring that generates an endless stream of water source blocks"),
_doc_items_usagehelp = S("Generates one source block of water directly on top of itself once per second, provided the space is clear. If this natural spring is dug out the flow stops and it is turned into ordinary cobble."),
drops = "default:gravel",
tiles = {"default_cobble.png^[combine:16x80:0,-48=crack_anylength.png",
"default_cobble.png","default_cobble.png","default_cobble.png","default_cobble.png","default_cobble.png",
},
is_ground_content = false,
groups = {cracky = 3, stone = 2},
sounds = spring_sounds,
})
dynamic_liquid.spring({
nodenames = {"dynamic_liquid:spring"},
water_source = "default:water_source",
water_flowing = "default:water_flowing",
pressure = 1,
})
end
--------------------------------------------------------
-- Cooling lava
if dynamic_liquid.config.new_lava_cooling then
default.cool_lava = function(pos, node)
-- no-op disables default cooling ABM
end
dynamic_liquid.cooling_lava({
flowing_destroys = {"default:water_flowing", "default:river_water_flowing", "default:snow", "default:snowblock"},
source_destroys = { "default:water_source",
"default:river_water_source",
"default:water_flowing",
"default:river_water_flowing",
"default:ice",
"default:snow",
"default:snowblock",
},
lava_source = "default:lava_source",
lava_flowing = "default:lava_flowing",
obsidian = "default:obsidian",
cooling_sound = "default_cool_lava",
})
end

136
dynamic_liquids.lua Normal file
View File

@ -0,0 +1,136 @@
-- By making this table of all possible permutations of horizontal direction we can avoid
-- lots of redundant calculations.
local all_direction_permutations = {
{{x=0,z=1},{x=0,z=-1},{x=1,z=0},{x=-1,z=0}},
{{x=0,z=1},{x=0,z=-1},{x=-1,z=0},{x=1,z=0}},
{{x=0,z=1},{x=1,z=0},{x=0,z=-1},{x=-1,z=0}},
{{x=0,z=1},{x=1,z=0},{x=-1,z=0},{x=0,z=-1}},
{{x=0,z=1},{x=-1,z=0},{x=0,z=-1},{x=1,z=0}},
{{x=0,z=1},{x=-1,z=0},{x=1,z=0},{x=0,z=-1}},
{{x=0,z=-1},{x=0,z=1},{x=-1,z=0},{x=1,z=0}},
{{x=0,z=-1},{x=0,z=1},{x=1,z=0},{x=-1,z=0}},
{{x=0,z=-1},{x=1,z=0},{x=-1,z=0},{x=0,z=1}},
{{x=0,z=-1},{x=1,z=0},{x=0,z=1},{x=-1,z=0}},
{{x=0,z=-1},{x=-1,z=0},{x=1,z=0},{x=0,z=1}},
{{x=0,z=-1},{x=-1,z=0},{x=0,z=1},{x=1,z=0}},
{{x=1,z=0},{x=0,z=1},{x=0,z=-1},{x=-1,z=0}},
{{x=1,z=0},{x=0,z=1},{x=-1,z=0},{x=0,z=-1}},
{{x=1,z=0},{x=0,z=-1},{x=0,z=1},{x=-1,z=0}},
{{x=1,z=0},{x=0,z=-1},{x=-1,z=0},{x=0,z=1}},
{{x=1,z=0},{x=-1,z=0},{x=0,z=1},{x=0,z=-1}},
{{x=1,z=0},{x=-1,z=0},{x=0,z=-1},{x=0,z=1}},
{{x=-1,z=0},{x=0,z=1},{x=1,z=0},{x=0,z=-1}},
{{x=-1,z=0},{x=0,z=1},{x=0,z=-1},{x=1,z=0}},
{{x=-1,z=0},{x=0,z=-1},{x=1,z=0},{x=0,z=1}},
{{x=-1,z=0},{x=0,z=-1},{x=0,z=1},{x=1,z=0}},
{{x=-1,z=0},{x=1,z=0},{x=0,z=-1},{x=0,z=1}},
{{x=-1,z=0},{x=1,z=0},{x=0,z=1},{x=0,z=-1}},
}
local get_node = minetest.get_node
local set_node = minetest.swap_node
-- Dynamic liquids
-----------------------------------------------------------------------------------------------------------------------
local disable_flow_above = dynamic_liquid.config.disable_flow_above or 32767
dynamic_liquid.liquid_abm = function(liquid, flowing_liquid, chance)
minetest.register_abm({
label = "dynamic_liquid " .. liquid .. " and " .. flowing_liquid,
nodenames = {liquid},
neighbors = {flowing_liquid},
interval = 1,
chance = chance or 1,
y_max = disable_flow_above,
catch_up = false,
action = function(pos,node) -- Do everything possible to optimize this method
local check_pos = {x=pos.x, y=pos.y-1, z=pos.z}
local check_node = get_node(check_pos)
local check_node_name = check_node.name
if check_node_name == flowing_liquid or check_node_name == "air" then
set_node(pos, check_node)
set_node(check_pos, node)
return
end
local perm = all_direction_permutations[math.random(24)]
local dirs -- declare outside of loop so it won't keep entering/exiting scope
for i=1,4 do
dirs = perm[i]
-- reuse check_pos to avoid allocating a new table
check_pos.x = pos.x + dirs.x
check_pos.y = pos.y
check_pos.z = pos.z + dirs.z
check_node = get_node(check_pos)
check_node_name = check_node.name
if check_node_name == flowing_liquid or check_node_name == "air" then
set_node(pos, check_node)
set_node(check_pos, node)
return
end
end
end
})
dynamic_liquid.registered_liquids[liquid] = flowing_liquid
table.insert(dynamic_liquid.registered_liquid_neighbors, liquid)
end
if dynamic_liquid.config.displace_liquid then
local cardinal_dirs = {
{x= 0, y=0, z= 1},
{x= 1, y=0, z= 0},
{x= 0, y=0, z=-1},
{x=-1, y=0, z= 0},
{x= 0, y=-1, z= 0},
{x= 0, y=1, z= 0},
}
-- breadth-first search passing through liquid searching for air or flowing liquid.
local flood_search_outlet = function(start_pos, source, flowing)
local start_node = minetest.get_node(start_pos)
local start_node_name = start_node.name
if start_node_name == "air" or start_node_name == flowing then
return start_pos
end
local visited = {}
visited[minetest.hash_node_position(start_pos)] = true
local queue = {start_pos}
local queue_pointer = 1
while #queue >= queue_pointer do
local current_pos = queue[queue_pointer]
queue_pointer = queue_pointer + 1
for _, cardinal_dir in ipairs(cardinal_dirs) do
local new_pos = vector.add(current_pos, cardinal_dir)
local new_hash = minetest.hash_node_position(new_pos)
if visited[new_hash] == nil then
local new_node = minetest.get_node(new_pos)
local new_node_name = new_node.name
if new_node_name == "air" or new_node_name == flowing then
return new_pos
end
visited[new_hash] = true
if new_node_name == source then
table.insert(queue, new_pos)
end
end
end
end
return nil
end
-- Conserve liquids, when placing nodes in liquids try to find a place to displace the liquid to.
minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
local flowing = dynamic_liquid.registered_liquids[oldnode.name]
if flowing ~= nil then
local dest = flood_search_outlet(pos, oldnode.name, flowing)
if dest ~= nil then
minetest.swap_node(dest, oldnode)
end
end
end)
end

62
flow_through.lua Normal file
View File

@ -0,0 +1,62 @@
local flow_through_directions = {
{{x=1,z=0},{x=0,z=1}},
{{x=0,z=1},{x=1,z=0}},
}
local get_node = minetest.get_node
local set_node = minetest.set_node
dynamic_liquid.flow_through_abm = function(def)
minetest.register_abm({
label = "dynamic_liquid flow-through",
nodenames = def.nodenames,
neighbors = dynamic_liquid.registered_liquid_neighbors,
interval = 1,
chance = 2, -- since liquid is teleported two nodes by this abm, halve the chance
catch_up = false,
action = function(pos)
local source_pos = {x=pos.x, y=pos.y+1, z=pos.z}
local dest_pos = {x=pos.x, y=pos.y-1, z=pos.z}
local source_node = get_node(source_pos)
local dest_node
local source_flowing_node = dynamic_liquid.registered_liquids[source_node.name]
local dest_flowing_node
if source_flowing_node ~= nil then
dest_node = get_node(dest_pos)
if dest_node.name == source_flowing_node or dest_node.name == "air" then
set_node(dest_pos, source_node)
set_node(source_pos, dest_node)
return
end
end
local perm = flow_through_directions[math.random(2)]
local dirs -- declare outside of loop so it won't keep entering/exiting scope
for i=1,2 do
dirs = perm[i]
-- reuse to avoid allocating a new table
source_pos.x = pos.x + dirs.x
source_pos.y = pos.y
source_pos.z = pos.z + dirs.z
dest_pos.x = pos.x - dirs.x
dest_pos.y = pos.y
dest_pos.z = pos.z - dirs.z
source_node = get_node(source_pos)
dest_node = get_node(dest_pos)
source_flowing_node = dynamic_liquid.registered_liquids[source_node.name]
dest_flowing_node = dynamic_liquid.registered_liquids[dest_node.name]
if (source_flowing_node ~= nil and (dest_node.name == source_flowing_node or dest_node.name == "air")) or
(dest_flowing_node ~= nil and (source_node.name == dest_flowing_node or source_node.name == "air"))
then
set_node(source_pos, dest_node)
set_node(dest_pos, source_node)
return
end
end
end,
})
end

577
init.lua
View File

@ -1,299 +1,29 @@
dynamic_liquid = {} -- global table to expose liquid_abm for other mods' usage
dynamic_liquid.config = {}
dynamic_liquid.config.water = minetest.settings:get_bool("dynamic_liquid_water", true)
dynamic_liquid.config.river_water = minetest.settings:get_bool("dynamic_liquid_river_water", false)
dynamic_liquid.config.lava = minetest.settings:get_bool("dynamic_liquid_lava", true)
dynamic_liquid.config.water_probability = tonumber(minetest.settings:get("dynamic_liquid_water_flow_propability")) or 1
dynamic_liquid.config.river_water_probability = tonumber(minetest.settings:get("dynamic_liquid_river_water_flow_propability")) or 1
dynamic_liquid.config.lava_probability = tonumber(minetest.settings:get("dynamic_liquid_lava_flow_propability")) or 5
dynamic_liquid.config.water_level = tonumber(minetest.get_mapgen_setting("water_level")) or 0
dynamic_liquid.config.springs = minetest.settings:get_bool("dynamic_liquid_springs", true)
dynamic_liquid.config.flow_through = minetest.settings:get_bool("dynamic_liquid_flow_through", true)
dynamic_liquid.config.mapgen_prefill = minetest.settings:get_bool("dynamic_liquid_mapgen_prefill", true)
dynamic_liquid.config.disable_flow_above = tonumber(minetest.settings:get("dynamic_liquid_disable_flow_above")) -- this one can be nil
dynamic_liquid.config.displace_liquid = minetest.settings:get_bool("dynamic_liquid_displace_liquid", true)
dynamic_liquid.config.new_lava_cooling = minetest.settings:get_bool("dynamic_liquid_new_lava_cooling", true)
dynamic_liquid.config.falling_obsidian = minetest.settings:get_bool("dynamic_liquid_falling_obsidian", false)
dynamic_liquid.registered_liquids = {} -- used by the flow-through node abm
dynamic_liquid.registered_liquid_neighbors = {}
local water_level = tonumber(minetest.get_mapgen_setting("water_level"))
local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
local S = minetest.get_translator(modname)
dofile(modpath.."/cooling_lava.lua")
-- By making this giant table of all possible permutations of horizontal direction we can avoid
-- lots of redundant calculations.
local all_direction_permutations = {
{{x=0,z=1},{x=0,z=-1},{x=1,z=0},{x=-1,z=0}},
{{x=0,z=1},{x=0,z=-1},{x=-1,z=0},{x=1,z=0}},
{{x=0,z=1},{x=1,z=0},{x=0,z=-1},{x=-1,z=0}},
{{x=0,z=1},{x=1,z=0},{x=-1,z=0},{x=0,z=-1}},
{{x=0,z=1},{x=-1,z=0},{x=0,z=-1},{x=1,z=0}},
{{x=0,z=1},{x=-1,z=0},{x=1,z=0},{x=0,z=-1}},
{{x=0,z=-1},{x=0,z=1},{x=-1,z=0},{x=1,z=0}},
{{x=0,z=-1},{x=0,z=1},{x=1,z=0},{x=-1,z=0}},
{{x=0,z=-1},{x=1,z=0},{x=-1,z=0},{x=0,z=1}},
{{x=0,z=-1},{x=1,z=0},{x=0,z=1},{x=-1,z=0}},
{{x=0,z=-1},{x=-1,z=0},{x=1,z=0},{x=0,z=1}},
{{x=0,z=-1},{x=-1,z=0},{x=0,z=1},{x=1,z=0}},
{{x=1,z=0},{x=0,z=1},{x=0,z=-1},{x=-1,z=0}},
{{x=1,z=0},{x=0,z=1},{x=-1,z=0},{x=0,z=-1}},
{{x=1,z=0},{x=0,z=-1},{x=0,z=1},{x=-1,z=0}},
{{x=1,z=0},{x=0,z=-1},{x=-1,z=0},{x=0,z=1}},
{{x=1,z=0},{x=-1,z=0},{x=0,z=1},{x=0,z=-1}},
{{x=1,z=0},{x=-1,z=0},{x=0,z=-1},{x=0,z=1}},
{{x=-1,z=0},{x=0,z=1},{x=1,z=0},{x=0,z=-1}},
{{x=-1,z=0},{x=0,z=1},{x=0,z=-1},{x=1,z=0}},
{{x=-1,z=0},{x=0,z=-1},{x=1,z=0},{x=0,z=1}},
{{x=-1,z=0},{x=0,z=-1},{x=0,z=1},{x=1,z=0}},
{{x=-1,z=0},{x=1,z=0},{x=0,z=-1},{x=0,z=1}},
{{x=-1,z=0},{x=1,z=0},{x=0,z=1},{x=0,z=-1}},
}
local get_node = minetest.get_node
local set_node = minetest.swap_node
-- Dynamic liquids
-----------------------------------------------------------------------------------------------------------------------
local disable_flow_above = tonumber(minetest.settings:get("dynamic_liquid_disable_flow_above"))
if disable_flow_above == nil or disable_flow_above >= 31000 then
-- version without altitude check
dynamic_liquid.liquid_abm = function(liquid, flowing_liquid, chance)
minetest.register_abm({
label = "dynamic_liquid " .. liquid .. " and " .. flowing_liquid,
nodenames = {liquid},
neighbors = {flowing_liquid},
interval = 1,
chance = chance or 1,
catch_up = false,
action = function(pos,node) -- Do everything possible to optimize this method
local check_pos = {x=pos.x, y=pos.y-1, z=pos.z}
local check_node = get_node(check_pos)
local check_node_name = check_node.name
if check_node_name == flowing_liquid or check_node_name == "air" then
set_node(pos, check_node)
set_node(check_pos, node)
return
end
local perm = all_direction_permutations[math.random(24)]
local dirs -- declare outside of loop so it won't keep entering/exiting scope
for i=1,4 do
dirs = perm[i]
-- reuse check_pos to avoid allocating a new table
check_pos.x = pos.x + dirs.x
check_pos.y = pos.y
check_pos.z = pos.z + dirs.z
check_node = get_node(check_pos)
check_node_name = check_node.name
if check_node_name == flowing_liquid or check_node_name == "air" then
set_node(pos, check_node)
set_node(check_pos, node)
return
end
end
end
})
dynamic_liquid.registered_liquids[liquid] = flowing_liquid
table.insert(dynamic_liquid.registered_liquid_neighbors, liquid)
end
else
-- version with altitude check
dynamic_liquid.liquid_abm = function(liquid, flowing_liquid, chance)
minetest.register_abm({
label = "dynamic_liquid " .. liquid .. " and " .. flowing_liquid .. " with altitude check",
nodenames = {liquid},
neighbors = {flowing_liquid},
interval = 1,
chance = chance or 1,
catch_up = false,
action = function(pos,node) -- Do everything possible to optimize this method
-- This altitude check is the only difference from the version above.
-- If the altitude check is disabled we don't ever need to make the comparison,
-- hence the two different versions.
if pos.y > disable_flow_above then
return
end
local check_pos = {x=pos.x, y=pos.y-1, z=pos.z}
local check_node = get_node(check_pos)
local check_node_name = check_node.name
if check_node_name == flowing_liquid or check_node_name == "air" then
set_node(pos, check_node)
set_node(check_pos, node)
return
end
local perm = all_direction_permutations[math.random(24)]
local dirs -- declare outside of loop so it won't keep entering/exiting scope
for i=1,4 do
dirs = perm[i]
-- reuse check_pos to avoid allocating a new table
check_pos.x = pos.x + dirs.x
check_pos.y = pos.y
check_pos.z = pos.z + dirs.z
check_node = get_node(check_pos)
check_node_name = check_node.name
if check_node_name == flowing_liquid or check_node_name == "air" then
set_node(pos, check_node)
set_node(check_pos, node)
return
end
end
end
})
dynamic_liquid.registered_liquids[liquid] = flowing_liquid
table.insert(dynamic_liquid.registered_liquid_neighbors, liquid)
end
end
if not minetest.get_modpath("default") then
return
end
local water = minetest.settings:get_bool("dynamic_liquid_water", true)
local river_water = minetest.settings:get_bool("dynamic_liquid_river_water", false)
local lava = minetest.settings:get_bool("dynamic_liquid_lava", true)
local water_probability = tonumber(minetest.settings:get("dynamic_liquid_water_flow_propability"))
if water_probability == nil then
water_probability = 1
end
local river_water_probability = tonumber(minetest.settings:get("dynamic_liquid_river_water_flow_propability"))
if river_water_probability == nil then
river_water_probability = 1
end
local lava_probability = tonumber(minetest.settings:get("dynamic_liquid_lava_flow_propability"))
if lava_probability == nil then
lava_probability = 5
end
local springs = minetest.settings:get_bool("dynamic_liquid_springs", true)
if water then
-- override water_source and water_flowing with liquid_renewable set to false
local override_def = {liquid_renewable = false}
minetest.override_item("default:water_source", override_def)
minetest.override_item("default:water_flowing", override_def)
end
if lava then
dynamic_liquid.liquid_abm("default:lava_source", "default:lava_flowing", lava_probability)
end
if water then
dynamic_liquid.liquid_abm("default:water_source", "default:water_flowing", water_probability)
end
if river_water then
dynamic_liquid.liquid_abm("default:river_water_source", "default:river_water_flowing", river_water_probability)
end
-- Flow-through nodes
-----------------------------------------------------------------------------------------------------------------------
local flow_through = minetest.settings:get_bool("dynamic_liquid_flow_through", true)
if flow_through then
local flow_through_directions = {
{{x=1,z=0},{x=0,z=1}},
{{x=0,z=1},{x=1,z=0}},
}
minetest.register_abm({
label = "dynamic_liquid flow-through",
nodenames = {"group:flow_through", "group:leaves", "group:sapling", "group:grass", "group:dry_grass", "group:flora", "groups:rail", "groups:flower"},
neighbors = dynamic_liquid.registered_liquid_neighbors,
interval = 1,
chance = 2, -- since liquid is teleported two nodes by this abm, halve the chance
catch_up = false,
action = function(pos)
local source_pos = {x=pos.x, y=pos.y+1, z=pos.z}
local dest_pos = {x=pos.x, y=pos.y-1, z=pos.z}
local source_node = get_node(source_pos)
local dest_node
local source_flowing_node = dynamic_liquid.registered_liquids[source_node.name]
local dest_flowing_node
if source_flowing_node ~= nil then
dest_node = minetest.get_node(dest_pos)
if dest_node.name == source_flowing_node or dest_node.name == "air" then
set_node(dest_pos, source_node)
set_node(source_pos, dest_node)
return
end
end
local perm = flow_through_directions[math.random(2)]
local dirs -- declare outside of loop so it won't keep entering/exiting scope
for i=1,2 do
dirs = perm[i]
-- reuse to avoid allocating a new table
source_pos.x = pos.x + dirs.x
source_pos.y = pos.y
source_pos.z = pos.z + dirs.z
dest_pos.x = pos.x - dirs.x
dest_pos.y = pos.y
dest_pos.z = pos.z - dirs.z
source_node = get_node(source_pos)
dest_node = get_node(dest_pos)
source_flowing_node = dynamic_liquid.registered_liquids[source_node.name]
dest_flowing_node = dynamic_liquid.registered_liquids[dest_node.name]
if (source_flowing_node ~= nil and (dest_node.name == source_flowing_node or dest_node.name == "air")) or
(dest_flowing_node ~= nil and (source_node.name == dest_flowing_node or source_node.name == "air"))
then
set_node(source_pos, dest_node)
set_node(dest_pos, source_node)
return
end
end
end,
})
local add_flow_through = function(node_name)
local node_def = minetest.registered_nodes[node_name]
if node_def == nil then
minetest.log("warning", "dynamic_liquid attempted to call add_flow_through on the node name "
.. node_name .. ", which was not found in minetest.registered_nodes.")
return
end
local new_groups = node_def.groups
new_groups.flow_through = 1
minetest.override_item(node_name,{groups = new_groups})
end
if minetest.get_modpath("default") then
for _, name in pairs({
"default:apple",
"default:papyrus",
"default:dry_shrub",
"default:bush_stem",
"default:acacia_bush_stem",
"default:sign_wall_wood",
"default:sign_wall_steel",
"default:ladder_wood",
"default:ladder_steel",
"default:fence_wood",
"default:fence_acacia_wood",
"default:fence_junglewood",
"default:fence_pine_wood",
"default:fence_aspen_wood",
}) do
add_flow_through(name)
end
end
if minetest.get_modpath("xpanes") then
add_flow_through("xpanes:bar")
add_flow_through("xpanes:bar_flat")
end
if minetest.get_modpath("carts") then
add_flow_through("carts:rail")
add_flow_through("carts:powerrail")
add_flow_through("carts:brakerail")
end
end
dynamic_liquid.mapgen_data = {} -- shared by various mapgens
-- Springs
-----------------------------------------------------------------------------------------------------------------------
local function deep_copy(table_in)
local table_out = {}
for index, value in pairs(table_in) do
@ -305,267 +35,24 @@ local function deep_copy(table_in)
end
return table_out
end
local duplicate_def = function (name)
-- utility function used when making clay into springs
dynamic_liquid.duplicate_def = function (name)
local old_def = minetest.registered_nodes[name]
return deep_copy(old_def)
end
-- register damp clay whether we're going to set the ABM or not, if the user disables this feature we don't want existing
-- spring clay to turn into unknown nodes.
local clay_def = duplicate_def("default:clay")
clay_def.description = S("Damp Clay")
if not springs then
clay_def.groups.not_in_creative_inventory = 1 -- take it out of creative inventory though
end
minetest.register_node("dynamic_liquid:clay", clay_def)
local modpath = minetest.get_modpath(minetest.get_current_modname())
if springs then
minetest.register_abm({
label = "dynamic_liquid damp clay spring",
nodenames = {"dynamic_liquid:clay"},
neighbors = {"air", "default:water_source", "default:water_flowing"},
interval = 1,
chance = 1,
catch_up = false,
action = function(pos,node)
local check_node
local check_node_name
while pos.y < water_level do
pos.y = pos.y + 1
check_node = get_node(pos)
check_node_name = check_node.name
if check_node_name == "air" or check_node_name == "default:water_flowing" then
set_node(pos, {name="default:water_source"})
elseif check_node_name ~= "default:water_source" then
--Something's been put on top of this clay, don't send water through it
break
end
end
end
})
local spring_sounds = nil
if default.node_sound_gravel_defaults ~= nil then
spring_sounds = default.node_sound_gravel_defaults()
elseif default.node_sound_sand_defaults ~= nil then
spring_sounds = default.node_sound_dirt_defaults()
end
-- This is a creative-mode only node that produces a modest amount of water continuously no matter where it is.
-- Allow this one to turn into "unknown node" when this feature is disabled, since players had to explicitly place it.
minetest.register_node("dynamic_liquid:spring", {
description = S("Spring"),
_doc_items_longdesc = S("A natural spring that generates an endless stream of water source blocks"),
_doc_items_usagehelp = S("Generates one source block of water directly on top of itself once per second, provided the space is clear. If this natural spring is dug out the flow stops and it is turned into ordinary cobble."),
drops = "default:gravel",
tiles = {"default_cobble.png^[combine:16x80:0,-48=crack_anylength.png",
"default_cobble.png","default_cobble.png","default_cobble.png","default_cobble.png","default_cobble.png",
},
is_ground_content = false,
groups = {cracky = 3, stone = 2},
sounds = spring_sounds,
})
minetest.register_abm({
label = "dynamic_liquid creative spring",
nodenames = {"dynamic_liquid:spring"},
neighbors = {"air", "default:water_flowing"},
interval = 1,
chance = 1,
catch_up = false,
action = function(pos,node)
pos.y = pos.y + 1
local check_node = get_node(pos)
local check_node_name = check_node.name
if check_node_name == "air" or check_node_name == "default:water_flowing" then
set_node(pos, {name="default:water_source"})
end
end
})
dofile(modpath.."/cooling_lava.lua")
dofile(modpath.."/dynamic_liquids.lua")
dofile(modpath.."/flow_through.lua")
dofile(modpath.."/springs.lua")
dofile(modpath.."/mapgen_prefill.lua")
if minetest.get_modpath("default") then
dofile(modpath.."/default.lua")
end
local mapgen_prefill = minetest.settings:get_bool("dynamic_liquid_mapgen_prefill", true)
if springs or mapgen_prefill then
local data = {}
local c_clay = minetest.get_content_id("default:clay")
local c_spring_clay = minetest.get_content_id("dynamic_liquid:clay")
local c_water = minetest.get_content_id("default:water_source")
local c_air = minetest.get_content_id("air")
local waternodes = {}
local fill_to = function (vi, data, area)
if area:containsi(vi) and area:position(vi).y <= water_level then
if data[vi] == c_air then
data[vi] = c_water
table.insert(waternodes, vi)
return true
end
end
return false
end
-- local count = 0
local drop_liquid = function(vi, data, area, min_y)
if data[vi] ~= c_water then
-- we only care about water.
return false
end
local start = vi -- remember the water node we started from
local ystride = area.ystride
vi = vi - ystride
if data[vi] ~= c_air then
-- if there's no air below this water node, give up immediately.
return false
end
vi = vi - ystride -- There's air below the water, so move down one.
while data[vi] == c_air and area:position(vi).y > min_y do
-- the min_y check is here to ensure that we don't put water into the mapgen
-- border zone below our current map chunk where it might get erased by future mapgen activity.
-- if there's more air, keep going.
vi = vi - ystride
end
vi = vi + ystride -- Move back up one. vi is now pointing at the last air node above the first non-air node.
data[vi] = c_water
data[start] = c_air
-- count = count + 1
-- if count % 100 == 0 then
-- minetest.chat_send_all("dropped water " .. (start-vi)/ystride .. " at " .. minetest.pos_to_string(area:position(vi)))
-- end
return true
end
minetest.register_on_generated(function(minp, maxp, seed)
local maxp_y = maxp.y
local minp_y = minp.y
local vm, emin, emax
local dirty = false
local update_liquids = false
if springs and minp_y < water_level and maxp_y > -15 then
vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
vm:get_data(data)
for voxelpos = 1, #data do
if data[voxelpos] == c_clay then
data[voxelpos] = c_spring_clay
dirty = true
end
end
end
if mapgen_prefill and minp_y <= water_level then
if not vm then
vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
vm:get_data(data)
end
local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
if maxp_y > -70 then
local top = vector.new(maxp.x, math.min(maxp_y, water_level), maxp.z) -- prevents flood fill from affecting any water above sea level
for vi in area:iterp(minp, top) do
if data[vi] == c_water then
table.insert(waternodes, vi)
end
end
while table.getn(waternodes) > 0 do
local vi = table.remove(waternodes)
local below = vi - area.ystride
local left = vi - area.zstride
local right = vi + area.zstride
local front = vi - 1
local back = vi + 1
dirty = fill_to(below, data, area) or dirty
dirty = fill_to(left, data, area) or dirty
dirty = fill_to(right, data, area) or dirty
dirty = fill_to(front, data, area) or dirty
dirty = fill_to(back, data, area) or dirty
end
else
-- Caves sometimes generate with liquid nodes hovering in mid air.
-- This immediately drops them straight down as far as they can go, reducing the ABM thrashing.
-- We only iterate down to minp.y+1 because anything at minp.y will never be dropped farther anyway.
for vi in area:iter(minp.x, minp_y+1, minp.z, maxp.x, maxp_y, maxp.z) do
-- fortunately, area:iter iterates through y columns going upward. Just what we need!
-- We could possibly be a bit more efficient by remembering how far we dropped then
-- last liquid node in a column and moving stuff down that far,
-- but for now let's keep it simple.
dirty = drop_liquid(vi, data, area, minp_y) or dirty
end
end
update_liquids = dirty
end
if dirty then
vm:set_data(data)
vm:write_to_map()
if update_liquids then
vm:update_liquids()
end
end
end)
if minetest.get_modpath("mcl_core") then
dofile(modpath.."/mineclone.lua")
end
local displace_liquid = minetest.settings:get_bool("dynamic_liquid_displace_liquid", true)
if displace_liquid then
local cardinal_dirs = {
{x= 0, y=0, z= 1},
{x= 1, y=0, z= 0},
{x= 0, y=0, z=-1},
{x=-1, y=0, z= 0},
{x= 0, y=-1, z= 0},
{x= 0, y=1, z= 0},
}
-- breadth-first search passing through liquid searching for air or flowing liquid.
local flood_search_outlet = function(start_pos, source, flowing)
local start_node = minetest.get_node(start_pos)
local start_node_name = start_node.name
if start_node_name == "air" or start_node_name == flowing then
return start_pos
end
local visited = {}
visited[minetest.hash_node_position(start_pos)] = true
local queue = {start_pos}
local queue_pointer = 1
while #queue >= queue_pointer do
local current_pos = queue[queue_pointer]
queue_pointer = queue_pointer + 1
for _, cardinal_dir in ipairs(cardinal_dirs) do
local new_pos = vector.add(current_pos, cardinal_dir)
local new_hash = minetest.hash_node_position(new_pos)
if visited[new_hash] == nil then
local new_node = minetest.get_node(new_pos)
local new_node_name = new_node.name
if new_node_name == "air" or new_node_name == flowing then
return new_pos
end
visited[new_hash] = true
if new_node_name == source then
table.insert(queue, new_pos)
end
end
end
end
return nil
end
-- Conserve liquids, when placing nodes in liquids try to find a place to displace the liquid to.
minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
local flowing = dynamic_liquid.registered_liquids[oldnode.name]
if flowing ~= nil then
local dest = flood_search_outlet(pos, oldnode.name, flowing)
if dest ~= nil then
minetest.swap_node(dest, oldnode)
end
end
end)
end

99
mapgen_prefill.lua Normal file
View File

@ -0,0 +1,99 @@
local data = dynamic_liquid.mapgen_data
dynamic_liquid.mapgen_prefill = function(def)
local water_level = def.liquid_level
local c_water = minetest.get_content_id(def.liquid)
local c_air = minetest.get_content_id("air")
local waternodes = {}
local fill_to = function (vi, data, area)
if area:containsi(vi) and area:position(vi).y <= water_level then
if data[vi] == c_air then
data[vi] = c_water
table.insert(waternodes, vi)
end
end
end
-- local count = 0
local drop_liquid = function(vi, data, area, min_y)
if data[vi] ~= c_water then
-- we only care about water.
return
end
local start = vi -- remember the water node we started from
local ystride = area.ystride
vi = vi - ystride
if data[vi] ~= c_air then
-- if there's no air below this water node, give up immediately.
return
end
vi = vi - ystride -- There's air below the water, so move down one.
while data[vi] == c_air and area:position(vi).y > min_y do
-- the min_y check is here to ensure that we don't put water into the mapgen
-- border zone below our current map chunk where it might get erased by future mapgen activity.
-- if there's more air, keep going.
vi = vi - ystride
end
vi = vi + ystride -- Move back up one. vi is now pointing at the last air node above the first non-air node.
data[vi] = c_water
data[start] = c_air
-- count = count + 1
-- if count % 100 == 0 then
-- minetest.chat_send_all("dropped water " .. (start-vi)/ystride .. " at " .. minetest.pos_to_string(area:position(vi)))
-- end
end
minetest.register_on_generated(function(minp, maxp, seed)
if minp.y > water_level then
-- we're in the sky.
return
end
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
vm:get_data(data)
local maxp_y = maxp.y
local minp_y = minp.y
if maxp_y > -70 then
local top = vector.new(maxp.x, math.min(maxp_y, water_level), maxp.z) -- prevents flood fill from affecting any water above sea level
for vi in area:iterp(minp, top) do
if data[vi] == c_water then
table.insert(waternodes, vi)
end
end
while table.getn(waternodes) > 0 do
local vi = table.remove(waternodes)
local below = vi - area.ystride
local left = vi - area.zstride
local right = vi + area.zstride
local front = vi - 1
local back = vi + 1
fill_to(below, data, area)
fill_to(left, data, area)
fill_to(right, data, area)
fill_to(front, data, area)
fill_to(back, data, area)
end
else
-- Caves sometimes generate with liquid nodes hovering in mid air.
-- This immediately drops them straight down as far as they can go, reducing the ABM thrashing.
-- We only iterate down to minp.y+1 because anything at minp.y will never be dropped farther anyway.
for vi in area:iter(minp.x, minp_y+1, minp.z, maxp.x, maxp_y, maxp.z) do
-- fortunately, area:iter iterates through y columns going upward. Just what we need!
-- We could possibly be a bit more efficient by remembering how far we dropped then
-- last liquid node in a column and moving stuff down that far,
-- but for now let's keep it simple.
drop_liquid(vi, data, area, minp_y)
end
end
vm:set_data(data)
vm:write_to_map()
vm:update_liquids()
end)
end

77
mineclone.lua Normal file
View File

@ -0,0 +1,77 @@
local S = minetest.get_translator(minetest.get_current_modname())
local water_probability = dynamic_liquid.config.water_probability
local river_water_probability = dynamic_liquid.config.river_water_probability
local lava_probability = dynamic_liquid.config.lava_probability
local water_level = dynamic_liquid.config.water_level
local springs = dynamic_liquid.config.springs
-- Since lava cooling behaviour can't be overridden in Mineclone, disabling dynamic liquid behaviour for lava
-- otherwise you get lava nodes wandering around on top of oceans covering the whole thing in stone.
--if dynamic_liquid.config.lava then
-- dynamic_liquid.liquid_abm("mcl_core:lava_source", "mcl_core:lava_flowing", lava_probability)
--end
if dynamic_liquid.config.water then
-- override water_source and water_flowing with liquid_renewable set to false
local override_def = {liquid_renewable = false}
minetest.override_item("mcl_core:water_source", override_def)
minetest.override_item("mcl_core:water_flowing", override_def)
dynamic_liquid.liquid_abm("mcl_core:water_source", "mcl_core:water_flowing", water_probability)
end
if dynamic_liquid.config.river_water then
dynamic_liquid.liquid_abm("mclx_core:river_water_source", "mclx_core:river_water_flowing", river_water_probability)
end
if dynamic_liquid.config.springs then
local clay_def = dynamic_liquid.duplicate_def("mcl_core:clay")
clay_def.description = S("Damp Clay")
minetest.register_node("dynamic_liquid:clay", clay_def)
local c_clay = minetest.get_content_id("mcl_core:clay")
local c_spring_clay = minetest.get_content_id("dynamic_liquid:clay")
local spring_placement = function(minp, maxp, data)
if minp.y >= water_level or maxp.y <= -15 then
return false
end
local placed_spring = false
for voxelpos, voxeldata in pairs(data) do
if voxeldata == c_clay then
data[voxelpos] = c_spring_clay
placed_spring = true
end
end
return placed_spring
end
-- mineclone 5
if minetest.get_modpath("mcl_mapgen") and mcl_mapgen.register_on_generated then
mcl_mapgen.register_on_generated(function(vm_context)
if spring_placement(vm_context.minp, vm_context.maxp, vm_context.data) then
vm_context.write = true
end
end, 999999999+1)
end
--mineclone 2
if minetest.get_modpath("mcl_mapgen_core") and mcl_mapgen_core.register_generator then
mcl_mapgen_core.register_generator("dynamic_liquid_damp_clay", function(vm, data, data2, emin, emax, area, minp, maxp, blockseed)
return spring_placement(minp, maxp, data)
end, nil, 999999+1)
end
dynamic_liquid.spring({
nodenames = {"mcl_core:clay"},
water_source = "mcl_core:water_source",
water_flowing = "mcl_core:water_flowing",
y_max = water_level,
y_min = -15,
pressure = 15,
})
end
if dynamic_liquid.config.mapgen_prefill then
dynamic_liquid.mapgen_prefill({liquid="mcl_core:water_source", liquid_level=water_level})
end

View File

@ -1,3 +1,3 @@
name = dynamic_liquid
optional_depends = default, doc, xpanes, carts
optional_depends = default, doc, xpanes, carts, mcl_core, mclx_core, mcl_mapgen_core, mcl_mapgen
description = Flowing dynamic liquids and ocean-maintenance springs.

41
springs.lua Normal file
View File

@ -0,0 +1,41 @@
dynamic_liquid.spring = function(def)
local water_source = def.water_source
local water_flowing = def.water_flowing
local pressure = def.pressure
local y_min = def.y_min or -32768
local y_max = def.y_max or 32767
local interval = def.interval or 1
local chance = def.chance or 1
local get_node = minetest.get_node
local set_node = minetest.set_node
minetest.register_abm({
label = "dynamic_liquid spring " .. table.concat(def.nodenames, ", "),
nodenames = def.nodenames,
neighbors = {"air", def.water_source, def.water_flowing},
interval = interval,
chance = chance,
min_y = y_min,
max_y = y_max-1,
catch_up = false,
action = function(pos,node)
local y = pos.y
local y_top = math.min(y+pressure, y_max)
if y < y_min or y >= y_max then return end
local check_node
local check_node_name
while pos.y < y_top do
pos.y = pos.y + 1
check_node = get_node(pos)
check_node_name = check_node.name
if check_node_name == "air" or check_node_name == water_flowing then
set_node(pos, {name=water_source})
elseif check_node_name ~= water_source then
--Something's been put on top of this clay, don't send water through it
break
end
end
end
})
end