Initial commit

master
kwolekr 2013-06-07 02:23:37 -04:00
commit 117a3cfe60
10 changed files with 1324 additions and 0 deletions

71
Makefile Executable file
View File

@ -0,0 +1,71 @@
PROGNAME = mcconvert
rm = /bin/rm -f
CC = cc
CXX = c++
AS = as
DEFS = -Wno-multichar
INCLUDES = -I. -I/usr/local/include
LIBS = -L/usr/local/lib -lz -lsqlite3
DEFINES = $(INCLUDES) $(DEFS) -DSYS_UNIX=1
CFLAGS = -pipe -Wall -O3 $(DEFINES)
CXXFLAGS = -pipe -Wall -O3 $(DEFINES)
ASFLAGS =
SOURCES = db.c \
mapcontent.c \
mcconvert.c \
vector.c
OBJECTS = ${SOURCES:.c=.o}
SRCS = ${addprefix src/,$(SOURCES)}
OBJS = ${addprefix obj/,$(OBJECTS)}
.SILENT:
obj/%.o: src/%.c
mkdir -p $(@D);
#$(rm) $@;
if ${CC} ${CFLAGS} -c -o $@ $<; then \
printf "\033[32mbuilt $@.\033[m\n"; \
else \
printf "\033[31mbuild of $@ failed!\033[m\n"; \
false; \
fi
obj/%.o: src/%.cpp
mkdir -p $(@D);
$(rm) $@;
if ${CXX} ${CXXFLAGS} -c -o $@ $<; then \
printf "\033[32mbuilt $@.\033[m\n"; \
else \
printf "\033[31mbuild of $@ failed!\033[m\n"; \
false; \
fi
obj/%.o: src/%.s
mkdir -p $(@D);
$(rm) $@;
if ${AS} ${ASFLAGS} $< -o $@; then \
printf "\033[32mbuilt $@.\033[m\n"; \
else \
printf "\033[31mbuild of $@ failed!\033[m\n"; \
false; \
fi
all: $(PROGNAME)
debug: CFLAGS = -pipe -Wall -g $(DEFINES)
debug: $(PROGNAME)
$(PROGNAME) : $(OBJS)
if $(CC) $(CFLAGS) -o $(PROGNAME) $(OBJS) $(LIBS); then \
printf "\033[32mlinked $@.\033[m\n"; \
else \
printf "\033[31mlink of $@ failed!\033[m\n"; \
false; \
fi
clean:
$(rm) $(PROGNAME) core *~
$(rm) -rf obj/*

63
mcconvert.cbp Normal file
View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="mcconvert" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug">
<Option output="bin/Debug/mcconvert" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/" />
<Option type="1" />
<Option compiler="gcc" />
<Option parameters="/usr/home/ryan/Desktop/asdf_uncompressed.mine" />
<Compiler>
<Add option="-g" />
</Compiler>
</Target>
<Target title="Release">
<Option output="bin/Release/mcconvert" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Release/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
</Compiler>
<Linker>
<Add option="-s" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wall" />
<Add directory="/usr/local/include" />
</Compiler>
<Linker>
<Add library="/usr/lib/libz.so" />
<Add library="/usr/local/lib/libsqlite3.so" />
</Linker>
<Unit filename="src/db.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/db.h" />
<Unit filename="src/mapcontent.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/mapcontent.h" />
<Unit filename="src/mcconvert.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/mcconvert.h" />
<Unit filename="src/vector.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/vector.h" />
<Extensions>
<envvars />
<code_completion />
<lib_finder disable_auto="1" />
<debugger />
</Extensions>
</Project>
</CodeBlocks_project_file>

132
src/db.c Normal file
View File

@ -0,0 +1,132 @@
/*-
* Copyright (c) 2013 Ryan Kwolek <kwolekr@minetest.net>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* db.c -
* Routines related to database manipulation
*/
#include "mcconvert.h"
#include "mapcontent.h"
#include "db.h"
sqlite3 *m_database = NULL;
sqlite3_stmt *m_database_read = NULL;
sqlite3_stmt *m_database_write = NULL;
sqlite3_stmt *m_database_list = NULL;
///////////////////////////////////////////////////////////////////////////////
void DBCreate() {
int e = sqlite3_exec(m_database,
"CREATE TABLE IF NOT EXISTS `blocks` ("
"`pos` INT NOT NULL PRIMARY KEY,"
"`data` BLOB"
");", NULL, NULL, NULL);
if (e == SQLITE_ABORT)
fprintf(stderr, "Could not create database structure\n");
else
printf("Database structure was created\n");
}
int DBVerify() {
if (!m_database) {
int needs_create;
int d;
needs_create = 1; //!stat(OUTPUT_FILENAME, NULL);
d = sqlite3_open_v2(OUTPUT_FILENAME, &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
if (d != SQLITE_OK) {
fprintf(stderr, "WARNING: Database failed to open: %s\n", sqlite3_errmsg(m_database));
return 0;
}
if (needs_create)
DBCreate();
d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
if (d != SQLITE_OK) {
fprintf(stderr, "WARNING: Database read statment failed to prepare: %s\n", sqlite3_errmsg(m_database));
return 0;
}
d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
if (d != SQLITE_OK) {
fprintf(stderr, "WARNING: Database write statment failed to prepare: %s\n", sqlite3_errmsg(m_database));
return 0;
}
d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
if (d != SQLITE_OK) {
fprintf(stderr, "WARNING: Database list statment failed to prepare: %s\n", sqlite3_errmsg(m_database));
return 0;
}
printf("Database opened\n");
}
return 1;
}
int DBSaveMapBlock(MapBlock *block) {
DBVerify();
// To make things easy, just guess the needed size of the buffer.
// This seems like a generous enough amount.
u8 *output = malloc(0x20000);
size_t outlen = MapBlockSerialize(block, output);
if (outlen > 0x20000) {
fprintf(stderr, "UH OH, serialized output was too big\n");
exit(0);
}
int success = 0;
if (sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
fprintf(stderr, "WARNING: begin save failed, saving might be slow.\n");
if (sqlite3_bind_int64(m_database_write, 1, MapBlockPosToInteger(block->pos)) != SQLITE_OK)
fprintf(stderr, "WARNING: Block position failed to bind: %s\n", sqlite3_errmsg(m_database));
if (sqlite3_bind_blob(m_database_write, 2, output, outlen, NULL) != SQLITE_OK)
fprintf(stderr, "WARNING: Block data failed to bind: %s\n", sqlite3_errmsg(m_database));
int written = sqlite3_step(m_database_write);
if (written != SQLITE_DONE)
fprintf(stderr, "ERROR: Block failed to save (%d, %d, %d) %s\n",
block->pos.X, block->pos.Y, block->pos.Z, sqlite3_errmsg(m_database));
success = 1;
sqlite3_reset(m_database_write);
if (sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
fprintf(stderr, "WARNING: end save failed, map might not have saved.\n");
free(output);
return success;
}

36
src/db.h Normal file
View File

@ -0,0 +1,36 @@
/*-
* Copyright (c) 2013 Ryan Kwolek <kwolekr@minetest.net>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DB_HEADER
#define DB_HEADER
extern sqlite3 *m_database;
extern sqlite3_stmt *m_database_read;
extern sqlite3_stmt *m_database_write;
extern sqlite3_stmt *m_database_list;
void DBCreate();
int DBVerify();
int DBSaveMapBlock(MapBlock *block);
#endif // DB_HEADER

233
src/mapcontent.c Normal file
View File

@ -0,0 +1,233 @@
/*-
* Copyright (c) 2013 Ryan Kwolek <kwolekr@minetest.net>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* mapcontent.c -
* Routines pertaining to map node names, name-id mapping, and map block serialization
*/
#include "mcconvert.h"
#include "mapcontent.h"
const char *node_names[] = {
"air",
"default:stone",
"default:dirt_with_grass",
"default:dirt",
"default:cobble",
"default:wood",
"default:sapling",
"default:cloud", //actually bedrock, but this is indestructable as well
"default:water_flowing",
"default:water_source",
"default:lava_flowing",
"default:lava_source",
"default:sand",
"default:gravel",
"default:stone_with_mese",
"default:stone_with_iron",
"default:stone_with_coal",
"default:tree",
"default:leaves",
"default:nyancat_rainbow", //sponge...
"default:glass",
"wool:red", //red
"wool:orange", //orange
"wool:yellow", //yellow
"wool:green", //lightgreen
"wool:green", //green
"wool:darkgreen", //aquagreen
"wool:cyan", //cyan
"wool:blue", //lightblue
"wool:blue", //blue
"wool:violet", //purple
"wool:violet", //lightpurple
"wool:pink", //pink
"wool:magenta", //darkpink
"wool:dark_grey", //darkgrey
"wool:grey", //lightgrey
"wool:white", //white
"", //yellow flower
"", //red flower
"", //mushroom1
"", //mushroom2
"default:mese",
"default:steelblock",
"default:cobble", //full step
"stairs:slab_cobble", //half step
"default:brick",
"", //tnt
"default:bookshelf",
"default:mossycobble",
"default:obsidian"
};
///////////////////////////////////////////////////////////////////////////////
sqlite3_int64 MapBlockPosToInteger(const v3s16 pos) {
return (sqlite3_int64)pos.Z * 16777216 +
(sqlite3_int64)pos.Y * 4096 +
(sqlite3_int64)pos.X;
}
LPVECTOR MapBlockCreateMappingTableAndFixNodes(MapNode *nodes, size_t nnodes) {
u8 global_to_relative_id_map[ARRAYLEN(node_names)];
LPVECTOR names_seen = NULL;
int i;
u8 id, global_id, relative_id, num_ids = 0;
memset(global_to_relative_id_map, 0xFF, sizeof(global_to_relative_id_map));
for (i = 0; i != nnodes; i++) {
global_id = nodes[i].param0;
if (global_id >= ARRAYLEN(node_names)) {
fprintf(stderr, "ERROR: Invalid node ID 0x%04x\n", (u16)global_id);
return NULL;
}
relative_id = global_to_relative_id_map[global_id];
if (relative_id != 0xFF) {
id = relative_id;
} else {
if (*node_names[global_id]) {
id = num_ids;
num_ids++;
global_to_relative_id_map[global_id] = id;
VectorAdd(&names_seen, node_names[global_id]);
} else {
id = 0; //just make it anything, whatever the first node was
}
}
nodes[i].param0 = id;
}
return names_seen;
}
size_t MapBlockSerialize(MapBlock *block, u8 *outbuf) {
u8 *os = outbuf;
u8 *compressed_data;
size_t compressed_len;
LPVECTOR names_seen;
// MapBlock serialization version
InsertU8(os, 25);
// Flag byte
u8 flags = 0;
InsertU8(os, flags);
// Bulk node data
u32 nodecount = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
u8 content_width = 2;
u8 params_width = 2;
InsertU8(os, content_width);
InsertU8(os, params_width);
names_seen = MapBlockCreateMappingTableAndFixNodes(block->data, nodecount);
if (!names_seen) {
fprintf(stderr, "crap\n");
return 0;
}
MapNodeSerializeBulk(block->data, nodecount, &compressed_data, &compressed_len);
memcpy(os, compressed_data, compressed_len);
os += compressed_len;
free(compressed_data);
// Node metadata
u8 buf[4];
WriteU8(buf, 0); //version 1 for real data, 0 for "go away"
ZLibCompress(buf, 1, &compressed_data, &compressed_len);
memcpy(os, compressed_data, compressed_len);
os += compressed_len;
free(compressed_data);
// Static objects
InsertU8(os, 0);
InsertU16(os, 0);
// Timestamp
InsertU32(os, 0xFFFFFFFF);
// Write block-specific node definition id mapping
InsertU8(os, 0);
InsertU16(os, names_seen->numelem); //num ids
int i;
for (i = 0; i != names_seen->numelem; i++) {
size_t len;
InsertU16(os, i);
len = strlen(names_seen->elem[i]);
InsertU16(os, len);
memcpy(os, names_seen->elem[i], len);
os += len;
}
free(names_seen);
InsertU8(os, 2+4+4);
InsertU16(os, 0); //number of timers, none
return os - outbuf;
}
void MapNodeSerializeBulk(const MapNode *nodes, u32 nodecount,
u8 **outbuf, size_t *outlen) {
unsigned int i;
size_t datalen = nodecount * sizeof(MapNode);
u8 *databuf = malloc(datalen);
u8 *d = databuf;
// Serialize content
for (i = 0; i != nodecount; i++) {
WriteU16(d, nodes[i].param0);
d += sizeof(nodes[i].param0);
}
// Serialize param1
for (i = 0; i != nodecount; i++) {
WriteU8(d, nodes[i].param1);
d += sizeof(nodes[i].param1);
}
// Serialize param2
for (i = 0; i != nodecount; i++) {
WriteU8(d, nodes[i].param2);
d += sizeof(nodes[i].param2);
}
ZLibCompress(databuf, datalen, outbuf, outlen);
free(databuf);
}

103
src/mapcontent.h Normal file
View File

@ -0,0 +1,103 @@
/*-
* Copyright (c) 2013 Ryan Kwolek <kwolekr@minetest.net>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
Disk serialized MapBlock format:
(u8) version = 8
basic information
(u8) flags = 0
(u8) content width = 2
(u8) params width = 2
node data
ZLib deflate {
for each node:
(u16) param0
for each node:
(u8) param1
for each node:
(u8) param2
}
ZLib deflate {
node metadata list
(u8) version = 1
(s16) count
for each nodemetadata:
()
}
static object list
(u8) version = 0
(u16) count
for each stored object:
()
for each active object:
()
name-id mapping
(u8) version = 0
(u16) count
for each name-id mapping:
(u16) id = ids are of what first occur in the block, start at 0
(u16) name length
(u8[]) name
node timer list
(u8) version = 10
(u16) count
*/
/*
Sample data:
19 ;mapblock version
08 ;flags
02 ;content width
02 ;params width
789CEDC13101000000C2A0F54F6D0C1FA000000000000000000000000000000080B70140000001789C63000000010001000000
FFFFFFFF ;timestamp
00 ;nameidmapping version
0001 ;count
0000 ;id
0006 ;strlen("ignore")
69 67 6E 6F 72 65 ;string "ignore"
0A ;node timer version
0000 ;node timer count
*/
#ifndef MAPCONTENT_HEADER
#define MAPCONTENT_HEADER
#include "vector.h"
LPVECTOR MapBlockCreateMappingTableAndFixNodes(MapNode *nodes, size_t nnodes);
size_t MapBlockSerialize(MapBlock *block, u8 *outbuf);
void MapNodeSerializeBulk(const MapNode *nodes, u32 nodecount,
u8 **outbuf, size_t *outlen);
sqlite3_int64 MapBlockPosToInteger(const v3s16 pos);
#endif // MAPCONTENT_HEADER

378
src/mcconvert.c Normal file
View File

@ -0,0 +1,378 @@
/*-
* Copyright (c) 2013 Ryan Kwolek <kwolekr@minetest.net>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* mcconvert.c -
* A utility to convert an extracted Minecraft Classic map to
* Minetest's 0.4.x SQLite3 format.
*/
#include "mcconvert.h"
#include "vector.h"
#include "mapcontent.h"
#include "db.h"
#include <zlib.h>
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char *argv[]) {
char fn_output_buf[256];
char *fn_input, *fn_output;
FILE *fin;
uint32_t magic;
uint8_t version;
if (argc < 2) {
fprintf(stderr, "Insufficient number of arguments\n");
return 1;
}
fn_input = argv[1];
fn_output = fn_output_buf;
strlcpy(fn_output_buf, fn_input, sizeof(fn_output_buf));
fin = fopen(fn_input, "rb");
if (!fin) {
perror("Could not open input file for read");
return 1;
}
fread(&magic, 1, sizeof(magic), fin);
magic = SWAP4(magic);
if (magic != 0x271bb788) {
fprintf(stderr, "Header mismatch, invalid Minecraft Classic map file\n");
fclose(fin);
return 1;
}
fread(&version, 1, sizeof(version), fin);
if (version != 2) {
fprintf(stderr, "Unhandled map file version\n");
fclose(fin);
return 1;
}
#if 0
fseek(fin, 6, SEEK_CUR); // ac ed 00 05 73 72
for (i = 0; i != 3; i++) {
char *str;
uint16_t slen;
fread(&slen, 1, sizeof(slen), fin);
slen = SWAP2(slen);
str = malloc(slen + 1);
fread(str, slen, 1, fin);
str[slen] = 0;
printf("str: %s\n", str);
free(str);
}
#endif
fseek(fin, MCC_MAPDATA_OFFSET, SEEK_SET);
u8 *mcdata = malloc(MAP_NNODES);
int nread = fread(mcdata, MAP_NNODES, 1, fin);
if (nread != 1) {
fprintf(stderr, "Failed to read node data\n");
return 1;
}
ConvertMCToMT(mcdata);
CreateWalls();
//free(mcdata);
printf("done!\n");
if (m_database_read)
sqlite3_finalize(m_database_read);
if (m_database_write)
sqlite3_finalize(m_database_write);
if (m_database)
sqlite3_close(m_database);
return 0;
}
void ConvertMCToMT(u8 *mcdata) {
int bx, by, bz;
MapBlock *block = malloc(sizeof(MapBlock));
for (by = 0; by != MAP_NBLOCKS_Y; by++) {
for (bz = 0; bz != MAP_NBLOCKS_Z; bz++) {
for (bx = 0; bx != MAP_NBLOCKS_X; bx++) {
CopyMapBlockFromMC(mcdata, bx, by, bz, block->data);
block->pos.X = bx;
block->pos.Y = by;
block->pos.Z = bz;
DBSaveMapBlock(block);
}
}
}
free(block);
}
void CopyMapBlockFromMC(u8 *mcdata, s16 bx, s16 by, s16 bz, MapNode *blockdata) {
int x, y, z;
int i = 0;
bx *= MAP_BLOCKSIZE;
by *= MAP_BLOCKSIZE;
bz *= MAP_BLOCKSIZE;
bx = 255 - bx;
for (z = 0; z != MAP_BLOCKSIZE; z++) {
for (y = 0; y != MAP_BLOCKSIZE; y++) {
// X coordinate needs to be inverted for some reason
for (x = 0; x != MAP_BLOCKSIZE; x++) {
int index = MINDEX(bx - x, by + y, bz + z);
blockdata[i].param0 = mcdata[index];
blockdata[i].param1 = 0x0F; // full lighting in daytime for now
blockdata[i].param2 = 0;
i++;
}
}
}
}
void CreateWalls() {
int bx, by, bz;
int x, y, z;
int i;
MapBlock *mblock = malloc(sizeof(MapBlock));
MapBlock *block = malloc(sizeof(MapBlock));
////////////////-y
i = 0;
for (z = 0; z != MAP_BLOCKSIZE; z++) {
for (y = 0; y != MAP_BLOCKSIZE; y++) {
for (x = 0; x != MAP_BLOCKSIZE; x++) {
mblock->data[i].param0 = (y == MAP_BLOCKSIZE - 1) ? 7 : 0;
mblock->data[i].param1 = 0x0F;
mblock->data[i].param2 = 0;
i++;
}
}
}
for (bz = 0; bz != MAP_NBLOCKS_Z; bz++) {
for (bx = 0; bx != MAP_NBLOCKS_X; bx++) {
block->pos.X = bx;
block->pos.Y = -1;
block->pos.Z = bz;
memcpy(block->data, mblock->data, sizeof(block->data));
DBSaveMapBlock(block);
}
}
////////////////-x
i = 0;
for (z = 0; z != MAP_BLOCKSIZE; z++) {
for (y = 0; y != MAP_BLOCKSIZE; y++) {
for (x = 0; x != MAP_BLOCKSIZE; x++) {
mblock->data[i].param0 = (x == MAP_BLOCKSIZE - 1) ? 7 : 0;
mblock->data[i].param1 = 0x0F;
mblock->data[i].param2 = 0;
i++;
}
}
}
for (bz = 0; bz != MAP_NBLOCKS_Z; bz++) {
for (by = 0; by != MAP_NBLOCKS_Y / 2; by++) {
block->pos.X = -1;
block->pos.Y = by;
block->pos.Z = bz;
memcpy(block->data, mblock->data, sizeof(block->data));
DBSaveMapBlock(block);
}
}
////////////////+x
i = 0;
for (z = 0; z != MAP_BLOCKSIZE; z++) {
for (y = 0; y != MAP_BLOCKSIZE; y++) {
for (x = 0; x != MAP_BLOCKSIZE; x++) {
mblock->data[i].param0 = (x == 0) ? 7 : 0;
mblock->data[i].param1 = 0x0F;
mblock->data[i].param2 = 0;
i++;
}
}
}
for (bz = 0; bz != MAP_NBLOCKS_Z; bz++) {
for (by = 0; by != MAP_NBLOCKS_Y / 2; by++) {
block->pos.X = MAP_NBLOCKS_X;
block->pos.Y = by;
block->pos.Z = bz;
memcpy(block->data, mblock->data, sizeof(block->data));
DBSaveMapBlock(block);
}
}
////////////////-z
i = 0;
for (z = 0; z != MAP_BLOCKSIZE; z++) {
for (y = 0; y != MAP_BLOCKSIZE; y++) {
for (x = 0; x != MAP_BLOCKSIZE; x++) {
mblock->data[i].param0 = (z == MAP_BLOCKSIZE - 1) ? 7 : 0;
mblock->data[i].param1 = 0x0F;
mblock->data[i].param2 = 0;
i++;
}
}
}
for (by = 0; by != MAP_NBLOCKS_Y / 2; by++) {
for (bx = 0; bx != MAP_NBLOCKS_X; bx++) {
block->pos.X = bx;
block->pos.Y = by;
block->pos.Z = -1;
memcpy(block->data, mblock->data, sizeof(block->data));
DBSaveMapBlock(block);
}
}
////////////////+z
i = 0;
for (z = 0; z != MAP_BLOCKSIZE; z++) {
for (y = 0; y != MAP_BLOCKSIZE; y++) {
for (x = 0; x != MAP_BLOCKSIZE; x++) {
mblock->data[i].param0 = (z == 0) ? 7 : 0;
mblock->data[i].param1 = 0x0F;
mblock->data[i].param2 = 0;
i++;
}
}
}
for (by = 0; by != MAP_NBLOCKS_Y / 2; by++) {
for (bx = 0; bx != MAP_NBLOCKS_X; bx++) {
block->pos.X = bx;
block->pos.Y = by;
block->pos.Z = MAP_NBLOCKS_Z;
memcpy(block->data, mblock->data, sizeof(block->data));
DBSaveMapBlock(block);
}
}
free(block);
free(mblock);
}
/////////////////// Zlib wrappers
int ZLibCompress(u8 *data, size_t datalen, u8 **out, size_t *outlen) {
z_stream z;
int status = 0;
int ret;
unsigned char *outbuf;
size_t outbuflen;
*out = NULL;
*outlen = 0;
z.zalloc = Z_NULL;
z.zfree = Z_NULL;
z.opaque = Z_NULL;
ret = deflateInit(&z, -1);
if (ret != Z_OK) {
fprintf(stderr, "compressZlib: deflateInit failed");
return 0;
}
outbuflen = deflateBound(&z, datalen);
outbuf = malloc(outbuflen);
z.next_in = (Bytef *)data;
z.avail_in = datalen;
z.next_out = outbuf;
z.avail_out = outbuflen;
status = deflate(&z, Z_FINISH);
deflateEnd(&z);
if (status != Z_STREAM_END) {
fprintf(stderr, "compressZlib: deflate failed");
return 0;
}
*outlen = outbuflen - z.avail_out;
*out = outbuf;
return 1;
}
int ZLibDecompress(u8 *data, size_t datalen, u8 **out, size_t *outlen) {
z_stream z;
int status = 0;
int ret;
unsigned char *outbuf;
size_t outbuflen;
*out = NULL;
*outlen = 0;
z.zalloc = Z_NULL;
z.zfree = Z_NULL;
z.opaque = Z_NULL;
ret = deflateInit(&z, -1);
if (ret != Z_OK) {
fprintf(stderr, "compressZlib: deflateInit failed");
return 0;
}
outbuflen = deflateBound(&z, datalen);
outbuf = malloc(outbuflen);
z.next_in = (Bytef *)data;
z.avail_in = datalen;
z.next_out = outbuf;
z.avail_out = outbuflen;
status = deflate(&z, Z_FINISH);
deflateEnd(&z);
if (status != Z_STREAM_END) {
fprintf(stderr, "compressZlib: deflate failed");
return 0;
}
*outlen = outbuflen - z.avail_out;
*out = outbuf;
return 1;
}

149
src/mcconvert.h Normal file
View File

@ -0,0 +1,149 @@
/*-
* Copyright (c) 2013 Ryan Kwolek <kwolekr@minetest.net>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MCCONVERT_HEADER
#define MCCONVERT_HEADER
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sqlite3.h>
#define MAP_BLOCKSIZE 16
#define MAP_BLOCKNUMNODES (MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE)
#define ARRAYLEN(a) (sizeof(a) / sizeof((a)[0]))
#define SWAP2(num) ((((num) >> 8) & 0x00FF) | \
(((num) << 8) & 0xFF00))
#define SWAP4(num) ((((num) >> 24) & 0x000000FF) | \
(((num) >> 8) & 0x0000FF00) | \
(((num) << 8) & 0x00FF0000) | \
(((num) << 24) & 0xFF000000))
#define OUTPUT_FILENAME "tehmap.sqlite"
// These parameters need to be guessed
#define MCC_MAP_CX 256
#define MCC_MAP_CY 64
#define MCC_MAP_CZ 256
#define MCC_MAPDATA_OFFSET 20630
#define MAP_NNODES (MCC_MAP_CX * MCC_MAP_CY * MCC_MAP_CZ)
#define MAP_NBLOCKS_X (MCC_MAP_CX / MAP_BLOCKSIZE)
#define MAP_NBLOCKS_Y (MCC_MAP_CY / MAP_BLOCKSIZE)
#define MAP_NBLOCKS_Z (MCC_MAP_CZ / MAP_BLOCKSIZE)
#define MINDEX(x,y,z) ((x) + ((y) * MCC_MAP_CX * MCC_MAP_CZ) + ((z) * MCC_MAP_CX))
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef struct _v2s16 {
s16 X;
s16 Y;
} v2s16;
typedef struct _v3s16 {
s16 X;
s16 Y;
s16 Z;
} v3s16;
typedef struct _MapNode {
u16 param0;
u8 param1;
u8 param2;
} MapNode;
typedef struct _MapBlock {
v3s16 pos;
MapNode data[MAP_BLOCKNUMNODES];
} MapBlock;
static inline void WriteU64(u8 *data, u64 i) {
data[0] = ((i >> 56) & 0xff);
data[1] = ((i >> 48) & 0xff);
data[2] = ((i >> 40) & 0xff);
data[3] = ((i >> 32) & 0xff);
data[4] = ((i >> 24) & 0xff);
data[5] = ((i >> 16) & 0xff);
data[6] = ((i >> 8) & 0xff);
data[7] = ((i >> 0) & 0xff);
}
static inline void WriteU32(u8 *data, u32 i) {
data[0] = ((i >> 24) & 0xff);
data[1] = ((i >> 16) & 0xff);
data[2] = ((i >> 8) & 0xff);
data[3] = ((i >> 0) & 0xff);
}
static inline void WriteU16(u8 *data, u16 i) {
data[0] = ((i >> 8) & 0xff);
data[1] = ((i >> 0) & 0xff);
}
static inline void WriteU8(u8 *data, u8 i) {
data[0] = ((i >> 0) & 0xff);
}
#define InsertU8(data, i) { \
WriteU8(data, i); \
data += sizeof(u8); \
}
#define InsertU16(data, i) { \
WriteU16(data, i); \
data += sizeof(u16); \
}
#define InsertU32(data, i) { \
WriteU32(data, i); \
data += sizeof(u32); \
}
#define InsertU64(data, i) { \
WriteU64(data, i); \
data += sizeof(u64); \
}
int ZLibCompress(u8 *data, size_t datalen, u8 **out, size_t *outlen);
int ZLibDecompress(u8 *data, size_t datalen, u8 **out, size_t *outlen);
void CopyMapBlockFromMC(u8 *mcdata, s16 bx, s16 by, s16 bz, MapNode *blockdata);
void ConvertMCToMT(u8 *mcdata);
void CreateWalls();
#endif //MCCONVERT_HEADER

116
src/vector.c Normal file
View File

@ -0,0 +1,116 @@
/*-
* Copyright (c) 2010 Ryan Kwolek <kwolekr@minetest.net>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* vector.c -
* Routines to maintain a dynamic, auto-resizing array with built in counter.
*/
#include <stdlib.h>
#include "vector.h"
///////////////////////////////////////////////////////////////////////////////
LPVECTOR VectorInit(unsigned int size) {
LPVECTOR vect;
vect = (LPVECTOR)malloc(sizeof(VECTOR) + size * sizeof(void *));
vect->numelem = 0;
vect->maxelem = size;
return vect;
}
LPVECTOR VectorAdd(LPVECTOR *vector, void *item) {
LPVECTOR v = *vector;
if (!v)
v = VectorInit(VECTOR_DEFAULT_SIZE);
if (v->numelem == v->maxelem) {
v->maxelem <<= 1;
v = realloc(v, sizeof(VECTOR) + v->maxelem * sizeof(void *));
}
v->elem[v->numelem] = item;
v->numelem++;
*vector = v;
return v;
}
int VectorRemove(LPVECTOR vector, void *item) {
int i, found = 0;
if (!vector)
return 0;
for (i = 0; i != vector->numelem; i++) {
if (found)
vector->elem[i - 1] = vector->elem[i];
if (vector->elem[i] == item) {
found = 1;
vector->numelem--;
}
}
#ifdef VECTOR_TRIM_ARRAYS
if (vector->numelem < (vector->maxelem >> 2)) {
vector->maxelem >>= 1;
vector = realloc(vector, sizeof(VECTOR) + vector->maxelem * sizeof(void *));
}
#endif
return found;
}
void VectorRemoveItem(LPVECTOR vector, int index) {
int i;
if (!vector || index >= vector->numelem)
return;
for (i = index; i != vector->numelem; i++)
vector->elem[i] = vector->elem[i + 1];
vector->numelem--;
}
void VectorClear(LPVECTOR vector) {
int i;
for (i = 0; i != vector->numelem; i++)
free(vector->elem[i]);
vector->numelem = 0;
}
void VectorDelete(LPVECTOR vector) {
int i;
for (i = 0; i != vector->numelem; i++)
free(vector->elem[i]);
free(vector);
}

43
src/vector.h Normal file
View File

@ -0,0 +1,43 @@
/*-
* Copyright (c) 2013 Ryan Kwolek <kwolekr@minetest.net>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef VECTOR_HEADER
#define VECTOR_HEADER
#define VECTOR_DEFAULT_SIZE 4
//#define VECTOR_TRIM_ARRAYS
typedef struct _vector {
int numelem;
int maxelem;
void *elem[0];
} VECTOR, *LPVECTOR;
LPVECTOR VectorInit(unsigned int size);
LPVECTOR VectorAdd(LPVECTOR *vector, void *item);
int VectorRemove(LPVECTOR vector, void *item);
void VectorRemoveItem(LPVECTOR vector, int index);
void VectorClear(LPVECTOR vector);
void VectorDelete(LPVECTOR vector);
#endif // VECTOR_HEADER