void NET_SV_Shutdown(void) { int i; boolean running; int start_time; if (!server_initialized) { return; } fprintf(stderr, "SV: Shutting down server...\n"); // Disconnect all clients for (i=0; i<MAXNETNODES; ++i) { if (clients[i].active) { NET_SV_DisconnectClient(&clients[i]); } } // Wait for all clients to finish disconnecting start_time = I_GetTimeMS(); running = true; while (running) { // Check if any clients are still not finished running = false; for (i=0; i<MAXNETNODES; ++i) { if (clients[i].active) { running = true; } } // Timed out? if (I_GetTimeMS() - start_time > 5000) { running = false; fprintf(stderr, "SV: Timed out waiting for clients to disconnect.\n"); } // Run the client code in case this is a loopback client. NET_CL_Run(); NET_SV_Run(); // Don't hog the CPU I_Sleep(1); } }
static net_packet_t *BlockForPacket(net_addr_t *addr, unsigned int packet_type, unsigned int timeout_ms) { net_packet_t *packet; net_addr_t *packet_src; unsigned int read_packet_type; unsigned int start_time; start_time = I_GetTimeMS(); while (I_GetTimeMS() < start_time + timeout_ms) { if (!NET_RecvPacket(query_context, &packet_src, &packet)) { I_Sleep(20); continue; } if (packet_src == addr && NET_ReadInt16(packet, &read_packet_type) && packet_type == read_packet_type) { return packet; } NET_FreePacket(packet); } // Timeout - no response. return NULL; }
static void NET_CL_SendResendRequest(int start, int end) { net_packet_t *packet; unsigned int nowtime; int i; //printf("CL: Send resend %i-%i\n", start, end); packet = NET_NewPacket(64); NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA_RESEND); NET_WriteInt32(packet, start); NET_WriteInt8(packet, end - start + 1); NET_Conn_SendPacket(&client_connection, packet); NET_FreePacket(packet); nowtime = I_GetTimeMS(); // Save the time we sent the resend request for (i=start; i<=end; ++i) { int index; index = i - recvwindow_start; if (index < 0 || index >= BACKUPTICS) continue; recvwindow[index].resend_time = nowtime; } }
void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic) { net_ticdiff_t diff; net_server_send_t *sendobj; int starttic, endtic; // Calculate the difference to the last ticcmd NET_TiccmdDiff(&last_ticcmd, ticcmd, &diff); // Store in the send queue sendobj = &send_queue[maketic % BACKUPTICS]; sendobj->active = true; sendobj->seq = maketic; sendobj->time = I_GetTimeMS(); sendobj->cmd = diff; last_ticcmd = *ticcmd; // Send to server. starttic = maketic - extratics; endtic = maketic; if (starttic < 0) starttic = 0; NET_CL_SendTics(starttic, endtic); }
static void UpdateMasterServer(void) { unsigned int now; now = I_GetTimeMS(); // The address of the master server can change. Periodically // re-resolve the master server to update. if (now - master_resolve_time > MASTER_RESOLVE_PERIOD * 1000) { net_addr_t *new_addr; printf("Re-resolve master server\n"); new_addr = NET_Query_ResolveMaster(server_context); // Has the master server changed address? if (new_addr != NULL && new_addr != master_server) { NET_FreeAddress(master_server); master_server = new_addr; } master_resolve_time = now; } // Possibly refresh our registration with the master server. if (now - master_refresh_time > MASTER_REFRESH_PERIOD * 1000) { NET_Query_AddToMaster(master_server); master_refresh_time = now; } }
void NET_SV_RegisterWithMaster(void) { //! // When running a server, don't register with the global master server. // Implies -server. // // @category net // if (!M_CheckParm("-privateserver")) { master_server = NET_Query_ResolveMaster(server_context); } else { master_server = NULL; } // Send request. if (master_server != NULL) { NET_Query_AddToMaster(master_server); master_refresh_time = I_GetTimeMS(); master_resolve_time = master_refresh_time; } }
static void CheckTargetTimeouts(void) { unsigned int i; unsigned int now; now = I_GetTimeMS(); for (i = 0; i < num_targets; ++i) { /* printf("target %i: state %i, queries %i, query time %i\n", i, targets[i].state, targets[i].query_attempts, now - targets[i].query_time); */ // We declare a target to be "no response" when we've sent // multiple query packets to it (QUERY_MAX_ATTEMPTS) and // received no response to any of them. if (targets[i].state == QUERY_TARGET_QUERIED && targets[i].query_attempts >= QUERY_MAX_ATTEMPTS && now - targets[i].query_time > QUERY_TIMEOUT_SECS * 1000) { targets[i].state = QUERY_TARGET_NO_RESPONSE; if (targets[i].type == QUERY_TARGET_MASTER) { fprintf(stderr, "NET_MasterQuery: no response " "from master server.\n"); } } } }
static int D_GetAdjustedTime(void) { int time_ms; time_ms = I_GetTimeMS(); time_ms += (offsetms / FRACUNIT); return (time_ms * TICRATE) / 1000; }
static void SendOneQuery(void) { unsigned int now; unsigned int i; now = I_GetTimeMS(); // Rate limit - only send one query every 50ms. if (now - last_query_time < 50) { return; } for (i = 0; i < num_targets; ++i) { // Not queried yet? // Or last query timed out without a response? if (targets[i].state == QUERY_TARGET_QUEUED || (targets[i].state == QUERY_TARGET_QUERIED && now - targets[i].query_time > QUERY_TIMEOUT_SECS * 1000)) { break; } } if (i >= num_targets) { return; } // Found a target to query. Send a query; how to do this depends on // the target type. switch (targets[i].type) { case QUERY_TARGET_SERVER: NET_Query_SendQuery(targets[i].addr); break; case QUERY_TARGET_BROADCAST: NET_Query_SendQuery(NULL); break; case QUERY_TARGET_MASTER: NET_Query_SendMasterQuery(targets[i].addr); break; } //printf("Queried %s\n", NET_AddrToString(targets[i].addr)); targets[i].state = QUERY_TARGET_QUERIED; targets[i].query_time = now; ++targets[i].query_attempts; last_query_time = now; }
void NET_SV_CheckDeadlock(net_client_t *client) { int nowtime; int i; // Don't expect game data from clients. if (client->drone) { return; } nowtime = I_GetTimeMS(); // If we haven't received anything for a long time, it may be a deadlock. if (nowtime - client->last_gamedata_time > 1000) { NET_Log("server: no gamedata from %s since %d - deadlock?", NET_AddrToString(client->addr), client->last_gamedata_time); // Search the receive window for the first tic we are expecting // from this player. for (i=0; i<BACKUPTICS; ++i) { if (!recvwindow[client->player_number][i].active) { NET_Log("server: deadlock: sending resend request for %d-%d", recvwindow_start + i, recvwindow_start + i + 5); // Found a tic we haven't received. Send a resend request. NET_SV_SendResendRequest(client, recvwindow_start + i, recvwindow_start + i + 5); client->last_gamedata_time = nowtime; break; } } // If we sent a resend request to break the deadlock, also trigger a // resend of any tics we have sitting in the send queue, in case the // client is blocked waiting on tics from us that have been lost. // This fixes deadlock with some older clients which do not send // resends to break deadlock. if (i < BACKUPTICS && client->sendseq > client->acknowledged) { NET_Log("server: also resending tics %d-%d to break deadlock", client->acknowledged, client->sendseq - 1); NET_SV_SendTics(client, client->acknowledged, client->sendseq - 1); } } }
boolean NET_Conn_Packet(net_connection_t *conn, net_packet_t *packet, unsigned int *packet_type) { conn->keepalive_recv_time = I_GetTimeMS(); // Is this a reliable packet? if (*packet_type & NET_RELIABLE_PACKET) { if (NET_Conn_ReliablePacket(conn, packet)) { // Invalid packet: eat it. return true; } // Remove the reliable bit *packet_type &= ~NET_RELIABLE_PACKET; } switch (*packet_type) { case NET_PACKET_TYPE_ACK: NET_Conn_ParseACK(conn, packet); break; case NET_PACKET_TYPE_DISCONNECT: NET_Conn_ParseDisconnect(conn, packet); break; case NET_PACKET_TYPE_DISCONNECT_ACK: NET_Conn_ParseDisconnectACK(conn, packet); break; case NET_PACKET_TYPE_KEEPALIVE: // No special action needed. break; case NET_PACKET_TYPE_REJECTED: NET_Conn_ParseReject(conn, packet); break; case NET_PACKET_TYPE_RELIABLE_ACK: NET_Conn_ParseReliableACK(conn, packet); break; default: // Not a common packet return false; } // We found a packet that we found interesting, and ate it. return true; }
void NET_CL_Disconnect(void) { int start_time; if (!net_client_connected) { return; } NET_Conn_Disconnect(&client_connection); start_time = I_GetTimeMS(); while (client_connection.state != NET_CONN_STATE_DISCONNECTED && client_connection.state != NET_CONN_STATE_DISCONNECTED_SLEEP) { if (I_GetTimeMS() - start_time > 5000) { // time out after 5 seconds client_state = NET_CONN_STATE_DISCONNECTED; fprintf(stderr, "NET_CL_Disconnect: Timeout while disconnecting from server\n"); break; } NET_CL_Run(); NET_SV_Run(); I_Sleep(1); } // Finished sending disconnect packets, etc. NET_CL_Shutdown(); }
// // haleyjd 20140904: [SVE] // Choco's sound engine won't tolerate the main loop running at full blast // and turns into chop city. We must give up a non-trivial amount of CPU // time on a consistent basis. // static boolean FE_CapFrameRate(void) { float frameMillis = 1000.0f / frontend_fpslimit; int curTics = I_GetTimeMS(); float elapsed = (float)(curTics - frontend_ticcount); if(elapsed < frameMillis) { if(frameMillis - elapsed > 3.0f) I_Sleep(2); return true; } return false; }
static int GetAdjustedTime(void) { int time_ms; time_ms = I_GetTimeMS(); if (net_cl_new_sync) { // Use the adjustments from net_client.c only if we are // using the new sync mode. time_ms += (offsetms / FRACUNIT); } return (time_ms * TICRATE) / 1000; }
static void NET_Conn_ParseDisconnect(net_connection_t *conn, net_packet_t *packet) { net_packet_t *reply; // Other end wants to disconnect // Send a DISCONNECT_ACK reply. reply = NET_NewPacket(10); NET_WriteInt16(reply, NET_PACKET_TYPE_DISCONNECT_ACK); NET_Conn_SendPacket(conn, reply); NET_FreePacket(reply); conn->last_send_time = I_GetTimeMS(); conn->state = NET_CONN_STATE_DISCONNECTED_SLEEP; conn->disconnect_reason = NET_DISCONNECT_REMOTE; }
static void NET_SV_InitNewClient(net_client_t *client, net_addr_t *addr, char *player_name) { client->active = true; client->connect_time = I_GetTimeMS(); NET_Conn_InitServer(&client->connection, addr); client->addr = addr; client->last_send_time = -1; client->name = strdup(player_name); // init the ticcmd send queue client->sendseq = 0; client->acknowledged = 0; client->drone = false; client->last_gamedata_time = 0; memset(client->sendqueue, 0xff, sizeof(client->sendqueue)); }
static void NET_SV_SendResendRequest(net_client_t *client, int start, int end) { net_packet_t *packet; net_client_recv_t *recvobj; int i; unsigned int nowtime; int index; NET_Log("server: send resend to %s for tics %d-%d", NET_AddrToString(client->addr), start, end); packet = NET_NewPacket(20); NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA_RESEND); NET_WriteInt32(packet, start); NET_WriteInt8(packet, end - start + 1); NET_Conn_SendPacket(&client->connection, packet); NET_FreePacket(packet); // Store the time we send the resend request nowtime = I_GetTimeMS(); for (i=start; i<=end; ++i) { index = i - recvwindow_start; if (index >= BACKUPTICS) { // Outside the range continue; } recvobj = &recvwindow[index][client->player_number]; recvobj->resend_time = nowtime; } }
void NET_SV_CheckDeadlock(net_client_t *client) { int nowtime; int i; // Don't expect game data from clients. if (client->drone) { return; } nowtime = I_GetTimeMS(); // If we haven't received anything for a long time, it may be a deadlock. if (nowtime - client->last_gamedata_time > 1000) { // Search the receive window for the first tic we are expecting // from this player. for (i=0; i<BACKUPTICS; ++i) { if (!recvwindow[client->player_number][i].active) { //printf("Possible deadlock: Sending resend request\n"); // Found a tic we haven't received. Send a resend request. NET_SV_SendResendRequest(client, recvwindow_start + i, recvwindow_start + i + 5); client->last_gamedata_time = nowtime; break; } } } }
static void NET_SV_InitNewClient(net_client_t *client, net_addr_t *addr, net_protocol_t protocol) { client->active = true; client->connect_time = I_GetTimeMS(); NET_Conn_InitServer(&client->connection, addr, protocol); client->addr = addr; NET_ReferenceAddress(addr); client->last_send_time = -1; // init the ticcmd send queue client->sendseq = 0; client->acknowledged = 0; client->drone = false; client->ready = false; client->last_gamedata_time = 0; memset(client->sendqueue, 0xff, sizeof(client->sendqueue)); NET_Log("server: initialized new client from %s", NET_AddrToString(addr)); }
static void NET_CL_ParseGameData(net_packet_t *packet) { net_server_recv_t *recvobj; unsigned int seq, num_tics; unsigned int nowtime; int resend_start, resend_end; size_t i; int index; // Read header if (!NET_ReadInt8(packet, &seq) || !NET_ReadInt8(packet, &num_tics)) { return; } nowtime = I_GetTimeMS(); // Whatever happens, we now need to send an acknowledgement of our // current receive point. if (!need_to_acknowledge) { need_to_acknowledge = true; gamedata_recv_time = nowtime; } // Expand byte value into the full tic number seq = NET_CL_ExpandTicNum(seq); for (i=0; i<num_tics; ++i) { net_full_ticcmd_t cmd; index = seq - recvwindow_start + i; if (!NET_ReadFullTiccmd(packet, &cmd, lowres_turn)) { return; } if (index < 0 || index >= BACKUPTICS) { // Out of range of the recv window continue; } // Store in the receive window recvobj = &recvwindow[index]; recvobj->active = true; recvobj->cmd = cmd; } // Has this been received out of sequence, ie. have we not received // all tics before the first tic in this packet? If so, send a // resend request. //printf("CL: %p: %i\n", client, seq); resend_end = seq - recvwindow_start; if (resend_end <= 0) return; if (resend_end >= BACKUPTICS) resend_end = BACKUPTICS - 1; index = resend_end - 1; resend_start = resend_end; while (index >= 0) { recvobj = &recvwindow[index]; if (recvobj->active) { // ended our run of unreceived tics break; } if (recvobj->resend_time != 0) { // Already sent a resend request for this tic break; } resend_start = index; --index; } // Possibly send a resend request if (resend_start < resend_end) { NET_CL_SendResendRequest(recvwindow_start + resend_start, recvwindow_start + resend_end - 1); } }
static void NET_Query_ParseResponse(net_addr_t *addr, net_packet_t *packet, net_query_callback_t callback, void *user_data) { unsigned int packet_type; net_querydata_t querydata; query_target_t *target; // Read the header if (!NET_ReadInt16(packet, &packet_type) || packet_type != NET_PACKET_TYPE_QUERY_RESPONSE) { return; } // Read query data if (!NET_ReadQueryData(packet, &querydata)) { return; } // Find the target that responded. target = GetTargetForAddr(addr, false); // If the target is not found, it may be because we are doing // a LAN broadcast search, in which case we need to create a // target for the new responder. if (target == NULL) { query_target_t *broadcast_target; broadcast_target = GetTargetForAddr(NULL, false); // Not in broadcast mode, unexpected response that came out // of nowhere. Ignore. if (broadcast_target == NULL || broadcast_target->state != QUERY_TARGET_QUERIED) { return; } // Create new target. target = GetTargetForAddr(addr, true); target->state = QUERY_TARGET_QUERIED; target->query_time = broadcast_target->query_time; } if (target->state != QUERY_TARGET_RESPONDED) { target->state = QUERY_TARGET_RESPONDED; memcpy(&target->data, &querydata, sizeof(net_querydata_t)); // Calculate RTT. target->ping_time = I_GetTimeMS() - target->query_time; // Invoke callback to signal that we have a new address. callback(addr, &target->data, target->ping_time, user_data); } }
static void NET_SV_ParseGameData(net_packet_t *packet, net_client_t *client) { net_client_recv_t *recvobj; unsigned int seq; unsigned int ackseq; unsigned int num_tics; unsigned int nowtime; size_t i; int player; int resend_start, resend_end; int index; if (server_state != SERVER_IN_GAME) { return; } if (client->drone) { // Drones do not contribute any game data. return; } player = client->player_number; // Read header if (!NET_ReadInt8(packet, &ackseq) || !NET_ReadInt8(packet, &seq) || !NET_ReadInt8(packet, &num_tics)) { return; } // Get the current time nowtime = I_GetTimeMS(); // Expand 8-bit values to the full sequence number ackseq = NET_SV_ExpandTicNum(ackseq); seq = NET_SV_ExpandTicNum(seq); // Sanity checks for (i=0; i<num_tics; ++i) { net_ticdiff_t diff; signed int latency; if (!NET_ReadSInt16(packet, &latency) || !NET_ReadTiccmdDiff(packet, &diff, sv_settings.lowres_turn)) { return; } index = seq + i - recvwindow_start; if (index < 0 || index >= BACKUPTICS) { // Not in range of the recv window continue; } recvobj = &recvwindow[index][player]; recvobj->active = true; recvobj->diff = diff; recvobj->latency = latency; client->last_gamedata_time = nowtime; } // Higher acknowledgement point? if (ackseq > client->acknowledged) { client->acknowledged = ackseq; } // Has this been received out of sequence, ie. have we not received // all tics before the first tic in this packet? If so, send a // resend request. //printf("SV: %p: %i\n", client, seq); resend_end = seq - recvwindow_start; if (resend_end <= 0) return; if (resend_end >= BACKUPTICS) resend_end = BACKUPTICS - 1; index = resend_end - 1; resend_start = resend_end; while (index >= 0) { recvobj = &recvwindow[index][player]; if (recvobj->active) { // ended our run of unreceived tics break; } if (recvobj->resend_time != 0) { // Already sent a resend request for this tic break; } resend_start = index; --index; } // Possibly send a resend request if (resend_start < resend_end) { /* printf("missed %i-%i before %i, send resend\n", recvwindow_start + resend_start, recvwindow_start + resend_end - 1, seq); */ NET_SV_SendResendRequest(client, recvwindow_start + resend_start, recvwindow_start + resend_end - 1); } }
static void NET_SV_CheckResends(net_client_t *client) { int i; int player; int resend_start, resend_end; unsigned int nowtime; nowtime = I_GetTimeMS(); player = client->player_number; resend_start = -1; resend_end = -1; for (i=0; i<BACKUPTICS; ++i) { net_client_recv_t *recvobj; boolean need_resend; recvobj = &recvwindow[i][player]; // if need_resend is true, this tic needs another retransmit // request (300ms timeout) need_resend = !recvobj->active && recvobj->resend_time != 0 && nowtime > recvobj->resend_time + 300; if (need_resend) { // Start a new run of resend tics? if (resend_start < 0) { resend_start = i; } resend_end = i; } else { if (resend_start >= 0) { // End of a run of resend tics //printf("SV: resend request timed out: %i-%i\n", resend_start, resend_end); NET_SV_SendResendRequest(client, recvwindow_start + resend_start, recvwindow_start + resend_end); resend_start = -1; } } } if (resend_start >= 0) { NET_SV_SendResendRequest(client, recvwindow_start + resend_start, recvwindow_start + resend_end); } }
static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client) { net_gamesettings_t settings; net_packet_t *startpacket; int nowtime; int i; if (client != NET_SV_Controller()) { // Only the controller can start a new game return; } if (!NET_ReadSettings(packet, &settings)) { // Malformed packet return; } // Check the game settings are valid if (!NET_ValidGameSettings(sv_gamemode, sv_gamemission, &settings)) { return; } if (server_state != SERVER_WAITING_START) { // Can only start a game if we are in the waiting start state. return; } // Assign player numbers NET_SV_AssignPlayers(); // Check if anyone is recording a demo and set lowres_turn if so. settings.lowres_turn = false; for (i=0; i<MAXPLAYERS; ++i) { if (sv_players[i] != NULL && sv_players[i]->recording_lowres) { settings.lowres_turn = true; } } nowtime = I_GetTimeMS(); // Send start packets to each connected node for (i=0; i<MAXNETNODES; ++i) { if (!ClientConnected(&clients[i])) continue; clients[i].last_gamedata_time = nowtime; startpacket = NET_Conn_NewReliable(&clients[i].connection, NET_PACKET_TYPE_GAMESTART); NET_WriteInt8(startpacket, NET_SV_NumPlayers()); NET_WriteInt8(startpacket, clients[i].player_number); NET_WriteSettings(startpacket, &settings); } // Change server state server_state = SERVER_IN_GAME; sv_settings = settings; memset(recvwindow, 0, sizeof(recvwindow)); recvwindow_start = 0; }
static void HU_DrawHUD(void) { const int health = MAX(0, plr->health); const weapontype_t pendingweapon = plr->pendingweapon; const weapontype_t readyweapon = plr->readyweapon; int ammotype = weaponinfo[readyweapon].ammo; int ammo = plr->ammo[ammotype]; const int armor = plr->armorpoints; int health_x = HUD_HEALTH_X; int keys = 0; int i = 0; byte *tinttab; const int invulnerability = plr->powers[pw_invulnerability]; static dboolean healthanim; patch_t *patch; const dboolean gamepaused = (menuactive || paused || consoleactive); const int currenttime = I_GetTimeMS(); tinttab = (!health || (health <= HUD_HEALTH_MIN && healthanim) || health > HUD_HEALTH_MIN ? tinttab66 : tinttab25); patch = (((readyweapon == wp_fist && pendingweapon == wp_nochange) || pendingweapon == wp_fist) && plr->powers[pw_strength] ? berserkpatch : healthpatch); if (patch) { if ((plr->cheats & CF_GODMODE) || invulnerability > STARTFLASHING || (invulnerability & 8)) godhudfunc(health_x, HUD_HEALTH_Y - (SHORT(patch->height) - 17), patch, tinttab); else hudfunc(health_x, HUD_HEALTH_Y - (SHORT(patch->height) - 17), patch, tinttab); health_x += SHORT(patch->width) + 8; } if (healthhighlight > currenttime) { DrawHUDNumber(&health_x, HUD_HEALTH_Y + hudnumoffset, MAX((minuspatch ? health_min : 0), plr->health), tinttab, V_DrawHighlightedHUDNumberPatch); if (!emptytallpercent) V_DrawHighlightedHUDNumberPatch(health_x, HUD_HEALTH_Y + hudnumoffset, tallpercent, tinttab); } else { DrawHUDNumber(&health_x, HUD_HEALTH_Y + hudnumoffset, MAX((minuspatch ? health_min : 0), plr->health), tinttab, hudnumfunc); if (!emptytallpercent) hudnumfunc(health_x, HUD_HEALTH_Y + hudnumoffset, tallpercent, tinttab); } if (!gamepaused) { static int healthwait; if (health <= HUD_HEALTH_MIN) { if (healthwait < currenttime) { healthanim = !healthanim; healthwait = currenttime + HUD_HEALTH_WAIT * health / HUD_HEALTH_MIN + 115; } } else { healthanim = false; healthwait = 0; } } if (pendingweapon != wp_nochange) { ammotype = weaponinfo[pendingweapon].ammo; ammo = plr->ammo[ammotype]; } if (health && ammo && ammotype != am_noammo) { int ammo_x = HUD_AMMO_X + ammopic[ammotype].x; static dboolean ammoanim; tinttab = ((ammo <= HUD_AMMO_MIN && ammoanim) || ammo > HUD_AMMO_MIN ? tinttab66 : tinttab25); if ((patch = ammopic[ammotype].patch)) { hudfunc(ammo_x, HUD_AMMO_Y + ammopic[ammotype].y, patch, tinttab); ammo_x += SHORT(patch->width) + 8; } if (ammohighlight > currenttime) DrawHUDNumber(&ammo_x, HUD_AMMO_Y + hudnumoffset, ammo, tinttab, V_DrawHighlightedHUDNumberPatch); else DrawHUDNumber(&ammo_x, HUD_AMMO_Y + hudnumoffset, ammo, tinttab, hudnumfunc); if (!gamepaused) { static int ammowait; if (ammo <= HUD_AMMO_MIN) { if (ammowait < currenttime) { ammoanim = !ammoanim; ammowait = currenttime + HUD_AMMO_WAIT * ammo / HUD_AMMO_MIN + 115; } } else { ammoanim = false; ammowait = 0; } } } while (i < NUMCARDS) if (plr->cards[i++] > 0) keys++; if (keys || plr->neededcardflash) { int keypic_x = HUD_KEYS_X - 20 * (keys - 1); static int keywait; static dboolean showkey; if (!armor) keypic_x += 114; else { if (emptytallpercent) keypic_x += tallpercentwidth; if (armor < 10) keypic_x += 26; else if (armor < 100) keypic_x += 12; } if (plr->neededcardflash) { if ((patch = keypic[plr->neededcard].patch)) { if (!gamepaused && keywait < currenttime) { showkey = !showkey; keywait = currenttime + HUD_KEY_WAIT; plr->neededcardflash--; } if (showkey) hudfunc(keypic_x - SHORT(patch->width) - 6, HUD_KEYS_Y, patch, tinttab66); } } else { showkey = false; keywait = 0; } for (i = 0; i < NUMCARDS; i++) if (plr->cards[i] > 0 && (patch = keypic[i].patch)) hudfunc(keypic_x + (SHORT(patch->width) + 6) * (cardsfound - plr->cards[i]), HUD_KEYS_Y, patch, tinttab66); } if (armor) { int armor_x = HUD_ARMOR_X; if ((patch = (plr->armortype == GREENARMOR ? greenarmorpatch : bluearmorpatch))) { armor_x -= SHORT(patch->width); hudfunc(armor_x, HUD_ARMOR_Y - (SHORT(patch->height) - 16), patch, tinttab66); armor_x -= 7; } if (armorhighlight > currenttime) { if (emptytallpercent) { armor_x -= HUDNumberWidth(armor); DrawHUDNumber(&armor_x, HUD_ARMOR_Y + hudnumoffset, armor, tinttab66, V_DrawHighlightedHUDNumberPatch); } else { armor_x -= tallpercentwidth; V_DrawHighlightedHUDNumberPatch(armor_x, HUD_ARMOR_Y + hudnumoffset, tallpercent, tinttab66); armor_x -= HUDNumberWidth(armor); DrawHUDNumber(&armor_x, HUD_ARMOR_Y + hudnumoffset, armor, tinttab66, V_DrawHighlightedHUDNumberPatch); } } else if (emptytallpercent) { armor_x -= HUDNumberWidth(armor); DrawHUDNumber(&armor_x, HUD_ARMOR_Y + hudnumoffset, armor, tinttab66, hudnumfunc); } else { armor_x -= tallpercentwidth; hudnumfunc(armor_x, HUD_ARMOR_Y + hudnumoffset, tallpercent, tinttab66); armor_x -= HUDNumberWidth(armor); DrawHUDNumber(&armor_x, HUD_ARMOR_Y + hudnumoffset, armor, tinttab66, hudnumfunc); } } }
static void HU_DrawAltHUD(void) { int health = MAX(health_min, plr->health); int armor = plr->armorpoints; int color2 = (health <= 20 ? red : (health >= 100 ? green : white)); int color1 = color2 + (color2 == green ? coloroffset : 0); int keys = 0; int i = 0; int powerup = 0; int powerupbar = 0; int max; DrawAltHUDNumber(ALTHUD_LEFT_X + 35 - AltHUDNumberWidth(ABS(health)), ALTHUD_Y + 12, health); health = MAX(0, plr->health) * 200 / maxhealth; if (health > 100) { fillrectfunc(0, ALTHUD_LEFT_X + 60, ALTHUD_Y + 13, 101, 8, color1); fillrectfunc(0, ALTHUD_LEFT_X + 60, ALTHUD_Y + 13, MAX(1, health - 100) + (health == 200), 8, color2); althudfunc(ALTHUD_LEFT_X + 40, ALTHUD_Y + 1, altleftpatch, WHITE, white); althudfunc(ALTHUD_LEFT_X + 60, ALTHUD_Y + 13, altendpatch, WHITE, color2); althudfunc(ALTHUD_LEFT_X + 60 + 98, ALTHUD_Y + 13, altmarkpatch, WHITE, color1); althudfunc(ALTHUD_LEFT_X + 60 + health - 100 - (health < 200) - 2, ALTHUD_Y + 10, altmark2patch, WHITE, color2); } else { fillrectfunc(0, ALTHUD_LEFT_X + 60, ALTHUD_Y + 13, MAX(1, health) + (health == 100), 8, color1); althudfunc(ALTHUD_LEFT_X + 40, ALTHUD_Y + 1, altleftpatch, WHITE, white); althudfunc(ALTHUD_LEFT_X + 60, ALTHUD_Y + 13, altendpatch, WHITE, color1); althudfunc(ALTHUD_LEFT_X + 60 + MAX(1, health) - (health < 100) - 2, ALTHUD_Y + 13, altmarkpatch, WHITE, color1); } if (armor) { color2 = (plr->armortype == GREENARMOR ? gray : lightgray); color1 = color2 + coloroffset; althudfunc(ALTHUD_LEFT_X + 43, ALTHUD_Y, altarmpatch, WHITE, color2); DrawAltHUDNumber2(ALTHUD_LEFT_X + 35 - AltHUDNumber2Width(armor), ALTHUD_Y, armor, color2); armor = armor * 200 / max_armor; if (armor > 100) { fillrectfunc(0, ALTHUD_LEFT_X + 60, ALTHUD_Y + 2, 100 + 1, 4, color1); fillrectfunc(0, ALTHUD_LEFT_X + 60, ALTHUD_Y + 2, armor - 100 + (armor == 200), 4, color2); } else fillrectfunc(0, ALTHUD_LEFT_X + 60, ALTHUD_Y + 2, armor + (armor == 100), 4, color1); } else althudfunc(ALTHUD_LEFT_X + 43, ALTHUD_Y, altarmpatch, WHITE, darkgray); if (health) { const weapontype_t pendingweapon = plr->pendingweapon; const weapontype_t weapon = (pendingweapon != wp_nochange ? pendingweapon : plr->readyweapon); const ammotype_t ammotype = weaponinfo[weapon].ammo; if (ammotype != am_noammo) { int ammo = plr->ammo[ammotype]; DrawAltHUDNumber(ALTHUD_RIGHT_X + 101 - AltHUDNumberWidth(ammo), ALTHUD_Y - 1, ammo); ammo = 100 * ammo / plr->maxammo[ammotype]; color1 = (ammo <= 15 ? yellow : white); fillrectfunc(0, ALTHUD_RIGHT_X + 100 - ammo, ALTHUD_Y + 13, ammo + 1, 8, color1); althudfunc(ALTHUD_RIGHT_X, ALTHUD_Y + 13, altrightpatch, WHITE, white); althudfunc(ALTHUD_RIGHT_X + 100, ALTHUD_Y + 13, altendpatch, WHITE, color1); althudfunc(ALTHUD_RIGHT_X + 100 - ammo - 2, ALTHUD_Y + 13, altmarkpatch, WHITE, color1); } if (weapon != wp_fist) althudfunc(ALTHUD_RIGHT_X + 107, ALTHUD_Y - 15, altweapon[weapon], WHITE, white); } while (i < NUMCARDS) if (plr->cards[i++] > 0) keys++; if (keys || plr->neededcardflash) { static int keywait; static dboolean showkey; if (plr->neededcardflash) { if (!(menuactive || paused || consoleactive)) { int currenttime = I_GetTimeMS(); if (keywait < currenttime) { showkey = !showkey; keywait = currenttime + HUD_KEY_WAIT; plr->neededcardflash--; } } if (showkey) { altkeypic_t altkeypic = altkeypics[plr->neededcard]; althudfunc(ALTHUD_RIGHT_X + 11 * cardsfound, ALTHUD_Y, altkeypic.patch, WHITE, altkeypic.color); } } else { showkey = false; keywait = 0; } for (i = 0; i < NUMCARDS; i++) { int card = plr->cards[i]; if (card > 0) { altkeypic_t altkeypic = altkeypics[i]; althudfunc(ALTHUD_RIGHT_X + 11 * (card - 1), ALTHUD_Y, altkeypic.patch, WHITE, altkeypic.color); } } } if ((powerup = plr->powers[pw_invulnerability])) { max = INVULNTICS; powerupbar = (powerup == -1 ? max : powerup); } if ((powerup = plr->powers[pw_invisibility]) && (!powerupbar || (powerup >= 0 && powerup < powerupbar))) { max = INVISTICS; powerupbar = (powerup == -1 ? max : powerup); } if ((powerup = plr->powers[pw_ironfeet]) && (!powerupbar || (powerup >= 0 && powerup < powerupbar))) { max = IRONTICS; powerupbar = (powerup == -1 ? max : powerup); } if ((powerup = plr->powers[pw_infrared]) && (!powerupbar || (powerup >= 0 && powerup < powerupbar))) { max = INFRATICS; powerupbar = (powerup == -1 ? max : powerup); } if ((powerup = plr->powers[pw_strength]) && plr->readyweapon == wp_fist && !powerupbar) { max = STARTFLASHING + 1; powerupbar = STARTFLASHING + 1; } if (powerupbar > STARTFLASHING || (powerupbar & 8)) { fillrectfunc(0, ALTHUD_RIGHT_X, ALTHUD_Y + 26, 101, 2, darkgray); fillrectfunc(0, ALTHUD_RIGHT_X, ALTHUD_Y + 26, powerupbar * 101 / max, 2, gray); } }
boolean NET_CL_Connect(net_addr_t *addr) { int start_time; int last_send_time; server_addr = addr; // Are we recording a demo? Possibly set lowres turn mode if (M_CheckParm("-record") > 0 && M_CheckParm("-longtics") == 0) { lowres_turn = true; } // Read checksums of our WAD directory and dehacked information W_Checksum(net_local_wad_md5sum); DEH_Checksum(net_local_deh_md5sum); // Are we playing with the Freedoom IWAD? net_local_is_freedoom = W_CheckNumForName("FREEDOOM") >= 0; // create a new network I/O context and add just the // necessary module client_context = NET_NewContext(); // initialize module for client mode if (!addr->module->InitClient()) { return false; } NET_AddModule(client_context, addr->module); net_client_connected = true; net_client_received_wait_data = false; // Initialize connection NET_Conn_InitClient(&client_connection, addr); // try to connect start_time = I_GetTimeMS(); last_send_time = -1; while (client_connection.state == NET_CONN_STATE_CONNECTING) { int nowtime = I_GetTimeMS(); // Send a SYN packet every second. if (nowtime - last_send_time > 1000 || last_send_time < 0) { NET_CL_SendSYN(); last_send_time = nowtime; } // time out after 5 seconds if (nowtime - start_time > 5000) { break; } // run client code NET_CL_Run(); // run the server, just incase we are doing a loopback // connect NET_SV_Run(); // Don't hog the CPU I_Sleep(1); } if (client_connection.state == NET_CONN_STATE_CONNECTED) { // connected ok! client_state = CLIENT_STATE_WAITING_START; return true; } else { // failed to connect NET_CL_Shutdown(); return false; } }
static void NET_SV_RunClient(net_client_t *client) { // Run common code NET_Conn_Run(&client->connection); if (client->connection.state == NET_CONN_STATE_DISCONNECTED && client->connection.disconnect_reason == NET_DISCONNECT_TIMEOUT) { NET_SV_BroadcastMessage("Client '%s' timed out and disconnected", client->name); } // Is this client disconnected? if (client->connection.state == NET_CONN_STATE_DISCONNECTED) { // deactivate and free back client->active = false; free(client->name); NET_FreeAddress(client->addr); // Are there any clients left connected? If not, return the // server to the waiting-for-players state. // // Disconnect any drones still connected. if (NET_SV_NumPlayers() <= 0) { NET_SV_GameEnded(); } } if (!ClientConnected(client)) { // client has not yet finished connecting return; } if (server_state == SERVER_WAITING_START) { // Waiting for the game to start // Send information once every second if (client->last_send_time < 0 || I_GetTimeMS() - client->last_send_time > 1000) { NET_SV_SendWaitingData(client); client->last_send_time = I_GetTimeMS(); } } if (server_state == SERVER_IN_GAME) { NET_SV_PumpSendQueue(client); NET_SV_CheckDeadlock(client); } }
static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd, unsigned int seq) { int latency; fixed_t adjustment; int i; // Update average_latency if (seq == send_queue[seq % BACKUPTICS].seq) { latency = I_GetTimeMS() - send_queue[seq % BACKUPTICS].time; } else if (seq > send_queue[seq % BACKUPTICS].seq) { // We have received the ticcmd from the server before we have // even sent ours latency = 0; } else { latency = -1; } if (latency >= 0) { if (seq <= 20) { average_latency = latency * FRACUNIT; } else { // Low level filter average_latency = (fixed_t)((average_latency * 0.9) + (latency * FRACUNIT * 0.1)); } } //printf("latency: %i\tremote:%i\n", average_latency / FRACUNIT, // cmd->latency); // Possibly adjust offsetms in d_net.c, try to make players all have // the same lag. Don't adjust in the first few tics of play, as // we don't have an accurate value for average_latency yet. if (seq > TICRATE) { adjustment = (cmd->latency * FRACUNIT) - average_latency; // Only adjust very slightly; the cumulative effect over // multiple tics will sort it out. adjustment = adjustment / 100; offsetms += adjustment; } // Expand tic diffs for all players for (i=0; i<MAXPLAYERS; ++i) { if (i == consoleplayer && !drone) { continue; } if (playeringame[i] && !cmd->playeringame[i]) { NET_CL_PlayerQuitGame(&players[i]); } playeringame[i] = cmd->playeringame[i]; if (playeringame[i]) { net_ticdiff_t *diff; ticcmd_t ticcmd; diff = &cmd->cmds[i]; // Use the ticcmd diff to patch the previous ticcmd to // the new ticcmd NET_TiccmdPatch(&recvwindow_cmd_base[i], diff, &ticcmd); // Save in d_net.c structures netcmds[i][nettics[i] % BACKUPTICS] = ticcmd; ++nettics[i]; // Store a copy for next time recvwindow_cmd_base[i] = ticcmd; } } }
static void NET_CL_CheckResends(void) { int i; int resend_start, resend_end; unsigned int nowtime; nowtime = I_GetTimeMS(); resend_start = -1; resend_end = -1; for (i=0; i<BACKUPTICS; ++i) { net_server_recv_t *recvobj; boolean need_resend; recvobj = &recvwindow[i]; // if need_resend is true, this tic needs another retransmit // request (300ms timeout) need_resend = !recvobj->active && recvobj->resend_time != 0 && nowtime > recvobj->resend_time + 300; if (need_resend) { // Start a new run of resend tics? if (resend_start < 0) { resend_start = i; } resend_end = i; } else { if (resend_start >= 0) { // End of a run of resend tics //printf("CL: resend request timed out: %i-%i\n", resend_start, resend_end); NET_CL_SendResendRequest(recvwindow_start + resend_start, recvwindow_start + resend_end); resend_start = -1; } } } if (resend_start >= 0) { //printf("CL: resend request timed out: %i-%i\n", resend_start, resend_end); NET_CL_SendResendRequest(recvwindow_start + resend_start, recvwindow_start + resend_end); } // We have received some data from the server and not acknowledged // it yet. Normally this gets acknowledged when we send our game // data, but if the client is a drone we need to do this. if (need_to_acknowledge && nowtime - gamedata_recv_time > 200) { NET_CL_SendGameDataACK(); } }