diff --git a/src/menu-fn/entry.qc b/src/menu-fn/entry.qc index 75708308..d5ed032b 100644 --- a/src/menu-fn/entry.qc +++ b/src/menu-fn/entry.qc @@ -134,6 +134,7 @@ m_init(void) g_btnofs = 26 / g_btnsize[1]; GameLibrary_Init(); + MapLibrary_Init(); main_init(); Colors_Init(); diff --git a/src/menu-fn/m_creategame.qc b/src/menu-fn/m_creategame.qc index b0b55443..4989956c 100644 --- a/src/menu-fn/m_creategame.qc +++ b/src/menu-fn/m_creategame.qc @@ -30,11 +30,6 @@ CFrame create_frMaps; CListBox create_lbMaps; CScrollbar create_sbMaps; -int g_mapcount; - -int map_blacklist_count; -string *map_blacklist; - void create_btnok_start(void) { @@ -104,8 +99,7 @@ create_sbmaps_changed(int val) void menu_creategame_init(void) { - int i = 0; - int realcount = 0; + int mapCount = 0i; fn_create = spawn(CWidget); create_btnAdv = spawn(CMainButton); @@ -165,72 +159,15 @@ menu_creategame_init(void) create_sbMaps.SetCallback(create_sbmaps_changed); Widget_Add(fn_createshared, create_sbMaps); - /* map blacklist code */ - filestream fs_blacklist; - fs_blacklist = fopen("scripts/map_blacklist", FILE_READ); + /* fill in our list box */ + mapCount = MapLibrary_GetMapCount(); - if (fs_blacklist < 0) { - print("^1WARNING: ^7Could NOT load scripts/map_blacklist\n"); + for (int i = 0i; i < mapCount; i++) { + string mapName = MapLibrary_GetInfo(i, MAPINFO_NAME); + create_lbMaps.AddEntry(mapName); } - if (fs_blacklist >= 0) { - string temp; - - while ((temp = fgets(fs_blacklist))) { - map_blacklist_count++; - } - - map_blacklist = memalloc(sizeof(string) * map_blacklist_count); - fseek(fs_blacklist, 0); - - i = 0; - while ((temp = fgets(fs_blacklist))) { - map_blacklist[i] = temp; - i++; - } - - fclose(fs_blacklist); - } - - searchhandle mapsearch = search_begin("maps/*.bsp", SEARCH_NAMESORT | SEARCH_FULLPACKAGE, TRUE); - g_mapcount = search_getsize(mapsearch); - for (i = 0; i < g_mapcount; i++) { - string tmp, dir; - string gdir = GameLibrary_GetInfo(GAMEINFO_GAMEDIR); - int list = TRUE; - tmp = substring(search_getfilename(mapsearch, i), 5, -1); - - /* work around FTEQW's path choice */ - if (gdir == "ftehl") - gdir = "valve"; - - /* only look for maps in the current gamedir, requires SEARCH_FULLPACKAGE */ - dir = substring(search_getpackagename(mapsearch, i), 0, strlen(gdir)); - if (dir != gdir) { - continue; - } - - /* ignore test_ prefix maps */ - if (substring(tmp, 0, 5) == "test_") { - continue; - } - - /* see if any of our blacklisted names match */ - for (int b = 0; b < map_blacklist_count; b++) { - if (tmp == map_blacklist[b]) { - list = FALSE; - break; - } - } - - if (list == TRUE) { - create_lbMaps.AddEntry(tmp); - realcount++; - } - } - - create_sbMaps.SetMax(realcount); - search_end(mapsearch); + create_sbMaps.SetMax(mapCount); } void diff --git a/src/platform/defs.h b/src/platform/defs.h index 6706b818..d5656635 100644 --- a/src/platform/defs.h +++ b/src/platform/defs.h @@ -24,6 +24,7 @@ #include "tcp.h" #include "updates.h" #include "gamelibrary.h" +#include "maplibrary.h" /** Definitions for FTE's internal package manager. We don't want you to talk to this one directly within Nuclide. */ typedef enum diff --git a/src/platform/gamelibrary.qc b/src/platform/gamelibrary.qc index 74fb1a9d..6ff541f8 100644 --- a/src/platform/gamelibrary.qc +++ b/src/platform/gamelibrary.qc @@ -561,6 +561,8 @@ GameLibrary_InitCustom(void) crash(); return; } + + print(sprintf("GameLibrary initialized (%i entries).\n", gameinfo_count)); } #endif diff --git a/src/platform/includes.src b/src/platform/includes.src index 9c1c0e92..e80ddc52 100644 --- a/src/platform/includes.src +++ b/src/platform/includes.src @@ -9,4 +9,5 @@ tcp.qc util.qc updates.qc gamelibrary.qc +maplibrary.qc #endlist diff --git a/src/platform/maplibrary.h b/src/platform/maplibrary.h new file mode 100644 index 00000000..a2505658 --- /dev/null +++ b/src/platform/maplibrary.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Vera Visions LLC. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +typedef enum +{ + MAPINFO_NAME, /**< (string) Name of the map. E.g. e1m1 */ + MAPINFO_TITLE, /**< (string) Title of the map. E.g. "Abyss of Cake" */ + MAPINFO_AUTHOR, /**< (string) Author of the map. E.g. "John Doe" */ + MAPINFO_TYPE /**< (string) Type of map.*/ +} mapType_t; + +/** Initialize the map library, MapLibrary_GetMapCount() will return the amount of maps available. */ +void MapLibrary_Init(void); + +/** Returns the total amount of maps available. */ +int MapLibrary_GetMapCount(void); + +/** Retrieve information about a given mapID. See mapType_t for which fields you can query. */ +__variant MapLibrary_GetInfo(int, mapType_t); \ No newline at end of file diff --git a/src/platform/maplibrary.qc b/src/platform/maplibrary.qc new file mode 100644 index 00000000..a788db2e --- /dev/null +++ b/src/platform/maplibrary.qc @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2023 Vera Visions LLC. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +typedef struct +{ + string name; + string title; + string author; + string type; +} mapLibrary_t; + +mapLibrary_t *g_mapLibrary; +var int g_mapLibrary_count = 0i; +var int map_blacklist_count = 0i; +string *map_blacklist; + +static string +MapLibrary_GetMapGamedir(void) +{ + string gdir = cvar_string("fs_game"); + + /* HACK: work around FTEQW's path choice */ + if (gdir == "ftehl") + gdir = "valve"; + + return gdir; +} + +static bool +MapLibrary_MapInGameDir(string fileName, string gameDir) +{ + bool list = true; + + /* only look for maps in the current gamedir, requires SEARCH_FULLPACKAGE */ + if (gameDir != MapLibrary_GetMapGamedir()) { + return false; + } + + /* ignore test_ prefix maps */ + if (substring(fileName, 0, 5) == "test_") { + return false; + } + + /* see if any of our blacklisted names match */ + for (int b = 0i; b < map_blacklist_count; b++) { + if (fileName == map_blacklist[b]) { + list = false; + break; + } + } + + return list; +} + +void +MapLibrary_Init(void) +{ + int i = 0i; + int c = 0i; + int mapCount = 0i; + string mapFile, mapDir; + searchhandle mapsearch; + string gameDir; + + /* already initialized */ + if (g_mapLibrary_count != 0i) + return; + + g_mapLibrary_count = 0i; + gameDir = MapLibrary_GetMapGamedir(); + + /* map blacklist code */ + filestream fs_blacklist; + fs_blacklist = fopen("scripts/map_blacklist", FILE_READ); + + if (fs_blacklist >= 0) { + string temp; + + while ((temp = fgets(fs_blacklist))) { + map_blacklist_count++; + } + + map_blacklist = memalloc(sizeof(string) * map_blacklist_count); + fseek(fs_blacklist, 0); + + while ((temp = fgets(fs_blacklist))) { + map_blacklist[i] = temp; + i++; + } + + fclose(fs_blacklist); + } + + /* search for all maps in the current PATH */ + mapsearch = search_begin("maps/*.bsp", SEARCH_NAMESORT | SEARCH_FULLPACKAGE, TRUE); + mapCount = search_getsize(mapsearch); + + /* we now iterate over the search entries to filter results out */ + for (i = 0i; i < mapCount; i++) { + mapFile = substring(search_getfilename(mapsearch, i), 5, -1); + + /* the strlen(gameDir) is technically wrong, but it'll work anyway because + we only care about maps in the current game directory */ + mapDir = substring(search_getpackagename(mapsearch, i), 0, strlen(gameDir)); + + if (MapLibrary_MapInGameDir(mapFile, mapDir) == true) { + g_mapLibrary_count++; + } + } + search_end(mapsearch); + + g_mapLibrary = (mapLibrary_t *)memalloc(sizeof(mapLibrary_t) * g_mapLibrary_count); + + /* let's do it again, but this time we'll sort the data into our array */ + mapsearch = search_begin("maps/*.bsp", SEARCH_NAMESORT | SEARCH_FULLPACKAGE, TRUE); + mapCount = search_getsize(mapsearch); + + for (i = 0i; i < mapCount; i++) { + mapFile = substring(search_getfilename(mapsearch, i), 5, -1); + mapDir = substring(search_getpackagename(mapsearch, i), 0, strlen(gameDir)); + + if (MapLibrary_MapInGameDir(mapFile, mapDir) == true) { + g_mapLibrary[c].name = mapFile; + g_mapLibrary[c].title = mapFile; + g_mapLibrary[c].author = "Unknown"; + g_mapLibrary[c].type = "Unknown"; + c++; + } + } + search_end(mapsearch); + + print(sprintf("MapLibrary initialized (%i entries).\n", g_mapLibrary_count)); +} + +int +MapLibrary_GetMapCount(void) +{ + return g_mapLibrary_count; +} + +__variant +MapLibrary_GetInfo(int mapID, mapType_t infoType) +{ + if (mapID >= g_mapLibrary_count || mapID < 0i) { + print(sprintf("MapLibrary_GetInfo: Invalid map id %i!\n", mapID)); + return __NULL__; + } + + switch (infoType) { + case MAPINFO_NAME: + return g_mapLibrary[mapID].name; + break; + case MAPINFO_TITLE: + return g_mapLibrary[mapID].title; + break; + case MAPINFO_AUTHOR: + return g_mapLibrary[mapID].author; + break; + case MAPINFO_TYPE: + return g_mapLibrary[mapID].type; + break; + default: + return __NULL__; + } +} \ No newline at end of file