map file addons: embedded config file; persistent undo/redo data

This commit establishes an extensible way of storing additional data in
map file headers. Those header extras can be permanent, like the embedded
config file or be used only once after map load like the undo/redo data.

Additional extra data can be easily added and will not break backward
compatibility, so this map format should hold up for quite some time.

To make things easier for mappers, maps can now be saved without invoking
the various optimisations. That, in combination with the stored undo data,
means, that editing a map can be picked up at exactly the same state, as
the map was saved in.

Maps will automatically be written in the appropriate fashion, depending
on the situation:
 1) for sendmap: no optimisation, no undo data
 2) savemap during editing: no optimisation, with undo data
 3) savemap when not editing: optimised, no undo data
 4) savemapoptimised: optimised, no undo data
(For savemap to save different maps during editing, the variable
 preserveundosonsave has to be "1". It is "0" by default.)

All of the above map files can be played without problems - they only
differ in file size. (However, maps with undo data may be too big to send)

The new command "embedconfigfile" will load the config file, include it in
the map header and rename the original text file.

"extractconfigfile" will write an embedded config file to a separate file
and remove it from the map header.

Embedded config files take precedence over regular config files and
therefore make it harder for cheaters to play with modified config files.

further changes: cleaned up some debugging code; more ASSERTs
This commit is contained in:
ac-stef
2014-05-15 16:07:52 +02:00
parent f4a4b843de
commit d3bda71212
9 changed files with 281 additions and 39 deletions
+81
View File
@@ -363,6 +363,87 @@ void editredo()
freeblock(p);
}
extern int worldiodebug;
void restoreeditundo(ucharbuf &q)
{
int type, len, explen;
while(!q.overread() && (type = getuint(q)))
{
int bx = getuint(q), by = getuint(q), bxs = getuint(q), bys = getuint(q);
short pp[5];
loopi(5) pp[i] = getint(q);
len = getuint(q);
if((bx | by | (bx + bxs) | (by + bys)) & ~(ssize - 1)) continue;
explen = bxs * bys;
block *b = (block *)new uchar[sizeof(block) + explen * sizeof(sqr)];
b->x = bx; b->y = by; b->xs = bxs; b->ys = bys;
loopi(5) b->p[i] = pp[i];
ucharbuf p = q.subbuf(len);
rldecodecubes(p, (sqr *)(b+1), explen, 6, true);
switch(type)
{
case 10: undos.insert(0, b); break;
case 20: redos.insert(0, b); break;
default: freeblock(b); break;
}
#ifdef _DEBUG
if(worldiodebug) switch(type)
{
case 10:
case 20:
clientlogf(" got %sdo x %d, y %d, xs %d, ys %d, remaining %d, overread %d", type == 10 ? "un" : "re", b->x, b->y, b->xs, b->ys, q.remaining(), int(q.overread()));
break;
}
#endif
}
if(undos.length() || redos.length()) conoutf("restored editing history: %d undos and %d redos", undos.length(), redos.length());
}
int rlencodeundo(int type, vector<uchar> &t, block *s)
{
putuint(t, type);
putuint(t, s->x);
putuint(t, s->y);
putuint(t, s->xs);
putuint(t, s->ys);
loopi(5) putint(t, s->p[i]);
vector<uchar> tmp;
rlencodecubes(tmp, (sqr *)(s+1), s->xs * s->ys, true);
putuint(t, tmp.length());
t.put(tmp.getbuf(), tmp.length());
#ifdef _DEBUG
if(worldiodebug) clientlogf(" compressing redo/undo x %d, y %d, xs %d, ys %d, compressed length %d, cubes %d", s->x, s->y, s->xs, s->ys, tmp.length(), s->xs * s->ys);
#endif
return t.length();
}
void backupeditundo(vector<uchar> &buf, int undolimit, int redolimit)
{
vector<uchar> tmp;
loopvrev(undos)
{
tmp.setsize(0);
undolimit -= rlencodeundo(10, tmp, undos[i]);
if(undolimit < 0) break;
buf.put(tmp.getbuf(), tmp.length());
#ifdef _DEBUG
if(worldiodebug) clientlogf(" written undo x %d, y %d, xs %d, ys %d, compressed length %d", undos[i]->x, undos[i]->y, undos[i]->xs, undos[i]->ys, tmp.length());
#endif
}
loopvrev(redos)
{
tmp.setsize(0);
redolimit -= rlencodeundo(20, tmp, redos[i]);
if(redolimit < 0) break;
buf.put(tmp.getbuf(), tmp.length());
#ifdef _DEBUG
if(worldiodebug) clientlogf(" written redo x %d, y %d, xs %d, ys %d, compressed length %d", redos[i]->x, redos[i]->y, redos[i]->xs, redos[i]->ys, tmp.length());
#endif
}
putuint(buf, 0);
}
vector<block *> copybuffers;
void resetcopybuffers()