void loadgamerest(void) { if (demoplayback || !f) return; if (gzgeti()!=game::ents.length()) return loadgameout(); loopv(game::ents) { game::ents[i].spawned = gzgetc(f)!=0; // TODO if (game::ents[i].type==game::CARROT && !game::ents[i].spawned) // world::trigger(game::ents[i].attr1, game::ents[i].attr2, true); } server::restoreserverstate(game::ents); gzread(f, game::player1, sizeof(game::dynent)); game::player1->lastaction = game::lastmillis(); int nmonsters = gzgeti(); game::dvector &monsters = game::getmonsters(); if (nmonsters!=monsters.length()) return loadgameout(); loopv(monsters) { gzread(f, monsters[i], sizeof(game::dynent)); monsters[i]->enemy = game::player1; // lazy, could save id of enemy instead monsters[i]->lastaction = monsters[i]->trigger = game::lastmillis()+500; // also lazy, but no real noticable effect on game if (monsters[i]->state==CS_DEAD) monsters[i]->lastaction = 0; } game::restoremonsterstate(); int nplayers = gzgeti(); loopi(nplayers) if (!gzget()) { game::dynent *d = game::getclient(i); assert(d); gzread(f, d, sizeof(game::dynent)); } con::out("savegame restored"); if (demoloading) start(); else stop(); }
static void readdemotime() { if (gzeof(f) || (playbacktime = gzgeti())==-1) { stopreset(); return; } playbacktime = scaletime(playbacktime); }
static void start(void) { democlientnum = gzgeti(); demoplayback = true; starttime = game::lastmillis(); con::out("now playing demo"); game::dynent *d = game::getclient(democlientnum); assert(d); *d = *game::player1; readdemotime(); }
void startdemo() { democlientnum = gzgeti(); demoplayback = true; starttime = lastmillis; conoutf("now playing demo"); Sprite *d = getclient(democlientnum); assert(d); *d = *player1; readdemotime(); }
void loadgamerest() { if (demoplayback || !f) return; if (gzgeti() != entityList.size()) return loadgameout(); for(Entity &en : entityList) { en.spawned = gzgetc(f) != 0; if (en.type == CARROT && !en.spawned) trigger(en.attr1, en.attr2, true); }; restoreserverstate(entityList); gzread(f, player1, sizeof(Sprite)); player1->lastaction = lastmillis; int nmonsters = gzgeti(); std::vector<Sprite *> &monsters = getmonsters(); if (nmonsters != monsters.size()) return loadgameout(); loopv(monsters) { gzread(f, monsters[i], sizeof(Sprite)); monsters[i]->enemy = player1; // lazy, could save id of enemy instead monsters[i]->lastaction = monsters[i]->trigger = lastmillis + 500; // also lazy, but no real noticable effect on game if (monsters[i]->state == CS_DEAD) monsters[i]->lastaction = 0; }; restoremonsterstate(); int nplayers = gzgeti(); loopi(nplayers) if (!gzget()) { Sprite *d = getclient(i); assert(d); gzread(f, d, sizeof(Sprite)); }; conoutf("savegame restored"); if (demoloading) startdemo(); else stop(); }
static void loadstate(char *fn) { stop(); if (client::multiplayer()) return; f = gzopen(fn, "rb9"); if (!f) { con::out("could not open %s", fn); return; } string buf; gzread(f, buf, 8); if (strncmp(buf, "CUBESAVE", 8)) goto out; if (gzgetc(f)!=sys::islittleendian()) goto out; // not supporting save->load accross incompatible architectures simpifies things a LOT if (gzgeti()!=SAVEGAMEVERSION || gzgeti()!=sizeof(game::dynent)) goto out; string mapname; gzread(f, mapname, MAXDEFSTR); game::setnextmode(gzgeti()); client::changemap(mapname); // continue below once map has been loaded and client & server have updated return; out: con::out("aborting: savegame/demo from a different version of cube or cpu architecture"); stop(); }
void loadstate(char *fn) { stop(); if (multiplayer()) return; f = gzopen(fn, "rb9"); if (!f) { conoutf("could not open %s", fn); return; }; char buf[_MAXDEFSTR]; gzread(f, buf, 8); // not supporting save->load accross incompatible architectures simpifies things a LOT if (strncmp(buf, "CUBESAVE", 8) || gzgetc(f) != islittleendian || gzgeti() != SAVEGAMEVERSION || gzgeti() != sizeof(Sprite)) { conoutf("aborting: savegame/demo from a different version of cube or cpu architecture"); stop(); } else { memset(buf, 0, _MAXDEFSTR); gzread(f, buf, _MAXDEFSTR); nextmode = gzgeti(); changemap(std::string(buf)); // continue below once map has been loaded and client & server have updated } }
void demoplaybackstep() { while(demoplayback && lastmillis>=playbacktime) { int len = gzgeti(); if(len<1 || len>MAXTRANS) { conoutf("error: huge packet during demo play (%d)", len); stopreset(); return; }; uchar buf[MAXTRANS]; gzread(f, buf, len); localservertoclient(buf, len); // update game state dynent *target = players[democlientnum]; assert(target); int extras; if(extras = gzget()) // read additional client side state not present in normal network stream { target->gunselect = gzget(); target->lastattackgun = gzget(); target->lastaction = scaletime(gzgeti()); target->gunwait = gzgeti(); target->health = gzgeti(); target->armour = gzgeti(); target->armourtype = gzget(); loopi(NUMGUNS) target->ammo[i] = gzget(); target->state = gzget(); target->lastmove = playbacktime; if(bdamage = gzgeti()) damageblend(bdamage); if(ddamage = gzgeti()) { gzgetv(dorig); particle_splash(3, ddamage, 1000, dorig); }; // FIXME: set more client state here }; // insert latest copy of player into history if(extras && (playerhistory.empty() || playerhistory.last()->lastupdate!=playbacktime)) { dynent *d = newdynent(); *d = *target; d->lastupdate = playbacktime; playerhistory.add(d); if(playerhistory.length()>20) { zapdynent(playerhistory[0]); playerhistory.remove(0); }; }; readdemotime(); }; if(demoplayback) { int itime = lastmillis-demodelaymsec; loopvrev(playerhistory) if(playerhistory[i]->lastupdate<itime) // find 2 positions in history that surround interpolation time point { dynent *a = playerhistory[i]; dynent *b = a; if(i+1<playerhistory.length()) b = playerhistory[i+1]; *player1 = *b; if(a!=b) // interpolate pos & angles { dynent *c = b; if(i+2<playerhistory.length()) c = playerhistory[i+2]; dynent *z = a; if(i-1>=0) z = playerhistory[i-1]; //if(a==z || b==c) printf("* %d\n", lastmillis); float bf = (itime-a->lastupdate)/(float)(b->lastupdate-a->lastupdate); fixwrap(a, player1); fixwrap(c, player1); fixwrap(z, player1); vdist(dist, v, z->o, c->o); if(dist<16) // if teleport or spawn, dont't interpolate { catmulrom(z->o, a->o, b->o, c->o, bf, player1->o); catmulrom(*(vec *)&z->yaw, *(vec *)&a->yaw, *(vec *)&b->yaw, *(vec *)&c->yaw, bf, *(vec *)&player1->yaw); }; fixplayer1range(); }; break; }; //if(player1->state!=CS_DEAD) showscores(false); }; };
void playbackstep(void) { while (demoplayback && game::lastmillis()>=playbacktime) { int len = gzgeti(); if (len<1 || len>MAXTRANS) { con::out("error: huge packet during demo play (%d)", len); stopreset(); return; } u8 buf[MAXTRANS]; gzread(f, buf, len); client::localservertoclient(buf, len); // update game state game::dynent *target = game::players[democlientnum]; assert(target); int extras; if ((extras = gzget())) { // read additional client side state not present in normal network stream target->gunselect = gzget(); target->lastattackgun = gzget(); target->lastaction = scaletime(gzgeti()); target->gunwait = gzgeti(); target->health = gzgeti(); target->armour = gzgeti(); target->armourtype = gzget(); loopi(game::NUMGUNS) target->ammo[i] = gzget(); target->state = gzget(); target->lastmove = playbacktime; // if ((bdamage = gzgeti()) != 0) rr::damageblend(bdamage); if ((ddamage = gzgeti()) != 0) { gzgetv(dorig); rr::particle_splash(rr::PT_BLOOD_SPATS, ddamage, 1000, dorig); } // FIXME: set more client state here } // insert latest copy of player into history if (extras && (playerhistory.empty() || playerhistory.last()->lastupdate!=playbacktime)) { game::dynent *d = game::newdynent(); *d = *target; d->lastupdate = playbacktime; playerhistory.add(d); if (playerhistory.length()>20) { game::zapdynent(playerhistory[0]); playerhistory.remove(0); } } readdemotime(); } if (demoplayback) { int itime = game::lastmillis()-demodelaymsec; loopvrev(playerhistory) if (playerhistory[i]->lastupdate<itime) { // find 2 positions in history that surround interpolation time point game::dynent *a = playerhistory[i]; game::dynent *b = a; if (i+1<playerhistory.length()) b = playerhistory[i+1]; *game::player1 = *b; if (a!=b) { // interpolate pos & angles game::dynent *c = b; if (i+2<playerhistory.length()) c = playerhistory[i+2]; game::dynent *z = a; if (i-1>=0) z = playerhistory[i-1]; float bf = (itime-a->lastupdate)/(float)(b->lastupdate-a->lastupdate); fixwrap(a, game::player1); fixwrap(c, game::player1); fixwrap(z, game::player1); const float dist = distance(z->o,c->o); if (dist<16.f) { // if teleport or spawn, dont't interpolate catmulrom(z->o, a->o, b->o, c->o, bf, game::player1->o); // catmulrom(*(vec3f*)&z->ypr.x, *(vec3f*)&a->ypr.x, *(vec3f*)&b->ypr.x, *(vec3f*)&c->ypr.x, bf, *(vec3f *)&game::player1->ypr.x); vec3f dstangle; catmulrom(z->ypr, a->ypr, b->ypr, c->ypr, bf, dstangle); game::player1->ypr.x = dstangle.x; game::player1->ypr.y = dstangle.y; game::player1->ypr.z = dstangle.z; } game::fixplayer1range(); } break; } } }