new commands to add modeinfo and artist info to maps

mapartist print|set|get|clear

  print:  prints the map artist player ID
  set:  sets the map artist player ID to the currently logged in player
  get:   returns the current map artist player ID
  clear:  erases an existing map artist record in the current map

modeinfo list|get|clear|<modelist> <modeflags>

  list:  lists current modeinfo entries
  get:  returns list of current modeinfo entries
  clear:  erases current list of modeinfo entries
  <modelist> <modeflags>:  specifies flags for a list of modes

DOCREF modeinfo mapartist
This commit is contained in:
ac-stef
2017-06-27 15:15:23 +02:00
parent cefe93ce18
commit 49232e05e0
9 changed files with 214 additions and 26 deletions
+1
View File
@@ -623,6 +623,7 @@ void entstats_(void)
}
if(es.entcnt[CTF_FLAG]) conoutf(" flag distance: %d", es.flagentdistance);
conoutf(" map capabilities: has ffa spawns %d, has team spawns %d, has flags %d", es.hasffaspawns ? 1 : 0, es.hasteamspawns ? 1 : 0, es.hasflags ? 1 : 0);
if(es.modes_possible & GMMASK__MPNOCOOP) conoutf(" possible multiplayer modes: %s", gmode_enum(es.modes_possible & GMMASK__MPNOCOOP, txt));
conoutf("total entities: %d", ents.length());
intret(xmodels + xsounds);
}
+2
View File
@@ -234,3 +234,5 @@ enum
#define FTXT__CONSOLEPASTE (FTXT_TABTOBLANK)
#define FTXT__VITACOMMENT (FTXT_NOWHITE | FTXT_ALLOWBLANKS | FTXT_NOCOLOR | FTXT_TABTOBLANK)
#define FTXT__VITACLAN (FTXT_NOWHITE | FTXT_NOCOLOR)
#define FTXT__MAPROT (FTXT_NOWHITE | FTXT_NOCOLOR | FTXT_TOLOWER)
+1
View File
@@ -1038,6 +1038,7 @@ extern void localservertoclient(int chan, uchar *buf, int len, bool demo = false
extern const char *modestr(int n, bool acronyms = false);
extern const char *voteerrorstr(int n);
extern const char *mmfullname(int n);
extern void filterconfigset(char *list, void *cs = NULL);
extern void fatal(const char *s, ...) PRINTFARGS(1, 2);
extern void initserver(bool dedicated);
extern void cleanupserver();
+2
View File
@@ -4758,6 +4758,8 @@ void initserver(bool dedicated)
readmapsthread_sem = new sl_semaphore(0, NULL);
defformatstring(readmapslogfilename)("%sreadmaps_log.txt", scl.logfilepath);
sl_createthread(readmapsthread, (void *)path(readmapslogfilename));
defformatstring(_modeinfologfilename)("%smisc/modeinfo.txt", scl.logfilepath);
modeinfologfilename = path(_modeinfologfilename);
readserverconfigsthread_sem = new sl_semaphore(0, NULL);
sl_createthread(readserverconfigsthread, NULL);
+2
View File
@@ -454,6 +454,8 @@ void sendf(int cn, int chan, const char *format, ...);
extern bool isdedicated;
const char *modeinfologfilename = NULL;
const char *messagenames[SV_NUM] =
{
"SV_SERVINFO", "SV_SERVINFO_RESPONSE", "SV_SERVINFO_CONTD", "SV_WELCOME", "SV_INITCLIENT", "SV_POS", "SV_POSC", "SV_POSN",
+92 -24
View File
@@ -31,12 +31,8 @@ struct configsetvalues
};
void empty() { weight = repeat = 0; time = mintime = maxtime = minplayers = maxplayers = maxteamsize = teamthreshold = manual = restrict = -1; }
void add(configsetvalues u)
{
weight = clamp(weight + u.weight, -100, 100);
repeat = clamp(repeat + u.repeat, -100, 100);
for(int i = 2; i < CONFIG_MAXPAR; i++) if(u.par[i] >= 0) par[i] = u.par[i];
}
void add(configsetvalues u);
bool parse(char *keyval);
};
// map management
@@ -82,6 +78,9 @@ struct servermap // in-memory version of a map file on a server
uchar *enttypes; // table of entity types
short *entpos_x, *entpos_y;
configsetvalues *hx_modeinfo; // maprot parameters from map author
uchar *hx_mapartist; // pubkey of map artist
int modes_allowed; // modes_possible reduced to MP modes (if dedicated server)
configsetvalues modes[GMODE_NUM]; // maprot parameters for this map
int modes_auto; // modes to be suggested automatically
@@ -100,7 +99,7 @@ struct servermap // in-memory version of a map file on a server
#endif
servermap(const char *mname, const char *mpath) { memset(&fname, 0, sizeof(struct servermap)); fname = newstring(mname); fpath = mpath; }
~servermap() { delstring(fname); DELETEA(cgzraw); DELETEA(cfgrawgz); DELETEA(enttypes); DELETEA(entpos_x); DELETEA(entpos_y); DELETEA(layoutgz); }
~servermap() { delstring(fname); DELETEA(cgzraw); DELETEA(cfgrawgz); DELETEA(enttypes); DELETEA(entpos_x); DELETEA(entpos_y); DELETEA(layoutgz); DELETEA(hx_modeinfo); DELETEA(hx_mapartist); }
bool isro() { return fpath == servermappath_off || fpath == servermappath_serv; }
bool isofficial() { return fpath == servermappath_off; }
@@ -137,7 +136,7 @@ struct servermap // in-memory version of a map file on a server
stream *f = NULL;
int restofhead;
string filename;
string filename, tmp;
if(!validmapname(fname)) err = "illegal filename";
if(err) goto loadfailed;
@@ -225,9 +224,27 @@ struct servermap // in-memory version of a map file on a server
case HX_CONFIG:
break;
case HX_MAPINFO:
case HX_MODEINFO: // for new maprot...
case HX_MODEINFO:
{
hx_modeinfo = new configsetvalues[GMODE_NUM];
char done[GMODE_NUM] = { 0 };
loopi(GMODE_NUM) hx_modeinfo[i].empty();
string line;
for(int mode = getuint(q); !q.overread() && mode > 0; mode = getuint(q))
{
getstring(line, q, MAXSTRLEN);
loopi(GMODE_NUM) if((mode & (1 << i)) && !done[i]++) filterconfigset(line, hx_modeinfo + i);
stream *mr = modeinfologfilename ? openfile(modeinfologfilename, "a") : NULL;
if(mr) { mr->printf("%s %s %s\n", fname, gmode_enum(mode, tmp), line); delete mr; } // dump modeinfo lines to file, may be used as maprot
}
break;
}
case HX_ARTIST:
if(len == 32) q.get((hx_mapartist = new uchar[32]), 32);
else err = "invalid HX_ARTIST record";
break;
case HX_MAPINFO:
default:
break;
}
@@ -288,6 +305,8 @@ struct servermap // in-memory version of a map file on a server
entpos_x[i] = e.x;
entpos_y[i] = e.y;
}
// respect map author wishes about disallowed modes
if(hx_modeinfo) loopi(GMODE_NUM) if(hx_modeinfo[i].restrict == 81) entstats.modes_possible &= ~(1 << i); // disallowed by elvis^2
}
if(err) goto loadfailed;
@@ -760,6 +779,60 @@ int readserverconfigsthread(void *data)
#define MODEHISTLEN 64 // remember the game modes of the last hour (roughly)
void configsetvalues::add(configsetvalues u)
{
weight = clamp(weight + u.weight, -100, 100);
repeat = clamp(repeat + u.repeat, -100, 100);
for(int i = 2; i < CONFIG_MAXPAR; i++) if(u.par[i] >= 0) par[i] = u.par[i];
}
bool configsetvalues::parse(char *keyval) // parse one key:value pair
{
char *kb, *k = strtok_r(keyval, ":", &kb);
if(k)
{
loopi(CONFIG_MAXPAR) if(!strcmp(k, maprotkeywords[i]))
{
if((k = strtok_r(NULL, ":", &kb)))
{
par[i] = clamp(atoi(k), -100, 100);
return true;
}
}
}
return false;
}
void filterconfigset(char *list, void *cs)
{
configsetvalues e, u, *c = cs ? (configsetvalues *) cs : &u;
e.empty(), c->empty();
char *b, *kv = strtok_r(list, " ", &b);
while(kv)
{
c->parse(kv);
kv = strtok_r(NULL, " ", &b);
}
list[0] = '\0';
loopi(CONFIG_MAXPAR) if(c->par[i] != e.par[i]) concatformatstring(list, "%s%s:%d", list[0] ? " " : "", maprotkeywords[i], c->par[i]);
}
SERVSTRF(use_hx_modeinfo, "weight|time|mintime|maxtime|minplayers|maxplayers|maxteamsize|teamthreshold", 0, 159, FTXT__MAPROT, filter_use_hx_modeinfo, "gList of maprot keywords to copy from map headers");
int use_hx_modeinfo_mask = 0;
void filter_use_hx_modeinfo()
{
use_hx_modeinfo_mask = 0;
char *tmp = newstring(use_hx_modeinfo), *b, *kv = strtok_r(tmp, "|", &b);
while(kv)
{
loopi(CONFIG_MAXPAR) if(!strcmp(kv, maprotkeywords[i])) use_hx_modeinfo_mask |= 1 << i;
kv = strtok_r(NULL, "|", &b);
}
delstring(tmp);
}
struct configset : configsetvalues
{
char mapname[MAXMAPNAMELEN + 1];
@@ -816,19 +889,7 @@ struct servermaprot : serverconfigfile
if(l) c.mmask = gmode_parse(l);
while((l = strtok_r(NULL, " ", &b)))
{
char *kb, *k = strtok_r(l, ":", &kb);
if(k)
{
loopi(CONFIG_MAXPAR) if(!strcmp(k, maprotkeywords[i]))
{
if((k = strtok_r(NULL, ":", &kb)))
{
c.par[i] = clamp(atoi(k), -100, 100);
haskeywords = true;
break;
}
}
}
if(c.parse(l)) haskeywords = true;
}
if(haskeywords)
{
@@ -855,7 +916,15 @@ struct servermaprot : serverconfigfile
void initmap(servermap *m, stream *f) // set maprot parameters of a servermap
{
configsetvalues e;
memcpy(m->modes, base, sizeof(m->modes));
if(m->hx_modeinfo && use_hx_modeinfo_mask) loopj(GMODE_NUM)
{
e.empty();
loopk(CONFIG_MAXPAR) if(use_hx_modeinfo_mask & (1 << k)) e.par[k] = m->hx_modeinfo[j].par[k];
m->modes[j].add(e);
}
loopv(configsets)
{
configset &c = configsets[i];
@@ -886,7 +955,6 @@ struct servermaprot : serverconfigfile
{
string s;
f->printf("maprot parameters for: %s%s\n", m->fpath, m->fname);
configsetvalues e;
e.empty();
loopj(GMODE_NUM) if((1 << j) & GMMASK__MPNOCOOP)
{
+108 -2
View File
@@ -283,7 +283,7 @@ void unpackheaderextra(uchar *buf, int len) // break the extra data from the ma
while(1)
{
int len = getuint(p), flags = getuint(p);
if(p.overread() || len > p.remaining()) break;
if(p.overread() || len > p.remaining() || len < 0 || flags < 0) break;
DEBUGCODE(clientlogf(" found headerextra \"%s\", %d bytes%s", hx_name(flags & HX_TYPEMASK), len, flags & HX_FLAG_PERSIST ? ", persistent" : "")); // debug info
headerextras.add(new headerextra(len, flags, p.subbuf(len).buf));
}
@@ -306,7 +306,8 @@ void parseheaderextra(bool clearnonpersist = true, int ignoretypes = 0) // pars
case HX_CONFIG:
setcontext("map", "embedded");
execute((const char *)q.buf); // needs to have '\0' at the end
if(headerextras[i]->len > 0 && headerextras[i]->data[headerextras[i]->len - 1] == '\0') execute((const char *)q.buf); // needs to have '\0' at the end, better check...
else conoutf("malformed emb config");
resetcontext();
break;
@@ -541,6 +542,111 @@ bool gotovantagepoint()
}
COMMANDF(gotovantagepoint, "", () { intret((editmode || (!multiplayer(NULL) && player1->isspectating())) && gotovantagepoint() ? 1 : 0); });
void modeinfo(char *mode, char *info)
{
char *modeinfolines[GMODE_NUM] = { NULL };
string line, tmp;
// find and unpack HX_MODEINFO
int he = findheaderextra(HX_MODEINFO);
if(he >= 0)
{
ucharbuf q(headerextras[he]->data, headerextras[he]->len);
for(int mode = getuint(q); !q.overread() && mode > 0; mode = getuint(q))
{
getstring(line, q, MAXSTRLEN);
filterconfigset(line);
loopi(GMODE_NUM) if((mode & (1 << i)) && !modeinfolines[i]) modeinfolines[i] = newstring(line);
}
}
// parse command arguments and apply changes or generate output
vector<char> res;
copystring(line, info);
filterconfigset(line);
int modes = gmode_parse(mode), n = 0;
if(!strcmp(mode, "*") || !strcmp(mode, "all")) modes = GMMASK__MPNOCOOP;
else if(!strcmp(mode, "list"))
{
loopi(GMODE_NUM) if(modeinfolines[i] && ++n) conoutf("%s: %s", gmode_enum(1 << i, tmp), escapestring(modeinfolines[i]));
if(!n) conoutf("no modeinfo lines set");
}
else if(!strcmp(mode, "get"))
{
loopi(GMODE_NUM) if(modeinfolines[i]) cvecprintf(res, "%s %s\n", gmode_enum(1 << i, tmp), escapestring(modeinfolines[i]));
}
else if(!strcmp(mode, "clear"))
{
loopi(GMODE_NUM) if(modeinfolines[i]) { n++; DELSTRING(modeinfolines[i]); }
conoutf("deleted %d modeinfo lines", n);
}
if(modes) loopi(GMODE_NUM)
{
if(modes & (1 << i))
{
DELSTRING(modeinfolines[i]);
modeinfolines[i] = newstring(line);
}
}
if(res.length()) res.last() = '\0';
else res.add('\0');
result(res.getbuf());
// recreate HX_MODEINFO
for(int n; (n = findheaderextra(HX_MODEINFO)) >= 0; ) deleteheaderextra(n);
vector<uchar> p;
entitystats_s es;
calcentitystats(es, NULL, 0);
int todo = es.modes_possible;
bool have_modeinfo = false;
loopk(GMODE_NUM) if(modeinfolines[k] && modeinfolines[k][0] && (todo & (1 << k)))
{
int modes = 0;
for(int i = k; i < GMODE_NUM; i++)
{
if(modeinfolines[i] && !strcmp(modeinfolines[k], modeinfolines[i])) modes |= (1 << i);
}
putuint(p, modes);
sendstring(modeinfolines[k], p);
todo &= ~modes;
have_modeinfo = true;
}
putuint(p, 0);
if(have_modeinfo) headerextras.add(new headerextra(p.length(), HX_MODEINFO|HX_FLAG_PERSIST, p.getbuf()));
}
COMMAND(modeinfo, "ss");
void mapartist(char *what)
{
uchar32 buf;
bool update = false, remove = false;;
// find and unpack HX_ARTIST
int he = findheaderextra(HX_ARTIST);
if(he >= 0 && headerextras[he]->len == 32) memcpy(buf.u, headerextras[he]->data, 32);
// parse command arguments and apply changes or generate output
string tmp;
if(!strcmp(what, "print")) conoutf("map artist key: %s", bin2hex(tmp, buf.u, 32));
else if(!strcmp(what, "set"))
{
if(*sk)
{
memcpy(buf.u, sk + 32, 32);
update = true;
}
else conoutf("no player account in use");
}
else if(!strcmp(what, "clear")) remove = true;
bin2hex(tmp, buf.u, 32);
result(he >= 0 || update ? tmp : "");
// recreate HX_ARTIST
if(update || remove) for(int n; (n = findheaderextra(HX_ARTIST)) >= 0; ) deleteheaderextra(n);
if(update) headerextras.add(new headerextra(32, HX_ARTIST|HX_FLAG_PERSIST, buf.u));
}
COMMAND(mapartist, "s");
void setmapinfo(const char *newlicense, const char *newcomment)
{
string s;