Artifact 11f87c82e6716f78c325b1a04a13804cf291dee3c0e31d83778a6c83b2f2dd29:
- File
src/clients2c.m
— part of check-in
[75e920ae30]
at
2025-03-29 14:25:43
on branch trunk
— Switch from clang-format to manual formatting
clang-format does too many weird things. (user: js, size: 9452) [annotate] [blame] [check-ins using]
// client processing of the incoming network stream #include "cube.h" #import "DynamicEntity.h" #import "Entity.h" #import "Player.h" extern int clientnum; extern bool c2sinit, senditemstoserver; extern OFString *toservermap; extern OFString *clientpassword; void neterr(OFString *s) { conoutf(@"illegal network message (%@)", s); disconnect(false, false); } void changemapserv(OFString *name, int mode) // forced map change from the server { gamemode = mode; load_world(name); } void changemap(OFString *name) // request map change, server may ignore { toservermap = name; } // update the position of other clients in the game in our world // don't care if he's in the scenery or other players, // just don't overlap with our client void updatepos(DynamicEntity *d) { Player *player1 = Player.player1; const float r = player1.radius + d.radius; const float dx = player1.origin.x - d.origin.x; const float dy = player1.origin.y - d.origin.y; const float dz = player1.origin.z - d.origin.z; const float rz = player1.aboveEye + d.eyeHeight; const float fx = (float)fabs(dx), fy = (float)fabs(dy), fz = (float)fabs(dz); if (fx < r && fy < r && fz < rz && d.state != CS_DEAD) { if (fx < fy) // push aside d.origin = OFAddVectors3D(d.origin, OFMakeVector3D( 0, (dy < 0 ? r - fy : -(r - fy)), 0)); else d.origin = OFAddVectors3D(d.origin, OFMakeVector3D( (dx < 0 ? r - fx : -(r - fx)), 0, 0)); } int lagtime = lastmillis - d.lastUpdate; if (lagtime) { d.lag = (d.lag * 5 + lagtime) / 6; d.lastUpdate = lastmillis; } } // processes any updates from the server void localservertoclient(unsigned char *buf, int len) { if (ENET_NET_TO_HOST_16(*(unsigned short *)buf) != len) neterr(@"packet length"); incomingdemodata(buf, len, false); unsigned char *end = buf + len; unsigned char *p = buf + 2; char text[MAXTRANS]; int cn = -1, type; DynamicEntity *d = nil; bool mapchanged = false; while (p < end) switch (type = getint(&p)) { case SV_INITS2C: // welcome messsage from the server { cn = getint(&p); int prot = getint(&p); if (prot != PROTOCOL_VERSION) { conoutf(@"you are using a different game " @"protocol (you: %d, server: %d)", PROTOCOL_VERSION, prot); disconnect(false, false); return; } toservermap = @""; clientnum = cn; // we are now fully connected if (!getint(&p)) // we are the first client on this server, set // map toservermap = getclientmap(); sgetstr(); if (text[0] && strcmp(text, clientpassword.UTF8String)) { conoutf(@"you need to set the correct password " @"to join this server!"); disconnect(false, false); return; } if (getint(&p) == 1) conoutf(@"server is FULL, disconnecting.."); break; } case SV_POS: { // position of another client cn = getint(&p); d = getclient(cn); if (d == nil) return; OFVector3D tmp; tmp.x = getint(&p) / DMF; tmp.y = getint(&p) / DMF; tmp.z = getint(&p) / DMF; d.origin = tmp; d.yaw = getint(&p) / DAF; d.pitch = getint(&p) / DAF; d.roll = getint(&p) / DAF; tmp.x = getint(&p) / DVF; tmp.y = getint(&p) / DVF; tmp.z = getint(&p) / DVF; d.velocity = tmp; int f = getint(&p); d.strafe = (f & 3) == 3 ? -1 : f & 3; f >>= 2; d.move = (f & 3) == 3 ? -1 : f & 3; d.onFloor = (f >> 2) & 1; int state = f >> 3; if (state == CS_DEAD && d.state != CS_DEAD) d.lastAction = lastmillis; d.state = state; if (!demoplayback) updatepos(d); break; } case SV_SOUND: { OFVector3D loc = d.origin; playsound(getint(&p), &loc); break; } case SV_TEXT: sgetstr(); conoutf(@"%@:\f %s", d.name, text); break; case SV_MAPCHANGE: sgetstr(); changemapserv(@(text), getint(&p)); mapchanged = true; break; case SV_ITEMLIST: { int n; if (mapchanged) { senditemstoserver = false; resetspawns(); } while ((n = getint(&p)) != -1) if (mapchanged) setspawn(n, true); break; } // server requests next map case SV_MAPRELOAD: { getint(&p); OFString *nextmapalias = [OFString stringWithFormat: @"nextmap_%@", getclientmap()]; // look up map in the cycle OFString *map = getalias(nextmapalias); changemap(map != nil ? map : getclientmap()); break; } // another client either connected or changed name/team case SV_INITC2S: { Player *d_ = (Player *)d; sgetstr(); if (d_.name.length > 0) { // already connected if (![d_.name isEqual: @(text)]) conoutf(@"%@ is now known as %s", d_.name, text); } else { // new client // send new players my info again c2sinit = false; conoutf(@"connected: %s", text); } d_.name = @(text); sgetstr(); d_.team = @(text); d_.lifeSequence = getint(&p); break; } case SV_CDIS: cn = getint(&p); if ((d = getclient(cn)) == nil) break; conoutf(@"player %@ disconnected", d.name.length ? d.name : @"[incompatible client]"); players[cn] = [OFNull null]; break; case SV_SHOT: { int gun = getint(&p); OFVector3D s, e; s.x = getint(&p) / DMF; s.y = getint(&p) / DMF; s.z = getint(&p) / DMF; e.x = getint(&p) / DMF; e.y = getint(&p) / DMF; e.z = getint(&p) / DMF; if (gun == GUN_SG) createrays(s, e); shootv(gun, s, e, d, false); break; } case SV_DAMAGE: { int target = getint(&p); int damage = getint(&p); int ls = getint(&p); if (target == clientnum) { if (ls == Player.player1.lifeSequence) selfdamage(damage, cn, d); } else { OFVector3D loc = getclient(target).origin; playsound(S_PAIN1 + rnd(5), &loc); } break; } case SV_DIED: { Player *d_ = (Player *)d; int actor = getint(&p); if (actor == cn) { conoutf(@"%@ suicided", d_.name); } else if (actor == clientnum) { int frags; if (isteam(Player.player1.team, d_.team)) { frags = -1; conoutf(@"you fragged a teammate (%@)", d_.name); } else { frags = 1; conoutf(@"you fragged %@", d_.name); } addmsg(1, 2, SV_FRAGS, (Player.player1.frags += frags)); } else { Player *a = getclient(actor); if (a != nil) { if (isteam(a.team, d.name)) conoutf(@"%@ fragged his " @"teammate (%@)", a.name, d.name); else conoutf(@"%@ fragged %@", a.name, d.name); } } OFVector3D loc = d_.origin; playsound(S_DIE1 + rnd(2), &loc); d_.lifeSequence++; break; } case SV_FRAGS: OFAssert([players[cn] isKindOfClass: Player.class]); ((Player *)players[cn]).frags = getint(&p); break; case SV_ITEMPICKUP: setspawn(getint(&p), false); getint(&p); break; case SV_ITEMSPAWN: { unsigned int i = getint(&p); setspawn(i, true); if (i >= ents.count) break; OFVector3D v = OFMakeVector3D(ents[i].x, ents[i].y, ents[i].z); playsound(S_ITEMSPAWN, &v); break; } // server acknowledges that I picked up this item case SV_ITEMACC: realpickup(getint(&p), Player.player1); break; case SV_EDITH: // coop editing messages, should be extended to // include all possible editing ops case SV_EDITT: case SV_EDITS: case SV_EDITD: case SV_EDITE: { int x = getint(&p); int y = getint(&p); int xs = getint(&p); int ys = getint(&p); int v = getint(&p); struct block b = { x, y, xs, ys }; switch (type) { case SV_EDITH: editheightxy(v != 0, getint(&p), &b); break; case SV_EDITT: edittexxy(v, getint(&p), &b); break; case SV_EDITS: edittypexy(v, &b); break; case SV_EDITD: setvdeltaxy(v, &b); break; case SV_EDITE: editequalisexy((v != 0), &b); break; } break; } case SV_EDITENT: // coop edit of ent { unsigned int i = getint(&p); while (ents.count <= i) { Entity *e = [Entity entity]; e.type = NOTUSED; [ents addObject: e]; } int to = ents[i].type; ents[i].type = getint(&p); ents[i].x = getint(&p); ents[i].y = getint(&p); ents[i].z = getint(&p); ents[i].attr1 = getint(&p); ents[i].attr2 = getint(&p); ents[i].attr3 = getint(&p); ents[i].attr4 = getint(&p); ents[i].spawned = false; if (ents[i].type == LIGHT || to == LIGHT) calclight(); break; } case SV_PING: getint(&p); break; case SV_PONG: addmsg(0, 2, SV_CLIENTPING, Player.player1.ping = (Player.player1.ping * 5 + lastmillis - getint(&p)) / 6); break; case SV_CLIENTPING: OFAssert([players[cn] isKindOfClass: Player.class]); ((Player *)players[cn]).ping = getint(&p); break; case SV_GAMEMODE: nextmode = getint(&p); break; case SV_TIMEUP: timeupdate(getint(&p)); break; case SV_RECVMAP: { sgetstr(); conoutf(@"received map \"%s\" from server, reloading..", text); int mapsize = getint(&p); OFString *string = @(text); writemap(string, mapsize, p); p += mapsize; changemapserv(string, gamemode); break; } case SV_SERVMSG: sgetstr(); conoutf(@"%s", text); break; case SV_EXT: // so we can messages without breaking previous // clients/servers, if necessary { for (int n = getint(&p); n; n--) getint(&p); break; } default: neterr(@"type"); return; } }