#!/usr/bin/perl
use strict;
use CGI;
use DBI qw(:sql_types);
my $y;
my $z;
my $a;
my $b;
my $cgi=CGI->new();
my $Game=$cgi->param('game')?$cgi->param('game'):'.';
my $Out=$cgi->param('out')?$cgi->param('out'):'map.sqlite';
if(-e "$Game/map.sqlite" && -e "$Game/savegame.txt"){
my $dbGame=DBI->connect("dbi:SQLite:$Game/map.sqlite",'','')||die 'Cannot open map.sqlite';
my $dbSave=DBI->connect('dbi:SQLite:dbname=:memory:','','')||die 'Cannot create inmemory database';
my $dbInput=$dbSave->prepare("CREATE TABLE `blocks` (`pos` INT NOT NULL PRIMARY KEY,`data` BLOB)");
$dbInput->execute();
open(FILE,"<$Game/savegame.txt")||die 'Cannot open savegame.txt';
foreach(<FILE>){
my @line=split(/\,/,$_);
if($line[5]){
$line[0]=int($line[0]/16-1);
$line[1]=int($line[1]/16+1);
$line[2]=int($line[2]/16-1);
$line[3]=int($line[3]/16+1);
$line[4]=int($line[4]/16-1);
$line[5]=int($line[5]/16+1);
print 'Writing ',$line[6];
for(my $x=$line[0];$x<=$line[1];$x++){
for(my $y=$line[2];$y<=$line[3];$y++){
for(my $z=$line[4];$z<=$line[5];$z++){
my $pos=minetest_get_block_as_integer($x,$y,$z);
my $dbData=$dbGame->prepare("SELECT * FROM `blocks` WHERE `pos`=?");
$dbData->execute($pos);
my $rows=$dbData->fetchall_arrayref;
if($rows->[0][1]){
my $dbTest=$dbSave->prepare("SELECT * FROM `blocks` WHERE `pos`=?");
$dbTest->execute($pos);
my $test=$dbTest->fetchall_arrayref;
unless($test->[0][1]){
$dbInput=$dbSave->prepare("INSERT INTO `blocks`(pos,data) VALUES (?,?)");
$dbInput->execute($rows->[0][0],$rows->[0][1]);
}
}
}
}
}
}
}
print "\n";
$dbSave->sqlite_backup_to_file($Out);
$dbSave->disconnect();
$dbGame->disconnect();
}else{
print "Minetest savegame with savegame.txt not found.\n\nUsage of this script:\n";
print "nt_clean.pl game=[path to the savegame directory] out=[path for the new database file]\n\n";
print "Width no use of the game parameter, the data is read from the actual directory.\nWidth no use of the out parameter, the database is written to 'map.sqlite'.\n\n";
print "If you use the script from the savegame directory with no set parameters, the game database will be overwritten with no warning!\n\n";
print "The file savegame.txt is a CSV file with no quotation marks and with comma as separator and following table columns:\n";
print "1 - x from\n2 - x to\n3 - y from\n4 - y to\n5 - z from\n6 - z to\n7 - Name of the block\n\n";
}
sub minetest_unsigned_to_signed{
if($_[0]<$_[1]){
return $_[0];
}else{
return ($_[0]-2*$_[1]);
}
}
sub minetest_get_integer_as_block{
my $int=shift;
my @return;
$return[0]=minetest_unsigned_to_signed($int%4096,2048);
$int=int(($int-$return[0])/4096);
$return[1]=minetest_unsigned_to_signed($int%4096,2048);
$int=int(($int-$return[1])/4096);
$return[2]=minetest_unsigned_to_signed($int%4096,2048);
return @return;
}
sub minetest_get_block_as_integer{
return $_[2]*16777216+$_[1]*4096+$_[0];
}
-100,100,-20,50,-100,100,Center of the World
20,300,200,250,-120,-50,My Skycastle
Marshall_maz wrote:I tried this script but doesn't work. I get sqlite db modules failures.
I can't believe there is no tool to do this. This must be a problem for lots of players all the time.
Krock wrote:Marshall_maz wrote:I tried this script but doesn't work. I get sqlite db modules failures.
I can't believe there is no tool to do this. This must be a problem for lots of players all the time.
Mostly, I delete the file map.sqlite in the world folder to reset the terrain.
But seriously, those worlds aren't that big, mostly I have file sizes between 5 and 10 MB.
Marshall_maz wrote:I tried this script but doesn't work. I get sqlite db modules failures.
aptitude install libdbi-perl
Sokomine wrote:Problem with that is that you don't want blocks to be deleted once players started building there. And finding out if they did is not that easy. I wished for a timestamp for last block change (which might be easy to do in sqlite and other sql databases, but not that easy in leveldb), but...blocks do get changed by abms as well. Especially the intresting surface blocks. While growing flowers are nice, they don't count as buildings worth preserving. The only way I can currently see is to have a database right from the beginning which counts player modifications per block.
#!/usr/bin/env python
import sqlite3
import time
source = r'<PutYourMinetestFolderPathHere>/worlds/<PutYourMapNameHere>/map.sqlite'
target = r'<PutYourMinetestFolderPathHere>/worlds/<PutYourMapNameHere>/map.sqlite.rebuilded'
sourceconn = sqlite3.connect(source)
targetconn = sqlite3.connect(target)
sourcecursor = sourceconn.cursor()
targetcursor = targetconn.cursor()
targetcursor.execute("CREATE TABLE IF NOT EXISTS `blocks` (`pos` INT NOT NULL PRIMARY KEY, `data` BLOB);")
i=0
for row in sourcecursor.execute("SELECT `pos`, `data` "+" FROM `blocks`;"):
pos=getIntegerAsBlock(row[0])
if pos[0]**2 + pos[2]**2 < (1600/16)**2 and pos[1]>(-60/16): #1600 blocks in each direction and 60 blocks deep
targetcursor.execute("INSERT OR IGNORE INTO `blocks` VALUES (?, ?);", (row[0], row[1]))
if ++i > 100:
targetconn.commit()
time.sleep(1)
i=0
targetconn.commit()
sourceconn.close()
targetconn.close()
mike wrote:how does it work?
can you set some areas which should be preserved?
if pos[0]**2 + pos[2]**2 < (160/16)**2 and pos[1]>(-60/16):
targetcursor.execute("INSERT OR IGNORE INTO `blocks` VALUES (?, ?);", (row[0], row[1]))
elif pos[0]>=(200/16) and pos[0]<=(250/16) and pos[2]>=(100/16) and pos[2]<=(150/16) and pos[1]>(-16/16):
targetcursor.execute("INSERT OR IGNORE INTO `blocks` VALUES (?, ?);", (row[0], row[1]))
mike wrote:its nearly the same function as you already coded, but just a special block with distance for each x,y,z, coord.
mike wrote:iam not sure if i can test ist.
currently i have many worlds in my world.
every world has special coordinates like (e.g.):
one 0,0,0
2nd -10000,0,0
3th -20000,0,0
4th -10000,0,-10000
5th 10000,0,0
i have to preserve all of these worlds and for all of these worlds i need to set an area.
so i have to create an sql command that preserves all nodes which are 1000 or more near to these coords.
otherwise i will loose most of the worlds.
mike wrote:i wrote the coords to you via pm.
for some world it could be nice to reset underground someday to uncripple the mines.
mike wrote:which is the "original" script?
many solutions are posted here, but all are hard to use.
i havent taken time to try out this because i have to take much time because i dont want to notice db damage after some weeks.
source = r'~/.minetest/worlds/world1/map.sqlite'
aldobr wrote:minetest map file format needs to be appended with two fields per chunk:
update -> the date of the last update this chunk received.
modified -> weather this chunk was modified from the one generated by the mapgen.
with both field we can write map shrinkers.
eli_3 wrote:Hello,
I minetest version 0.4.10 and I would like to install the 0.4.12.
If I install the 0.4.12 I duplicate the worlds of 0.4.10?
Users browsing this forum: No registered users and 3 guests