minetest/util/minesplice.py

295 lines
8.3 KiB
Python
Raw Normal View History

2012-06-18 12:51:27 +02:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
minesplice.py: copy, swap, and delete minetest blocks between map files
2012-06-21 08:47:35 +02:00
Copyright (C) 2012 Bad_Command
2012-06-18 12:51:27 +02:00
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
'''
from optparse import OptionParser
import re
import math
import sqlite3 as sql
def blockAsInt(x, y, z):
return int(z * 16777216 + y * 4096 + x)
def swapBlocks(srcmap, srcvol, dstmap, dstpos):
try:
srcCon = sql.connect(srcmap);
dstCon = sql.connect(dstmap);
srcCurs = srcCon.cursor();
dstCurs = dstCon.cursor();
selectStmt = "SELECT `data` FROM `blocks` WHERE `pos` = ?1"
insertStmt = "REPLACE INTO `blocks`(`pos`, `data`) VALUES (?1, ?2)"
srcvol = srcvol.toBlockCoord();
tX = 0;
tY = 0;
tZ = 0;
if dstpos:
dstpos = dstpos.toBlockCoord();
tX = dstpos.X - srcvol.X
tY = dstpos.Y - srcvol.Y
tZ = dstpos.Z - srcvol.Z
swapcount = 0
progresscount = 0
totalvolume = srcvol.dX * srcvol.dY * srcvol.dZ
for x in range(0, srcvol.dX):
for y in range(0, srcvol.dY):
for z in range(0, srcvol.dZ):
srcblockid = blockAsInt(srcvol.X + x, srcvol.Y + y, srcvol.Z + z)
srcCurs.execute(selectStmt, (srcblockid,))
srcdata = srcCurs.fetchone();
dstblockid = blockAsInt(srcvol.X + x + tX, srcvol.Y + y + tY, srcvol.Z + z + tZ)
dstCurs.execute(selectStmt, (dstblockid,))
dstdata = dstCurs.fetchone();
if srcdata:
dstCurs.execute(insertStmt, (dstblockid, srcdata[0]))
if dstdata:
srcCurs.execute(insertStmt, (srcblockid, dstdata[0]))
if ( srcdata and dstdata ):
swapcount += 1;
progresscount += 1
if ( progresscount % (totalvolume/10) == 0):
print 100 * progresscount / totalvolume, "% done";
srcCon.commit()
dstCon.commit()
print "Swapped", swapcount, "/", totalvolume, "blocks,", (100 * swapcount) / totalvolume, "% (anything else had void space)"
except sql.Error, e:
print "Error %s:" % e.args[0]
finally:
if srcCon:
srcCon.close
if dstCon:
dstCon.close
def copyBlocks(srcmap, srcvol, dstmap, dstpos):
try:
srcCon = sql.connect(srcmap);
dstCon = sql.connect(dstmap);
srcCurs = srcCon.cursor();
dstCurs = dstCon.cursor();
selectStmt = "SELECT `data` FROM `blocks` WHERE `pos` = ?1"
insertStmt = "REPLACE INTO `blocks`(`pos`, `data`) VALUES (?1, ?2)"
srcvol = srcvol.toBlockCoord();
tX = 0;
tY = 0;
tZ = 0;
if dstpos:
dstpos = dstpos.toBlockCoord();
tX = dstpos.X - srcvol.X
tY = dstpos.Y - srcvol.Y
tZ = dstpos.Z - srcvol.Z
copycount = 0
progresscount = 0
totalvolume = srcvol.dX * srcvol.dY * srcvol.dZ
for x in range(0, srcvol.dX):
for y in range(0, srcvol.dY):
for z in range(0, srcvol.dZ):
blockid = blockAsInt(srcvol.X + x, srcvol.Y + y, srcvol.Z + z)
srcCurs.execute(selectStmt, (blockid,))
data = srcCurs.fetchone();
if data:
blockid = blockAsInt(srcvol.X + x + tX, srcvol.Y + y + tY, srcvol.Z + z + tZ)
dstCurs.execute(insertStmt, (blockid, data[0]))
copycount += 1
progresscount += 1
if ( progresscount % (totalvolume/10) == 0):
print 100 * progresscount / totalvolume, "% done";
dstCon.commit()
print "Copied", copycount, "/", totalvolume, "blocks,", (100 * copycount) / totalvolume, "% (anything else was void space)"
except sql.Error, e:
print "Error %s:" % e.args[0]
finally:
if srcCon:
srcCon.close
if dstCon:
dstCon.close
def deleteBlocks(srcmap, srcvol):
try:
con = sql.connect(srcmap);
curs = con.cursor();
deleteStmt = "DELETE FROM `blocks` WHERE `pos` = ?1"
srcvol = srcvol.toBlockCoord();
progresscount = 0
deletecount = 0
totalvolume = srcvol.dX * srcvol.dY * srcvol.dZ
for x in range(0, srcvol.dX):
for y in range(0, srcvol.dY):
for z in range(0, srcvol.dZ):
blockid = blockAsInt(srcvol.X + x, srcvol.Y + y, srcvol.Z + z)
curs.execute(deleteStmt, (blockid,))
if ( curs.rowcount > 0 ):
deletecount += 1
progresscount += 1
if ( progresscount % (totalvolume/10) == 0):
print 100 * progresscount / totalvolume, "% done";
con.commit()
print "Deleted", deletecount, "/", totalvolume, "blocks,", (100 * deletecount) / totalvolume, "% (anything else was void space)"
except sql.Error, e:
print "Error %s:" % e.args[0]
finally:
if con:
con.close
class Coordinates:
X = 0;
Y = 0;
Z = 0;
dX = 0;
dY = 0;
dZ = 0;
def toBlockCoord(self):
coords = Coordinates();
coords.X = int(math.floor(self.X / 16.0));
coords.Y = int(math.floor(self.Y / 16.0));
coords.Z = int(math.floor(self.Z / 16.0));
coords.dX = int(math.ceil(self.dX / 16.0));
coords.dY = int(math.ceil(self.dY / 16.0));
coords.dZ = int(math.ceil(self.dZ / 16.0));
return coords;
def parseVolume(vol):
p = re.compile("^src=(-?\\d{1,5}),(-?\\d{1,5}),(-?\\d{1,5})\\+(\\d{1,5})\\+(\\d{1,5})\\+(\\d{1,5})$")
match = p.match(vol);
if match == None:
return None;
o = Coordinates()
o.X = int(match.group(1));
o.Y = int(match.group(2));
o.Z = int(match.group(3));
o.dX = int(match.group(4));
o.dY = int(match.group(5));
o.dZ = int(match.group(6));
return o;
def parseCoord(coord):
p = re.compile("^dst=(-?\\d{1,5}),(-?\\d{1,5}),(-?\\d{1,5})$")
match = p.match(coord);
if match == None:
return None;
o = Coordinates()
o.X = int(match.group(1));
o.Y = int(match.group(2));
o.Z = int(match.group(3));
return o;
def main():
2012-06-18 13:07:06 +02:00
parser = OptionParser("""Usage: %prog [-c|-s|-d] source-map.sqlite src=X,Y,Z+dX+dY+dZ [destination-map.sqlite] [dst=X',Y',Z']
source-map.sqlite is the source map
2012-06-18 12:51:27 +02:00
X,Y,Z are coordinates for the start of the operation volume
+dX is the length (along X-axis) of the operation volume
+dY is the height (along Y-axis) of the operation volume
+dZ is the width (along Z-axis) of the operation volume
2012-06-18 13:07:06 +02:00
destination-map.sqlite is the destination map (not needed when deleting)
X',Y',Z' are the coordinates in the destination map (used when moving blocks)
2012-06-18 12:51:27 +02:00
Ideally coordinates should be multiples of 16 (block boundaries). If not:
X, Y, Z will round down
dX, dY, dZ will round up""")
parser.add_option("-c", "--copy", action="store_true", dest="copy",
2012-06-21 08:47:35 +02:00
help="Copy blocks from source-map to destination-map")
2012-06-18 12:51:27 +02:00
parser.add_option("-s", "--swap", action="store_true", dest="swap",
2012-06-21 08:47:35 +02:00
help="Swap the specified blocks between the source-map and destination-map")
2012-06-18 12:51:27 +02:00
parser.add_option("-d", "--delete", action="store_true", dest="delete",
2012-06-21 08:47:35 +02:00
help="Delete blocks from source-map")
2012-06-18 12:51:27 +02:00
(options, args) = parser.parse_args()
print options;
print args;
optCount = 0;
if options.copy == True:
optCount += 1;
if options.swap == True:
optCount += 1;
if options.delete == True:
optCount += 1;
if optCount > 1 or optCount < 1:
print "Must specify one and only one option"
return
if len(args) < 2:
print "Must at least specify source.mt X,Y,Z+dX+dY+dZ"
return
if len(args) > 4:
print "Too many arguments"
return
srcmap = args[0];
srcvol = parseVolume(args[1]);
if srcvol == None:
print "Invalid source volume: ", args[1];
return;
if len(args) >= 3:
dstmap = args[2];
dstpos = None
if len(args) == 4:
dstpos = parseCoord(args[3]);
if dstpos == None:
print "Invalid destination location: " , args[3];
return
if options.copy == True:
if len(args) < 3:
print "Must specify source.mt X,Y,Z+dX+dY+dZ destination.mt";
return;
copyBlocks(srcmap, srcvol, dstmap, dstpos);
if options.swap == True:
if len(args) < 3:
print "Must specify source.mt X,Y,Z+dX+dY+dZ destination.mt";
return;
swapBlocks(srcmap, srcvol, dstmap, dstpos);
if options.delete == True:
if len(args) != 2:
print "Must specify source.mt X,Y,Z+dX+dY+dZ";
return;
deleteBlocks(srcmap, srcvol);
if __name__ == '__main__':
main();