Skip to content

Commit

Permalink
Add optional conversion to MineClone2, along with a few related fixes.
Browse files Browse the repository at this point in the history
  • Loading branch information
MysticTempest committed Feb 7, 2019
1 parent 3553351 commit 6a52293
Show file tree
Hide file tree
Showing 7 changed files with 2,235 additions and 21 deletions.
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,25 @@ not critical to users, and left out.
- hoppers, dispensers, droppers
- entities

### Extra Notes

License:
Now allows a choice of conversion to Minetest Game or MineClone2.

Currrently compatible with Minecraft Worlds up to, & including v1.12.2


##### Coordinate Conversion from Minecraft to Minetest:
```
X = Approximately the same in both.
Y = Approximately -64 nodes.
Z = The number is approximately inverted.
Example of converted coordinates:
Minecraft: 704, 4, -318
Minetest: 720, -60, 334
```

### License:

Copyright (C) 2016 - Nore, dgm555, sofar and others

Expand Down
40 changes: 37 additions & 3 deletions block.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,6 @@ def isdoor(b):
# rotate lily pads randomly
elif blocks[i] == 111:
param2[i] = random.randint(0,3)
# melon/pumpkin blocks
elif blocks[i] == 86 or blocks[i] == 103:
param2[i] = random.randint(0,23)
# grass of varying length randomly
elif blocks[i] == 31 and data[i] == 1:
content[i], param2[i] = conversion_table[931][random.randint(0,4)]
Expand All @@ -290,6 +287,43 @@ def isdoor(b):
alt = 964
if blocks[i] == 71:
alt = 966
if blocks[i] == 193:
alt = 968
if blocks[i] == 194:
alt = 970
if blocks[i] == 195:
alt = 972
if blocks[i] == 196:
alt = 974
if blocks[i] == 197:
alt = 976
content[i], param2[i] = conversion_table[alt][d_face|d_open|(d_right<<3)]
if d_right == 1:
self.metadata[(i & 0xf, (i>>8) & 0xf, (i>>4) & 0xf)] = ({ "right": "1" }, {})
# re-add code for converting top part of door for MineClone2, ignored for Minetest Game
elif isdoor(blocks[i]) and data[i] >= 8: # top part
below = i - 256
if (below < 0):
logger.warning('Unable to fix door - bottom part is across block boundary! (%d < 0)' % below)
elif isdoor(blocks[below]) and data[below] >= 8:
logger.warning('Unable to fix door - top part 0x%x below top part 0x%x!', data[i], data[below])
else:
d_right = data[i] & 1 # 0 - left, 1 - right
d_open = data[below] & 4 # 0 - closed, 1 - open
d_face = data[below] & 3 # n,e,s,w orientation
alt = 965
if blocks[i] == 71:
alt = 967
if blocks[i] == 193:
alt = 969
if blocks[i] == 194:
alt = 971
if blocks[i] == 195:
alt = 973
if blocks[i] == 196:
alt = 975
if blocks[i] == 197:
alt = 977
content[i], param2[i] = conversion_table[alt][d_face|d_open|(d_right<<3)]
if d_right == 1:
self.metadata[(i & 0xf, (i>>8) & 0xf, (i>>4) & 0xf)] = ({ "right": "1" }, {})
Expand Down
76 changes: 76 additions & 0 deletions content_mcl2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@

def preprocess(lines, flags):
output = []
skip_level = 0
for line in lines:
line = line.split("//")[0].strip() # Remove comment
if line == "":
continue
if line[0] == "#":
if line.startswith("#ifdef"):
cond = line[7:].strip()
if skip_level > 0 or cond not in flags:
skip_level += 1
elif line.startswith("#else"):
if skip_level == 0:
skip_level = 1
elif skip_level == 1:
skip_level = 0
elif line.startswith("#endif"):
if skip_level > 0:
skip_level -= 1
continue
if skip_level == 0:
output.append(line)
return output

def get_id(name_id_mapping, name):
try:
# if the name of the node is known then return the location with the name_id_mapping list
return name_id_mapping.index(name)
except:
# else add the name of the node to the list then return the location
name_id_mapping.append(name)
return len(name_id_mapping)-1

def read_content(flags):
with open("mcl2_map_content.txt", "r") as f:
lines = f.readlines()

lines = preprocess(lines, flags)
# if you map to air, then unknown blocks will be ignored
name_id_mapping = ["air"]
# name_id_mapping = ["mcblock:unknown"]
bd = {} # bd is block data, and keeps a list of the node names in the block
# iterate through all the lines in the map_content.txt file
for line in lines:
s = line.split("\t")
if len(s) >= 2:
r = s[1].split(" ")
if len(r) == 0:
print(line)
raise ValueError("Malformed data")
name = r[0]
param2 = 0
for i in range(1, len(r)):
if r[i] != "":
param2 = int(r[i])
break
t = s[0].split(" ")
if len(t) == 2:
for data in t[1].split(","):
key = (int(t[0]), int(data))
if key not in bd:
bd[key] = (get_id(name_id_mapping, name), param2)
elif len(t) == 1:
for data in range(16):
key = (int(t[0]), data)
if key not in bd:
bd[key] = (get_id(name_id_mapping, name), param2)

#blocks_len = max([i[0] for i in bd.keys()])+1
blocks_len = 4096
blocks = [[(0, 0)]*16 for i in range(blocks_len)]
for (id, data), value in bd.items():
blocks[id][data] = value
return name_id_mapping, blocks
95 changes: 95 additions & 0 deletions map_content.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1139,3 +1139,98 @@
966 13 doors:door_steel_a 1
966 14 doors:door_steel_a 2
966 15 doors:door_steel_a 3


//spruce wood door
968 0 doors:door_wood_a 1
968 1 doors:door_wood_a 2
968 2 doors:door_wood_a 3
968 3 doors:door_wood_a 0
968 4 doors:door_wood_b 2
968 5 doors:door_wood_b 3
968 6 doors:door_wood_b 0
968 7 doors:door_wood_b 1
968 8 doors:door_wood_b 1
968 9 doors:door_wood_b 2
968 10 doors:door_wood_b 3
968 11 doors:door_wood_b 0
968 12 doors:door_wood_a 0
968 13 doors:door_wood_a 1
968 14 doors:door_wood_a 2
968 15 doors:door_wood_a 3


//birch wood door
970 0 doors:door_wood_a 1
970 1 doors:door_wood_a 2
970 2 doors:door_wood_a 3
970 3 doors:door_wood_a 0
970 4 doors:door_wood_b 2
970 5 doors:door_wood_b 3
970 6 doors:door_wood_b 0
970 7 doors:door_wood_b 1
970 8 doors:door_wood_b 1
970 9 doors:door_wood_b 2
970 10 doors:door_wood_b 3
970 11 doors:door_wood_b 0
970 12 doors:door_wood_a 0
970 13 doors:door_wood_a 1
970 14 doors:door_wood_a 2
970 15 doors:door_wood_a 3


//jungle wood door
972 0 doors:door_wood_a 1
972 1 doors:door_wood_a 2
972 2 doors:door_wood_a 3
972 3 doors:door_wood_a 0
972 4 doors:door_wood_b 2
972 5 doors:door_wood_b 3
972 6 doors:door_wood_b 0
972 7 doors:door_wood_b 1
972 8 doors:door_wood_b 1
972 9 doors:door_wood_b 2
972 10 doors:door_wood_b 3
972 11 doors:door_wood_b 0
972 12 doors:door_wood_a 0
972 13 doors:door_wood_a 1
972 14 doors:door_wood_a 2
972 15 doors:door_wood_a 3


//acacia wood door
974 0 doors:door_wood_a 1
974 1 doors:door_wood_a 2
974 2 doors:door_wood_a 3
974 3 doors:door_wood_a 0
974 4 doors:door_wood_b 2
974 5 doors:door_wood_b 3
974 6 doors:door_wood_b 0
974 7 doors:door_wood_b 1
974 8 doors:door_wood_b 1
974 9 doors:door_wood_b 2
974 10 doors:door_wood_b 3
974 11 doors:door_wood_b 0
974 12 doors:door_wood_a 0
974 13 doors:door_wood_a 1
974 14 doors:door_wood_a 2
974 15 doors:door_wood_a 3


//dark oak wood door
976 0 doors:door_wood_a 1
976 1 doors:door_wood_a 2
976 2 doors:door_wood_a 3
976 3 doors:door_wood_a 0
976 4 doors:door_wood_b 2
976 5 doors:door_wood_b 3
976 6 doors:door_wood_b 0
976 7 doors:door_wood_b 1
976 8 doors:door_wood_b 1
976 9 doors:door_wood_b 2
976 10 doors:door_wood_b 3
976 11 doors:door_wood_b 0
976 12 doors:door_wood_a 0
976 13 doors:door_wood_a 1
976 14 doors:door_wood_a 2
976 15 doors:door_wood_a 3
49 changes: 32 additions & 17 deletions mcimport.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

cd `dirname $0`

if [ ! -f map_content.txt ]; then
zenity --info --width=800 --text "Unable to locate \"map_content.txt\" file - this is a critical error, and this program is unable to continue."
if [ ! -f map_content.txt ] || [ ! -f mcl2_map_content.txt ]; then
zenity --info --width=800 --text "Unable to locate \"map_content.txt\" or \"mcl2_map_content.txt\" file - this is a critical error, and this program is unable to continue."
exit 1
fi

Expand All @@ -32,23 +32,38 @@ if [ -d "${HOME}/.minetest/worlds/$OUT" ]; then
rm -rf "${HOME}/.minetest/worlds/$OUT"
fi

zenity --info --width=800 --title="Conversion in progress" --text="The conversion is now running and make take a *very* long time to finish. Do not be alarmed by output lines that show \"Unknown Minecraft Block\" messages, this is normal and can usually be ignored without issues. You can safely close this window." &
if [ $? == 0 ]; then
`zenity --question --width=800 --title="Select a game for the converted map?" --text="Would you like mcimport to convert the map for use in Minetest Game or MineClone2?" --ok-label="Minetest Game" --cancel-label="MineClone2"`
if [ $? == 0 ]; then
zenity --info --width=800 --title="Conversion in progress" --text="The conversion is now running and may take a *very* long time to finish. Do not be alarmed by output lines that show \"Unknown Minecraft Block\" messages, this is normal and can usually be ignored without issues. You can safely close this window." &

python3 mcimport.py "$IN" "${HOME}/.minetest/worlds/$OUT"
python3 mcimport.py "$IN" "${HOME}/.minetest/worlds/$OUT"

if [ $? == 0 ]; then
if ! zenity --width=800 --question --title="Download required mods?" --text="The world was succesfully converted. Do you want me to download and install all the required mods now? This should be done for each converted world."; then
exit 0
if [ $? == 0 ]; then
if ! zenity --width=800 --question --title="Download required mods?" --text="The world was succesfully converted. Do you want me to download and install all the required mods now? This should be done for each converted world."; then
exit 0
fi
cd "${HOME}/.minetest/worlds/$OUT"
(
bash get-mods.sh
echo "====================="
echo "Finished! You can now close this window!"
) | zenity --text-info --width=800 --height=600 --title='Downloading required mods.' --text='Downloading...'
zenity --width=800 --info --text "Conversion finished! Your world should now be playable in Minetest."
else
zenity --info --width=800 --text "Conversion didn't finish normally, the resulting world may not be playable."
exit
fi
else zenity --info --width=800 --title="Conversion in progress" --text="The conversion is now running and may take a *very* long time to finish. Do not be alarmed by output lines that show \"Unknown Minecraft Block\" messages, this is normal and can usually be ignored without issues. You can safely close this window." &

python3 mcimport_mcl2.py "$IN" "${HOME}/.minetest/worlds/$OUT"

if [ $? == 0 ]; then
zenity --width=800 --info --text "Conversion finished! Your world should now be playable in Minetest."
else
zenity --info --width=800 --text "Conversion didn't finish normally, the resulting world may not be playable."
exit
fi
fi
cd "${HOME}/.minetest/worlds/$OUT"
(
bash get-mods.sh
echo "====================="
echo "Finished! You can now close this window!"
) | zenity --text-info --width=800 --height=600 --title='Downloading required mods.' --text='Downloading...'
else
zenity --info --width=800 --text "Conversion didn't finish normally, the resulting world may not be playable."
exit 1
fi

zenity --width=800 --info --text "Conversion finished! Your world should now be playable in Minetest."
63 changes: 63 additions & 0 deletions mcimport_mcl2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/bin/env python

import os
import stat
import sys
import logging
from block import *
import content_mcl2

logging.basicConfig(level=logging.INFO)

if (sys.version_info < (3, 0)):
print("This script does not work with Python < 3.0, sorry.")
exit(1)

if not os.path.exists(sys.argv[1]):
print("The provided minecraft world path does not exist.")
exit(1)

if not os.path.exists(sys.argv[2]):
os.makedirs(sys.argv[2])

if os.path.exists(sys.argv[2] + "map.sqlite"):
print("A minetest world already exists - refusing to overwrite it.")
exit(1)

if not os.path.exists(sys.argv[2] + "/world.mt"):
with open(sys.argv[2] + "/world.mt", "w") as wo:
wo.write("backend = sqlite3\n")
wo.write("gameid = MineClone2\n")

if not os.path.exists(sys.argv[2] + "/worldmods"):
os.makedirs(sys.argv[2]+"/worldmods")
if not os.path.exists(sys.argv[2] + "/worldmods/mcimport"):
os.makedirs(sys.argv[2]+"/worldmods/mcimport")
if not os.path.exists(sys.argv[2]+"/worldmods/mcimport/init.lua"):
with open(sys.argv[2]+"/worldmods/mcimport/init.lua", "w") as sn:
sn.write("-- map conversion requires a special water level\n")
sn.write("minetest.set_mapgen_params({water_level = -2})\n\n")
sn.write("-- prevent overgeneration in incomplete chunks, and allow lbms to work\n")
sn.write("minetest.set_mapgen_params({chunksize = 1})\n\n")
sn.write("-- comment the line below if you want to enable mapgen (will destroy things!)\n")
sn.write("minetest.set_mapgen_params({mgname = \"singlenode\"})\n\n")
sn.write("-- below lines will recalculate lighting on map block load\n")
sn.write("minetest.register_on_generated(function(minp, maxp, seed)\n")
sn.write(" local vm = minetest.get_voxel_manip(minp, maxp)\n")
sn.write(" vm:set_lighting({day = 15, night = 0}, minp, maxp)\n")
sn.write(" vm:update_liquids()\n")
sn.write(" vm:write_to_map()\n")
sn.write(" vm:update_map()\n")
sn.write("end)\n\n")


mcmap = MCMap(sys.argv[1])
mtmap = MTMap(sys.argv[2])

nimap, ct = content_mcl2.read_content(["NETHER", "QUARTZ"])
mtmap.fromMCMap(mcmap, nimap, ct)
mtmap.save()

print("Conversion finished!\n")
print("Please enjoy your new MineClone2 world!")

Loading

0 comments on commit 6a52293

Please sign in to comment.