allow copy, paste, undo, redo and selectionwalk in coop edit

limited to selection areas of at max 4096 cubes, which is 64x64 cubes
This commit is contained in:
ac-stef
2016-09-17 22:11:07 +02:00
parent 27c8f43711
commit aca74e1b59
7 changed files with 118 additions and 18 deletions
+17 -2
View File
@@ -920,7 +920,7 @@ void parsemessages(int cn, playerent *d, ucharbuf &p, bool demo = false)
int ys = getint(p);
int a1 = getint(p);
int a2 = getint(p);
if(!OUTBORD(x,y) && xs > 0 && ys > 0 && !OUTBORD(x + xs-1, y + ys - 1))
if(m_coop && !OUTBORD(x,y) && xs > 0 && ys > 0 && !OUTBORD(x + xs-1, y + ys - 1))
{
block b = { x, y, xs, ys };
switch(cmd)
@@ -948,7 +948,7 @@ void parsemessages(int cn, playerent *d, ucharbuf &p, bool demo = false)
int ys = getint(p);
int a1 = getint(p);
loopi(50) av[i] = getint(p);
if(!OUTBORD(x,y) && xs > 0 && ys > 0 && !OUTBORD(x + xs-1, y + ys - 1))
if(m_coop && !OUTBORD(x,y) && xs > 0 && ys > 0 && !OUTBORD(x + xs-1, y + ys - 1))
{
block b = { x, y, xs, ys };
archxy(a1, av, b);
@@ -956,9 +956,19 @@ void parsemessages(int cn, playerent *d, ucharbuf &p, bool demo = false)
break;
}
case SV_EDITBLOCK:
{
int bx = getuint(p), by = getuint(p), bxs = getuint(p), bys = getuint(p), light = getuint(p);
ucharbuf *pp = getgzbuf(p);
if(m_coop) netblockpastexy(pp, bx, by, bxs, bys, light);
freegzbuf(pp);
break;
}
case SV_NEWMAP:
{
int size = getint(p);
if(!m_coop) break;
if(size < 0 && sfactor > 9) break; // don't enlarge over 10 in MP
empty_world(size, true);
if(d && d!=player1)
@@ -968,6 +978,11 @@ void parsemessages(int cn, playerent *d, ucharbuf &p, bool demo = false)
case SV_EDITENT: // coop edit of ent
{
if(!m_coop)
{
loopi(12) getint(p);
break;
}
uint i = getint(p);
while((uint)ents.length()<=i) ents.add().type = NOTUSED;
int to = ents[i].type;
+87 -12
View File
@@ -421,15 +421,52 @@ void gotoposition(char *x, char *y, char *z, char *yaw, char *pitch)
}
COMMAND(gotoposition, "sssss");
const int MAXNETBLOCKSQR = MAXGZMSGSIZE / sizeof(sqr);
void netblockpaste(const block &b, int bx, int by, bool light) // transmit block to be pasted at bx,by
{
ASSERT(b.xs * b.ys <= MAXNETBLOCKSQR);
vector<uchar> t, tmp;
putuint(t, bx);
putuint(t, by);
putuint(t, b.xs);
putuint(t, b.ys);
putuint(t, light ? 1 : 0);
tmp.put((uchar *)((&b)+1), b.xs * b.ys * (int)sizeof(sqr));
putgzbuf(t, tmp);
packetbuf p(t.length() + 10, ENET_PACKET_FLAG_RELIABLE);
putint(p, SV_EDITBLOCK);
p.put(t.getbuf(), t.length());
sendpackettoserv(1, p.finalize());
}
void netblockpastexy(ucharbuf *p, int bx, int by, int bxs, int bys, int light)
{
if(bxs < 0 || bys < 0 || bxs > ssize || bys > ssize || bxs * bys > MAXNETBLOCKSQR || OUTBORD(bx, by) || OUTBORD(bx+bxs-1, by+bys-1)) return;
block *b = (block *)new uchar[sizeof(block) + bxs * bys * sizeof(sqr)];
b->x = bx; b->y = by; b->xs = bxs; b->ys = bys;
memcpy(b + 1, p->buf, p->maxlen);
makeundo(*b);
blockpaste(*b, bx, by, light != 0, NULL);
freeblockp(b);
}
void editundo()
{
EDITMP("undo");
EDIT("undo");
bool mp = multiplayer(NULL);
if(mp && undos.length() && undos.last()->xs * undos.last()->ys > MAXNETBLOCKSQR)
{
conoutf("\f3next undo area too big for multiplayer editing");
return;
}
if(undos.empty()) { conoutf("nothing more to undo"); return; }
block *p = undos.pop();
undolevel--;
redos.add(blockcopy(*p));
if(editmetakeydown) restoreposition(*p);
blockpaste(*p);
if(mp) netblockpaste(*p, p->x, p->y, true);
freeblock(p);
unsavededits++;
}
@@ -449,13 +486,20 @@ COMMANDN(undolevel, gotoundolevel, "s");
void editredo()
{
EDITMP("redo");
EDIT("redo");
bool mp = multiplayer(NULL);
if(mp && redos.length() && redos.last()->xs * redos.last()->ys > MAXNETBLOCKSQR)
{
conoutf("\f3next redo area too big for multiplayer editing");
return;
}
if(redos.empty()) { conoutf("nothing more to redo"); return; }
block *p = redos.pop();
undos.add(blockcopy(*p));
undolevel++;
if(editmetakeydown) restoreposition(*p);
blockpaste(*p);
if(mp) netblockpaste(*p, p->x, p->y, true);
freeblock(p);
unsavededits++;
}
@@ -561,7 +605,7 @@ void resetcopybuffers()
void copy()
{
EDITSELMP("copy");
EDITSEL("copy");
resetcopybuffers();
copytexconfig = texconfig_copy();
@@ -576,12 +620,24 @@ COMMAND(copy, "");
void paste()
{
EDITSELMP("paste");
EDITSEL("paste");
bool mp = multiplayer(NULL);
if(mp)
{
loopv(copybuffers) if(copybuffers[i]->xs * copybuffers[i]->ys > MAXNETBLOCKSQR)
{
conoutf("\f3copied area too big for multiplayer pasting");
return;
}
}
if(!copybuffers.length()) { conoutf("nothing to paste"); return; }
uchar usedslots[256] = { 0 }, *texmap = NULL;
loopv(copybuffers) blocktexusage(*copybuffers[i], usedslots);
if(sels.length() && copytexconfig) texmap = texconfig_paste(copytexconfig, usedslots);
if(!mp)
{
loopv(copybuffers) blocktexusage(*copybuffers[i], usedslots);
if(sels.length() && copytexconfig) texmap = texconfig_paste(copytexconfig, usedslots);
}
loopv(sels)
{
@@ -601,6 +657,7 @@ void paste()
if(!correctsel(sel) || sel.xs!=copyblock->xs || sel.ys!=copyblock->ys) { conoutf("incorrect selection"); return; }
makeundo(sel);
blockpaste(*copyblock, sel.x, sel.y, true, texmap);
if(mp) netblockpaste(*copyblock, sel.x, sel.y, true);
}
}
}
@@ -1141,7 +1198,8 @@ COMMAND(selectionflip, "s");
void selectionwalk(char *action, char *beginsel, char *endsel)
{
EDITSELMP("selectionwalk");
EDITSEL("selectionwalk");
bool mp = multiplayer(NULL);
if(*action)
{
const char *localvars[] = { "sw_cursel", "sw_abs_x", "sw_abs_y", "sw_rel_x", "sw_rel_y", "sw_type", "sw_floor", "sw_ceil", "sw_wtex", "sw_ftex", "sw_ctex", "sw_utex", "sw_vdelta", "sw_tag", "sw_r", "sw_g", "sw_b", "" };
@@ -1154,7 +1212,7 @@ void selectionwalk(char *action, char *beginsel, char *endsel)
defformatstring(tmp)("%d %d %d %d", sel.x, sel.y, sel.xs, sel.ys);
alias("sw_cursel", tmp);
if(*beginsel) execute(beginsel);
bool haveundo = false;
bool haveundo = false, isro = mp && sel.xs * sel.ys > MAXNETBLOCKSQR, didwarn = false;
loop(x, sel.xs) loop(y, sel.ys)
{
sqr *s = S(sel.x + x, sel.y + y), so = *s;
@@ -1172,12 +1230,29 @@ void selectionwalk(char *action, char *beginsel, char *endsel)
#undef GETA
if(memcmp(s, &so, sizeof(sqr)))
{
if(!haveundo) makeundo(sel);
haveundo = true;
*s = so;
if(isro)
{
if(!didwarn) conoutf("\f3selectionwalk: selected area %dx%d too big for multiplayer editing, changes ignored!", sel.xs, sel.ys);
didwarn = true;
}
else
{
if(!haveundo) makeundo(sel);
haveundo = true;
*s = so;
}
}
}
if(haveundo) remip(sel);
if(haveundo)
{
if(mp)
{
block *b = blockcopy(sel);
netblockpaste(*b, sel.x, sel.y, true);
freeblockp(b);
}
remip(sel);
}
if(*endsel) execute(endsel);
}
for(int i = 0; *localvars[i]; i++) pop(localvars[i]);
+1 -1
View File
@@ -399,7 +399,7 @@ static const int msgsizes[] = // size inclusive message token, 0 f
SV_DISCSCORES, 0, SV_TIMEUP, 3, SV_EDITENT, 13, SV_ITEMACC, 2,
SV_MAPCHANGE, 0, SV_ITEMSPAWN, 2, SV_ITEMPICKUP, 2,
SV_PING, 2, SV_PONG, 2, SV_CLIENTPING, 2, SV_GAMEMODE, 2,
SV_EDITMODE, 2, SV_EDITXY, 8, SV_EDITARCH, 56, SV_EDITS, 6, SV_EDITD, 6, SV_EDITE, 6, SV_NEWMAP, 2,
SV_EDITMODE, 2, SV_EDITXY, 8, SV_EDITARCH, 56, SV_EDITBLOCK, 0, SV_EDITD, 6, SV_EDITE, 6, SV_NEWMAP, 2,
SV_SENDMAP, 0, SV_RECVMAP, 1, SV_REMOVEMAP, 0,
SV_SERVMSG, 0, SV_ITEMLIST, 0, SV_WEAPCHANGE, 2, SV_PRIMARYWEAP, 2,
SV_FLAGACTION, 3, SV_FLAGINFO, 0, SV_FLAGMSG, 0, SV_FLAGCNT, 3,
+1 -1
View File
@@ -30,7 +30,7 @@ enum
SV_DISCSCORES, SV_TIMEUP, SV_EDITENT, SV_ITEMACC,
SV_MAPCHANGE, SV_ITEMSPAWN, SV_ITEMPICKUP,
SV_PING, SV_PONG, SV_CLIENTPING, SV_GAMEMODE,
SV_EDITMODE, SV_EDITXY, SV_EDITARCH, SV_EDITS, SV_EDITD, SV_EDITE, SV_NEWMAP,
SV_EDITMODE, SV_EDITXY, SV_EDITARCH, SV_EDITBLOCK, SV_EDITD, SV_EDITE, SV_NEWMAP,
SV_SENDMAP, SV_RECVMAP, SV_REMOVEMAP,
SV_SERVMSG, SV_ITEMLIST, SV_WEAPCHANGE, SV_PRIMARYWEAP,
SV_FLAGACTION, SV_FLAGINFO, SV_FLAGMSG, SV_FLAGCNT,
+2
View File
@@ -716,6 +716,7 @@ extern void text_endcolumns();
#define EDITSEL(x) if(noteditmode(x) || noselection()) return
#define EDITSELMP(x) if(noteditmode(x) || noselection() || multiplayer(x)) return
#define EDITMP(x) if(noteditmode(x) || multiplayer(x)) return
#define EDIT(x) if(noteditmode(x)) return
extern void cursorupdate();
extern void toggleedit(bool force = false);
extern void reseteditor();
@@ -723,6 +724,7 @@ extern char *editinfo();
extern void makeundo(block &sel);
extern void editdrag(bool isdown);
extern void checkselections();
extern void netblockpastexy(ucharbuf *p, int bx, int by, int bxs, int bys, int light);
extern void setvdeltaxy(int delta, block &sel);
extern void editequalisexy(bool isfloor, block &sel);
extern void edittypexy(int type, block &sel);
+9 -1
View File
@@ -2743,7 +2743,7 @@ int checktype(int type, client *cl)
SV_SENDDEMOLIST, SV_SENDDEMO, SV_DEMOPLAYBACK,
SV_CLIENT, SV_HUDEXTRAS, SV_POINTS };
// only allow edit messages in coop-edit mode
static int edittypes[] = { SV_EDITENT, SV_EDITXY, SV_EDITARCH, SV_EDITS, SV_EDITD, SV_EDITE, SV_NEWMAP };
static int edittypes[] = { SV_EDITENT, SV_EDITXY, SV_EDITARCH, SV_EDITBLOCK, SV_EDITD, SV_EDITE, SV_NEWMAP };
if(cl)
{
loopi(sizeof(servtypes)/sizeof(int)) if(type == servtypes[i]) return -1;
@@ -3725,6 +3725,14 @@ void process(ENetPacket *packet, int sender, int chan)
break;
}
case SV_EDITBLOCK:
{
loopi(5) getuint(p);
freegzbuf(getgzbuf(p));
QUEUE_MSG;
break;
}
case -1:
disconnect_client(sender, DISC_TAGT);
return;
+1 -1
View File
@@ -426,7 +426,7 @@ const char *messagenames[SV_NUM] =
"SV_DISCSCORES", "SV_TIMEUP", "SV_EDITENT", "SV_ITEMACC",
"SV_MAPCHANGE", "SV_ITEMSPAWN", "SV_ITEMPICKUP",
"SV_PING", "SV_PONG", "SV_CLIENTPING", "SV_GAMEMODE",
"SV_EDITMODE", "SV_EDITXY", "SV_EDITARCH", "SV_EDITS", "SV_EDITD", "SV_EDITE", "SV_NEWMAP",
"SV_EDITMODE", "SV_EDITXY", "SV_EDITARCH", "SV_EDITBLOCK", "SV_EDITD", "SV_EDITE", "SV_NEWMAP",
"SV_SENDMAP", "SV_RECVMAP", "SV_REMOVEMAP",
"SV_SERVMSG", "SV_ITEMLIST", "SV_WEAPCHANGE", "SV_PRIMARYWEAP",
"SV_FLAGACTION", "SV_FLAGINFO", "SV_FLAGMSG", "SV_FLAGCNT",