Also allow saving maps as .mine that can be imported by minecraft classic, still a WIP though

This commit is contained in:
UnknownShadow200 2022-11-10 23:08:12 +11:00
parent 70258163f1
commit 6aec5e83f2
3 changed files with 105 additions and 5 deletions

View File

@ -1587,3 +1587,97 @@ cc_result Schematic_Save(struct Stream* stream) {
}
return Stream_Write(stream, sc_end, sizeof(sc_end));
}
const int spawn_value = 8;
static const struct JField {
cc_uint8 type;
const char* name;
void* value;
} level_fields[] = {
{ JFIELD_I32, "width", &World.Width },
{ JFIELD_I32, "depth", &World.Height },
{ JFIELD_I32, "height", &World.Length },
{ JFIELD_I32, "xSpawn", &spawn_value },
{ JFIELD_I32, "ySpawn", &spawn_value },
{ JFIELD_I32, "zSpawn", &spawn_value },
/*{JFIELD_I32, "skyColor", &Env.SkyCol},
{ JFIELD_I32, "fogColor", &Env.FogCol},
{ JFIELD_I32, "cloudColor", &Env.CloudsCol},*/
{ JFIELD_ARRAY, "blocks", &World.Blocks }
/* TODO spawn, classic only blocks */
};
static int WriteJavaString(cc_uint8* dst, const char* value) {
int length = String_Length(value);
dst[0] = 0;
dst[1] = length;
Mem_Copy(dst + 2, value, length);
return length;
}
static cc_result WriteClassDesc(struct Stream* stream, cc_uint8 typecode, const char* klass,
int numFields, const struct JField* fields) {
cc_uint8 header[256] = { 0 };
static const cc_uint8 footer[] = {
TC_ENDBLOCKDATA, /* classAnnotations */
TC_NULL /* superClassDesc */
};
int i, length;
cc_result res;
header[0] = typecode;
header[1] = TC_CLASSDESC;
length = WriteJavaString(header + 2, klass);
header[4 + length + 8] = SC_SERIALIZABLE;
header[4 + length + 9] = 0;
header[4 + length + 10] = numFields;
if ((res = Stream_Write(stream, header, 15 + length))) return res;
for (i = 0; i < numFields; i++)
{
header[0] = fields[i].type;
length = WriteJavaString(header + 1, fields[i].name);
if (fields[i].type == JFIELD_ARRAY) {
header[3 + length + 0] = TC_STRING;
WriteJavaString(&header[3 + length + 1], "[B");
length += 5;
}
if ((res = Stream_Write(stream, header, 3 + length))) return res;
}
if ((res = Stream_Write(stream, footer, sizeof(footer)))) return res;
return 0;
}
cc_result Dat_Save(struct Stream* stream) {
static const cc_uint8 header[] = {
/* DAT signature + version */
0x27,0x1B,0xB7,0x88, 0x02,
/* JSF signature + version */
0xAC,0xED, 0x00,0x05
};
cc_uint8 tmp[4];
cc_result res;
int i;
if ((res = Stream_Write(stream, header, sizeof(header)))) return res;
if ((res = WriteClassDesc(stream, TC_OBJECT, "com.mojang.minecraft.level.Level",
Array_Elems(level_fields), level_fields))) return res;
/* Write field values */
for (i = 0; i < Array_Elems(level_fields); i++)
{
if (level_fields[i].type == JFIELD_I32) {
Stream_SetU32_BE(tmp, *((int*)level_fields[i].value));
if ((res = Stream_Write(stream, tmp, 4))) return res;
} else {
if ((res = WriteClassDesc(stream, TC_ARRAY, "[B", 0, NULL))) return res;
Stream_SetU32_BE(tmp, World.Volume);
if ((res = Stream_Write(stream, tmp, 4))) return res;
if ((res = Stream_Write(stream, World.Blocks, World.Volume))) return res;
}
}
return 0;
}

View File

@ -29,9 +29,12 @@ cc_result Cw_Load(struct Stream* stream);
cc_result Dat_Load(struct Stream* stream);
/* Exports a world to a .cw ClassicWorld map file. */
/* Compatible with ClassiCube/ClassicalSharp. */
/* Compatible with ClassiCube/ClassicalSharp */
cc_result Cw_Save(struct Stream* stream);
/* Exports a world to a .schematic Schematic map file. */
/* Used by MCEdit and other tools. */
/* Exports a world to a .schematic Schematic map file */
/* Used by MCEdit and other tools */
cc_result Schematic_Save(struct Stream* stream);
/* Exports a world to a .dat Classic map file */
/* Used by MineCraft Classic */
cc_result Dat_Save(struct Stream* stream);
#endif

View File

@ -1324,6 +1324,7 @@ static void DownloadMap(const cc_string* path) {
static cc_result SaveLevelScreen_SaveMap(struct SaveLevelScreen* s, const cc_string* path) {
static const cc_string schematic = String_FromConst(".schematic");
static const cc_string mine = String_FromConst(".mine");
struct Stream stream, compStream;
struct GZipState state;
cc_result res;
@ -1337,6 +1338,8 @@ static cc_result SaveLevelScreen_SaveMap(struct SaveLevelScreen* s, const cc_str
#else
if (String_CaselessEnds(path, &schematic)) {
res = Schematic_Save(&compStream);
} else if (String_CaselessEnds(path, &mine)) {
res = Dat_Save(&compStream);
} else {
res = Cw_Save(&compStream);
}
@ -1411,10 +1414,10 @@ static void SaveLevelScreen_UploadCallback(const cc_string* path) {
static void SaveLevelScreen_File(void* a, void* b) {
static const char* const titles[] = {
"ClassiCube map", "MineCraft schematic", NULL
"ClassiCube map", "MineCraft schematic", "MineCraft classic map", NULL
};
static const char* const filters[] = {
".cw", ".schematic", NULL
".cw", ".schematic", ".mine", NULL
};
static struct SaveFileDialogArgs args = {
filters, titles, SaveLevelScreen_UploadCallback