Skip to content

Commit 7bdc95c

Browse files
authored
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
1 parent cf67547 commit 7bdc95c

File tree

10 files changed

+765
-575
lines changed

10 files changed

+765
-575
lines changed

autotranslate.py

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# A quick-and-dirty script to run untranslated text through Google Translate's API.
2+
# The result will likely include comical errors a native speaker will laugh at you for
3+
# or that will puzzle them, and some manual correction of escaped codes such as @1 and @= may be
4+
# required, but hopefully it will serve as a start to something useful
5+
6+
# Copyright (C) 2020 FaceDeer
7+
# LGPLv2.1+
8+
9+
# See https://github.com/minetest-tools/update_translations for
10+
# potential future updates to this script.
11+
12+
from googletrans import Translator, LANGUAGES
13+
import os, re, shutil
14+
15+
pattern_tr_filename = re.compile(r'\.tr$')
16+
pattern_tr_id = re.compile(r'\.([^.]*)\.tr$')
17+
pattern_line_to_translate = re.compile(r'^([^#].*[^@])=$') #finds lines that don't have a translation
18+
19+
translator = Translator()
20+
21+
def translate(tr_filename):
22+
lang_id = pattern_tr_id.search(tr_filename)
23+
if not lang_id:
24+
print("Could not find language ID in tr filename " + tr_filename)
25+
return
26+
27+
lang_id = lang_id.group(1)
28+
29+
if not lang_id in LANGUAGES:
30+
print("language ID " + lang_id + " is not supported by Google Translate's API")
31+
return
32+
33+
lines_to_translate = [] # this list of strings will ultimately be sent to Google for translation
34+
with open(tr_filename, "r", encoding="utf-8") as tr_file_handle:
35+
for line in tr_file_handle:
36+
# Look for lines that end in "=", ie, that don't have a valid translation added to them
37+
line_lacking_translation = pattern_line_to_translate.search(line)
38+
if line_lacking_translation:
39+
#break the line up at @n markers, this is not ideal for Google
40+
#as it may remove some context but it's necessary to allow the
41+
#@n markers to be preserved in the output later
42+
lines_to_translate = lines_to_translate + line_lacking_translation.group(1).split("@n")
43+
44+
# Remove duplicates, and the empty string (a common artefact of splitting)
45+
line_set = set(lines_to_translate)
46+
line_set.discard("")
47+
lines_to_translate = list(line_set)
48+
49+
# Only do more work if there are lines in need of translation
50+
if lines_to_translate:
51+
print("Calling Google API for " + tr_filename)
52+
output = translator.translate(lines_to_translate, src="en", dest=lang_id)
53+
54+
#convert the output translations into a dictionary for easy substitution later
55+
translation_dictionary = dict()
56+
for out_line in output:
57+
#Google's API sometimes seems to fail to translate a line for no apparent reason
58+
#Don't put them in the dictionary, we can leave those untranslated and maybe try again
59+
if out_line.origin != out_line.text:
60+
translation_dictionary[out_line.origin] = out_line.text
61+
62+
translation_dictionary["@n"] = "@n" #These are to be left unchanged
63+
64+
tr_file_handle.seek(0)
65+
with open(tr_filename + ".temp", "w", encoding="utf-8") as tr_file_new:
66+
for line in tr_file_handle:
67+
line_lacking_translation = pattern_line_to_translate.search(line)
68+
if line_lacking_translation:
69+
line = line.rstrip('\n') #remove trailing newline so we can add the translated string to the same line
70+
line_split = re.split("(@n)", line[:-1]) #slice to leave off the "=" that's the last character of the line
71+
translated_line = ""
72+
73+
#After splitting the line up on @n again, as was done before, we should have
74+
#line segments that match the strings that were sent to Google.
75+
for line_piece in line_split:
76+
if line_piece in translation_dictionary:
77+
translated_line = translated_line + translation_dictionary[line_piece]
78+
else:
79+
print("Google returned string unchanged in file " + tr_filename + ":")
80+
print(line_piece)
81+
translated_line = None
82+
break
83+
84+
if translated_line:
85+
tr_file_new.write("#WARNING: AUTOTRANSLATED BY GOOGLE TRANSLATE\n")
86+
tr_file_new.write(line)
87+
tr_file_new.write(translated_line)
88+
tr_file_new.write("\n")
89+
else:
90+
tr_file_new.write(line)
91+
tr_file_new.write("\n")
92+
else:
93+
tr_file_new.write(line)
94+
shutil.move(tr_filename + ".temp", tr_filename) # Overwrite the original file with the new one
95+
96+
pattern_domain = re.compile(r'^# textdomain: (.+)$')
97+
98+
def create_tr_files_from_template(folder, lang_id):
99+
if not lang_id in LANGUAGES:
100+
print("language ID " + lang_id + " is not supported by Google Translate's API")
101+
return
102+
for root, dirs, files in os.walk(folder):
103+
if root == "." or os.path.split(root)[1] == "locale":
104+
for name in files:
105+
if name == "template.txt":
106+
template_filename = os.path.join(root,name)
107+
with open(template_filename, "r", encoding="utf-8") as template_file:
108+
first_line = template_file.readline()
109+
domain = pattern_domain.search(first_line)
110+
if domain:
111+
translation_filename = domain.group(1) + "." + lang_id + ".tr"
112+
translation_filename = os.path.join(root,translation_filename)
113+
if not os.path.isfile(translation_filename):
114+
print("Copying template.txt to " + translation_filename)
115+
shutil.copy(template_filename, translation_filename)
116+
else:
117+
print(translation_filename + " already exists")
118+
119+
#If there are already .tr files in /locale, returns a list of their names
120+
def get_existing_tr_files(folder):
121+
out = []
122+
for root, dirs, files in os.walk(folder):
123+
for name in files:
124+
if pattern_tr_filename.search(name):
125+
out.append(os.path.join(root,name))
126+
return out
127+
128+
#create_tr_files_from_template(".", "de")
129+
#create_tr_files_from_template(".", "it")
130+
131+
tr_files = get_existing_tr_files(".")
132+
for tr_file in tr_files:
133+
translate(tr_file)

cooling_lava.lua

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
if not minetest.get_modpath("default") then return end
1+
dynamic_liquid.cooling_lava = function(def)
22

3-
local new_lava_cooling = minetest.settings:get_bool("dynamic_liquid_new_lava_cooling", true)
4-
if not new_lava_cooling then return end
3+
local lava_source = def.lava_source
4+
local lava_flowing = def.lava_flowing
5+
local obsidian = def.obsidian
6+
local flowing_destroys = def.flowing_destroys or {}
7+
local source_destroys = def.source_destroys or {}
8+
local cooling_sound = def.cooling_sound
9+
10+
local falling_obsidian = dynamic_liquid.config.falling_obsidian
511

6-
local falling_obsidian = minetest.settings:get_bool("dynamic_liquid_falling_obsidian", false)
712

813
-- The existing cool_lava ABM is hard-coded to respond to water nodes
914
-- and overriding node groups doesn't appear to work:
@@ -20,7 +25,6 @@ local falling_obsidian = minetest.settings:get_bool("dynamic_liquid_falling_obsi
2025
-- to nodes that should be destroyed by proximity to lava.
2126

2227
local particles = minetest.settings:get_bool("enable_particles", true)
23-
2428
local steam = function(pos)
2529
if particles then
2630
minetest.add_particlespawner({
@@ -43,22 +47,19 @@ local steam = function(pos)
4347
end
4448
end
4549

46-
default.cool_lava = function(pos, node)
47-
-- no-op disables default cooling ABM
48-
end
4950

5051
-------------------------------------------------------------------------------------------------
5152

53+
5254
local dynamic_cools_lava_flowing = {"group:dynamic_cools_lava_flowing", "group:cools_lava"}
5355

5456
-- Flowing lava will turn these blocks into steam.
5557
local dynamic_lava_flowing_destroys = {
5658
"group:dynamic_lava_flowing_destroys",
57-
"default:water_flowing",
58-
"default:river_water_flowing",
59-
"default:snow",
60-
"default:snowblock"
6159
}
60+
for _, node_name in pairs(flowing_destroys) do
61+
table.insert(dynamic_lava_flowing_destroys, node_name)
62+
end
6263

6364
local all_flowing_nodes = {unpack(dynamic_cools_lava_flowing)}
6465
for i = 1, #dynamic_lava_flowing_destroys do
@@ -71,9 +72,9 @@ local cool_lava_flowing = function(pos, node)
7172
if cooler_adjacent ~= nil then
7273
-- pulling nearby sources into position is necessary to break certain classes of
7374
-- flow "deadlock". Weird, but what're you gonna do.
74-
local nearby_source = minetest.find_node_near(pos, 1, "default:lava_source")
75+
local nearby_source = minetest.find_node_near(pos, 1, lava_source)
7576
if nearby_source then
76-
minetest.set_node(pos, {name="default:lava_source"})
77+
minetest.set_node(pos, {name=lava_source})
7778
minetest.set_node(nearby_source, {name="air"})
7879
steam(nearby_source)
7980
else
@@ -92,13 +93,13 @@ local cool_lava_flowing = function(pos, node)
9293
steam(loc)
9394
end
9495

95-
minetest.sound_play("default_cool_lava",
96+
minetest.sound_play(cooling_sound,
9697
{pos = pos, max_hear_distance = 16, gain = 0.25})
9798
end
9899

99100
minetest.register_abm({
100101
label = "Lava flowing cooling",
101-
nodenames = {"default:lava_flowing"},
102+
nodenames = {lava_flowing},
102103
neighbors = all_flowing_nodes,
103104
interval = 1,
104105
chance = 1,
@@ -122,14 +123,11 @@ end
122123
-- lava source blocks will turn these blocks into steam.
123124
local dynamic_lava_source_destroys = {
124125
"group:dynamic_lava_source_destroys",
125-
"default:water_source",
126-
"default:river_water_source",
127-
"default:water_flowing",
128-
"default:river_water_flowing",
129-
"default:ice",
130-
"default:snow",
131-
"default:snowblock"
132126
}
127+
for _, node_name in pairs(source_destroys) do
128+
table.insert(dynamic_lava_source_destroys, node_name)
129+
end
130+
133131

134132
local all_source_nodes = {unpack(dynamic_cools_lava_source)}
135133
for i = 1, #dynamic_lava_source_destroys do
@@ -193,32 +191,35 @@ local cool_lava_source = function(pos, node)
193191

194192
if obsidian_location ~= nil then
195193
minetest.set_node(pos, {name = "air"})
196-
minetest.set_node(obsidian_location, {name = "default:obsidian"})
197-
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.
194+
minetest.set_node(obsidian_location, {name = obsidian})
195+
if falling_obsidian then
198196
minetest.spawn_falling_node(obsidian_location)
199197
end
200198
elseif #evaporate_list > 0 then
201199
-- Again, this weird bit is necessary for breaking certain types of flow deadlock
202200
local loc = evaporate_list[math.random(1,#evaporate_list)]
203201
if loc.y <= pos.y then
204202
minetest.set_node(pos, {name = "air"})
205-
minetest.set_node(loc, {name = "default:lava_source"})
203+
minetest.set_node(loc, {name = lava_source})
206204
end
207205
end
208206

209-
minetest.sound_play("default_cool_lava",
207+
minetest.sound_play(cooling_sound,
210208
{pos = pos, max_hear_distance = 16, gain = 0.25})
211209
end
212210

213211

214212
minetest.register_abm({
215213
label = "Lava source cooling",
216-
nodenames = {"default:lava_source"},
214+
nodenames = {lava_source},
217215
neighbors = all_source_nodes,
218216
interval = 1,
219217
chance = 1,
220218
catch_up = false,
221219
action = function(...)
222220
cool_lava_source(...)
223221
end,
224-
})
222+
})
223+
224+
225+
end

0 commit comments

Comments
 (0)