r2951 - in trunk/data/qcsrc: common menu-div0test server
DONOTREPLY at icculus.org
DONOTREPLY at icculus.org
Thu Nov 15 05:30:27 EST 2007
Author: div0
Date: 2007-11-15 05:30:27 -0500 (Thu, 15 Nov 2007)
New Revision: 2951
Added:
trunk/data/qcsrc/common/mapinfo.qc
trunk/data/qcsrc/common/mapinfo.qh
Modified:
trunk/data/qcsrc/menu-div0test/mbuiltin.qh
trunk/data/qcsrc/menu-div0test/menu.qc
trunk/data/qcsrc/menu-div0test/progs.src
trunk/data/qcsrc/server/progs.src
Log:
start of mapinfo system; beware: menu-div0test now starts up longer for the first time, and you may need to delete .nexuiz/data/data/maps/*.mapinfo when there are trouble with maplist later, as the mapinfo format isn't fixed yet
Added: trunk/data/qcsrc/common/mapinfo.qc
===================================================================
--- trunk/data/qcsrc/common/mapinfo.qc (rev 0)
+++ trunk/data/qcsrc/common/mapinfo.qc 2007-11-15 10:30:27 UTC (rev 2951)
@@ -0,0 +1,272 @@
+// HUGE SET - stored in a string
+string HugeSetOfIntegers_empty()
+{
+ return "";
+}
+float HugeSetOfIntegers_get(string pArr, float i)
+{
+ return stof(substring(pArr, i * 4, 4));
+}
+float HugeSetOfIntegers_length(string pArr)
+{
+ return strlen(pArr) / 4;
+}
+string HugeSetOfIntegers_concat(string a1, string a2)
+{
+ return strcat(a1, a2);
+}
+string HugeSetOfIntegers_insert(string a1, float n, string a2)
+ // special concat function to build up large lists in less time by binary concatenation
+{
+ string s;
+ s = strcat(" ", ftos(n));
+ return strcat(a1, substring(s, strlen(s) - 4, 4), a2);
+}
+
+// generic string stuff
+float startsWith(string haystack, string needle)
+{
+ return substring(haystack, 0, strlen(needle)) == needle;
+}
+string extractRestOfLine(string haystack, string needle)
+{
+ if(startsWith(haystack, needle))
+ return substring(haystack, strlen(needle), strlen(haystack) - strlen(needle));
+ return string_null;
+}
+
+// GLOB HANDLING (for all BSP files)
+float _MapInfo_globopen;
+float _MapInfo_globcount;
+float _MapInfo_globhandle;
+string _MapInfo_GlobItem(float i)
+{
+ string s;
+ s = search_getfilename(_MapInfo_globhandle, i);
+ return substring(s, 5, strlen(s) - 9); // without maps/ and .bsp
+}
+
+void MapInfo_Enumerate()
+{
+ if(_MapInfo_globopen)
+ search_end(_MapInfo_globhandle);
+ _MapInfo_globhandle = search_begin("maps/*.bsp", TRUE, TRUE);
+ _MapInfo_globcount = search_getsize(_MapInfo_globhandle);
+ _MapInfo_globopen = 1;
+}
+
+// filter the info by game type mask (updates MapInfo_count)
+string _MapInfo_filtered;
+string MapInfo_FilterGametype_Recursive(float pGametype, float pBegin, float pEnd)
+{
+ float m;
+ string l, r;
+
+ if(pBegin == pEnd)
+ return HugeSetOfIntegers_empty();
+
+ m = floor((pBegin + pEnd) / 2);
+
+ l = MapInfo_FilterGametype_Recursive(pGametype, pBegin, m);
+ if not(l)
+ return string_null; // BAIL OUT
+ if(MapInfo_Get_ByName(_MapInfo_GlobItem(m), 1) == 2) // if we generated one... BAIL OUT and let the caller continue in the next frame.
+ return string_null; // BAIL OUT
+ r = MapInfo_FilterGametype_Recursive(pGametype, m + 1, pEnd);
+ if not(r)
+ return string_null; // BAIL OUT
+
+ if(MapInfo_Map_supportedGametypes & pGametype)
+ return HugeSetOfIntegers_insert(l, m, r);
+ else
+ return HugeSetOfIntegers_concat(l, r);
+}
+float MapInfo_FilterGametype(float gametype)
+{
+ _MapInfo_filtered = MapInfo_FilterGametype_Recursive(gametype, 0, _MapInfo_globcount);
+ if(!_MapInfo_filtered)
+ {
+ dprint("Autogenerated a .mapinfo, bailing out to avoid loop counter\n");
+ return 0;
+ }
+ MapInfo_count = HugeSetOfIntegers_length(_MapInfo_filtered);
+ dprint("Filter ", ftos(gametype), " results in ", _MapInfo_filtered, "\n");
+ return 1;
+}
+
+// load info about the i-th map into the MapInfo_Map_* globals
+float MapInfo_Get_ByID(float i); // 1 on success, 0 on failure
+
+float _MapInfo_Generate(string pFilename)
+{
+ string fn;
+ float fh;
+ string s, v;
+ vector o;
+ float inWorldspawn, l;
+
+ float spawns, diameter;
+ vector mapMins, mapMaxs;
+
+ fn = strcat("maps/", pFilename, ".ent");
+ fh = fopen(fn, FILE_READ);
+ if(fh < 0)
+ {
+ fn = strcat("maps/", pFilename, ".bsp");
+ fh = fopen(fn, FILE_READ);
+ }
+ if(fh < 0)
+ return 0;
+ dprint("Analyzing ", fn, " to generate initial mapinfo\n");
+
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_DEATHMATCH; // DM always works
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_RUNEMATCH; // Rune always works
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_LMS; // LMS always works
+
+ inWorldspawn = 2;
+
+ for(;;)
+ {
+ if not((s = fgets(fh)))
+ break;
+ if(inWorldspawn == 1)
+ if(startsWith(s, "}"))
+ inWorldspawn = 0;
+ if(inWorldspawn)
+ {
+ if(startsWith(s, "\"classname\" \"worldspawn\""))
+ inWorldspawn = 1;
+ else if((v = extractRestOfLine(s, "\"message\" \"")))
+ {
+ for(l = strlen(v) - 1; l > 0; --l)
+ if(substring(v, l, 1) == "\"")
+ break;
+ MapInfo_Map_title = substring(v, 0, l);
+ }
+ }
+ else
+ {
+ if((v = extractRestOfLine(s, "\"origin\" \"")))
+ {
+ for(l = strlen(v) - 1; l > 0; --l)
+ if(substring(v, l, 1) == "\"")
+ break;
+ o = stov(strcat("'", substring(v, 0, l), "'"));
+ mapMins_x = min(mapMins_x, o_x);
+ mapMins_y = min(mapMins_y, o_y);
+ mapMins_z = min(mapMins_z, o_z);
+ mapMaxs_x = max(mapMaxs_x, o_x);
+ mapMaxs_y = max(mapMaxs_y, o_y);
+ mapMaxs_z = max(mapMaxs_z, o_z);
+ }
+ else if((v = extractRestOfLine(s, "\"classname\" \"")))
+ {
+ if(startsWith(v, "dom_controlpoint\""))
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_DOMINATION;
+ else if(startsWith(v, "item_flag_team2\""))
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTF;
+ else if(startsWith(v, "runematch_spawn_point\""))
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_RUNEMATCH;
+ else if(startsWith(v, "target_assault_roundend\""))
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ASSAULT;
+ else if(startsWith(v, "onslaught_generator\""))
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ONSLAUGHT;
+ else if(startsWith(v, "info_player_team1\""))
+ ++spawns;
+ else if(startsWith(v, "info_player_team2\""))
+ ++spawns;
+ else if(startsWith(v, "info_player_deathmatch\""))
+ ++spawns;
+ else if(startsWith(v, "info_player_start\""))
+ ++spawns;
+ }
+ }
+ }
+ if(inWorldspawn)
+ {
+ print(strcat(fn, " ended still in worldspawn, BUG"));
+ return 0;
+ }
+ diameter = vlen(mapMaxs - mapMins);
+ if(spawns >= 8 && diameter > 2048)
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_TEAM_DEATHMATCH;
+ if( diameter < 4096)
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ARENA;
+ if(spawns >= 16 && diameter > 4096)
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_KEYHUNT;
+ fclose(fh);
+ dprint(fn, ": types = ", ftos(MapInfo_Map_supportedGametypes), " spawns ", ftos(spawns), " diameter ", ftos(diameter), "\n");
+ return 1;
+}
+
+// load info about a map by name into the MapInfo_Map_* globals
+float MapInfo_Get_ByName(string pFilename, float pAllowGenerate)
+{
+ string fn;
+ string s, t;
+ float fh;
+
+ // default all generic fields so they have "good" values in case something fails
+ MapInfo_Map_title = "Untitled1";
+ MapInfo_Map_description = "Bleh.";
+ MapInfo_Map_supportedGametypes = 0;
+
+ fn = strcat("maps/", pFilename, ".mapinfo");
+ fh = fopen(fn, FILE_READ);
+ if(fh < 0)
+ {
+ if(!pAllowGenerate)
+ return 0;
+ if(!_MapInfo_Generate(pFilename))
+ return 0;
+ fh = fopen(fn, FILE_WRITE);
+ fputs(fh, strcat("title ", MapInfo_Map_title, "\n"));
+ fputs(fh, strcat("description ", MapInfo_Map_description, "\n"));
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_DEATHMATCH) fputs(fh, "type dm 30 20\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_TEAM_DEATHMATCH) fputs(fh, "type tdm 50 20 2\n"); // TODO count tdm_team entities
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_DOMINATION) fputs(fh, "type dom 200 20 2\n"); // TODO count tdm_team entities
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_CTF) fputs(fh, "type ctf 300 20\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_RUNEMATCH) fputs(fh, "type rune 200 20\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_LMS) fputs(fh, "type lms 9 20\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_ARENA) fputs(fh, "type arena 10 20\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_KEYHUNT) fputs(fh, "type kh 1000 20\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_ASSAULT) fputs(fh, "type as 20\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_ONSLAUGHT) fputs(fh, "type ons 20\n");
+ fclose(fh);
+ return 2;
+ }
+ for(;;)
+ {
+ if not((s = fgets(fh)))
+ break;
+ tokenize(s);
+ t = argv(0);
+ if(t == "title")
+ MapInfo_Map_title = substring(s, 6, strlen(s) - 6); // without "title"
+ else if(t == "description")
+ MapInfo_Map_description = substring(s, 12, strlen(s) - 12);
+ else if(t == "type")
+ {
+ t = argv(1);
+ if (t == "dm") MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_DEATHMATCH;
+ else if(t == "tdm") MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_TEAM_DEATHMATCH;
+ else if(t == "dom") MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_DOMINATION;
+ else if(t == "ctf") MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTF;
+ else if(t == "rune") MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_RUNEMATCH;
+ else if(t == "lms") MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_LMS;
+ else if(t == "arena") MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ARENA;
+ else if(t == "kh") MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_KEYHUNT;
+ else if(t == "as") MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ASSAULT;
+ else if(t == "ons") MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ONSLAUGHT;
+ else
+ dprint("Map ", pFilename, " supports unknown game type ", t, ", ignored\n");
+ }
+ else
+ dprint("Map ", pFilename, " supports unknown game type ", t, ", ignored\n");
+ }
+ fclose(fh);
+ if(MapInfo_Map_supportedGametypes != 0)
+ return 1;
+ dprint("Map ", pFilename, " supports no game types, ignored\n");
+ return 0;
+}
Added: trunk/data/qcsrc/common/mapinfo.qh
===================================================================
--- trunk/data/qcsrc/common/mapinfo.qh (rev 0)
+++ trunk/data/qcsrc/common/mapinfo.qh 2007-11-15 10:30:27 UTC (rev 2951)
@@ -0,0 +1,31 @@
+float MAPINFO_TYPE_DEATHMATCH = 1;
+float MAPINFO_TYPE_TEAM_DEATHMATCH = 2;
+float MAPINFO_TYPE_DOMINATION = 4;
+float MAPINFO_TYPE_CTF = 8;
+float MAPINFO_TYPE_RUNEMATCH = 16;
+float MAPINFO_TYPE_LMS = 32;
+float MAPINFO_TYPE_ARENA = 64;
+float MAPINFO_TYPE_KEYHUNT = 128;
+float MAPINFO_TYPE_ASSAULT = 256;
+float MAPINFO_TYPE_ONSLAUGHT = 512;
+float MAPINFO_TYPE_ALL = 65535; // this has to include all above bits
+
+float MapInfo_count;
+
+// info about a map that MapInfo loads
+string MapInfo_Map_title;
+string MapInfo_Map_description;
+float MapInfo_Map_supportedGametypes;
+
+// load MapInfo_count; generate mapinfo for maps that miss them, and clear the
+// cache; you need to call MapInfo_FilterGametype afterwards!
+void MapInfo_Enumerate();
+
+// filter the info by game type mask (updates MapInfo_count)
+float MapInfo_FilterGametype(float gametype); // 1 on success, 0 on temporary failure (call it again next frame then)
+
+// load info about the i-th map into the MapInfo_Map_* globals
+float MapInfo_Get_ByID(float i); // 1 on success, 0 on failure
+
+// load info about a map by name into the MapInfo_Map_* globals
+float MapInfo_Get_ByName(string s, float allowGenerate); // 1 on success, 0 on failure, 2 if it autogenerated a mapinfo file
Modified: trunk/data/qcsrc/menu-div0test/mbuiltin.qh
===================================================================
--- trunk/data/qcsrc/menu-div0test/mbuiltin.qh 2007-11-14 17:24:07 UTC (rev 2950)
+++ trunk/data/qcsrc/menu-div0test/mbuiltin.qh 2007-11-15 10:30:27 UTC (rev 2951)
@@ -4,7 +4,6 @@
// AK FIXME: Create perhaps a special builtin file for the common cmds
//#define PROFILESTRZONE
-#define FIXEDFOPEN
void checkextension(string ext) = #1;
@@ -88,11 +87,7 @@
float pow(float a, float b) = #46;
void copyentity(entity src, entity dst) = #47;
-#ifdef FIXEDFOPEN
-float _fopen( string filename, float mode ) = #48;
-#else
float fopen(string filename, float mode) = #48;
-#endif
void fclose(float fhandle) = #49;
string fgets(float fhandle) = #50;
void fputs(float fhandle, string s) = #51;
@@ -233,23 +228,3 @@
float gethostcacheindexforkey(string key) = #622;
void addwantedhostcachekey(string key) = #623;
string getextresponse(void) = #624;
-
-#ifdef FIXEDFOPEN
-float fopen( string filename, float mode ) =
-{
- local float handle;
- if( mode == FILE_READ ) {
- return _fopen( filename, mode );
- }
-
- // check for data/
- filename = strzone( filename );
- if( substring( filename, 0, 5 ) != "data/" ) {
- print( "menu: fopen: all output must go into data/!\n" );
- return -1;
- }
- handle = _fopen( substring( filename, 5, 10000 ), mode );
- strunzone( filename );
- return handle;
-};
-#endif
Modified: trunk/data/qcsrc/menu-div0test/menu.qc
===================================================================
--- trunk/data/qcsrc/menu-div0test/menu.qc 2007-11-14 17:24:07 UTC (rev 2950)
+++ trunk/data/qcsrc/menu-div0test/menu.qc 2007-11-15 10:30:27 UTC (rev 2951)
@@ -11,12 +11,20 @@
float menuPrevTime;
float menuAlpha;
float prevMenuAlpha;
+float menuLoadedMaplist;
void SUB_Null() { };
void() m_init =
{
dprint_load();
+
+ menuLoadedMaplist = 0;
+ MapInfo_Enumerate();
+ if(!MapInfo_FilterGametype(MAPINFO_TYPE_ALL))
+ return;
+ menuLoadedMaplist = 1;
+
GameCommand_Init();
if(cvar("developer") == 42)
@@ -32,10 +40,15 @@
main.resizeNotify(main, draw_shift, draw_scale, draw_shift, draw_scale);
main.focused = 1;
menuShiftState = 0;
+
+ if(Menu_Active)
+ m_display(); // delayed menu display
};
void(float key, float ascii) m_keyup =
{
+ if(!menuLoadedMaplist)
+ return;
if(!Menu_Active)
return;
draw_reset();
@@ -58,6 +71,8 @@
void(float key, float ascii) m_keydown =
{
+ if(!menuLoadedMaplist)
+ return;
if(!Menu_Active)
return;
if(keyGrabber)
@@ -96,6 +111,11 @@
{
float t;
float realFrametime;
+ if(!menuLoadedMaplist)
+ {
+ m_init();
+ return;
+ }
t = gettime();
realFrametime = frametime = min(0.2, t - menuPrevTime);
menuPrevTime = t;
@@ -156,14 +176,16 @@
void() m_display =
{
Menu_Active = true;
+ setkeydest(KEY_MENU);
+ setmousetarget(MT_MENU);
+ if(!menuLoadedMaplist)
+ return;
+
if(mouseButtonsPressed)
main.mouseRelease(main, menuMousePos);
mouseButtonsPressed = 0;
- setkeydest(KEY_MENU);
- setmousetarget(MT_MENU);
-
main.focusEnter(main);
main.showNotify(main);
};
@@ -174,6 +196,9 @@
setkeydest(KEY_GAME);
setmousetarget(MT_CLIENT);
+ if(!menuLoadedMaplist)
+ return;
+
main.focusLeave(main);
main.hideNotify(main);
};
@@ -194,6 +219,8 @@
void(string itemname) m_goto =
{
entity e;
+ if(!menuLoadedMaplist)
+ return;
if(itemname == "") // this can be called by GameCommand
{
if(gamestatus & (GAME_ISSERVER | GAME_CONNECTED))
Modified: trunk/data/qcsrc/menu-div0test/progs.src
===================================================================
--- trunk/data/qcsrc/menu-div0test/progs.src 2007-11-14 17:24:07 UTC (rev 2950)
+++ trunk/data/qcsrc/menu-div0test/progs.src 2007-11-15 10:30:27 UTC (rev 2951)
@@ -6,6 +6,9 @@
oo/base.h
../common/util.qh
+
+../common/mapinfo.qh
+
gamecommand.qh
menu.qh
draw.qh
@@ -27,3 +30,4 @@
draw.qc
nexuiz/util.qc
+../common/mapinfo.qc
Modified: trunk/data/qcsrc/server/progs.src
===================================================================
--- trunk/data/qcsrc/server/progs.src 2007-11-14 17:24:07 UTC (rev 2950)
+++ trunk/data/qcsrc/server/progs.src 2007-11-15 10:30:27 UTC (rev 2951)
@@ -12,6 +12,8 @@
../common/util.qh
../common/util.qc
+../common/mapinfo.qh
+
ipban.qh
keyhunt.qh
@@ -95,3 +97,5 @@
assault.qc
ipban.qc
+
+../common/mapinfo.qc
More information about the nexuiz-commits
mailing list