Menu-FN: Parse liblist.gam files instead of relying on manifests outright.

This commit is contained in:
Marco Cawthorne 2021-05-28 10:26:42 +02:00
parent 42960cda05
commit 2082f1355a
10 changed files with 876 additions and 610 deletions

18
base/liblist.gam Normal file
View File

@ -0,0 +1,18 @@
game "Nuclide Base"
gamedir "base"
base_dir ""
fallback_dir ""
mpentity "info_player_deathmatch"
size "1000080"
url_info "www.vera-visions.com"
version "1.0"
url_dl ""
type "Both"
nomodels 1
gamedll "progs.dat"
startmap "test_shader"
trainingmap "map test_hdr"
cldll 1
svonly "0"
menutrack ""
chatroom "lobby"

View File

@ -5,26 +5,6 @@ BASEGAME platform
BASEGAME logos
BASEGAME base
// custom game menu variables
-set gameinfo_game "Nuclide Base"
-set gameinfo_gamedir "base"
-set gameinfo_fallback_dir ""
-set gameinfo_mpentity "info_player_deathmatch"
-set gameinfo_size "1000080"
-set gameinfo_url_info "www.vera-visions.com"
-set gameinfo_version "1.0"
-set gameinfo_url_dl ""
-set gameinfo_type "Both"
-set gameinfo_nomodels 1
-set gameinfo_gamedll "progs.dat"
-set gameinfo_startmap "c0a0"
-set gameinfo_trainingmap "map t0a0"
-set gameinfo_cldll 1
-set gameinfo_hlversion "1110"
-set gameinfo_svonly "0"
-set gameinfo_menutrack ""
-set gameinfo_chatroom "lobby"
// you don't really want to change these
RTCBROKER master.frag-net.com:27950
PROTOCOLNAME "Nuclide"

View File

@ -97,9 +97,11 @@ void ClientGame_ModelEvent(float, int, string);
/* this really should be done in-engine */
__wrap float(vector pos, string pic, vector size, vector rgb, float alpha, optional float drawflag) drawpic =
__wrap float(vector position, string pic, vector size, vector rgb='1 1 1', float alpha=1, optional float drawflag=0) drawpic =
{
return prior([(int)pos[0],(int)pos[1]], pic, size, rgb, alpha, drawflag);
position[0] = rint(position[0]);
position[1] = rint(position[1]);
return prior(position, pic, size, rgb, alpha, drawflag);
};
__wrap void(vector pos, vector sz, string pic, vector srcpos, vector srcsz, vector rgb, float alpha, optional float drawflag) drawsubpic =
{

View File

@ -33,6 +33,7 @@ CSQC_Init(float apilevel, string enginename, float engineversion)
registercommand("dev_sunpos");
registercommand("dev_measure");
registercommand("view_geomtest");
registercommand("player_geomtest");
registercommand("way_menu");
/* basic actions */
@ -661,6 +662,9 @@ CSQC_Parse_Event(void)
pSeat->m_flShakeFreq = readfloat();
pSeat->m_flShakeTime = pSeat->m_flShakeDuration;
break;
case EV_SENTENCE_VOX:
Vox_PlaySentence(readstring());
break;
default:
ClientGame_EventParse(fHeader);
}
@ -808,6 +812,9 @@ CSQC_ConsoleCommand(string sCMD)
case "view_geomtest":
Weapons_SetGeomset(sprintf("geomset %s %s\n", argv(1), argv(2)));
break;
case "player_geomtest":
setcustomskin(pSeat->m_ePlayer, "", sprintf("geomset %s %s\n", argv(1), argv(2)));
break;
default:
return ClientGame_ConsoleCommand();
}

View File

@ -72,6 +72,7 @@ func_pushable::customphysics(void)
return;
/* run the physics, then fix our helper bbox! */
friction = 0.5f;
runstandardplayerphysics(this);
setorigin(m_eCollBox, absmin + (0.5 * (absmax - absmin)));
}

View File

@ -68,6 +68,7 @@ typedef struct
{
string game;
string gamedir;
string base_dir;
string url_info;
string url_dl;
string version;

View File

@ -134,47 +134,6 @@ game_updateinstallcount(void)
return count;
}
#if 0
/* get installing id */
void
game_getinstallcache(void)
{
int ret;
filestream fs_cache;
ret = 0;
fs_cache = fopen("mcache.dat", FILE_READ);
if (fs_cache >= 0) {
g_iModInstallCache = (int)stof(fgets(fs_cache));
g_strModInstallCache = fgets(fs_cache);
fclose(fs_cache);
} else {
g_iModInstallCache = -1;
g_strModInstallCache = "";
}
print(sprintf("id: %i, name: %s\n", ret, g_strModInstallCache));
}
/* write installing id */
void
game_writeinstallcache(int id, string gamedir)
{
filestream fs_cache;
fs_cache = fopen("mcache.dat", FILE_WRITE);
g_iModInstallCache = id;
g_strModInstallCache = gamedir;
if (fs_cache >= 0) {
fputs(fs_cache, sprintf("%i\n",id));
fputs(fs_cache, gamedir);
fclose(fs_cache);
}
}
#endif
/* local game/mod info parsing */
void
games_set(int id)
@ -188,18 +147,39 @@ void
games_init(void)
{
int id;
float county;
string gamedirname;
string gamedescription;
gameinfo_count = 0;
searchhandle sh;
searchhandle psh;
string temp;
filestream fh;
for (id = 0; (gamedirname = getgamedirinfo(id, 0)); id++) {
/* skip any manifest (or modinfo) without cvars setting things */
if (getgamedirinfo(id, 2) == "") {
continue;
/* first let's see if we've got a liblist.gam just floating inside the gamedir */
sh = search_begin("liblist.gam", SB_FULLPACKAGEPATH | SB_FORCESEARCH, FALSE, gamedirname);
/* we do not. let's search for pk3's to sift through */
if (search_getsize(sh) < 0) {
/* let's search for every pk3 in the gamedir and search for a liblist, one at a time. */
psh = search_begin("*.pk3", SB_FULLPACKAGEPATH | SB_FORCESEARCH, FALSE, gamedirname);
/* loop through each pk3 */
for (int i = 0; i < search_getsize(psh); i++) {
string full = search_getfilename(psh, i);
sh = search_begin("liblist.gam", SB_FULLPACKAGEPATH | SB_FORCESEARCH, FALSE, strcat(gamedirname, "/", full));
print(sprintf("%s\n", full));
/* we found one */
if (search_getsize(sh) >= 0)
gameinfo_count++;
}
search_end(psh);
} else {
gameinfo_count++;
}
gameinfo_count++;
search_end(sh);
}
if (!gameinfo_count) {
@ -210,22 +190,16 @@ games_init(void)
games = memalloc(sizeof(gameinfo_t) * gameinfo_count);
/* The things we do for frequent flyer mileage. */
if (!games)
error(sprintf("Attempting to allocate mod data for %i entries failed\n", gameinfo_count));
for (id = 0; (gamedirname = getgamedirinfo(id, 0)); id++) {
gamedescription = getgamedirinfo(id, 2);
/* CONT: skip any manifest (or modinfo) without cvars setting things */
if (gamedescription == "") {
continue;
}
county = tokenize_console(gamedescription);
/* Fill in the defaults */
games[id].game = gamedirname;
games[id].gamedir = gamedirname;
games[id].base_dir = GAME_DIR;
games[id].url_info = "";
games[id].url_dl = "";
games[id].version = "1.0";
@ -246,206 +220,163 @@ games_init(void)
games[id].pkgid = -1;
games[id].steambg = 0;
for (int i = 0; i < county; i++) {
switch(argv(i)) {
case "gameinfo_game":
games[id].game = argv(i+1);
break;
case "gameinfo_gamedir":
games[id].gamedir = argv(i+1);
break;
case "gameinfo_fallback_dir":
games[id].fallback_dir = argv(i+1);
break;
case "gameinfo_url_info":
games[id].url_info = argv(i+1);
break;
case "gameinfo_url_dl":
games[id].url_dl = argv(i+1);
break;
case "gameinfo_version":
games[id].version = argv(i+1);
break;
case "gameinfo_size":
games[id].size = (int)stof(argv(i+1));
break;
case "gameinfo_svonly":
games[id].svonly = (int)stof(argv(i+1));
break;
case "gameinfo_cldll":
games[id].cldll = (int)stof(argv(i+1));
break;
case "gameinfo_type":
switch (strtolower(argv(i+1))) {
case "multiplayer_only":
case "multiplayer only":
case "mp":
case "multi":
case "multiplayer":
games[id].type = "Multiplayer";
break;
case "singleplayer_only":
case "singleplayer only":
case "sp":
case "single":
case "singleplayer":
games[id].type = "Singleplayer";
break;
default:
games[id].type = "Both";
}
break;
case "gameinfo_hlversion":
games[id].hlversion = argv(i+1);
break;
case "gameinfo_nomodels":
games[id].nomodels = (int)stof(argv(i+1));
break;
case "gameinfo_nosprays":
games[id].nosprays = (int)stof(argv(i+1));
break;
case "gameinfo_mpentity":
games[id].mpentity = argv(i+1);
break;
case "gameinfo_gamedll":
games[id].gamedll = argv(i+1);
break;
case "gameinfo_startmap":
games[id].startmap = argv(i+1);
break;
case "gameinfo_trainingmap":
games[id].trainingmap = argv(i+1);
break;
case "gameinfo_pkgname":
games[id].pkgname = argv(i+1);
games[id].pkgid = game_getpackageid(games[id].pkgname);
break;
case "gameinfo_pkgfile":
games[id].pkgfile = argv(i+1);
break;
case "gameinfo_chatroom":
games[id].chatroom = argv(i+1);
break;
case "gameinfo_readme":
games[id].readme = argv(i+1);
break;
case "gameinfo_introvideo":
games[id].introvideo = argv(i+1);
break;
case "gameinfo_steambg":
games[id].steambg = (int)stof(argv(i+1));
break;
default:
break;
#if 1
/* first let's see if we've got a liblist.gam just floating inside the gamedir */
sh = search_begin("liblist.gam", SB_FULLPACKAGEPATH | SB_FORCESEARCH, FALSE, gamedirname);
fh = search_fopen(sh, 0);
/* we do not. let's search for pk3's to sift through */
if (fh < 0) {
/* let's search for every pk3 in the gamedir and search for a liblist, one at a time. */
psh = search_begin("*.pk3", SB_FULLPACKAGEPATH | SB_FORCESEARCH, FALSE, gamedirname);
/* loop through each pk3 */
for (int i = 0; i < search_getsize(psh); i++) {
string full = search_getfilename(psh, i);
sh = search_begin("liblist.gam", SB_FULLPACKAGEPATH | SB_FORCESEARCH, FALSE, strcat(gamedirname, "/", full));
fh = search_fopen(sh, 0);
/* we found one */
if (fh >= 0)
break;
}
search_end(psh);
}
if (games[id].gamedir == cvar_string("gameinfo_gamedir")) {
/* we still haven't found a liblist.gam */
if (fh < 0) {
/* sift through dlcache. that's where downloaded mods go */
psh = search_begin("dlcache/*.pk3.*", SB_FULLPACKAGEPATH | SB_FORCESEARCH, FALSE, gamedirname);
/* loop through each pk3 hash */
for (int i = 0; i < search_getsize(psh); i++) {
string full = search_getfilename(psh, i);
sh = search_begin("liblist.gam", SB_FULLPACKAGEPATH | SB_FORCESEARCH, FALSE, strcat(gamedirname, "/dlcache/", full));
fh = search_fopen(sh, 0);
/* we finally found one */
if (fh >= 0)
break;
}
search_end(psh);
}
#endif
if (fh >= 0) {
while ((temp = fgets(fh))) {
int i = 0;
tokenize(temp);
switch(argv(i)) {
case "game":
games[id].game = argv(i+1);
break;
case "gamedir":
games[id].gamedir = argv(i+1);
break;
case "fallback_dir":
games[id].fallback_dir = argv(i+1);
break;
case "base_dir":
games[id].base_dir = argv(i+1);
break;
case "url_info":
games[id].url_info = argv(i+1);
break;
case "url_dl":
games[id].url_dl = argv(i+1);
break;
case "version":
games[id].version = argv(i+1);
break;
case "size":
games[id].size = (int)stof(argv(i+1));
break;
case "svonly":
games[id].svonly = (int)stof(argv(i+1));
break;
case "cldll":
games[id].cldll = (int)stof(argv(i+1));
break;
case "type":
switch (strtolower(argv(i+1))) {
case "multiplayer_only":
case "multiplayer only":
case "mp":
case "multi":
case "multiplayer":
games[id].type = "Multiplayer";
break;
case "singleplayer_only":
case "singleplayer only":
case "sp":
case "single":
case "singleplayer":
games[id].type = "Singleplayer";
break;
default:
games[id].type = "Both";
}
break;
case "hlversion":
games[id].hlversion = argv(i+1);
break;
case "nomodels":
games[id].nomodels = (int)stof(argv(i+1));
break;
case "nosprays":
games[id].nosprays = (int)stof(argv(i+1));
break;
case "mpentity":
games[id].mpentity = argv(i+1);
break;
case "gamedll":
games[id].gamedll = argv(i+1);
break;
case "startmap":
games[id].startmap = argv(i+1);
break;
case "trainingmap":
games[id].trainingmap = argv(i+1);
break;
case "pkgname":
games[id].pkgname = argv(i+1);
games[id].pkgid = game_getpackageid(games[id].pkgname);
break;
case "pkgfile":
games[id].pkgfile = argv(i+1);
break;
case "chatroom":
games[id].chatroom = argv(i+1);
break;
case "readme":
games[id].readme = argv(i+1);
break;
case "introvideo":
games[id].introvideo = argv(i+1);
break;
case "steambg":
games[id].steambg = (int)stof(argv(i+1));
break;
default:
break;
}
}
fclose(fh);
}
search_end(sh);
if (games[id].gamedir == cvar_string("game")) {
games_set(id);
}
}
#if 0
game_getinstallcache();
#endif
if (gameinfo_current == -1) {
print("^1FATAL ERROR: NO MODINFO.TXT FOR CURRENT MOD FOUND!\n");
print("^1FATAL ERROR: NO LIBLIST.GAM FOR CURRENT MOD FOUND!\n");
crash();
return;
}
}
#if 0
void
customgame_installstart(int gameid)
{
int count;
count = tokenize(games[gameid].pkgname);
for (int i = 0; i < count; i++) {
int pkgid = game_getpackageid(argv(i));
localcmd(sprintf("pkg add %s\n", argv(i)));
print(sprintf("Marking package %s for install.\n",
argv(i)));
}
game_writeinstallcache(gameid, games[gameid].gamedir);
localcmd("pkg apply\n");
print("Starting installation of custom game packages\n");
}
void
customgame_installend(void)
{
int gid = g_iModInstallCache;
print("install-end!\n");
localcmd(sprintf("fs_changegame %s http://www.frag-net.com/mods/%s.fmf\n", g_strModInstallCache, g_strModInstallCache));
game_writeinstallcache(-1, g_strModInstallCache);
}
void
customgame_installframe(void)
{
int id;
float perc;
float c;
int loading;
/* graphical frame */
customgame_dlgWait.Draw();
WField_Static(162, 180, "Installing mod data...", 320, 260,
col_prompt_text, 1.0f, 2, font_label_p);
/* download percentage */
perc = 0.0f;
loading = FALSE;
/* a game can have multiple packages associated */
id = g_iModInstallCache;
c = tokenize(games[id].pkgname);
/* go through all invididual packages */
for (float i = 0; i < c; i++) {
string st;
int pkgid;
/* package query */
pkgid = game_getpackageid(argv(i));
st = getpackagemanagerinfo(pkgid, GPMI_INSTALLED);
/* filter out statuses so we can calculate percentage */
switch (st) {
case "":
case "pending":
case "enabled":
case "present":
case "corrupt":
break;
default:
perc += stof(st);
}
/* all packages need to be 'enabled', else fail to end */
if (st != "enabled")
loading = TRUE;
}
/* display download percentage we calculated */
perc = perc / c;
WField_Static(162, 220, sprintf("%d%%", perc), 320, 260,
[1,1,1], 1.0f, 2, font_label_p);
WField_Static(162, 260, "Service provided by frag-net.com through archive.org", 320, 260,
[1,1,1], 1.0f, 2, font_label);
/* not everything has been downloaded */
if (loading == TRUE)
return;
customgame_installend();
}
#endif
void
customgame_btnactivate_start(void)
{
@ -453,14 +384,14 @@ customgame_btnactivate_start(void)
games_set(nextgame);
#if 1
localcmd(sprintf("fs_changegame %s %s.fmf\nfs_changegame %s -\n", games[nextgame].gamedir, games[nextgame].gamedir, games[nextgame].gamedir));
#if 0
localcmd(sprintf("gamedir %s %s.fmf\nfs_changegame %s -\n", games[nextgame].gamedir, games[nextgame].gamedir, games[nextgame].gamedir));
#else
/* some games/mods inherit other directories */
if (games[nextgame].fallback_dir) {
localcmd(sprintf("gamedir \"%s;%s\"\n", games[nextgame].fallback_dir, games[nextgame].gamedir));
localcmd(sprintf("gamedir \"logos;platform;%s;%s;%s\"\n", games[nextgame].base_dir, games[nextgame].fallback_dir, games[nextgame].gamedir));
} else {
localcmd(sprintf("gamedir \"%s\"\n", games[nextgame].gamedir));
localcmd(sprintf("gamedir \"logos;platform;%s;%s\"\n", games[nextgame].base_dir, games[nextgame].gamedir));
}
#endif
@ -474,32 +405,14 @@ customgame_btnactivate_start(void)
void
customgame_btninstall_start(void)
{
#if 0
int id = customgame_lbMods.GetSelected();
string st;
st = getpackagemanagerinfo(games[id].pkgid, GPMI_INSTALLED);
print(st);
print("\n");
if (st != "enabled") {
customgame_installstart(id);
return;
}
game_writeinstallcache(id, games[id].gamedir);
customgame_installend();
#else
int nextgame = customgame_lbMods.GetSelected();
localcmd(sprintf("fs_changegame %s http://www.frag-net.com/mods/%s.fmf\n", games[nextgame].gamedir, games[nextgame].gamedir));
#endif
}
void
customgame_btndeactivate_start(void)
{
localcmd(sprintf("fs_changegame %s %s.fmf\n", GAME_DIR, GAME_DIR));
localcmd(sprintf("gamedir %s\n", GAME_DIR));
localcmd("stopmusic\nsnd_restart\nwait\nvid_reload\n");
localcmd("menu_restart\n");
localcmd("menu_customgame\n");
@ -631,12 +544,6 @@ menu_customgame_draw(void)
}
customgame_sbMods.SetMax(gameinfo_count-1); /* don't show our current game */
#if 0
if (g_iModInstallCache >= 0) {
customgame_installframe();
}
#endif
}
void

View File

@ -64,6 +64,7 @@ entity eActivator;
.float deaths;
.float identity;
.float botinfo;
.void(float) Save;
/* in idTech the .owner field causes collisions to fail against set entity,
* we don't want this all of the time. so use this as a fallback */
@ -88,3 +89,10 @@ var int g_ents_initialized = FALSE;
void main(void)
{
}
#define SAVE_DECIMAL(x,y,z) fputs(x, sprintf("%S \"%d\" ", y, z))
#define SAVE_INTEGER(x,y,z) fputs(x, sprintf("%S \"%i\" ", y, z))
#define SAVE_FLOAT(x,y,z) fputs(x, sprintf("%S \"%f\" ", y, z))
#define SAVE_VECTOR(x,y,z) fputs(x, sprintf("%S \"%v\" ", y, z))
#define SAVE_STRING(x,y,z) fputs(x, sprintf("%S \"%s\" ", y, z))
#define SAVE_HEX(x,y,z) fputs(x, sprintf("%S \"%x\" ", y, z))

View File

@ -51,7 +51,7 @@ The 'self' global is the connecting client in question.
=================
*/
void
ClientConnect(float csqc_active)
ClientConnect(void)
{
int playercount = 0;
@ -512,6 +512,14 @@ as they do not exist yet. Keep this in mind.
=================
*/
var int autocvar_sv_levelexec = 1;
void
worldspawn_save(float fh)
{
SAVE_VECTOR(fh, "origin", self.origin);
SAVE_STRING(fh, "model", self.model);
}
void
worldspawn(void)
{
@ -544,6 +552,8 @@ worldspawn(void)
}
forceinfokey(world, "skyname", self.skyname);
}
self.Save = worldspawn_save;
}
/*
@ -642,3 +652,94 @@ SV_ShouldPause(float newstatus)
return newstatus;
}
void
SV_PerformLoad(float fh)
{
entity e;
entity eold;
string l;
float n;
eold = self;
e = world;
/*
while ((e=nextent(e))) {
if (edict_num(1) != e)
remove(e);
}
*/
#if 1
while ((l=fgets(fh))) {
float braced = FALSE;
float args = tokenize(l);
if (!args)
break;
if (args != 3) {
continue;
}
if (argv(0) == "ENTITY") {
string cname;
n = stof(argv(1));
cname = argv(2);
e = edict_num(n);
__fullspawndata = fgets(fh);
print(sprintf("Try spawning %s\n", cname));
/* call the constructor if one is present, init the default fields */
if (isfunction(strcat("spawnfunc_", cname))) {
e.classname = cname;
print(sprintf("I'm actually spawning %s\n", cname));
self = e;
callfunction(strcat("spawnfunc_", cname));
e.classname = cname;
self = eold;
setmodel(e, e.model);
setsize(e, e.mins, e.maxs);
setorigin(e, e.origin);
} else {
print(sprintf("Could not spawn %s\n", cname));
remove(e);
continue;
}
} else if (argv(1) == "GLOBAL") {
// TODO
}
}
#endif
}
void
SV_PerformSave(float fh, float numents)
{
float i = 0;
entity e;
for (i = 0; i < numents; i++) {
e = edict_num(i);
if (e==world && i)
continue;
if (wasfreed(e))
continue;
if (e.Save) {
entity oself = self;
self = e;
fputs(fh, sprintf("ENTITY \"%d\" %S\n", i, e.classname));
fputs(fh, "{ ");
e.Save(fh);
fputs(fh, "}\n");
self = oself;
}
}
fclose(fh);
};

File diff suppressed because it is too large Load Diff