00001
00024 #include "color.h"
00025 #include "playernet.h"
00026 #include "game.h"
00027 #include "net.h"
00028 #include <assert.h>
00029 #include <string.h>
00030 #ifdef USE_AUDIO
00031 #include "audio.h"
00032 #endif
00033
00034 #if (MAX_PLAYERS > 256)
00035 #error More than 256 players is not supported.
00036 #endif
00037
00038 MsgDescr *AppendPlayerData(MsgDescr *msg, Player *p, Uint32 time) {
00039 Uint8 *ptr;
00040 int flags, len = 3, nameLen;
00041
00042
00043
00044 assert((msg == NULL) || (msg->buffer->data[0] == MSG_TYPE_PLAYER_UPDATE));
00045
00046
00047 if (networkState == NETSTATE_CLIENT) {
00048
00049 flags = p->flags & (PLAYER_CLIENT_MASK | PLAYER_MOVEMENT_MASK);
00050 }
00051 else {
00052
00053 flags = p->flags;
00054 }
00055
00056 assert(flags & PLAYER_UPDATE_ITEMS);
00057
00058 if (flags & PLAYER_UPDATE_IDENT) {
00059 len += 1 + ((nameLen = (int)rtsa_strlen(p->name)) << 1);
00060 assert(nameLen < MAX_NAME_LEN);
00061 }
00062 if (flags & PLAYER_UPDATE_TANK) {
00063 len += 10;
00064 }
00065 if (flags & PLAYER_UPDATE_SHELL) {
00066 len += 12;
00067 }
00068
00069 if (flags & PLAYER_UPDATE_DFS) {
00070 len += 5;
00071 }
00072
00073 if ((msg == NULL) || ((MSG_MAX_SIZE - msg->buffer->length) < len)) {
00074
00075 if ((msg != NULL) && !AddMessage(msg)) {
00076
00077 return NULL;
00078 }
00079
00080 if ((msg = MessageNew()) == NULL) {
00081
00082 return NULL;
00083 }
00084
00085 if ((msg->buffer = BufferNew()) == NULL) {
00086
00087 MessageFree(msg);
00088 return NULL;
00089 }
00090
00091 msg->approveFunc = NULL;
00093 msg->ackFunc = NULL;
00094 msg->failFunc = MsgFailDisconnect;
00095
00096 msg->buffer->length = 7;
00097 msg->buffer->data[0] = MSG_TYPE_PLAYER_UPDATE;
00098 MSG_WRITE_32C(msg->buffer->data, 3, time);
00099
00100 if (networkState == NETSTATE_SERVER) {
00101
00103 SetDestToAll(msg);
00104 }
00105 else {
00106
00107 msg->destMap[0] = 1;
00108 }
00109 }
00110
00111 ptr = &(msg->buffer->data[msg->buffer->length]);
00112
00113 msg->buffer->length += len;
00114
00115 MSG_WRITE_8(ptr, p->pid);
00116
00117
00118 MSG_WRITE_16(ptr, flags);
00119
00120 if (flags & PLAYER_UPDATE_IDENT) {
00121 int loop;
00122
00123
00124 MSG_WRITE_8(ptr, nameLen | p->team << 6);
00125
00126 loop = TextNativeToUTF16((Uint16*)ptr, MAX_NAME_LEN, p->name,
00127 nameLen);
00128 assert(loop == nameLen);
00129
00130 ptr += nameLen << 1;
00131 }
00132
00133 if (flags & PLAYER_UPDATE_DFS) {
00134
00135
00136 MSG_WRITE_16(ptr, p->kills);
00137 MSG_WRITE_16(ptr, p->captures);
00138 MSG_WRITE_8(ptr, p->deadTime);
00139 }
00140
00141 if (flags & PLAYER_UPDATE_TANK) {
00142 MSG_WRITE_32(ptr, p->x);
00143 MSG_WRITE_32(ptr, p->y);
00144 MSG_WRITE_16(ptr, p->rot);
00145 }
00146
00147 if (flags & PLAYER_UPDATE_SHELL) {
00148 MSG_WRITE_32(ptr, p->shellX);
00149 MSG_WRITE_32(ptr, p->shellY);
00150 MSG_WRITE_16(ptr, p->shellRot);
00151 MSG_WRITE_16(ptr, p->shellDist);
00152 }
00153
00154 assert(ptr == msg->buffer->data + msg->buffer->length);
00155
00156 return msg;
00157 }
00158
00171 static int CalculateOffset(NetBuffer *buffer, int offset) {
00172 int flags;
00173
00174 flags = buffer->data[++offset] << 8;
00175
00176 if (networkState == NETSTATE_SERVER) {
00177
00178 flags &= PLAYER_CLIENT_MASK;
00179 }
00180
00181 if ((flags & PLAYER_UPDATE_IDENT) && (++offset < buffer->length)) {
00182
00183 offset += (buffer->data[offset + 1] & 0x1F) << 1;
00184 }
00185
00186 offset += ((flags & PLAYER_UPDATE_TANK) ? 10 : 0) +
00187 ((flags & PLAYER_UPDATE_SHELL) ? 12 : 0) +
00188 ((flags & PLAYER_UPDATE_DFS) ? 5 : 0) + 2;
00189
00190 if (offset > buffer->length) {
00191
00192 offset = -offset;
00193 }
00194 return offset;
00195 }
00196
00210 static Uint8 *ReadPlayer(Uint8 *ptr, Uint32 time) {
00211 Player *p;
00212 int flags, pid;
00213 Bool readTank = FALSE;
00214
00215
00216 MSG_READ_8(ptr, pid);
00217 #if (MAX_PLAYERS < 256)
00218
00219 if (pid >= MAX_PLAYERS) return FALSE;
00220 #endif
00221
00222 p = &(players[pid]);
00223
00224 MSG_READ_16(ptr, flags);
00225
00226 if (networkState == NETSTATE_SERVER) {
00227
00228 flags &= PLAYER_CLIENT_MASK | PLAYER_MOVEMENT_MASK;
00229
00230
00231 p->flags = (p->flags & (PLAYER_DEAD | PLAYER_ACTIVE |
00232 PLAYER_MOVEMENT_MASK)) | (flags & ~PLAYER_MOVEMENT_MASK);
00233 }
00234
00235 else {
00236
00237 if (p->pid == localPlayer) {
00238
00239
00240 flags = (flags & PLAYER_LOCAL_MASK) | PLAYER_ACTIVE;
00241
00242 if (p->flags & PLAYER_DEAD) {
00243
00244 readTank = TRUE;
00245 }
00246 #ifdef USE_AUDIO
00247
00248 else if (flags & PLAYER_DEAD) {
00249
00250 PlayLocalDeath();
00251 }
00252 #endif
00253
00254 p->flags = (flags & ~(PLAYER_UPDATE_IDENT | PLAYER_MOVEMENT_MASK |
00255 PLAYER_UPDATE_TANK | PLAYER_UPDATE_SHELL)) |
00256 (p->flags & (PLAYER_UPDATE_IDENT | PLAYER_MOVEMENT_MASK |
00257 PLAYER_UPDATE_TANK | PLAYER_UPDATE_SHELL));
00258 }
00259 else {
00260
00261 p->flags = (flags & ~(PLAYER_ACTIVE | PLAYER_MOVEMENT_MASK)) |
00262 (p->flags & (PLAYER_ACTIVE | PLAYER_MOVEMENT_MASK));
00263 #ifdef USE_AUDIO
00264
00265 if ((p->flags & PLAYER_DEAD) && ((p->deadTime == 0) ||
00266 (p->deadTime > DEAD_TIME))) {
00267
00268 int distsq = DistSq(p, &players[localPlayer]);
00269
00270 if (distsq < MAX_SQ_DIST) {
00271
00272 PlayTankKilled(distsq);
00273 }
00274 }
00275 #endif
00276 }
00277
00278 if (p->flags & PLAYER_DEAD) {
00279
00280 p->flags &= ~(PLAYER_SHOT | PLAYER_FORWARD | PLAYER_BACKWARD |
00281 PLAYER_ROTRIGHT | PLAYER_ROTLEFT | PLAYER_SHOT);
00282
00283 ClearRenderItem(&(p->shell));
00284 RemoveShell(p->pid);
00285
00286 readTank = TRUE;
00287 }
00288 }
00289
00290 if (flags & PLAYER_UPDATE_IDENT) {
00291 int nameLen;
00292
00293 MSG_READ_8(ptr, nameLen);
00294
00295 if (time > p->lastUpdate.identTime) {
00296 int len;
00297
00298 p->flags &= ~PLAYER_UPDATE_IDENT;
00299
00300 p->lastUpdate.identTime = time;
00301
00302 p->team = nameLen >> 6;
00303
00304
00305 len = TextUTF16toNative(p->name, MAX_NAME_LEN, (Uint16*)ptr,
00306 nameLen &= 0x1F);
00307 assert(len == nameLen);
00308
00309 ptr += nameLen << 1;
00310
00311 #ifdef MSG_DEBUG
00312 printf("Got ident for player #%d, %s\n", p->pid, p->name);
00313 #endif
00314 }
00315 else {
00316
00317 ptr += (nameLen & 0x1F) << 1;
00318 #ifdef MSG_DEBUG
00319 printf("Ignoring ident for player #%d, %s\n", p->pid, p->name);
00320 #endif
00321 }
00322 }
00323
00324 if (!(p->flags & PLAYER_ACTIVE)) {
00325 p->pid = pid;
00326 p->flags |= PLAYER_DEAD;
00327 AddPlayer(p);
00328 }
00329
00330 assert(pid == p->pid);
00331
00332
00333 if (flags & PLAYER_UPDATE_DFS) {
00334
00335 if (time > p->lastUpdate.dfsTime) {
00336
00337 p->lastUpdate.dfsTime = time;
00338
00339 MSG_READ_16(ptr, p->kills);
00340 MSG_READ_16(ptr, p->captures);
00341 MSG_READ_8(ptr, p->deadTime);
00342
00343 if (!(flags & PLAYER_SHOT)) {
00344 p->flags &= ~PLAYER_SHOT;
00345
00346 ClearRenderItem(&(p->shell));
00347 RemoveShell(p->pid);
00348 }
00349
00350 if (!(flags & PLAYER_DEAD)) {
00351
00352 p->flags &= ~PLAYER_DEAD;
00353 }
00354 #ifdef MSG_DEBUG
00355 printf("Got DFS update for player #%d at time %d\n", p->pid, time);
00356 #endif
00357 }
00358 else {
00359
00360 ptr += 5;
00361 }
00362 }
00363
00364
00365 if (flags & PLAYER_UPDATE_TANK) {
00366
00367 if ((readTank || (pid != localPlayer)) &&
00368 (time > p->lastUpdate.tankPosTime)) {
00369 Uint16 oldRot = p->rot;
00370
00371 p->flags = (p->flags & ~(PLAYER_UPDATE_TANK | PLAYER_MOVEMENT_MASK))
00372 | (flags & PLAYER_MOVEMENT_MASK);
00373
00374 p->lastUpdate.tankPosTime = time;
00375
00376 MSG_READ_32(ptr, p->x);
00377 MSG_READ_32(ptr, p->y);
00378 MSG_READ_16(ptr, p->rot);
00379
00380 if (!(p->flags & PLAYER_DEAD)) {
00381 MoveTank(p, 0);
00382
00383 if (!p->tank.placed && ((oldRot & 0xF00) != (p->rot & 0xF00))) {
00384
00385 QueuePlaceTank(p->pid);
00386 }
00387 }
00388 #ifdef MSG_DEBUG
00389 printf("Got tank update for player #%d at time %d\n", p->pid, time);
00390 printf("\tcoords: x = %d y = %d\n", p->x >> 8, p->y >> 8);
00391 #endif
00392 }
00393 else {
00394
00395 ptr += 10;
00396 #ifdef MSG_DEBUG
00397 printf("Ignoring tank update for player #%d at time %d\n", p->pid,
00398 time);
00399 #endif
00400 }
00401 }
00402
00403
00404 if (flags & PLAYER_UPDATE_SHELL) {
00405
00406 if ((pid != localPlayer) && !(p->flags & PLAYER_DEAD) &&
00407 (time > p->lastUpdate.tankPosTime)) {
00408
00409 p->flags &= ~PLAYER_UPDATE_SHELL;
00410
00411 p->lastUpdate.shellPosTime = time;
00412
00413 MSG_READ_32(ptr, p->shellX);
00414 MSG_READ_32(ptr, p->shellY);
00415 MSG_READ_16(ptr, p->shellRot);
00416 MSG_READ_16(ptr, p->shellDist);
00417
00418 p->shell.loc.x = (p->shellX >> 8) * dInfo.luh;
00419 p->shell.loc.y = (p->shellY >> 8) * dInfo.luh;
00420
00421 if (flags & PLAYER_SHOT) {
00422
00423 p->flags |= PLAYER_SHOT;
00424
00425 QueuePlaceShell(p->pid);
00426 #ifdef USE_AUDIO
00427
00428 if ((p->pid != localPlayer) &&
00429 !(players[localPlayer].flags & PLAYER_DEAD)) {
00430
00431 int distsq = DistSq(p, &players[localPlayer]);
00432
00433 if (distsq < MAX_SQ_DIST) {
00434
00435 PlayTankShoot(distsq);
00436 }
00437 }
00438 #endif
00439 }
00440 else {
00441
00442 p->flags &= ~PLAYER_SHOT;
00443
00444 ClearRenderItem(&(p->shell));
00445 RemoveShell(p->pid);
00446 }
00447 }
00448 else {
00449
00450 ptr += 12;
00451 }
00452 }
00453
00454
00455 if (networkState == NETSTATE_SERVER) {
00456
00457 p->flags |= flags & PLAYER_UPDATE_ITEMS;
00458 }
00459
00460
00461 return ptr;
00462 }
00463
00464 Bool HandlePlayerUpdate(SocketAddr *origin, NetBuffer *buffer, Uint8 *clientId,
00465 Uint16 messageId) {
00466 int len = 7;
00467 Uint32 time;
00468 Uint8 *ptr;
00469
00470 if (buffer->length < 12) return FALSE;
00471
00472 if ((networkState >= NETSTATE_RCVCFG) && (networkState <= NETSTATE_CLIENT)
00473 && ValidateServer(origin)) {
00474 int numplay = 0;
00475
00476 do {
00477
00478 if ((len = CalculateOffset(buffer, len)) < 0) {
00479 #ifdef MSG_DEBUG
00480 printf("Got bad player update in message %d\n", messageId);
00481 #endif
00482
00483 return FALSE;
00484 }
00485
00486 numplay++;
00487 } while (len < buffer->length);
00488
00489 if (len != buffer->length) {
00490 #ifdef MSG_DEBUG
00491 printf("Got bad player update in message %d\n", messageId);
00492 printf("\tMessage length: %i Calculated length: %i Players: %i\n",
00493 buffer->length, len, numplay);
00494 #endif
00495
00496 return FALSE;
00497 }
00498
00499 ptr = &(buffer->data[3]);
00500
00501 MSG_READ_32(ptr, time);
00502
00503 for (; numplay > 0; numplay--) {
00504 ptr = ReadPlayer(ptr, time);
00505 assert((ptr - buffer->data) <= len);
00506 }
00507 assert((ptr - buffer->data) == buffer->length);
00508 }
00509
00510 else if ((networkState == NETSTATE_SERVER) &&
00511 ValidateClient(origin, buffer->data[len]) &&
00512 (CalculateOffset(buffer, len) == buffer->length)) {
00513
00514 *clientId = buffer->data[7];
00515
00516 ptr = &(buffer->data[3]);
00517
00518 MSG_READ_32(ptr, time);
00519
00520 ptr = ReadPlayer(ptr, time);
00521 assert((ptr - buffer->data) == buffer->length);
00522 }
00523 else {
00524 #ifdef MSG_DEBUG
00525 printf("Got bad player update in message %d\n", messageId);
00526 #endif
00527
00528 return FALSE;
00529 }
00530 return TRUE;
00531 }
00532
00533 Bool SendSpawnRequest() {
00534 MsgDescr *msg;
00535
00536
00537 if ((msg = MessageNew()) == NULL) {
00538
00539 return FALSE;
00540 }
00541
00542 if ((msg->buffer = BufferNew()) == NULL) {
00543
00544 MessageFree(msg);
00545 return FALSE;
00546 }
00547
00548 msg->approveFunc = NULL;
00549 msg->ackFunc = NULL;
00550 msg->failFunc = MsgFailDropConnection;
00551 msg->buffer->length = 4;
00552
00553 msg->buffer->data[0] = MSG_TYPE_PLAYER_SPWAN;
00554 msg->buffer->data[3] = localPlayer;
00555 msg->bcast = TRUE;
00556
00557 msg->destMap[0] = 1;
00558
00559 return AddMessage(msg);
00560 }
00561
00562 Bool HandlePlayerSpawn(SocketAddr *origin, NetBuffer *buffer, Uint8 *clientId,
00563 Uint16 noid) {
00564 Player *p;
00565
00566 if ((networkState != NETSTATE_SERVER) || (buffer->length != 4) ||
00567 !ValidateClient(origin, buffer->data[3])) {
00568
00569 return FALSE;
00570 }
00571
00572 p = &players[*clientId = buffer->data[3]];
00573
00574 if ((p->flags & PLAYER_DEAD) && (p->deadTime > DEAD_TIME)) {
00575
00576 SpawnTank(p);
00577 }
00578 return TRUE;
00579 }