Redesign map importing to not be so hardcoded

This commit is contained in:
UnknownShadow200 2023-06-17 18:32:09 +10:00
parent 7204116ad1
commit e9ddb97f56
4 changed files with 88 additions and 48 deletions

View File

@ -17,6 +17,8 @@
#include "TexturePack.h" #include "TexturePack.h"
#include "Utils.h" #include "Utils.h"
static cc_bool calcDefaultSpawn; static cc_bool calcDefaultSpawn;
static struct MapImporter* imp_head;
static struct MapImporter* imp_tail;
/*########################################################################################################################* /*########################################################################################################################*
@ -41,25 +43,25 @@ static cc_result Map_SkipGZipHeader(struct Stream* stream) {
return 0; return 0;
} }
IMapImporter Map_FindImporter(const cc_string* path) { void MapImporter_Register(struct MapImporter* imp) {
static const cc_string cw = String_FromConst(".cw"), lvl = String_FromConst(".lvl"); LinkedList_Append(imp, imp_head, imp_tail);
static const cc_string fcm = String_FromConst(".fcm"), dat = String_FromConst(".dat"); }
static const cc_string mine = String_FromConst(".mine");
static const cc_string mclvl = String_FromConst(".mclevel");
if (String_CaselessEnds(path, &cw)) return Cw_Load; struct MapImporter* MapImporter_Find(const cc_string* path) {
if (String_CaselessEnds(path, &lvl)) return Lvl_Load; struct MapImporter* imp;
if (String_CaselessEnds(path, &fcm)) return Fcm_Load; cc_string ext;
if (String_CaselessEnds(path, &dat)) return Dat_Load;
if (String_CaselessEnds(path, &mine)) return Dat_Load;
if (String_CaselessEnds(path, &mclvl)) return MCLevel_Load;
for (imp = imp_head; imp; imp = imp->next)
{
ext = String_FromReadonly(imp->fileExt);
if (String_CaselessEnds(path, &ext)) return imp;
}
return NULL; return NULL;
} }
cc_result Map_LoadFrom(const cc_string* path) { cc_result Map_LoadFrom(const cc_string* path) {
cc_string relPath, fileName, fileExt; cc_string relPath, fileName, fileExt;
IMapImporter importer; struct MapImporter* imp;
struct Stream stream; struct Stream stream;
cc_result res; cc_result res;
Game_Reset(); Game_Reset();
@ -68,10 +70,10 @@ cc_result Map_LoadFrom(const cc_string* path) {
res = Stream_OpenFile(&stream, path); res = Stream_OpenFile(&stream, path);
if (res) { Logger_SysWarn2(res, "opening", path); return res; } if (res) { Logger_SysWarn2(res, "opening", path); return res; }
importer = Map_FindImporter(path); imp = MapImporter_Find(path);
if (!importer) { if (!imp) {
res = ERR_NOT_SUPPORTED; res = ERR_NOT_SUPPORTED;
} else if ((res = importer(&stream))) { } else if ((res = imp->import(&stream))) {
World_Reset(); World_Reset();
} }
@ -171,7 +173,9 @@ static cc_result Lvl_ReadCustomBlocks(struct Stream* stream) {
return 0; return 0;
} }
cc_result Lvl_Load(struct Stream* stream) { /* Imports a world from a .lvl MCSharp server map file */
/* Used by MCSharp/MCLawl/MCForge/MCDzienny/MCGalaxy */
static cc_result Lvl_Load(struct Stream* stream) {
cc_uint8 header[18]; cc_uint8 header[18];
cc_uint8* blocks; cc_uint8* blocks;
cc_uint8 section; cc_uint8 section;
@ -258,7 +262,9 @@ static cc_result Fcm_ReadString(struct Stream* stream) {
return stream->Skip(stream, len); return stream->Skip(stream, len);
} }
cc_result Fcm_Load(struct Stream* stream) { /* Imports a world from a .fcm fCraft server map file (v3 only) */
/* Used by fCraft/800Craft/LegendCraft/ProCraft */
static cc_result Fcm_Load(struct Stream* stream) {
cc_uint8 header[79]; cc_uint8 header[79];
cc_result res; cc_result res;
int i, count; int i, count;
@ -863,7 +869,9 @@ static void Cw_Callback(struct NbtTag* tag) {
0 1 2 3 4 */ 0 1 2 3 4 */
} }
cc_result Cw_Load(struct Stream* stream) { /* Imports a world from a .cw ClassicWorld map file */
/* Used by ClassiCube/ClassicalSharp */
static cc_result Cw_Load(struct Stream* stream) {
return Nbt_Read(stream, Cw_Callback); return Nbt_Read(stream, Cw_Callback);
} }
@ -1326,7 +1334,9 @@ static cc_result Dat_LoadFormat2(struct Stream* stream) {
return 0; return 0;
} }
cc_result Dat_Load(struct Stream* stream) { /* Imports a world from a .dat classic map file */
/* Used by Minecraft Classic/WoM client */
static cc_result Dat_Load(struct Stream* stream) {
cc_uint8 header[4 + 1]; cc_uint8 header[4 + 1];
cc_uint32 signature; cc_uint32 signature;
cc_result res; cc_result res;
@ -1417,6 +1427,7 @@ static void MCLevel_ParseEnvironment(struct NbtTag* tag) {
} else if (IsTag(tag, "SurroundingWaterHeight")) { } else if (IsTag(tag, "SurroundingWaterHeight")) {
mcl_edgeHeight = NbtTag_U16(tag); mcl_edgeHeight = NbtTag_U16(tag);
} }
/* TODO: SkyBrightness */
} }
@ -1455,7 +1466,9 @@ static void MCLevel_Callback(struct NbtTag* tag) {
0 1 2 */ 0 1 2 */
} }
cc_result MCLevel_Load(struct Stream* stream) { /* Imports a world from a .mclevel NBT map file */
/* Used by Minecraft Indev client */
static cc_result MCLevel_Load(struct Stream* stream) {
cc_result res = Nbt_Read(stream, MCLevel_Callback); cc_result res = Nbt_Read(stream, MCLevel_Callback);
Env.EdgeHeight = mcl_edgeHeight; Env.EdgeHeight = mcl_edgeHeight;
@ -1836,3 +1849,32 @@ cc_result Dat_Save(struct Stream* stream) {
} }
return 0; return 0;
} }
/*########################################################################################################################*
*-------------------------------------------------------Formats component-------------------------------------------------*
*#########################################################################################################################*/
static struct MapImporter cw_imp = { ".cw", Cw_Load };
static struct MapImporter dat_imp = { ".dat", Dat_Load };
static struct MapImporter lvl_imp = { ".lvl", Lvl_Load };
static struct MapImporter mine_imp = { ".mine", Dat_Load };
static struct MapImporter fcm_imp = { ".fcm", Fcm_Load };
static struct MapImporter mclvl_imp = { ".mclevel", MCLevel_Load };
static void OnInit(void) {
MapImporter_Register(&cw_imp);
MapImporter_Register(&dat_imp);
MapImporter_Register(&lvl_imp);
MapImporter_Register(&mine_imp);
MapImporter_Register(&fcm_imp);
MapImporter_Register(&mclvl_imp);
}
static void OnFree(void) {
imp_head = NULL;
}
struct IGameComponent Formats_Component = {
OnInit, /* Init */
OnFree /* Free */
};

View File

@ -6,30 +6,26 @@
*/ */
struct Stream; struct Stream;
/* Imports a world encoded in a particular map file format. */ struct IGameComponent;
typedef cc_result (*IMapImporter)(struct Stream* stream); extern struct IGameComponent Formats_Component;
/* Attempts to find a suitable importer based on filename. */
/* Returns NULL if no match found. */
CC_API IMapImporter Map_FindImporter(const cc_string* path);
/* Attempts to import the map from the given file. */
/* NOTE: Uses Map_FindImporter to import based on filename. */
CC_API cc_result Map_LoadFrom(const cc_string* path);
/* Imports a world from a .lvl MCSharp server map file. */ /* Imports a world encoded in a particular map file format */
/* Used by MCSharp/MCLawl/MCForge/MCDzienny/MCGalaxy. */ typedef cc_result (*MapImportFunc)(struct Stream* stream);
cc_result Lvl_Load(struct Stream* stream); struct MapImporter;
/* Imports a world from a .fcm fCraft server map file. (v3 only) */ /* Reads/Loads world data (and potentially metadata) encoded in a particular format */
/* Used by fCraft/800Craft/LegendCraft/ProCraft. */ struct MapImporter {
cc_result Fcm_Load(struct Stream* stream); const char* fileExt; /* File extension of the map format */
/* Imports a world from a .cw ClassicWorld map file. */ MapImportFunc import; /* Function that imports the encoded data */
/* Used by ClassiCube/ClassicalSharp. */ struct MapImporter* next; /* Next importer in linked-list of map importers */
cc_result Cw_Load(struct Stream* stream); };
/* Imports a world from a .dat classic map file. */
/* Used by Minecraft Classic/WoM client. */ /* Adds the given importer to the list of map importers */
cc_result Dat_Load(struct Stream* stream); CC_API void MapImporter_Register(struct MapImporter* imp);
/* Imports a world from a .mclevel NBT map file. */ /* Attempts to find a suitable map importer based on filename */
/* Used by Minecraft Indev client. */ /* Returns NULL if no match found */
cc_result MCLevel_Load(struct Stream* stream); CC_API struct MapImporter* MapImporter_Find(const cc_string* path);
/* Attempts to import a map from the given file */
CC_API cc_result Map_LoadFrom(const cc_string* path);
/* Exports a world to a .cw ClassicWorld map file. */ /* Exports a world to a .cw ClassicWorld map file. */
/* Compatible with ClassiCube/ClassicalSharp */ /* Compatible with ClassiCube/ClassicalSharp */

View File

@ -37,6 +37,7 @@
#include "Picking.h" #include "Picking.h"
#include "Animations.h" #include "Animations.h"
#include "SystemFonts.h" #include "SystemFonts.h"
#include "Formats.h"
struct _GameData Game; struct _GameData Game;
cc_uint64 Game_FrameStart; cc_uint64 Game_FrameStart;
@ -414,6 +415,7 @@ static void Game_Load(void) {
Game_AddComponent(&PickedPosRenderer_Component); Game_AddComponent(&PickedPosRenderer_Component);
Game_AddComponent(&Audio_Component); Game_AddComponent(&Audio_Component);
Game_AddComponent(&AxisLinesRenderer_Component); Game_AddComponent(&AxisLinesRenderer_Component);
Game_AddComponent(&Formats_Component);
LoadPlugins(); LoadPlugins();
for (comp = comps_head; comp; comp = comp->next) { for (comp = comps_head; comp; comp = comp->next) {

View File

@ -1711,9 +1711,9 @@ static void LoadLevelScreen_EntryClick(void* screen, void* widget) {
} }
static void LoadLevelScreen_FilterFiles(const cc_string* path, void* obj) { static void LoadLevelScreen_FilterFiles(const cc_string* path, void* obj) {
IMapImporter importer = Map_FindImporter(path); struct MapImporter* imp = MapImporter_Find(path);
cc_string relPath = *path; cc_string relPath = *path;
if (!importer) return; if (!imp) return;
Utils_UNSAFE_TrimFirstDirectory(&relPath); Utils_UNSAFE_TrimFirstDirectory(&relPath);
StringsBuffer_Add((struct StringsBuffer*)obj, &relPath); StringsBuffer_Add((struct StringsBuffer*)obj, &relPath);
@ -1729,7 +1729,7 @@ static void LoadLevelScreen_UploadCallback(const cc_string* path) { Map_LoadFrom
static void LoadLevelScreen_UploadFunc(void* s, void* w) { static void LoadLevelScreen_UploadFunc(void* s, void* w) {
static const char* const filters[] = { static const char* const filters[] = {
".cw", ".dat", ".lvl", ".mine", ".fcm", ".mclevel", NULL ".cw", ".dat", ".lvl", ".mine", ".fcm", ".mclevel", NULL
}; }; /* TODO not hardcode list */
static struct OpenFileDialogArgs args = { static struct OpenFileDialogArgs args = {
"Classic map files", filters, "Classic map files", filters,
LoadLevelScreen_UploadCallback, LoadLevelScreen_UploadCallback,