From 4f18f6d3cf2bf06d23aad8cc1d78b5046a4def51 Mon Sep 17 00:00:00 2001 From: lachablock Date: Thu, 18 Mar 2021 14:48:15 +1100 Subject: [PATCH 01/96] Remove PF_SPINNING upon use of any jump ability, so that directionchar works properly --- src/p_user.c | 351 ++++++++++++++++++++++++++------------------------- 1 file changed, 177 insertions(+), 174 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 02592053d..261272313 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -5012,7 +5012,7 @@ void P_Telekinesis(player_t *player, fixed_t thrust, fixed_t range) static void P_DoTwinSpin(player_t *player) { - player->pflags &= ~PF_NOJUMPDAMAGE; + player->pflags &= ~(PF_NOJUMPDAMAGE|PF_SPINNING); player->pflags |= P_GetJumpFlags(player) | PF_THOKKED; S_StartSound(player->mo, sfx_s3k42); player->mo->frame = 0; @@ -5286,194 +5286,197 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) else if (player->pflags & PF_JUMPED) { if (!LUAh_AbilitySpecial(player)) - switch (player->charability) { - case CA_THOK: - case CA_HOMINGTHOK: - case CA_JUMPTHOK: // Credit goes to CZ64 and Sryder13 for the original - // Now it's Sonic's abilities turn! - // THOK! - if (!(player->pflags & PF_THOKKED) || (player->charflags & SF_MULTIABILITY)) - { - // Catapult the player - fixed_t actionspd = player->actionspd; - - if (player->charflags & SF_DASHMODE) - actionspd = max(player->normalspeed, FixedDiv(player->speed, player->mo->scale)); - - if (player->mo->eflags & MFE_UNDERWATER) - actionspd >>= 1; - - if ((player->charability == CA_JUMPTHOK) && !(player->pflags & PF_THOKKED)) + switch (player->charability) + { + case CA_THOK: + case CA_HOMINGTHOK: + case CA_JUMPTHOK: // Credit goes to CZ64 and Sryder13 for the original + // Now it's Sonic's abilities turn! + // THOK! + if (!(player->pflags & PF_THOKKED) || (player->charflags & SF_MULTIABILITY)) { - player->pflags &= ~PF_JUMPED; - P_DoJump(player, false); - } + // Catapult the player + fixed_t actionspd = player->actionspd; - P_InstaThrust(player->mo, player->mo->angle, FixedMul(actionspd, player->mo->scale)); + if (player->charflags & SF_DASHMODE) + actionspd = max(player->normalspeed, FixedDiv(player->speed, player->mo->scale)); - if (maptol & TOL_2D) - { - player->mo->momx /= 2; - player->mo->momy /= 2; - } - if (player->charability == CA_HOMINGTHOK) - { - player->mo->momx /= 2; - player->mo->momy /= 2; - } + if (player->mo->eflags & MFE_UNDERWATER) + actionspd >>= 1; - if (player->charability == CA_HOMINGTHOK) - { - P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockonthok)); - if (lockonthok) + if ((player->charability == CA_JUMPTHOK) && !(player->pflags & PF_THOKKED)) { - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockonthok->x, lockonthok->y); - player->homing = 3*TICRATE; - } - else - { - P_SetPlayerMobjState(player->mo, S_PLAY_FALL); player->pflags &= ~PF_JUMPED; - player->mo->height = P_GetPlayerHeight(player); + P_DoJump(player, false); } - player->pflags &= ~PF_NOJUMPDAMAGE; - } - player->drawangle = player->mo->angle; + P_InstaThrust(player->mo, player->mo->angle, FixedMul(actionspd, player->mo->scale)); - if (player->mo->info->attacksound && !player->spectator) - S_StartSound(player->mo, player->mo->info->attacksound); // Play the THOK sound - - P_SpawnThokMobj(player); - - player->pflags &= ~(PF_SPINNING|PF_STARTDASH); - player->pflags |= PF_THOKKED; - - // Change localangle to match for simple controls? (P.S. chalupa) - // disabled because it seemed to disorient people and Z-targeting exists now - /*if (!demoplayback) - { - if (player == &players[consoleplayer] && cv_cam_turnfacingability[0].value > 0 && !(PLAYER1INPUTDOWN(gc_turnleft) || PLAYER1INPUTDOWN(gc_turnright))) - P_SetPlayerAngle(player, player->mo->angle);; - else if (player == &players[secondarydisplayplayer] && cv_cam_turnfacingability[1].value > 0 && !(PLAYER2INPUTDOWN(gc_turnleft) || PLAYER2INPUTDOWN(gc_turnright))) - P_SetPlayerAngle(player, player->mo->angle); - }*/ - } - break; - - case CA_FLY: - case CA_SWIM: - // If currently in the air from a jump, and you pressed the - // button again and have the ability to fly, do so! - if (player->charability == CA_SWIM && !(player->mo->eflags & MFE_UNDERWATER)) - ; // Can't do anything if you're a fish out of water! - else if (!(player->pflags & PF_THOKKED) && !(player->powers[pw_tailsfly])) - { - P_SetPlayerMobjState(player->mo, S_PLAY_FLY); // Change to the flying animation - - player->powers[pw_tailsfly] = tailsflytics + 1; // Set the fly timer - - player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_STARTDASH); - if (player->bot == 1) - player->pflags |= PF_THOKKED; - else - player->pflags |= (PF_THOKKED|PF_CANCARRY); - } - break; - case CA_GLIDEANDCLIMB: - // Now Knuckles-type abilities are checked. - if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) - { - fixed_t glidespeed = FixedMul(player->actionspd, player->mo->scale); - fixed_t playerspeed = player->speed; - - if (player->mo->eflags & MFE_UNDERWATER) - { - glidespeed >>= 1; - playerspeed = 2*playerspeed/3; - if (!(player->powers[pw_super] || player->powers[pw_sneakers])) + if (maptol & TOL_2D) { - player->mo->momx = (2*(player->mo->momx - player->cmomx)/3) + player->cmomx; - player->mo->momy = (2*(player->mo->momy - player->cmomy)/3) + player->cmomy; + player->mo->momx /= 2; + player->mo->momy /= 2; } + if (player->charability == CA_HOMINGTHOK) + { + player->mo->momx /= 2; + player->mo->momy /= 2; + } + + if (player->charability == CA_HOMINGTHOK) + { + P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockonthok)); + if (lockonthok) + { + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockonthok->x, lockonthok->y); + player->homing = 3*TICRATE; + } + else + { + P_SetPlayerMobjState(player->mo, S_PLAY_FALL); + player->pflags &= ~PF_JUMPED; + player->mo->height = P_GetPlayerHeight(player); + } + player->pflags &= ~PF_NOJUMPDAMAGE; + } + + player->drawangle = player->mo->angle; + + if (player->mo->info->attacksound && !player->spectator) + S_StartSound(player->mo, player->mo->info->attacksound); // Play the THOK sound + + P_SpawnThokMobj(player); + + player->pflags &= ~(PF_STARTDASH); + player->pflags |= PF_THOKKED; + + // Change localangle to match for simple controls? (P.S. chalupa) + // disabled because it seemed to disorient people and Z-targeting exists now + /*if (!demoplayback) + { + if (player == &players[consoleplayer] && cv_cam_turnfacingability[0].value > 0 && !(PLAYER1INPUTDOWN(gc_turnleft) || PLAYER1INPUTDOWN(gc_turnright))) + P_SetPlayerAngle(player, player->mo->angle);; + else if (player == &players[secondarydisplayplayer] && cv_cam_turnfacingability[1].value > 0 && !(PLAYER2INPUTDOWN(gc_turnleft) || PLAYER2INPUTDOWN(gc_turnright))) + P_SetPlayerAngle(player, player->mo->angle); + }*/ } + break; - player->pflags |= PF_GLIDING|PF_THOKKED; - player->glidetime = 0; + case CA_FLY: + case CA_SWIM: + // If currently in the air from a jump, and you pressed the + // button again and have the ability to fly, do so! + if (player->charability == CA_SWIM && !(player->mo->eflags & MFE_UNDERWATER)) + ; // Can't do anything if you're a fish out of water! + else if (!(player->pflags & PF_THOKKED) && !(player->powers[pw_tailsfly])) + { + P_SetPlayerMobjState(player->mo, S_PLAY_FLY); // Change to the flying animation - P_SetPlayerMobjState(player->mo, S_PLAY_GLIDE); - if (playerspeed < glidespeed) - P_Thrust(player->mo, player->mo->angle, glidespeed - playerspeed); - player->pflags &= ~(PF_SPINNING|PF_STARTDASH); - } - break; - case CA_DOUBLEJUMP: // Double-Jump - if (!(player->pflags & PF_THOKKED) || ((player->charflags & SF_MULTIABILITY) && (player->secondjump < (player->actionspd >> FRACBITS)))) - { - player->pflags |= PF_THOKKED; - player->pflags &= ~PF_JUMPED; - P_DoJump(player, true); - player->secondjump++; - } - break; - case CA_FLOAT: // Float - case CA_SLOWFALL: // Slow descent hover - if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) - { - if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD) - P_SetPlayerMobjState(player->mo, S_PLAY_DASH); - else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)) - P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT_RUN); - else - P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT); - player->pflags |= PF_THOKKED; - player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING); - player->secondjump = 1; - } - break; - case CA_TELEKINESIS: - if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) - { - P_Telekinesis(player, - FixedMul(player->actionspd, player->mo->scale), // +ve thrust (pushing away from player) - FixedMul(384*FRACUNIT, player->mo->scale)); - } - break; - case CA_FALLSWITCH: - if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) - { - player->mo->momz = -player->mo->momz; - P_SpawnThokMobj(player); - player->pflags |= PF_THOKKED; - } - break; - case CA_AIRDRILL: - if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) - { - player->flyangle = 56 + (60-(player->actionspd>>FRACBITS))/3; - player->pflags |= PF_THOKKED; - S_StartSound(player->mo, sfx_spndsh); - } - break; - case CA_BOUNCE: - if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) - { - P_SetPlayerMobjState(player->mo, S_PLAY_BOUNCE); - player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); - player->pflags |= PF_THOKKED|PF_BOUNCING; - player->mo->momx >>= 1; - player->mo->momy >>= 1; - player->mo->momz >>= 1; - } - break; - case CA_TWINSPIN: - if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) - P_DoTwinSpin(player); - break; - default: - break; + player->powers[pw_tailsfly] = tailsflytics + 1; // Set the fly timer + + player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_STARTDASH); + if (player->bot == 1) + player->pflags |= PF_THOKKED; + else + player->pflags |= (PF_THOKKED|PF_CANCARRY); + } + break; + case CA_GLIDEANDCLIMB: + // Now Knuckles-type abilities are checked. + if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + { + fixed_t glidespeed = FixedMul(player->actionspd, player->mo->scale); + fixed_t playerspeed = player->speed; + + if (player->mo->eflags & MFE_UNDERWATER) + { + glidespeed >>= 1; + playerspeed = 2*playerspeed/3; + if (!(player->powers[pw_super] || player->powers[pw_sneakers])) + { + player->mo->momx = (2*(player->mo->momx - player->cmomx)/3) + player->cmomx; + player->mo->momy = (2*(player->mo->momy - player->cmomy)/3) + player->cmomy; + } + } + + player->pflags |= PF_GLIDING|PF_THOKKED; + player->glidetime = 0; + + P_SetPlayerMobjState(player->mo, S_PLAY_GLIDE); + if (playerspeed < glidespeed) + P_Thrust(player->mo, player->mo->angle, glidespeed - playerspeed); + player->pflags &= ~(PF_STARTDASH); + } + break; + case CA_DOUBLEJUMP: // Double-Jump + if (!(player->pflags & PF_THOKKED) || ((player->charflags & SF_MULTIABILITY) && (player->secondjump < (player->actionspd >> FRACBITS)))) + { + player->pflags |= PF_THOKKED; + player->pflags &= ~PF_JUMPED; + P_DoJump(player, true); + player->secondjump++; + } + break; + case CA_FLOAT: // Float + case CA_SLOWFALL: // Slow descent hover + if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + { + if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD) + P_SetPlayerMobjState(player->mo, S_PLAY_DASH); + else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)) + P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT_RUN); + else + P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT); + player->pflags |= PF_THOKKED; + player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); + player->secondjump = 1; + } + break; + case CA_TELEKINESIS: + if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + { + P_Telekinesis(player, + FixedMul(player->actionspd, player->mo->scale), // +ve thrust (pushing away from player) + FixedMul(384*FRACUNIT, player->mo->scale)); + } + break; + case CA_FALLSWITCH: + if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + { + player->mo->momz = -player->mo->momz; + P_SpawnThokMobj(player); + player->pflags |= PF_THOKKED; + } + break; + case CA_AIRDRILL: + if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + { + player->flyangle = 56 + (60-(player->actionspd>>FRACBITS))/3; + player->pflags |= PF_THOKKED; + S_StartSound(player->mo, sfx_spndsh); + } + break; + case CA_BOUNCE: + if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + { + P_SetPlayerMobjState(player->mo, S_PLAY_BOUNCE); + player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); + player->pflags |= PF_THOKKED|PF_BOUNCING; + player->mo->momx >>= 1; + player->mo->momy >>= 1; + player->mo->momz >>= 1; + } + break; + case CA_TWINSPIN: + if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + P_DoTwinSpin(player); + break; + default: + break; + } + player->pflags &= ~PF_SPINNING; } } else if (player->pflags & PF_THOKKED) From 04c021777487956cdd29ea9d6d9a91b1ba65d24d Mon Sep 17 00:00:00 2001 From: lachablock Date: Tue, 23 Mar 2021 14:50:05 +1100 Subject: [PATCH 02/96] Revert "Remove PF_SPINNING upon use of any jump ability, so that directionchar works properly" This reverts commit 4f18f6d3cf2bf06d23aad8cc1d78b5046a4def51. --- src/p_user.c | 363 +++++++++++++++++++++++++-------------------------- 1 file changed, 180 insertions(+), 183 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 261272313..02592053d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -5012,7 +5012,7 @@ void P_Telekinesis(player_t *player, fixed_t thrust, fixed_t range) static void P_DoTwinSpin(player_t *player) { - player->pflags &= ~(PF_NOJUMPDAMAGE|PF_SPINNING); + player->pflags &= ~PF_NOJUMPDAMAGE; player->pflags |= P_GetJumpFlags(player) | PF_THOKKED; S_StartSound(player->mo, sfx_s3k42); player->mo->frame = 0; @@ -5286,197 +5286,194 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) else if (player->pflags & PF_JUMPED) { if (!LUAh_AbilitySpecial(player)) + switch (player->charability) { - switch (player->charability) - { - case CA_THOK: - case CA_HOMINGTHOK: - case CA_JUMPTHOK: // Credit goes to CZ64 and Sryder13 for the original - // Now it's Sonic's abilities turn! - // THOK! - if (!(player->pflags & PF_THOKKED) || (player->charflags & SF_MULTIABILITY)) + case CA_THOK: + case CA_HOMINGTHOK: + case CA_JUMPTHOK: // Credit goes to CZ64 and Sryder13 for the original + // Now it's Sonic's abilities turn! + // THOK! + if (!(player->pflags & PF_THOKKED) || (player->charflags & SF_MULTIABILITY)) + { + // Catapult the player + fixed_t actionspd = player->actionspd; + + if (player->charflags & SF_DASHMODE) + actionspd = max(player->normalspeed, FixedDiv(player->speed, player->mo->scale)); + + if (player->mo->eflags & MFE_UNDERWATER) + actionspd >>= 1; + + if ((player->charability == CA_JUMPTHOK) && !(player->pflags & PF_THOKKED)) { - // Catapult the player - fixed_t actionspd = player->actionspd; - - if (player->charflags & SF_DASHMODE) - actionspd = max(player->normalspeed, FixedDiv(player->speed, player->mo->scale)); - - if (player->mo->eflags & MFE_UNDERWATER) - actionspd >>= 1; - - if ((player->charability == CA_JUMPTHOK) && !(player->pflags & PF_THOKKED)) - { - player->pflags &= ~PF_JUMPED; - P_DoJump(player, false); - } - - P_InstaThrust(player->mo, player->mo->angle, FixedMul(actionspd, player->mo->scale)); - - if (maptol & TOL_2D) - { - player->mo->momx /= 2; - player->mo->momy /= 2; - } - if (player->charability == CA_HOMINGTHOK) - { - player->mo->momx /= 2; - player->mo->momy /= 2; - } - - if (player->charability == CA_HOMINGTHOK) - { - P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockonthok)); - if (lockonthok) - { - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockonthok->x, lockonthok->y); - player->homing = 3*TICRATE; - } - else - { - P_SetPlayerMobjState(player->mo, S_PLAY_FALL); - player->pflags &= ~PF_JUMPED; - player->mo->height = P_GetPlayerHeight(player); - } - player->pflags &= ~PF_NOJUMPDAMAGE; - } - - player->drawangle = player->mo->angle; - - if (player->mo->info->attacksound && !player->spectator) - S_StartSound(player->mo, player->mo->info->attacksound); // Play the THOK sound - - P_SpawnThokMobj(player); - - player->pflags &= ~(PF_STARTDASH); - player->pflags |= PF_THOKKED; - - // Change localangle to match for simple controls? (P.S. chalupa) - // disabled because it seemed to disorient people and Z-targeting exists now - /*if (!demoplayback) - { - if (player == &players[consoleplayer] && cv_cam_turnfacingability[0].value > 0 && !(PLAYER1INPUTDOWN(gc_turnleft) || PLAYER1INPUTDOWN(gc_turnright))) - P_SetPlayerAngle(player, player->mo->angle);; - else if (player == &players[secondarydisplayplayer] && cv_cam_turnfacingability[1].value > 0 && !(PLAYER2INPUTDOWN(gc_turnleft) || PLAYER2INPUTDOWN(gc_turnright))) - P_SetPlayerAngle(player, player->mo->angle); - }*/ - } - break; - - case CA_FLY: - case CA_SWIM: - // If currently in the air from a jump, and you pressed the - // button again and have the ability to fly, do so! - if (player->charability == CA_SWIM && !(player->mo->eflags & MFE_UNDERWATER)) - ; // Can't do anything if you're a fish out of water! - else if (!(player->pflags & PF_THOKKED) && !(player->powers[pw_tailsfly])) - { - P_SetPlayerMobjState(player->mo, S_PLAY_FLY); // Change to the flying animation - - player->powers[pw_tailsfly] = tailsflytics + 1; // Set the fly timer - - player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_STARTDASH); - if (player->bot == 1) - player->pflags |= PF_THOKKED; - else - player->pflags |= (PF_THOKKED|PF_CANCARRY); - } - break; - case CA_GLIDEANDCLIMB: - // Now Knuckles-type abilities are checked. - if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) - { - fixed_t glidespeed = FixedMul(player->actionspd, player->mo->scale); - fixed_t playerspeed = player->speed; - - if (player->mo->eflags & MFE_UNDERWATER) - { - glidespeed >>= 1; - playerspeed = 2*playerspeed/3; - if (!(player->powers[pw_super] || player->powers[pw_sneakers])) - { - player->mo->momx = (2*(player->mo->momx - player->cmomx)/3) + player->cmomx; - player->mo->momy = (2*(player->mo->momy - player->cmomy)/3) + player->cmomy; - } - } - - player->pflags |= PF_GLIDING|PF_THOKKED; - player->glidetime = 0; - - P_SetPlayerMobjState(player->mo, S_PLAY_GLIDE); - if (playerspeed < glidespeed) - P_Thrust(player->mo, player->mo->angle, glidespeed - playerspeed); - player->pflags &= ~(PF_STARTDASH); - } - break; - case CA_DOUBLEJUMP: // Double-Jump - if (!(player->pflags & PF_THOKKED) || ((player->charflags & SF_MULTIABILITY) && (player->secondjump < (player->actionspd >> FRACBITS)))) - { - player->pflags |= PF_THOKKED; player->pflags &= ~PF_JUMPED; - P_DoJump(player, true); - player->secondjump++; + P_DoJump(player, false); } - break; - case CA_FLOAT: // Float - case CA_SLOWFALL: // Slow descent hover - if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + + P_InstaThrust(player->mo, player->mo->angle, FixedMul(actionspd, player->mo->scale)); + + if (maptol & TOL_2D) { - if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD) - P_SetPlayerMobjState(player->mo, S_PLAY_DASH); - else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)) - P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT_RUN); + player->mo->momx /= 2; + player->mo->momy /= 2; + } + if (player->charability == CA_HOMINGTHOK) + { + player->mo->momx /= 2; + player->mo->momy /= 2; + } + + if (player->charability == CA_HOMINGTHOK) + { + P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockonthok)); + if (lockonthok) + { + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockonthok->x, lockonthok->y); + player->homing = 3*TICRATE; + } else - P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT); + { + P_SetPlayerMobjState(player->mo, S_PLAY_FALL); + player->pflags &= ~PF_JUMPED; + player->mo->height = P_GetPlayerHeight(player); + } + player->pflags &= ~PF_NOJUMPDAMAGE; + } + + player->drawangle = player->mo->angle; + + if (player->mo->info->attacksound && !player->spectator) + S_StartSound(player->mo, player->mo->info->attacksound); // Play the THOK sound + + P_SpawnThokMobj(player); + + player->pflags &= ~(PF_SPINNING|PF_STARTDASH); + player->pflags |= PF_THOKKED; + + // Change localangle to match for simple controls? (P.S. chalupa) + // disabled because it seemed to disorient people and Z-targeting exists now + /*if (!demoplayback) + { + if (player == &players[consoleplayer] && cv_cam_turnfacingability[0].value > 0 && !(PLAYER1INPUTDOWN(gc_turnleft) || PLAYER1INPUTDOWN(gc_turnright))) + P_SetPlayerAngle(player, player->mo->angle);; + else if (player == &players[secondarydisplayplayer] && cv_cam_turnfacingability[1].value > 0 && !(PLAYER2INPUTDOWN(gc_turnleft) || PLAYER2INPUTDOWN(gc_turnright))) + P_SetPlayerAngle(player, player->mo->angle); + }*/ + } + break; + + case CA_FLY: + case CA_SWIM: + // If currently in the air from a jump, and you pressed the + // button again and have the ability to fly, do so! + if (player->charability == CA_SWIM && !(player->mo->eflags & MFE_UNDERWATER)) + ; // Can't do anything if you're a fish out of water! + else if (!(player->pflags & PF_THOKKED) && !(player->powers[pw_tailsfly])) + { + P_SetPlayerMobjState(player->mo, S_PLAY_FLY); // Change to the flying animation + + player->powers[pw_tailsfly] = tailsflytics + 1; // Set the fly timer + + player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_STARTDASH); + if (player->bot == 1) player->pflags |= PF_THOKKED; - player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); - player->secondjump = 1; - } - break; - case CA_TELEKINESIS: - if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + else + player->pflags |= (PF_THOKKED|PF_CANCARRY); + } + break; + case CA_GLIDEANDCLIMB: + // Now Knuckles-type abilities are checked. + if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + { + fixed_t glidespeed = FixedMul(player->actionspd, player->mo->scale); + fixed_t playerspeed = player->speed; + + if (player->mo->eflags & MFE_UNDERWATER) { - P_Telekinesis(player, - FixedMul(player->actionspd, player->mo->scale), // +ve thrust (pushing away from player) - FixedMul(384*FRACUNIT, player->mo->scale)); + glidespeed >>= 1; + playerspeed = 2*playerspeed/3; + if (!(player->powers[pw_super] || player->powers[pw_sneakers])) + { + player->mo->momx = (2*(player->mo->momx - player->cmomx)/3) + player->cmomx; + player->mo->momy = (2*(player->mo->momy - player->cmomy)/3) + player->cmomy; + } } - break; - case CA_FALLSWITCH: - if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) - { - player->mo->momz = -player->mo->momz; - P_SpawnThokMobj(player); - player->pflags |= PF_THOKKED; - } - break; - case CA_AIRDRILL: - if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) - { - player->flyangle = 56 + (60-(player->actionspd>>FRACBITS))/3; - player->pflags |= PF_THOKKED; - S_StartSound(player->mo, sfx_spndsh); - } - break; - case CA_BOUNCE: - if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) - { - P_SetPlayerMobjState(player->mo, S_PLAY_BOUNCE); - player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); - player->pflags |= PF_THOKKED|PF_BOUNCING; - player->mo->momx >>= 1; - player->mo->momy >>= 1; - player->mo->momz >>= 1; - } - break; - case CA_TWINSPIN: - if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) - P_DoTwinSpin(player); - break; - default: - break; - } - player->pflags &= ~PF_SPINNING; + + player->pflags |= PF_GLIDING|PF_THOKKED; + player->glidetime = 0; + + P_SetPlayerMobjState(player->mo, S_PLAY_GLIDE); + if (playerspeed < glidespeed) + P_Thrust(player->mo, player->mo->angle, glidespeed - playerspeed); + player->pflags &= ~(PF_SPINNING|PF_STARTDASH); + } + break; + case CA_DOUBLEJUMP: // Double-Jump + if (!(player->pflags & PF_THOKKED) || ((player->charflags & SF_MULTIABILITY) && (player->secondjump < (player->actionspd >> FRACBITS)))) + { + player->pflags |= PF_THOKKED; + player->pflags &= ~PF_JUMPED; + P_DoJump(player, true); + player->secondjump++; + } + break; + case CA_FLOAT: // Float + case CA_SLOWFALL: // Slow descent hover + if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + { + if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD) + P_SetPlayerMobjState(player->mo, S_PLAY_DASH); + else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)) + P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT_RUN); + else + P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT); + player->pflags |= PF_THOKKED; + player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING); + player->secondjump = 1; + } + break; + case CA_TELEKINESIS: + if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + { + P_Telekinesis(player, + FixedMul(player->actionspd, player->mo->scale), // +ve thrust (pushing away from player) + FixedMul(384*FRACUNIT, player->mo->scale)); + } + break; + case CA_FALLSWITCH: + if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + { + player->mo->momz = -player->mo->momz; + P_SpawnThokMobj(player); + player->pflags |= PF_THOKKED; + } + break; + case CA_AIRDRILL: + if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + { + player->flyangle = 56 + (60-(player->actionspd>>FRACBITS))/3; + player->pflags |= PF_THOKKED; + S_StartSound(player->mo, sfx_spndsh); + } + break; + case CA_BOUNCE: + if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + { + P_SetPlayerMobjState(player->mo, S_PLAY_BOUNCE); + player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); + player->pflags |= PF_THOKKED|PF_BOUNCING; + player->mo->momx >>= 1; + player->mo->momy >>= 1; + player->mo->momz >>= 1; + } + break; + case CA_TWINSPIN: + if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) + P_DoTwinSpin(player); + break; + default: + break; } } else if (player->pflags & PF_THOKKED) From 5ed5984cc549b3889e7b5bc5307c36577062c526 Mon Sep 17 00:00:00 2001 From: lachablock Date: Tue, 23 Mar 2021 15:03:12 +1100 Subject: [PATCH 03/96] Make more player abilities and all shieldabilities remove PF_SPINNING on use --- src/p_user.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 02592053d..5e4829564 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -5012,7 +5012,7 @@ void P_Telekinesis(player_t *player, fixed_t thrust, fixed_t range) static void P_DoTwinSpin(player_t *player) { - player->pflags &= ~PF_NOJUMPDAMAGE; + player->pflags &= ~(PF_NOJUMPDAMAGE|PF_SPINNING); player->pflags |= P_GetJumpFlags(player) | PF_THOKKED; S_StartSound(player->mo, sfx_s3k42); player->mo->frame = 0; @@ -5059,6 +5059,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE) { player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + player->pflags &= ~PF_SPINNING; player->mo->momx = player->mo->momy = player->mo->momz = 0; S_StartSound(player->mo, sfx_ngskid); } @@ -5074,11 +5075,13 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock // Armageddon pow case SH_ARMAGEDDON: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + player->pflags &= ~PF_SPINNING; P_BlackOw(player); break; // Attraction blast case SH_ATTRACT: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + player->pflags &= ~PF_SPINNING; player->homing = 2; P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockonshield)); if (lockonshield) @@ -5098,6 +5101,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock { boolean elem = ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL); player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + player->pflags &= ~PF_SPINNING; if (elem) { player->mo->momx = player->mo->momy = 0; @@ -5120,7 +5124,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock player->pflags |= PF_THOKKED|PF_SHIELDABILITY; P_Thrust(player->mo, player->mo->angle, FixedMul(30*FRACUNIT - FixedSqrt(FixedDiv(player->speed, player->mo->scale)), player->mo->scale)); player->drawangle = player->mo->angle; - player->pflags &= ~PF_NOJUMPDAMAGE; + player->pflags &= ~(PF_NOJUMPDAMAGE|PF_SPINNING); P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); S_StartSound(player->mo, sfx_s3k43); default: @@ -5413,7 +5417,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) if (!(player->pflags & PF_THOKKED) || ((player->charflags & SF_MULTIABILITY) && (player->secondjump < (player->actionspd >> FRACBITS)))) { player->pflags |= PF_THOKKED; - player->pflags &= ~PF_JUMPED; + player->pflags &= ~(PF_JUMPED|PF_SPINNING); P_DoJump(player, true); player->secondjump++; } @@ -5439,6 +5443,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) P_Telekinesis(player, FixedMul(player->actionspd, player->mo->scale), // +ve thrust (pushing away from player) FixedMul(384*FRACUNIT, player->mo->scale)); + player->pflags &= ~PF_SPINNING; } break; case CA_FALLSWITCH: @@ -5447,6 +5452,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->mo->momz = -player->mo->momz; P_SpawnThokMobj(player); player->pflags |= PF_THOKKED; + player->pflags &= ~PF_SPINNING; } break; case CA_AIRDRILL: @@ -5454,6 +5460,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) { player->flyangle = 56 + (60-(player->actionspd>>FRACBITS))/3; player->pflags |= PF_THOKKED; + player->pflags &= ~PF_SPINNING; S_StartSound(player->mo, sfx_spndsh); } break; @@ -5461,7 +5468,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY) { P_SetPlayerMobjState(player->mo, S_PLAY_BOUNCE); - player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); + player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING); player->pflags |= PF_THOKKED|PF_BOUNCING; player->mo->momx >>= 1; player->mo->momy >>= 1; From 691b17a88e468174549573e89228e45490ab328b Mon Sep 17 00:00:00 2001 From: GoldenTails Date: Sun, 25 Apr 2021 23:28:35 -0500 Subject: [PATCH 04/96] Dynamically allocate space for a state's action field It was previously restricted arbitrarily to 32 cells (31 usable characters) due to someone else's laziness --- src/deh_soc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 5b12ea1b0..df1ebc275 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2776,13 +2776,13 @@ void readframe(MYFILE *f, INT32 num) { size_t z; boolean found = false; - char actiontocompare[32]; + size_t actionlen = strlen(word2) + 1; + char *actiontocompare = calloc(actionlen, 1); - memset(actiontocompare, 0x00, sizeof(actiontocompare)); - strlcpy(actiontocompare, word2, sizeof (actiontocompare)); + strcpy(actiontocompare, word2); strupr(actiontocompare); - for (z = 0; z < 32; z++) + for (z = 0; z < actionlen; z++) { if (actiontocompare[z] == '\n' || actiontocompare[z] == '\r') { @@ -2815,6 +2815,8 @@ void readframe(MYFILE *f, INT32 num) if (!found) deh_warning("Unknown action %s", actiontocompare); + + free(actiontocompare); } else deh_warning("Frame %d: unknown word '%s'", num, word1); From 7e3a6bd44c471303082ce0bfcc4e008ee1961a11 Mon Sep 17 00:00:00 2001 From: GoldenTails Date: Sat, 31 Oct 2020 09:08:48 -0500 Subject: [PATCH 05/96] Increase Connect via IP textbox width and have shorten and truncate the text as necessary --- src/m_menu.c | 60 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index db2aa09c6..452a31c71 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -11605,7 +11605,10 @@ static void M_StartServerMenu(INT32 choice) // CONNECT VIA IP // ============== -static char setupm_ip[28]; +#define CONNIP_LEN 128 +static char setupm_ip[CONNIP_LEN]; + +#define DOTS "... " // Draw the funky Connect IP menu. Tails 11-19-2002 // So much work for such a little thing! @@ -11613,6 +11616,11 @@ static void M_DrawMPMainMenu(void) { INT32 x = currentMenu->x; INT32 y = currentMenu->y; + const INT32 boxwidth = /*16*8 + 6*/ (BASEVIDWIDTH - 2*(x+5)); + const INT32 maxstrwidth = boxwidth - 5; + char drawnstr[CONNIP_LEN]; + char *drawnstrptr = malloc(sizeof(setupm_ip)); + boolean drawthin, shorten = false; // use generic drawer for cursor, items and title M_DrawGenericMenu(); @@ -11628,17 +11636,53 @@ static void M_DrawMPMainMenu(void) y += 22; - V_DrawFill(x+5, y+4+5, /*16*8 + 6,*/ BASEVIDWIDTH - 2*(x+5), 8+6, 159); + V_DrawFill(x+5, y+4+5, boxwidth, 8+6, 159); + + strcpy(drawnstrptr, setupm_ip); + drawthin = V_StringWidth(drawnstrptr, V_ALLOWLOWERCASE) + V_StringWidth("_", V_ALLOWLOWERCASE) > maxstrwidth; // draw name string - V_DrawString(x+8,y+12, V_ALLOWLOWERCASE, setupm_ip); + if (drawthin) + { + INT32 dotswidth = V_ThinStringWidth(DOTS, V_ALLOWLOWERCASE); + //UINT32 color = 0; + while (V_ThinStringWidth(drawnstrptr, V_ALLOWLOWERCASE) + V_ThinStringWidth("_", V_ALLOWLOWERCASE) >= maxstrwidth) + { + shorten = true; + drawnstrptr++; + } + + if (shorten) + { + INT32 initiallen = V_ThinStringWidth(drawnstrptr, V_ALLOWLOWERCASE); + INT32 cutofflen = 0; + while ((cutofflen = initiallen - V_ThinStringWidth(drawnstrptr, V_ALLOWLOWERCASE)) < dotswidth) + drawnstrptr++; + + V_DrawThinString(x+8,y+13, V_ALLOWLOWERCASE|V_GRAYMAP, DOTS); + x += V_ThinStringWidth(DOTS, V_ALLOWLOWERCASE); + } + + V_DrawThinString(x+8,y+13, V_ALLOWLOWERCASE, drawnstrptr); + } + else + { + V_DrawString(x+8,y+12, V_ALLOWLOWERCASE, drawnstrptr); + } // draw text cursor for name if (itemOn == 2 //0 - && skullAnimCounter < 4) //blink cursor - V_DrawCharacter(x+8+V_StringWidth(setupm_ip, V_ALLOWLOWERCASE),y+12,'_',false); + && skullAnimCounter < 4) //blink cursor + { + if (drawthin) + V_DrawCharacter(x+8+V_ThinStringWidth(drawnstrptr, V_ALLOWLOWERCASE),y+12,'_',false); + else + V_DrawCharacter(x+8+V_StringWidth(drawnstrptr, V_ALLOWLOWERCASE),y+12,'_',false); + } } +#undef DOTS + // Tails 11-19-2002 static void M_ConnectIP(INT32 choice) { @@ -11719,7 +11763,7 @@ static void M_HandleConnectIP(INT32 choice) const char *paste = I_ClipboardPaste(); if (paste != NULL) { - strncat(setupm_ip, paste, 28-1 - l); // Concat the ip field with clipboard + strncat(setupm_ip, paste, CONNIP_LEN-1 - l); // Concat the ip field with clipboard if (strlen(paste) != 0) // Don't play sound if nothing was pasted S_StartSound(NULL,sfx_menu1); // Tails } @@ -11753,7 +11797,7 @@ static void M_HandleConnectIP(INT32 choice) const char *paste = I_ClipboardPaste(); if (paste != NULL) { - strncat(setupm_ip, paste, 28-1 - l); // Concat the ip field with clipboard + strncat(setupm_ip, paste, CONNIP_LEN-1 - l); // Concat the ip field with clipboard if (strlen(paste) != 0) // Don't play sound if nothing was pasted S_StartSound(NULL,sfx_menu1); // Tails } @@ -11770,7 +11814,7 @@ static void M_HandleConnectIP(INT32 choice) } } - if (l >= 28-1) + if (l >= CONNIP_LEN-1) break; // Rudimentary number and period enforcing - also allows letters so hostnames can be used instead From f0bee67d6e097fea8d07e16b85bf459948de06cf Mon Sep 17 00:00:00 2001 From: GoldenTails Date: Sat, 20 Feb 2021 17:01:45 -0600 Subject: [PATCH 06/96] Remove unused static-alloc `drawnstr`, rename `drawnstrptr` to `drawnstr`. --- src/m_menu.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 452a31c71..6db0f4c78 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -11618,8 +11618,7 @@ static void M_DrawMPMainMenu(void) INT32 y = currentMenu->y; const INT32 boxwidth = /*16*8 + 6*/ (BASEVIDWIDTH - 2*(x+5)); const INT32 maxstrwidth = boxwidth - 5; - char drawnstr[CONNIP_LEN]; - char *drawnstrptr = malloc(sizeof(setupm_ip)); + char *drawnstr = malloc(sizeof(setupm_ip)); boolean drawthin, shorten = false; // use generic drawer for cursor, items and title @@ -11638,36 +11637,36 @@ static void M_DrawMPMainMenu(void) V_DrawFill(x+5, y+4+5, boxwidth, 8+6, 159); - strcpy(drawnstrptr, setupm_ip); - drawthin = V_StringWidth(drawnstrptr, V_ALLOWLOWERCASE) + V_StringWidth("_", V_ALLOWLOWERCASE) > maxstrwidth; + strcpy(drawnstr, setupm_ip); + drawthin = V_StringWidth(drawnstr, V_ALLOWLOWERCASE) + V_StringWidth("_", V_ALLOWLOWERCASE) > maxstrwidth; // draw name string if (drawthin) { INT32 dotswidth = V_ThinStringWidth(DOTS, V_ALLOWLOWERCASE); //UINT32 color = 0; - while (V_ThinStringWidth(drawnstrptr, V_ALLOWLOWERCASE) + V_ThinStringWidth("_", V_ALLOWLOWERCASE) >= maxstrwidth) + while (V_ThinStringWidth(drawnstr, V_ALLOWLOWERCASE) + V_ThinStringWidth("_", V_ALLOWLOWERCASE) >= maxstrwidth) { shorten = true; - drawnstrptr++; + drawnstr++; } if (shorten) { - INT32 initiallen = V_ThinStringWidth(drawnstrptr, V_ALLOWLOWERCASE); + INT32 initiallen = V_ThinStringWidth(drawnstr, V_ALLOWLOWERCASE); INT32 cutofflen = 0; - while ((cutofflen = initiallen - V_ThinStringWidth(drawnstrptr, V_ALLOWLOWERCASE)) < dotswidth) - drawnstrptr++; + while ((cutofflen = initiallen - V_ThinStringWidth(drawnstr, V_ALLOWLOWERCASE)) < dotswidth) + drawnstr++; V_DrawThinString(x+8,y+13, V_ALLOWLOWERCASE|V_GRAYMAP, DOTS); x += V_ThinStringWidth(DOTS, V_ALLOWLOWERCASE); } - V_DrawThinString(x+8,y+13, V_ALLOWLOWERCASE, drawnstrptr); + V_DrawThinString(x+8,y+13, V_ALLOWLOWERCASE, drawnstr); } else { - V_DrawString(x+8,y+12, V_ALLOWLOWERCASE, drawnstrptr); + V_DrawString(x+8,y+12, V_ALLOWLOWERCASE, drawnstr); } // draw text cursor for name @@ -11675,9 +11674,9 @@ static void M_DrawMPMainMenu(void) && skullAnimCounter < 4) //blink cursor { if (drawthin) - V_DrawCharacter(x+8+V_ThinStringWidth(drawnstrptr, V_ALLOWLOWERCASE),y+12,'_',false); + V_DrawCharacter(x+8+V_ThinStringWidth(drawnstr, V_ALLOWLOWERCASE),y+12,'_',false); else - V_DrawCharacter(x+8+V_StringWidth(drawnstrptr, V_ALLOWLOWERCASE),y+12,'_',false); + V_DrawCharacter(x+8+V_StringWidth(drawnstr, V_ALLOWLOWERCASE),y+12,'_',false); } } From 1639676e8da2db5c20cfc0f9465739600e40384a Mon Sep 17 00:00:00 2001 From: GoldenTails Date: Fri, 3 Sep 2021 09:14:04 -0500 Subject: [PATCH 07/96] Actually free the drawnstr pointer after we're done using it. It probably was like this originally because past Golden was confused about why free was throwing errors :P --- src/m_menu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/m_menu.c b/src/m_menu.c index 6db0f4c78..ac5269c3e 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -11619,6 +11619,7 @@ static void M_DrawMPMainMenu(void) const INT32 boxwidth = /*16*8 + 6*/ (BASEVIDWIDTH - 2*(x+5)); const INT32 maxstrwidth = boxwidth - 5; char *drawnstr = malloc(sizeof(setupm_ip)); + char *drawnstr_orig = drawnstr; boolean drawthin, shorten = false; // use generic drawer for cursor, items and title @@ -11678,6 +11679,8 @@ static void M_DrawMPMainMenu(void) else V_DrawCharacter(x+8+V_StringWidth(drawnstr, V_ALLOWLOWERCASE),y+12,'_',false); } + + free(drawnstr_orig); } #undef DOTS From 98aafc6056ad0ef89731ebbc18591684a8460ec3 Mon Sep 17 00:00:00 2001 From: SteelT Date: Thu, 3 Feb 2022 18:44:46 -0500 Subject: [PATCH 08/96] Don't force bit depth to 8-bit when setting default video mode --- src/screen.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/screen.c b/src/screen.c index 770f1c802..af044ffe1 100644 --- a/src/screen.c +++ b/src/screen.c @@ -390,7 +390,6 @@ void SCR_SetDefaultMode(void) // remember the default screen size CV_SetValue(&cv_scr_width, vid.width); CV_SetValue(&cv_scr_height, vid.height); - CV_SetValue(&cv_scr_depth, vid.bpp*8); } // Change fullscreen on/off according to cv_fullscreen From d0a91646ef1e87b967d543135c6df78475ff614b Mon Sep 17 00:00:00 2001 From: spherallic Date: Wed, 7 Dec 2022 12:34:35 +0100 Subject: [PATCH 09/96] Allow setting hoop pitch/yaw in degrees (binary) --- extras/conf/SRB2-22.cfg | 4 +++- src/p_setup.c | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg index 6bae1494f..952ce6969 100644 --- a/extras/conf/SRB2-22.cfg +++ b/extras/conf/SRB2-22.cfg @@ -6491,7 +6491,7 @@ thingtypes centerHitbox = true; flagsvaluetext = "Height"; angletext = "Pitch/Yaw"; - fixedrotation = 1; + parametertext = "Degrees?"; } 1706 { @@ -6551,6 +6551,8 @@ thingtypes height = 160; unflippable = true; centerHitbox = true; + angletext = "Pitch/Yaw"; + parametertext = "Degrees?"; } 1714 { diff --git a/src/p_setup.c b/src/p_setup.c index deb308da2..4faba1358 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -6627,8 +6627,8 @@ static void P_ConvertBinaryThingTypes(void) case 1713: //Hoop (Customizable) { UINT16 oldangle = mapthings[i].angle; - mapthings[i].angle = ((oldangle >> 8)*360)/256; - mapthings[i].pitch = ((oldangle & 255)*360)/256; + mapthings[i].angle = (mapthings[i].extrainfo == 1) ? oldangle - 90 : ((oldangle >> 8)*360)/256; + mapthings[i].pitch = (mapthings[i].extrainfo == 1) ? oldangle / 360 : ((oldangle & 255)*360)/256; mapthings[i].args[0] = (mapthings[i].type == 1705) ? 96 : (mapthings[i].options & 0xF)*16 + 32; mapthings[i].options &= ~0xF; mapthings[i].type = 1713; From 003ee55ccdb2398cc55a45fad3ad4e69edfd18f7 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 12 Dec 2022 16:17:20 -0600 Subject: [PATCH 10/96] http-mserv: add SRB2-specific user agent string --- src/http-mserv.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/http-mserv.c b/src/http-mserv.c index b0ef37fa1..7b418c99a 100644 --- a/src/http-mserv.c +++ b/src/http-mserv.c @@ -65,6 +65,8 @@ static I_mutex hms_api_mutex; static char *hms_server_token; +static char hms_useragent[512]; + struct HMS_buffer { CURL *curl; @@ -81,6 +83,27 @@ Contact_error (void) ); } +static void +get_user_agent(char *buf, size_t len) +{ +#if defined(__STDC__) && __STDC_VERSION__ >= 201112L + if (sprintf_s(buf, len, "%s/%s (%s; %s; %i; %i) SRB2BASE/%i", SRB2APPLICATION, VERSIONSTRING, compbranch, comprevision, MODID, MODVERSION, CODEBASE) < 1) + I_Error("http-mserv: get_user_agent failed"); +#else + if (sprintf(buf, "%s/%s (%s; %s; %i; %i) SRB2BASE/%i", SRB2APPLICATION, VERSIONSTRING, compbranch, comprevision, MODID, MODVERSION, CODEBASE) < 0) + I_Error("http-mserv: get_user_agent failed"); +#endif +} + +static void +init_user_agent_once(void) +{ + if (hms_useragent[0] != '\0') + return; + + get_user_agent(hms_useragent, 512); +} + static size_t HMS_on_read (char *s, size_t _1, size_t n, void *userdata) { @@ -156,6 +179,8 @@ HMS_connect (const char *format, ...) I_lock_mutex(&hms_api_mutex); #endif + init_user_agent_once(); + seek = strlen(hms_api) + 1;/* + '/' */ va_start (ap, format); @@ -202,6 +227,8 @@ HMS_connect (const char *format, ...) curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HMS_on_read); curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer); + curl_easy_setopt(curl, CURLOPT_USERAGENT, hms_useragent); + curl_free(quack_token); free(url); From a85876d0c266e02e1aa8cd19cbd89e68466756a7 Mon Sep 17 00:00:00 2001 From: spherallic Date: Fri, 16 Dec 2022 01:25:54 +0100 Subject: [PATCH 11/96] Change gamepad defaults again, post-refactor --- src/g_game.c | 6 +++--- src/g_input.c | 32 ++++++++++++++++++-------------- src/g_input.h | 1 + 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index b4a127a73..c832af0a5 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -297,10 +297,10 @@ CV_PossibleValue_t joyaxis_cons_t[] = {{0, "None"}, #ifndef OLD_GAMEPAD_AXES #define MOVEAXIS_DEFAULT "Left Stick Y" #define SIDEAXIS_DEFAULT "Left Stick X" -#define LOOKAXIS_DEFAULT "Right Stick Y-" +#define LOOKAXIS_DEFAULT "Right Stick Y" #define TURNAXIS_DEFAULT "Right Stick X" -#define FIREAXIS_DEFAULT "Right Trigger" -#define FIRENAXIS_DEFAULT "Left Trigger" +#define FIREAXIS_DEFAULT "None" +#define FIRENAXIS_DEFAULT "None" #else #define MOVEAXIS_DEFAULT "Y-Axis" #define SIDEAXIS_DEFAULT "X-Axis" diff --git a/src/g_input.c b/src/g_input.c index 465db0316..4222951fa 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -1377,15 +1377,17 @@ void G_DefineDefaultControls(void) gamecontroldefault[i][GC_CUSTOM1 ][1] = GAMEPAD_KEY(B); // B gamecontroldefault[i][GC_CUSTOM2 ][1] = GAMEPAD_KEY(Y); // Y gamecontroldefault[i][GC_CUSTOM3 ][1] = GAMEPAD_KEY(LEFTSTICK); // Left Stick - gamecontroldefault[i][GC_CENTERVIEW ][1] = GAMEPAD_KEY(RIGHTSTICK); // Right Stick - gamecontroldefault[i][GC_WEAPONPREV ][1] = GAMEPAD_KEY(LEFTSHOULDER); // LB - gamecontroldefault[i][GC_WEAPONNEXT ][1] = GAMEPAD_KEY(RIGHTSHOULDER); // RB + gamecontroldefault[i][GC_CENTERVIEW ][1] = GAMEPAD_KEY(RIGHTSHOULDER); // R1 + gamecontroldefault[i][GC_CAMTOGGLE ][1] = GAMEPAD_KEY(LEFTSHOULDER); // L1 gamecontroldefault[i][GC_SCREENSHOT ][1] = GAMEPAD_KEY(BACK); // Back gamecontroldefault[i][GC_SYSTEMMENU ][0] = GAMEPAD_KEY(START); // Start - gamecontroldefault[i][GC_CAMTOGGLE ][1] = GAMEPAD_KEY(DPAD_UP); // D-Pad Up - gamecontroldefault[i][GC_VIEWPOINTNEXT][1] = GAMEPAD_KEY(DPAD_DOWN); // D-Pad Down - gamecontroldefault[i][GC_TOSSFLAG ][1] = GAMEPAD_KEY(DPAD_LEFT); // D-Pad Left - gamecontroldefault[i][GC_SCORES ][1] = GAMEPAD_KEY(DPAD_RIGHT); // D-Pad Right + gamecontroldefault[i][GC_TOSSFLAG ][1] = GAMEPAD_KEY(DPAD_UP); // D-Pad Up + gamecontroldefault[i][GC_WEAPONPREV ][1] = GAMEPAD_KEY(DPAD_LEFT); // D-Pad Left + gamecontroldefault[i][GC_WEAPONNEXT ][1] = GAMEPAD_KEY(DPAD_RIGHT); // D-Pad Right + gamecontroldefault[i][GC_SCORES ][1] = GAMEPAD_KEY(DPAD_DOWN); // D-Pad Down + gamecontroldefault[i][GC_VIEWPOINTNEXT][1] = GAMEPAD_KEY(RIGHTSTICK); // Right Stick + gamecontroldefault[i][GC_FIRE ][1] = GAMEPAD_AXIS(TRIGGERRIGHT); // R2 + gamecontroldefault[i][GC_FIRENORMAL ][1] = GAMEPAD_AXIS(TRIGGERLEFT); // L2 // Second player only has gamepad defaults gamecontrolbisdefault[i][GC_JUMP ][1] = GAMEPAD_KEY(A); // A @@ -1393,15 +1395,17 @@ void G_DefineDefaultControls(void) gamecontrolbisdefault[i][GC_CUSTOM1 ][1] = GAMEPAD_KEY(B); // B gamecontrolbisdefault[i][GC_CUSTOM2 ][1] = GAMEPAD_KEY(Y); // Y gamecontrolbisdefault[i][GC_CUSTOM3 ][1] = GAMEPAD_KEY(LEFTSTICK); // Left Stick - gamecontrolbisdefault[i][GC_CENTERVIEW ][1] = GAMEPAD_KEY(RIGHTSTICK); // Right Stick - gamecontrolbisdefault[i][GC_WEAPONPREV ][1] = GAMEPAD_KEY(LEFTSHOULDER); // LB - gamecontrolbisdefault[i][GC_WEAPONNEXT ][1] = GAMEPAD_KEY(RIGHTSHOULDER); // RB + gamecontrolbisdefault[i][GC_CENTERVIEW ][1] = GAMEPAD_KEY(RIGHTSHOULDER); // R1 + gamecontrolbisdefault[i][GC_CAMTOGGLE ][1] = GAMEPAD_KEY(LEFTSHOULDER); // L1 gamecontrolbisdefault[i][GC_SCREENSHOT ][1] = GAMEPAD_KEY(BACK); // Back //gamecontrolbisdefault[i][GC_SYSTEMMENU ][0] = GAMEPAD_KEY(START); // Start - gamecontrolbisdefault[i][GC_CAMTOGGLE ][1] = GAMEPAD_KEY(DPAD_UP); // D-Pad Up - gamecontrolbisdefault[i][GC_VIEWPOINTNEXT][1] = GAMEPAD_KEY(DPAD_DOWN); // D-Pad Down - gamecontrolbisdefault[i][GC_TOSSFLAG ][1] = GAMEPAD_KEY(DPAD_LEFT); // D-Pad Left - //gamecontrolbisdefault[i][GC_SCORES ][1] = GAMEPAD_KEY(DPAD_RIGHT); // D-Pad Right + gamecontrolbisdefault[i][GC_TOSSFLAG ][1] = GAMEPAD_KEY(DPAD_UP); // D-Pad Up + gamecontrolbisdefault[i][GC_WEAPONPREV ][1] = GAMEPAD_KEY(DPAD_LEFT); // D-Pad Left + gamecontrolbisdefault[i][GC_WEAPONNEXT ][1] = GAMEPAD_KEY(DPAD_RIGHT); // D-Pad Right + //gamecontrolbisdefault[i][GC_SCORES ][1] = GAMEPAD_KEY(DPAD_DOWN); // D-Pad Down + gamecontrolbisdefault[i][GC_VIEWPOINTNEXT][1] = GAMEPAD_KEY(RIGHTSTICK); // Right Stick + gamecontrolbisdefault[i][GC_FIRE ][1] = GAMEPAD_AXIS(TRIGGERRIGHT); // R2 + gamecontrolbisdefault[i][GC_FIRENORMAL ][1] = GAMEPAD_AXIS(TRIGGERLEFT); // L2 } } diff --git a/src/g_input.h b/src/g_input.h index fe623034a..9d393fee1 100644 --- a/src/g_input.h +++ b/src/g_input.h @@ -188,6 +188,7 @@ typedef enum } key_input_e; #define GAMEPAD_KEY(key) (KEY_GAMEPAD + GAMEPAD_BUTTON_##key) +#define GAMEPAD_AXIS(key) (KEY_AXES + GAMEPAD_AXIS_##key) typedef enum { From c1b85b212d73fd75da52d60e89233665b67b1bbe Mon Sep 17 00:00:00 2001 From: Lamibe <986-Lamibe@users.noreply.git.do.srb2.org> Date: Mon, 19 Dec 2022 10:38:17 +0100 Subject: [PATCH 12/96] Increased maxsend to 200MB --- src/d_clisrv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 57c3e5924..3091f3344 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3469,7 +3469,7 @@ consvar_t cv_resynchattempts = CVAR_INIT ("resynchattempts", "10", CV_SAVE|CV_NE consvar_t cv_blamecfail = CVAR_INIT ("blamecfail", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); // max file size to send to a player (in kilobytes) -static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {204800, "MAX"}, {0, NULL}}; consvar_t cv_maxsend = CVAR_INIT ("maxsend", "4096", CV_SAVE|CV_NETVAR, maxsend_cons_t, NULL); consvar_t cv_noticedownload = CVAR_INIT ("noticedownload", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); From 7abdab09bd4384b1cecb4414762ed213e20fd932 Mon Sep 17 00:00:00 2001 From: spherallic Date: Wed, 21 Dec 2022 23:51:24 +0100 Subject: [PATCH 13/96] Check double usage per-player, remove 2.1 code --- src/g_input.c | 116 +++++--------------------------------------------- src/g_input.h | 2 +- src/m_menu.c | 2 +- 3 files changed, 13 insertions(+), 107 deletions(-) diff --git a/src/g_input.c b/src/g_input.c index 4222951fa..7d9633216 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -1475,7 +1475,7 @@ void G_SaveKeySetting(FILE *f, INT32 (*fromcontrols)[2], INT32 (*fromcontrolsbis } } -INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify) +INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify, UINT8 player) { INT32 result = GC_NULL; if (cv_controlperkey.value == 1) @@ -1483,22 +1483,22 @@ INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify) INT32 i; for (i = 0; i < NUM_GAMECONTROLS; i++) { - if (gamecontrol[i][0] == keynum) + if (gamecontrol[i][0] == keynum && player != 2) { result = i; if (modify) gamecontrol[i][0] = KEY_NULL; } - if (gamecontrol[i][1] == keynum) + if (gamecontrol[i][1] == keynum && player != 2) { result = i; if (modify) gamecontrol[i][1] = KEY_NULL; } - if (gamecontrolbis[i][0] == keynum) + if (gamecontrolbis[i][0] == keynum && player != 1) { result = i; if (modify) gamecontrolbis[i][0] = KEY_NULL; } - if (gamecontrolbis[i][1] == keynum) + if (gamecontrolbis[i][1] == keynum && player != 1) { result = i; if (modify) gamecontrolbis[i][1] = KEY_NULL; @@ -1510,7 +1510,7 @@ INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify) return result; } -static INT32 G_FilterKeyByVersion(INT32 numctrl, INT32 keyidx, INT32 player, INT32 *keynum1, INT32 *keynum2, boolean *nestedoverride) +static INT32 G_FilterSpecialKeys(INT32 keyidx, INT32 player, INT32 *keynum1, INT32 *keynum2) { // Special case: ignore KEY_PAUSE because it's hardcoded if (keyidx == 0 && *keynum1 == KEY_PAUSE) @@ -1526,99 +1526,6 @@ static INT32 G_FilterKeyByVersion(INT32 numctrl, INT32 keyidx, INT32 player, INT else if (keyidx == 1 && *keynum2 == KEY_PAUSE) return -1; // skip setting control - if (GETMAJOREXECVERSION(cv_execversion.value) < 27 && ( // v2.1.22 - numctrl == GC_WEAPONNEXT || numctrl == GC_WEAPONPREV || numctrl == GC_TOSSFLAG || - numctrl == GC_SPIN || numctrl == GC_CAMRESET || numctrl == GC_JUMP || - numctrl == GC_PAUSE || numctrl == GC_SYSTEMMENU || numctrl == GC_CAMTOGGLE || - numctrl == GC_SCREENSHOT || numctrl == GC_TALKKEY || numctrl == GC_SCORES || - numctrl == GC_CENTERVIEW - )) - { - INT32 keynum = 0, existingctrl = 0; - INT32 defaultkey; - boolean defaultoverride = false; - - // get the default gamecontrol - if (player == 0 && numctrl == GC_SYSTEMMENU) - defaultkey = gamecontrol[numctrl][0]; - else - defaultkey = (player == 1 ? gamecontrolbis[numctrl][0] : gamecontrol[numctrl][1]); - - // Assign joypad button defaults if there is an open slot. - // At this point, gamecontrol/bis should have the default controls - // (unless LOADCONFIG is being run) - // - // If the player runs SETCONTROL in-game, this block should not be reached - // because EXECVERSION is locked onto the latest version. - if (keyidx == 0 && !*keynum1) - { - if (*keynum2) // push keynum2 down; this is an edge case - { - *keynum1 = *keynum2; - *keynum2 = 0; - keynum = *keynum1; - } - else - { - keynum = defaultkey; - defaultoverride = true; - } - } - else if (keyidx == 1 && (!*keynum2 || (!*keynum1 && *keynum2))) // last one is the same edge case as above - { - keynum = defaultkey; - defaultoverride = true; - } - else // default to the specified keynum - keynum = (keyidx == 1 ? *keynum2 : *keynum1); - - // Did our last call override keynum2? - if (*nestedoverride) - { - defaultoverride = true; - *nestedoverride = false; - } - - // Fill keynum2 with the default control - if (keyidx == 0 && !*keynum2) - { - *keynum2 = defaultkey; - // Tell the next call that this is an override - *nestedoverride = true; - - // if keynum2 already matches keynum1, we probably recursed - // so unset it - if (*keynum1 == *keynum2) - { - *keynum2 = 0; - *nestedoverride = false; - } - } - - // check if the key is being used somewhere else before passing it - // pass it through if it's the same numctrl. This is an edge case -- when using - // LOADCONFIG, gamecontrol is not reset with default. - // - // Also, only check if we're actually overriding, to preserve behavior where - // config'd keys overwrite default keys. - if (defaultoverride) - existingctrl = G_CheckDoubleUsage(keynum, false); - - if (keynum && (!existingctrl || existingctrl == numctrl)) - return keynum; - else if (keyidx == 0 && *keynum2) - { - // try it again and push down keynum2 - *keynum1 = *keynum2; - *keynum2 = 0; - return G_FilterKeyByVersion(numctrl, keyidx, player, keynum1, keynum2, nestedoverride); - // recursion *should* be safe because we only assign keynum2 to a joy default - // and then clear it if we find that keynum1 already has the joy default. - } - else - return 0; - } - // All's good, so pass the keynum as-is if (keyidx == 1) return *keynum2; @@ -1632,7 +1539,6 @@ static void setcontrol(INT32 (*gc)[2]) const char *namectrl; INT32 keynum, keynum1, keynum2; INT32 player = ((void*)gc == (void*)&gamecontrolbis ? 1 : 0); - boolean nestedoverride = false; // Update me for 2.3 namectrl = (stricmp(COM_Argv(1), "use")) ? COM_Argv(1) : "spin"; @@ -1647,20 +1553,20 @@ static void setcontrol(INT32 (*gc)[2]) } keynum1 = G_KeyNameToNum(COM_Argv(2)); keynum2 = G_KeyNameToNum(COM_Argv(3)); - keynum = G_FilterKeyByVersion(numctrl, 0, player, &keynum1, &keynum2, &nestedoverride); + keynum = G_FilterSpecialKeys(0, player, &keynum1, &keynum2); if (keynum >= 0) { - (void)G_CheckDoubleUsage(keynum, true); + (void)G_CheckDoubleUsage(keynum, true, player+1); // if keynum was rejected, try it again with keynum2 if (!keynum && keynum2) { keynum1 = keynum2; // push down keynum2 keynum2 = 0; - keynum = G_FilterKeyByVersion(numctrl, 0, player, &keynum1, &keynum2, &nestedoverride); + keynum = G_FilterSpecialKeys(0, player, &keynum1, &keynum2); if (keynum >= 0) - (void)G_CheckDoubleUsage(keynum, true); + (void)G_CheckDoubleUsage(keynum, true, player+1); } } @@ -1669,7 +1575,7 @@ static void setcontrol(INT32 (*gc)[2]) if (keynum2) { - keynum = G_FilterKeyByVersion(numctrl, 1, player, &keynum1, &keynum2, &nestedoverride); + keynum = G_FilterSpecialKeys(1, player, &keynum1, &keynum2); if (keynum >= 0) { if (keynum != gc[numctrl][0]) diff --git a/src/g_input.h b/src/g_input.h index 9d393fee1..ff42d1489 100644 --- a/src/g_input.h +++ b/src/g_input.h @@ -355,7 +355,7 @@ void G_DefineDefaultControls(void); INT32 G_GetControlScheme(INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gclen); void G_CopyControls(INT32 (*setupcontrols)[2], INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gclen); void G_SaveKeySetting(FILE *f, INT32 (*fromcontrols)[2], INT32 (*fromcontrolsbis)[2]); -INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify); +INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify, UINT8 player); // sets the members of a mouse_t given position deltas void G_SetMouseDeltas(INT32 dx, INT32 dy, UINT8 ssplayer); diff --git a/src/m_menu.c b/src/m_menu.c index 7c67cf2da..461a08552 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -12969,7 +12969,7 @@ static void M_ChangeControlResponse(event_t *ev) setupcontrols[control][1] = KEY_NULL; //replace key 1,clear key2 } - G_CheckDoubleUsage(ch, true); + G_CheckDoubleUsage(ch, true, setupcontrols_secondaryplayer ? 2 : 1); setupcontrols[control][found] = ch; } From b772c3a00d9488b254433575508b65436f813499 Mon Sep 17 00:00:00 2001 From: spherallic Date: Thu, 22 Dec 2022 00:02:30 +0100 Subject: [PATCH 14/96] Remove "controls per key" option --- src/d_netcmd.c | 1 - src/g_input.c | 55 +++++++++++++++++++++++++------------------------- src/g_input.h | 1 - src/m_menu.c | 1 - 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 5f02bc2de..5dc391109 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -841,7 +841,6 @@ void D_RegisterClientCommands(void) #if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON) CV_RegisterVar(&cv_mouse2opt); #endif - CV_RegisterVar(&cv_controlperkey); CV_RegisterVar(&cv_usemouse); CV_RegisterVar(&cv_usemouse2); diff --git a/src/g_input.c b/src/g_input.c index 7d9633216..ee9f8a24b 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -24,14 +24,12 @@ #define MAXMOUSESENSITIVITY 100 // sensitivity steps static CV_PossibleValue_t mousesens_cons_t[] = {{1, "MIN"}, {MAXMOUSESENSITIVITY, "MAX"}, {0, NULL}}; -static CV_PossibleValue_t onecontrolperkey_cons_t[] = {{1, "One"}, {2, "Several"}, {0, NULL}}; // mouse values are used once consvar_t cv_mousesens = CVAR_INIT ("mousesens", "20", CV_SAVE, mousesens_cons_t, NULL); consvar_t cv_mousesens2 = CVAR_INIT ("mousesens2", "20", CV_SAVE, mousesens_cons_t, NULL); consvar_t cv_mouseysens = CVAR_INIT ("mouseysens", "20", CV_SAVE, mousesens_cons_t, NULL); consvar_t cv_mouseysens2 = CVAR_INIT ("mouseysens2", "20", CV_SAVE, mousesens_cons_t, NULL); -consvar_t cv_controlperkey = CVAR_INIT ("controlperkey", "One", CV_SAVE, onecontrolperkey_cons_t, NULL); mouse_t mouse; mouse_t mouse2; @@ -1478,35 +1476,33 @@ void G_SaveKeySetting(FILE *f, INT32 (*fromcontrols)[2], INT32 (*fromcontrolsbis INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify, UINT8 player) { INT32 result = GC_NULL; - if (cv_controlperkey.value == 1) + INT32 i; + for (i = 0; i < NUM_GAMECONTROLS; i++) { - INT32 i; - for (i = 0; i < NUM_GAMECONTROLS; i++) + if (gamecontrol[i][0] == keynum && player != 2) { - if (gamecontrol[i][0] == keynum && player != 2) - { - result = i; - if (modify) gamecontrol[i][0] = KEY_NULL; - } - if (gamecontrol[i][1] == keynum && player != 2) - { - result = i; - if (modify) gamecontrol[i][1] = KEY_NULL; - } - if (gamecontrolbis[i][0] == keynum && player != 1) - { - result = i; - if (modify) gamecontrolbis[i][0] = KEY_NULL; - } - if (gamecontrolbis[i][1] == keynum && player != 1) - { - result = i; - if (modify) gamecontrolbis[i][1] = KEY_NULL; - } - if (result && !modify) - return result; + result = i; + if (modify) gamecontrol[i][0] = KEY_NULL; } + if (gamecontrol[i][1] == keynum && player != 2) + { + result = i; + if (modify) gamecontrol[i][1] = KEY_NULL; + } + if (gamecontrolbis[i][0] == keynum && player != 1) + { + result = i; + if (modify) gamecontrolbis[i][0] = KEY_NULL; + } + if (gamecontrolbis[i][1] == keynum && player != 1) + { + result = i; + if (modify) gamecontrolbis[i][1] = KEY_NULL; + } + if (result && !modify) + return result; } + return result; } @@ -1533,6 +1529,11 @@ static INT32 G_FilterSpecialKeys(INT32 keyidx, INT32 player, INT32 *keynum1, INT return *keynum1; } +static INT32 G_TranslateJoyKeys(INT32 *keynum1, INT32 *keynum2) +{ + +} + static void setcontrol(INT32 (*gc)[2]) { INT32 numctrl; diff --git a/src/g_input.h b/src/g_input.h index ff42d1489..bb50d3516 100644 --- a/src/g_input.h +++ b/src/g_input.h @@ -249,7 +249,6 @@ typedef enum // mouse values are used once extern consvar_t cv_mousesens, cv_mouseysens; extern consvar_t cv_mousesens2, cv_mouseysens2; -extern consvar_t cv_controlperkey; typedef struct { diff --git a/src/m_menu.c b/src/m_menu.c index 461a08552..29a07a28d 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1070,7 +1070,6 @@ static menuitem_t OP_MainMenu[] = { {IT_SUBMENU | IT_STRING, NULL, "Player 1 Controls...", &OP_P1ControlsDef, 10}, {IT_SUBMENU | IT_STRING, NULL, "Player 2 Controls...", &OP_P2ControlsDef, 20}, - {IT_CVAR | IT_STRING, NULL, "Controls per key", &cv_controlperkey, 30}, {IT_CALL | IT_STRING, NULL, "Video Options...", M_VideoOptions, 50}, {IT_SUBMENU | IT_STRING, NULL, "Sound Options...", &OP_SoundOptionsDef, 60}, From 1964869c69ff2d60b754f51779fce18edc20a602 Mon Sep 17 00:00:00 2001 From: spherallic Date: Thu, 22 Dec 2022 01:40:33 +0100 Subject: [PATCH 15/96] Remove redundant control axes & cleanup --- src/command.c | 160 ----------------------------------------------- src/d_netcmd.c | 8 --- src/deh_tables.c | 5 -- src/g_game.c | 59 +++-------------- src/g_game.h | 8 --- src/g_input.c | 13 ++-- src/m_menu.c | 47 ++++++++------ 7 files changed, 40 insertions(+), 260 deletions(-) diff --git a/src/command.c b/src/command.c index 9be081fb7..762752cdd 100644 --- a/src/command.c +++ b/src/command.c @@ -2177,132 +2177,6 @@ static void CV_EnforceExecVersion(void) CV_StealthSetValue(&cv_execversion, EXECVERSION); } -static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr) -{ - // If ALL axis settings are previous defaults, set them to the new defaults - // EXECVERSION < 26 (2.1.21) - - if (joyaxis_default) - { - if (!stricmp(v->name, "joyaxis_turn")) - { - if (joyaxis_count > 6) return false; - // we're currently setting the new defaults, don't interfere - else if (joyaxis_count == 6) return true; - - if (!stricmp(valstr, "X-Axis")) joyaxis_count++; - else joyaxis_default = false; - } - if (!stricmp(v->name, "joyaxis_move")) - { - if (joyaxis_count > 6) return false; - else if (joyaxis_count == 6) return true; - - if (!stricmp(valstr, "Y-Axis")) joyaxis_count++; - else joyaxis_default = false; - } - if (!stricmp(v->name, "joyaxis_side")) - { - if (joyaxis_count > 6) return false; - else if (joyaxis_count == 6) return true; - - if (!stricmp(valstr, "Z-Axis")) joyaxis_count++; - else joyaxis_default = false; - } - if (!stricmp(v->name, "joyaxis_look")) - { - if (joyaxis_count > 6) return false; - else if (joyaxis_count == 6) return true; - - if (!stricmp(valstr, "None")) joyaxis_count++; - else joyaxis_default = false; - } - if (!stricmp(v->name, "joyaxis_fire") - || !stricmp(v->name, "joyaxis_firenormal")) - { - if (joyaxis_count > 6) return false; - else if (joyaxis_count == 6) return true; - - if (!stricmp(valstr, "None")) joyaxis_count++; - else joyaxis_default = false; - } - // reset all axis settings to defaults - if (joyaxis_count == 6) - { - COM_BufInsertText(va("%s \"%s\"\n", cv_turnaxis[0].name, cv_turnaxis[0].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_moveaxis[0].name, cv_moveaxis[0].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_sideaxis[0].name, cv_sideaxis[0].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_lookaxis[0].name, cv_lookaxis[0].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_fireaxis[0].name, cv_fireaxis[0].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_firenaxis[0].name, cv_firenaxis[0].defaultvalue)); - joyaxis_count++; - return false; - } - } - - if (joyaxis2_default) - { - if (!stricmp(v->name, "joyaxis2_turn")) - { - if (joyaxis2_count > 6) return false; - // we're currently setting the new defaults, don't interfere - else if (joyaxis2_count == 6) return true; - - if (!stricmp(valstr, "X-Axis")) joyaxis2_count++; - else joyaxis2_default = false; - } - if (!stricmp(v->name, "joyaxis2_move")) - { - if (joyaxis2_count > 6) return false; - else if (joyaxis2_count == 6) return true; - - if (!stricmp(valstr, "Y-Axis")) joyaxis2_count++; - else joyaxis2_default = false; - } - if (!stricmp(v->name, "joyaxis2_side")) - { - if (joyaxis2_count > 6) return false; - else if (joyaxis2_count == 6) return true; - - if (!stricmp(valstr, "Z-Axis")) joyaxis2_count++; - else joyaxis2_default = false; - } - if (!stricmp(v->name, "joyaxis2_look")) - { - if (joyaxis2_count > 6) return false; - else if (joyaxis2_count == 6) return true; - - if (!stricmp(valstr, "None")) joyaxis2_count++; - else joyaxis2_default = false; - } - if (!stricmp(v->name, "joyaxis2_fire") - || !stricmp(v->name, "joyaxis2_firenormal")) - { - if (joyaxis2_count > 6) return false; - else if (joyaxis2_count == 6) return true; - - if (!stricmp(valstr, "None")) joyaxis2_count++; - else joyaxis2_default = false; - } - - // reset all axis settings to defaults - if (joyaxis2_count == 6) - { - COM_BufInsertText(va("%s \"%s\"\n", cv_turnaxis[1].name, cv_turnaxis[1].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_moveaxis[1].name, cv_moveaxis[1].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_sideaxis[1].name, cv_sideaxis[1].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_lookaxis[1].name, cv_lookaxis[1].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_fireaxis[1].name, cv_fireaxis[1].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_firenaxis[1].name, cv_firenaxis[1].defaultvalue)); - joyaxis2_count++; - return false; - } - } - - // we haven't reached our counts yet, or we're not default - return true; -} - #ifndef OLD_GAMEPAD_AXES static boolean CV_ConvertOldJoyAxisVars(consvar_t *v, const char *valstr) { @@ -2355,40 +2229,6 @@ static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr) if (!(v->flags & CV_SAVE)) return true; - if (GETMAJOREXECVERSION(cv_execversion.value) < 26) // 26 = 2.1.21 - { - // MOUSE SETTINGS - // alwaysfreelook split between first and third person (chasefreelook) - // mousemove was on by default, which invalidates the current approach - if (!stricmp(v->name, "alwaysmlook") - || !stricmp(v->name, "alwaysmlook2") - || !stricmp(v->name, "mousemove") - || !stricmp(v->name, "mousemove2")) - return false; - - // mousesens was changed from 35 to 20 due to oversensitivity - if ((!stricmp(v->name, "mousesens") - || !stricmp(v->name, "mousesens2") - || !stricmp(v->name, "mouseysens") - || !stricmp(v->name, "mouseysens2")) - && atoi(valstr) == 35) - return false; - - // GAMEPAD DEFAULTS - // use_gamepad was changed from 0 to 1 to automatically use a gamepad if available -#if defined(HAVE_SDL) || defined(_WINDOWS) - if ((!stricmp(v->name, "use_joystick") - || !stricmp(v->name, "use_joystick2")) - && atoi(valstr) == 0) - return false; -#endif - - // axis defaults were changed to be friendly to 360 controllers - // if ALL axis settings are defaults, then change them to new values - if (!CV_FilterJoyAxisVars(v, valstr)) - return false; - } - #ifndef OLD_GAMEPAD_AXES if (GETMAJOREXECVERSION(cv_execversion.value) <= 51 && GETMINOREXECVERSION(cv_execversion.value) < 1) { diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 5dc391109..f64d51a43 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -814,14 +814,6 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_moveaxis[1]); CV_RegisterVar(&cv_lookaxis[0]); CV_RegisterVar(&cv_lookaxis[1]); - CV_RegisterVar(&cv_jumpaxis[0]); - CV_RegisterVar(&cv_jumpaxis[1]); - CV_RegisterVar(&cv_spinaxis[0]); - CV_RegisterVar(&cv_spinaxis[1]); - CV_RegisterVar(&cv_fireaxis[0]); - CV_RegisterVar(&cv_fireaxis[1]); - CV_RegisterVar(&cv_firenaxis[0]); - CV_RegisterVar(&cv_firenaxis[1]); CV_RegisterVar(&cv_deadzone[0]); CV_RegisterVar(&cv_deadzone[1]); CV_RegisterVar(&cv_digitaldeadzone[0]); diff --git a/src/deh_tables.c b/src/deh_tables.c index a2cc9732d..90c3047a8 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5648,11 +5648,6 @@ struct int_const_s const INT_CONST[] = { {"JA_MOVE",JA_MOVE}, {"JA_LOOK",JA_LOOK}, {"JA_STRAFE",JA_STRAFE}, - {"JA_DIGITAL",JA_DIGITAL}, - {"JA_JUMP",JA_JUMP}, - {"JA_SPIN",JA_SPIN}, - {"JA_FIRE",JA_FIRE}, - {"JA_FIRENORMAL",JA_FIRENORMAL}, {"JOYAXISRANGE",OLDJOYAXISRANGE}, // Game controls diff --git a/src/g_game.c b/src/g_game.c index c832af0a5..dc12c2bab 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -299,15 +299,11 @@ CV_PossibleValue_t joyaxis_cons_t[] = {{0, "None"}, #define SIDEAXIS_DEFAULT "Left Stick X" #define LOOKAXIS_DEFAULT "Right Stick Y" #define TURNAXIS_DEFAULT "Right Stick X" -#define FIREAXIS_DEFAULT "None" -#define FIRENAXIS_DEFAULT "None" #else #define MOVEAXIS_DEFAULT "Y-Axis" #define SIDEAXIS_DEFAULT "X-Axis" #define LOOKAXIS_DEFAULT "Y-Rudder-" #define TURNAXIS_DEFAULT "X-Rudder" -#define FIREAXIS_DEFAULT "Z-Rudder" -#define FIRENAXIS_DEFAULT "Z-Axis" #endif // don't mind me putting these here, I was lazy to figure out where else I could put those without blowing up the compiler. @@ -439,22 +435,6 @@ consvar_t cv_turnaxis[2] = { CVAR_INIT ("joyaxis_turn", TURNAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL), CVAR_INIT ("joyaxis2_turn", TURNAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL) }; -consvar_t cv_jumpaxis[2] = { - CVAR_INIT ("joyaxis_jump", "None", CV_SAVE, joyaxis_cons_t, NULL), - CVAR_INIT ("joyaxis2_jump", "None", CV_SAVE, joyaxis_cons_t, NULL) -}; -consvar_t cv_spinaxis[2] = { - CVAR_INIT ("joyaxis_spin", "None", CV_SAVE, joyaxis_cons_t, NULL), - CVAR_INIT ("joyaxis2_spin", "None", CV_SAVE, joyaxis_cons_t, NULL) -}; -consvar_t cv_fireaxis[2] = { - CVAR_INIT ("joyaxis_fire", FIREAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL), - CVAR_INIT ("joyaxis2_fire", FIREAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL) -}; -consvar_t cv_firenaxis[2] = { - CVAR_INIT ("joyaxis_firenormal", FIRENAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL), - CVAR_INIT ("joyaxis2_firenormal", FIRENAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL) -}; consvar_t cv_deadzone[2] = { CVAR_INIT ("joy_deadzone", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), CVAR_INIT ("joy_deadzone2", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL) @@ -890,7 +870,7 @@ static gamepad_axis_e ConvertXboxControllerAxes(int type) } #endif -static INT16 GetJoystickAxisValue(UINT8 which, joyaxis_e axissel, INT32 axisval) +static INT16 GetJoystickAxisValue(INT32 axisval) { boolean flp = false; @@ -925,14 +905,7 @@ static INT16 GetJoystickAxisValue(UINT8 which, joyaxis_e axissel, INT32 axisval) } INT16 retaxis = G_GetGamepadAxisValue(0, gp_axis); - - if (gamepads[which].digital && axissel >= JA_DIGITAL) - { - const UINT16 jdeadzone = G_GetGamepadDigitalDeadZone(which) / 2; - if (-jdeadzone < retaxis && retaxis < jdeadzone) - return 0; - } - + // flip it around if (flp) { @@ -965,23 +938,11 @@ INT16 G_JoyAxis(UINT8 which, joyaxis_e axissel) case JA_STRAFE: axisval = cv_sideaxis[which].value; break; - case JA_JUMP: - axisval = cv_jumpaxis[which].value; - break; - case JA_SPIN: - axisval = cv_spinaxis[which].value; - break; - case JA_FIRE: - axisval = cv_fireaxis[which].value; - break; - case JA_FIRENORMAL: - axisval = cv_firenaxis[which].value; - break; default: return 0; } - value = GetJoystickAxisValue(which, axissel, axisval); + value = GetJoystickAxisValue(axisval); if (axissel == JA_LOOK) { // Look is inverted because +Y goes _down_ in gamepads. @@ -1092,7 +1053,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) boolean forcestrafe = false; boolean forcefullinput = false; - INT32 tspeed, forward, side, axis, strafeaxis, moveaxis, turnaxis, lookaxis, i; + INT32 tspeed, forward, side, strafeaxis, moveaxis, turnaxis, lookaxis, i; joystickvector2_t movejoystickvector, lookjoystickvector; @@ -1378,13 +1339,11 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) } // fire with any button/key - axis = G_JoyAxis(forplayer, JA_FIRE); - if (G_PlayerInputDown(forplayer, GC_FIRE) || (usegamepad && axis > 0)) + if (G_PlayerInputDown(forplayer, GC_FIRE)) cmd->buttons |= BT_ATTACK; // fire normal with any button/key - axis = G_JoyAxis(forplayer, JA_FIRENORMAL); - if (G_PlayerInputDown(forplayer, GC_FIRENORMAL) || (usegamepad && axis > 0)) + if (G_PlayerInputDown(forplayer, GC_FIRENORMAL)) cmd->buttons |= BT_FIRENORMAL; if (G_PlayerInputDown(forplayer, GC_TOSSFLAG)) @@ -1399,8 +1358,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) cmd->buttons |= BT_CUSTOM3; // spin with any button/key - axis = G_JoyAxis(forplayer, JA_SPIN); - if (G_PlayerInputDown(forplayer, GC_SPIN) || (usegamepad && axis > 0)) + if (G_PlayerInputDown(forplayer, GC_SPIN)) cmd->buttons |= BT_SPIN; // Centerview can be a toggle in simple mode! @@ -1516,8 +1474,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) resetdown[forplayer] = false; // jump button - axis = G_JoyAxis(forplayer, JA_JUMP); - if (G_PlayerInputDown(forplayer, GC_JUMP) || (usegamepad && axis > 0)) + if (G_PlayerInputDown(forplayer, GC_JUMP)) cmd->buttons |= BT_JUMP; // player aiming shit, ahhhh... diff --git a/src/g_game.h b/src/g_game.h index e798176af..8d6e84b12 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -71,7 +71,6 @@ extern consvar_t cv_autobrake, cv_autobrake2; extern consvar_t cv_ghost_bestscore, cv_ghost_besttime, cv_ghost_bestrings, cv_ghost_last, cv_ghost_guest; extern consvar_t cv_sideaxis[2], cv_turnaxis[2], cv_moveaxis[2], cv_lookaxis[2], - cv_jumpaxis[2], cv_spinaxis[2], cv_fireaxis[2], cv_firenaxis[2], cv_deadzone[2], cv_digitaldeadzone[2]; extern CV_PossibleValue_t joyaxis_cons_t[]; @@ -98,13 +97,6 @@ typedef enum JA_MOVE, JA_LOOK, JA_STRAFE, - - JA_DIGITAL, // axes henceforth use digital deadzone - - JA_JUMP = JA_DIGITAL, - JA_SPIN, - JA_FIRE, - JA_FIRENORMAL, } joyaxis_e; INT16 G_JoyAxis(UINT8 which, joyaxis_e axissel); diff --git a/src/g_input.c b/src/g_input.c index ee9f8a24b..58a51fd89 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -1506,7 +1506,7 @@ INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify, UINT8 player) return result; } -static INT32 G_FilterSpecialKeys(INT32 keyidx, INT32 player, INT32 *keynum1, INT32 *keynum2) +static INT32 G_FilterSpecialKeys(INT32 keyidx, INT32 *keynum1, INT32 *keynum2) { // Special case: ignore KEY_PAUSE because it's hardcoded if (keyidx == 0 && *keynum1 == KEY_PAUSE) @@ -1529,11 +1529,6 @@ static INT32 G_FilterSpecialKeys(INT32 keyidx, INT32 player, INT32 *keynum1, INT return *keynum1; } -static INT32 G_TranslateJoyKeys(INT32 *keynum1, INT32 *keynum2) -{ - -} - static void setcontrol(INT32 (*gc)[2]) { INT32 numctrl; @@ -1554,7 +1549,7 @@ static void setcontrol(INT32 (*gc)[2]) } keynum1 = G_KeyNameToNum(COM_Argv(2)); keynum2 = G_KeyNameToNum(COM_Argv(3)); - keynum = G_FilterSpecialKeys(0, player, &keynum1, &keynum2); + keynum = G_FilterSpecialKeys(0, &keynum1, &keynum2); if (keynum >= 0) { @@ -1565,7 +1560,7 @@ static void setcontrol(INT32 (*gc)[2]) { keynum1 = keynum2; // push down keynum2 keynum2 = 0; - keynum = G_FilterSpecialKeys(0, player, &keynum1, &keynum2); + keynum = G_FilterSpecialKeys(0, &keynum1, &keynum2); if (keynum >= 0) (void)G_CheckDoubleUsage(keynum, true, player+1); } @@ -1576,7 +1571,7 @@ static void setcontrol(INT32 (*gc)[2]) if (keynum2) { - keynum = G_FilterSpecialKeys(1, player, &keynum1, &keynum2); + keynum = G_FilterSpecialKeys(1, &keynum1, &keynum2); if (keynum >= 0) { if (keynum != gc[numctrl][0]) diff --git a/src/m_menu.c b/src/m_menu.c index 29a07a28d..71cb2cbec 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1071,7 +1071,8 @@ static menuitem_t OP_MainMenu[] = {IT_SUBMENU | IT_STRING, NULL, "Player 1 Controls...", &OP_P1ControlsDef, 10}, {IT_SUBMENU | IT_STRING, NULL, "Player 2 Controls...", &OP_P2ControlsDef, 20}, - {IT_CALL | IT_STRING, NULL, "Video Options...", M_VideoOptions, 50}, + {IT_CALL | IT_STRING, NULL, "Video Options...", M_VideoOptions, 40}, + {IT_SUBMENU | IT_STRING, NULL, "Sound Options...", &OP_SoundOptionsDef, 60}, {IT_CALL | IT_STRING, NULL, "Server Options...", M_ServerOptions, 80}, @@ -1079,6 +1080,16 @@ static menuitem_t OP_MainMenu[] = {IT_SUBMENU | IT_STRING, NULL, "Data Options...", &OP_DataOptionsDef, 100}, }; +enum +{ + opplayer1, + opplayer2, + opvideo, + opsound, + opserver, + opdata +}; + static menuitem_t OP_P1ControlsMenu[] = { {IT_CALL | IT_STRING, NULL, "Control Configuration...", M_Setup1PControlsMenu, 10}, @@ -1166,15 +1177,11 @@ static menuitem_t OP_Gamepad1Menu[] = {IT_STRING | IT_CVAR, NULL, "Move \x18 Axis" , &cv_sideaxis[0] , 40}, {IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis[0] , 50}, {IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis[0] , 60}, - {IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis[0] , 70}, - {IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis[0] , 80}, - {IT_STRING | IT_CVAR, NULL, "Fire Axis" , &cv_fireaxis[0] , 90}, - {IT_STRING | IT_CVAR, NULL, "Fire Normal Axis" , &cv_firenaxis[0] ,100}, - {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook, 120}, - {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook, 130}, - {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Analog Deadzone", &cv_deadzone[0], 140}, - {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Digital Deadzone", &cv_digitaldeadzone[0], 150}, + {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook, 80}, + {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook, 90}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Analog Deadzone", &cv_deadzone[0], 100}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Digital Deadzone", &cv_digitaldeadzone[0], 110}, }; static menuitem_t OP_Gamepad2Menu[] = @@ -1184,15 +1191,11 @@ static menuitem_t OP_Gamepad2Menu[] = {IT_STRING | IT_CVAR, NULL, "Move \x18 Axis" , &cv_sideaxis[1] , 40}, {IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis[1] , 50}, {IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis[1] , 60}, - {IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis[1] , 70}, - {IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis[1] , 80}, - {IT_STRING | IT_CVAR, NULL, "Fire Axis" , &cv_fireaxis[1] , 90}, - {IT_STRING | IT_CVAR, NULL, "Fire Normal Axis" , &cv_firenaxis[1] ,100}, - {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook2,120}, - {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook2, 130}, - {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Analog Deadzone", &cv_deadzone[1],140}, - {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Digital Deadzone", &cv_digitaldeadzone[1],150}, + {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook2,80}, + {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook2, 90}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Analog Deadzone", &cv_deadzone[1],100}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Digital Deadzone", &cv_digitaldeadzone[1],110}, }; static menuitem_t OP_GamepadSetMenu[MAX_CONNECTED_GAMEPADS + 1]; @@ -1540,6 +1543,12 @@ static menuitem_t OP_DataOptionsMenu[] = {IT_STRING | IT_SUBMENU, NULL, "\x85" "Erase Data...", &OP_EraseDataDef, 40}, }; +enum{ + opdataaddon, + opdatascreenshot, + opdataerase +}; + static menuitem_t OP_ScreenshotOptionsMenu[] = { {IT_HEADER, NULL, "General", NULL, 0}, @@ -7028,10 +7037,10 @@ static void M_Options(INT32 choice) (void)choice; // if the player is not admin or server, disable server options - OP_MainMenu[5].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); + OP_MainMenu[opserver].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); // if the player is playing _at all_, disable the erase data options - OP_DataOptionsMenu[2].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); + OP_DataOptionsMenu[opdataerase].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); OP_MainDef.prevMenu = currentMenu; M_SetupNextMenu(&OP_MainDef); From f3988231d4f71f7290f2b7d877bb5d1b8beaa381 Mon Sep 17 00:00:00 2001 From: spherallic Date: Thu, 22 Dec 2022 14:40:35 +0100 Subject: [PATCH 16/96] Convert old joy## constants --- src/g_input.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/src/g_input.c b/src/g_input.c index 58a51fd89..41b051a25 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -960,9 +960,6 @@ static keyname_t keynames[] = DEF_GAMEPAD_AXIS(TRIGGERLEFT, "left trigger"), DEF_GAMEPAD_AXIS(TRIGGERRIGHT, "right trigger"), -#undef DEF_GAMEPAD_NAME -#undef DEF_GAMEPAD_AXIS - {KEY_DBLMOUSE1+0, "dblmouse1"}, {KEY_DBLMOUSE1+1, "dblmouse2"}, {KEY_DBLMOUSE1+2, "dblmouse3"}, @@ -981,7 +978,50 @@ static keyname_t keynames[] = {KEY_DBL2MOUSE1+7, "dblsec_mouse8"} }; +static keyname_t oldjoynames[] = +{ + DEF_GAMEPAD_NAME(A, "joy1"), + DEF_GAMEPAD_NAME(B, "joy2"), + DEF_GAMEPAD_NAME(X, "joy3"), + DEF_GAMEPAD_NAME(Y, "joy4"), + + DEF_GAMEPAD_NAME(BACK, "joy7"), + DEF_GAMEPAD_NAME(START, "joy8"), + DEF_GAMEPAD_NAME(LEFTSTICK, "joy9"), + DEF_GAMEPAD_NAME(RIGHTSTICK, "joy10"), + + DEF_GAMEPAD_NAME(LEFTSHOULDER, "joy5"), + DEF_GAMEPAD_NAME(RIGHTSHOULDER, "joy6"), + + DEF_GAMEPAD_NAME(DPAD_UP, "hatup"), + DEF_GAMEPAD_NAME(DPAD_DOWN, "hatdown"), + DEF_GAMEPAD_NAME(DPAD_LEFT, "hatleft"), + DEF_GAMEPAD_NAME(DPAD_RIGHT, "hatright"), + + DEF_GAMEPAD_NAME(A, "sec_joy1"), + DEF_GAMEPAD_NAME(B, "sec_joy2"), + DEF_GAMEPAD_NAME(X, "sec_joy3"), + DEF_GAMEPAD_NAME(Y, "sec_joy4"), + + DEF_GAMEPAD_NAME(BACK, "sec_joy7"), + DEF_GAMEPAD_NAME(START, "sec_joy8"), + DEF_GAMEPAD_NAME(LEFTSTICK, "sec_joy9"), + DEF_GAMEPAD_NAME(RIGHTSTICK, "sec_joy10"), + + DEF_GAMEPAD_NAME(LEFTSHOULDER, "sec_joy5"), + DEF_GAMEPAD_NAME(RIGHTSHOULDER, "sec_joy6"), + + DEF_GAMEPAD_NAME(DPAD_UP, "sec_hatup"), + DEF_GAMEPAD_NAME(DPAD_DOWN, "sec_hatdown"), + DEF_GAMEPAD_NAME(DPAD_LEFT, "sec_hatleft"), + DEF_GAMEPAD_NAME(DPAD_RIGHT, "sec_hatright"), +}; + +#undef DEF_GAMEPAD_NAME +#undef DEF_GAMEPAD_AXIS + #define NUMKEYNAMES (sizeof(keynames) / sizeof(keyname_t)) +#define NUMOLDJOYNAMES (sizeof(oldjoynames) / sizeof(keyname_t)) static keyname_t displaykeynames[] = { @@ -1270,6 +1310,10 @@ INT32 G_KeyNameToNum(const char *keystr) if (!stricmp(keynames[j].name, keystr)) return keynames[j].keynum; + for (j = 0; j < NUMOLDJOYNAMES; j++) + if (!stricmp(oldjoynames[j].name, keystr)) + return oldjoynames[j].keynum; + return 0; } From 98d544b459b1a618ef2d913a35ff8ab8a584c7c2 Mon Sep 17 00:00:00 2001 From: MIDIManNoah <59802822+MIDIManNoah@users.noreply.github.com> Date: Fri, 23 Dec 2022 22:19:09 -0500 Subject: [PATCH 17/96] Make some fixes for Metal Sonic's boss fight --- src/info.c | 8 ++++---- src/p_mobj.c | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/info.c b/src/info.c index c4c197027..174eb5cc4 100644 --- a/src/info.c +++ b/src/info.c @@ -1758,14 +1758,14 @@ state_t states[NUMSTATES] = // Metal Sonic {SPR_PLAY, SPR2_STND, -1, {NULL}, 0, 0, S_METALSONIC_RACE}, // S_METALSONIC_RACE - {SPR_METL, 4, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_FLOAT + {SPR_METL, 4, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_FLOAT {SPR_METL, 16|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_METALSONIC_STUN}, // S_METALSONIC_VECTOR {SPR_METL, 15, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_STUN {SPR_METL, 17, 20, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_RAISE - {SPR_METL, 18, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_GATHER + {SPR_METL, 18, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_GATHER {SPR_METL, 6|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 1, 2, S_METALSONIC_BOUNCE},// S_METALSONIC_DASH - {SPR_METL, 18|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 1, 2, S_NULL}, // S_METALSONIC_BOUNCE - {SPR_METL, 14, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BADBOUNCE + {SPR_METL, 18|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 1, 2, S_METALSONIC_FLOAT}, // S_METALSONIC_BOUNCE + {SPR_METL, 14, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_BADBOUNCE {SPR_METL, 17, -1, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_SHOOT {SPR_METL, 15, 40, {A_Pain}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_PAIN {SPR_METL, 17, 2, {A_Fall}, 0, 0, S_METALSONIC_DEATH2},// S_METALSONIC_DEATH1 diff --git a/src/p_mobj.c b/src/p_mobj.c index 49c438b3f..e1657c12f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5664,6 +5664,8 @@ static void P_Boss9Thinker(mobj_t *mobj) { mobj_t *missile = P_SpawnMissile(spawner, mobj, MT_MSGATHER); missile->fuse = (dist/P_AproxDistance(missile->momx, missile->momy)); + if (missile->fuse <= 0) // Prevents a division by zero when calculating missile->scalespeed + missile->fuse = 1; if (missile->fuse > mobj->fuse) P_RemoveMobj(missile); From f5ede24775db9ec453775cf9ad5c6c060374099b Mon Sep 17 00:00:00 2001 From: spherallic Date: Tue, 27 Dec 2022 11:44:56 +0100 Subject: [PATCH 18/96] Fix gamepad being unable to skip tutorial prompt --- src/m_menu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 71cb2cbec..69c056319 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -3466,7 +3466,7 @@ boolean M_Responder(event_t *ev) if (!useEventHandler) { UINT16 type = currentMenu->menuitems[itemOn].alphaKey; - if (type == MM_YESNO && !(ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE || ch == KEY_ENTER || ch == KEY_DEL)) + if (type == MM_YESNO && !(ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE || ch == KEY_ENTER || ch == KEY_DEL || ch == KEY_BACKSPACE)) return true; if (routine) routine(ch); @@ -9115,7 +9115,7 @@ static void M_LoadGame(INT32 choice) if (tutorialmap && cv_tutorialprompt.value) { - M_StartMessage("Do you want to \x82play a brief Tutorial\x80?\n\nWe highly recommend this because \nthe controls are slightly different \nfrom other games.\n\nPress the\x82 Y\x80 key or the\x83 A button\x80 to go\nPress the\x82 N\x80 key or the\x83 Y button\x80 to skip\n", + M_StartMessage("Do you want to \x82play a brief Tutorial\x80?\n\nWe highly recommend this because \nthe controls are slightly different \nfrom other games.\n\nPress the\x82 Y\x80 key or the\x83 A button\x80 to go\nPress the\x82 N\x80 key or the\x83 X button\x80 to skip\n", M_FirstTimeResponse, MM_YESNO); return; } From d7606fd85a9a63e96feb74568f68042d43fe126e Mon Sep 17 00:00:00 2001 From: spherallic Date: Tue, 27 Dec 2022 13:48:42 +0100 Subject: [PATCH 19/96] { --- src/m_menu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 69c056319..79b23ac2f 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1543,7 +1543,8 @@ static menuitem_t OP_DataOptionsMenu[] = {IT_STRING | IT_SUBMENU, NULL, "\x85" "Erase Data...", &OP_EraseDataDef, 40}, }; -enum{ +enum +{ opdataaddon, opdatascreenshot, opdataerase From 58e5473c9efd2d521f768217918efd1328228e87 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Tue, 27 Dec 2022 20:26:08 +0100 Subject: [PATCH 20/96] Fix integer overflow with diagonal node splits Fixes random invisible walls and possibly more errors --- src/r_main.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/r_main.c b/src/r_main.c index cd5e255ed..3763092fc 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -266,13 +266,13 @@ INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node) if (!node->dy) return y <= node->y ? node->dx < 0 : node->dx > 0; - x -= node->x; - y -= node->y; + fixed_t dx = (x >> 1) - (node->x >> 1); + fixed_t dy = (y >> 1) - (node->y >> 1); // Try to quickly decide by looking at sign bits. - if ((node->dy ^ node->dx ^ x ^ y) < 0) - return (node->dy ^ x) < 0; // (left is negative) - return FixedMul(y, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, x); + if ((node->dy ^ node->dx ^ dx ^ dy) < 0) + return (node->dy ^ dx) < 0; // (left is negative) + return FixedMul(dy, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, dx); } // killough 5/2/98: reformatted @@ -289,13 +289,13 @@ INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line) if (!ldy) return y <= ly ? ldx < 0 : ldx > 0; - x -= lx; - y -= ly; + fixed_t dx = (x >> 1) - (lx >> 1); + fixed_t dy = (y >> 1) - (ly >> 1); // Try to quickly decide by looking at sign bits. - if ((ldy ^ ldx ^ x ^ y) < 0) - return (ldy ^ x) < 0; // (left is negative) - return FixedMul(y, ldx>>FRACBITS) >= FixedMul(ldy>>FRACBITS, x); + if ((ldy ^ ldx ^ dx ^ dy) < 0) + return (ldy ^ dx) < 0; // (left is negative) + return FixedMul(dy, ldx>>FRACBITS) >= FixedMul(ldy>>FRACBITS, dx); } // From c8e579618a4de098a4540a6769adcdf1c91d2346 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Tue, 27 Dec 2022 20:29:15 +0100 Subject: [PATCH 21/96] Fix maps with more than 65535 segs not working correctly This renders the "quadrant hack" and ZenNode largely useless --- src/p_setup.c | 2 +- src/r_defs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index cd9185484..5309705f6 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3009,7 +3009,7 @@ static inline void P_LoadSubsectors(UINT8 *data) for (i = 0; i < numsubsectors; i++, ss++, ms++) { ss->numlines = SHORT(ms->numsegs); - ss->firstline = SHORT(ms->firstseg); + ss->firstline = (UINT16)SHORT(ms->firstseg); P_InitializeSubsector(ss); } } diff --git a/src/r_defs.h b/src/r_defs.h index dbede806e..3746643c6 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -587,7 +587,7 @@ typedef struct subsector_s { sector_t *sector; INT16 numlines; - UINT16 firstline; + UINT32 firstline; struct polyobj_s *polyList; // haleyjd 02/19/06: list of polyobjects size_t validcount; } subsector_t; From d03ef0a4417381d6f404336da67056b5b542223e Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Tue, 27 Dec 2022 20:31:55 +0100 Subject: [PATCH 22/96] Fix HOMs in large rooms Credits go to Lactozilla --- src/r_bsp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/r_bsp.c b/src/r_bsp.c index bf238a435..c9c169a51 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -399,8 +399,8 @@ static void R_AddLine(seg_t *line) return; // big room fix - angle1 = R_PointToAngleEx(viewx, viewy, line->v1->x, line->v1->y); - angle2 = R_PointToAngleEx(viewx, viewy, line->v2->x, line->v2->y); + angle1 = R_PointToAngle64(line->v1->x, line->v1->y); + angle2 = R_PointToAngle64(line->v2->x, line->v2->y); curline = line; // Clip to view edges. @@ -620,8 +620,8 @@ static boolean R_CheckBBox(const fixed_t *bspcoord) check = checkcoord[boxpos]; // big room fix - angle1 = R_PointToAngleEx(viewx, viewy, bspcoord[check[0]], bspcoord[check[1]]) - viewangle; - angle2 = R_PointToAngleEx(viewx, viewy, bspcoord[check[2]], bspcoord[check[3]]) - viewangle; + angle1 = R_PointToAngle64(bspcoord[check[0]], bspcoord[check[1]]) - viewangle; + angle2 = R_PointToAngle64(bspcoord[check[2]], bspcoord[check[3]]) - viewangle; if ((signed)angle1 < (signed)angle2) { From ffbe140af59e1010092cf194903c96cc292e8d10 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Wed, 28 Dec 2022 16:12:05 +0100 Subject: [PATCH 23/96] Move snake minigame to its own files --- src/Sourcefile | 1 + src/d_clisrv.c | 525 +----------------------------------------------- src/snake.c | 535 +++++++++++++++++++++++++++++++++++++++++++++++++ src/snake.h | 20 ++ 4 files changed, 564 insertions(+), 517 deletions(-) create mode 100644 src/snake.c create mode 100644 src/snake.h diff --git a/src/Sourcefile b/src/Sourcefile index 9de90eee4..83e9ebc3b 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -83,6 +83,7 @@ i_tcp.c lzf.c vid_copy.s b_bot.c +snake.c lua_script.c lua_baselib.c lua_mathlib.c diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 3091f3344..be10e4f9b 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -57,6 +57,7 @@ // cl loading screen #include "v_video.h" #include "f_finale.h" +#include "snake.h" #endif // @@ -543,505 +544,7 @@ static cl_mode_t cl_mode = CL_SEARCHING; static UINT16 cl_lastcheckedfilecount = 0; // used for full file list #ifndef NONET -#define SNAKE_SPEED 5 - -#define SNAKE_NUM_BLOCKS_X 20 -#define SNAKE_NUM_BLOCKS_Y 10 -#define SNAKE_BLOCK_SIZE 12 -#define SNAKE_BORDER_SIZE 12 - -#define SNAKE_MAP_WIDTH (SNAKE_NUM_BLOCKS_X * SNAKE_BLOCK_SIZE) -#define SNAKE_MAP_HEIGHT (SNAKE_NUM_BLOCKS_Y * SNAKE_BLOCK_SIZE) - -#define SNAKE_LEFT_X ((BASEVIDWIDTH - SNAKE_MAP_WIDTH) / 2 - SNAKE_BORDER_SIZE) -#define SNAKE_RIGHT_X (SNAKE_LEFT_X + SNAKE_MAP_WIDTH + SNAKE_BORDER_SIZE * 2 - 1) -#define SNAKE_BOTTOM_Y (BASEVIDHEIGHT - 48) -#define SNAKE_TOP_Y (SNAKE_BOTTOM_Y - SNAKE_MAP_HEIGHT - SNAKE_BORDER_SIZE * 2 + 1) - -enum snake_bonustype_s { - SNAKE_BONUS_NONE = 0, - SNAKE_BONUS_SLOW, - SNAKE_BONUS_FAST, - SNAKE_BONUS_GHOST, - SNAKE_BONUS_NUKE, - SNAKE_BONUS_SCISSORS, - SNAKE_BONUS_REVERSE, - SNAKE_BONUS_EGGMAN, - SNAKE_NUM_BONUSES, -}; - -static const char *snake_bonuspatches[] = { - NULL, - "DL_SLOW", - "TVSSC0", - "TVIVC0", - "TVARC0", - "DL_SCISSORS", - "TVRCC0", - "TVEGC0", -}; - -static const char *snake_backgrounds[] = { - "RVPUMICF", - "FRSTRCKF", - "TAR", - "MMFLRB4", - "RVDARKF1", - "RVZWALF1", - "RVZWALF4", - "RVZWALF5", - "RVZGRS02", - "RVZGRS04", -}; - -typedef struct snake_s -{ - boolean paused; - boolean pausepressed; - tic_t time; - tic_t nextupdate; - boolean gameover; - UINT8 background; - - UINT16 snakelength; - enum snake_bonustype_s snakebonus; - tic_t snakebonustime; - UINT8 snakex[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; - UINT8 snakey[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; - UINT8 snakedir[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; - - UINT8 applex; - UINT8 appley; - - enum snake_bonustype_s bonustype; - UINT8 bonusx; - UINT8 bonusy; -} snake_t; - -static snake_t *snake = NULL; - -static void Snake_Initialise(void) -{ - if (!snake) - snake = malloc(sizeof(snake_t)); - - snake->paused = false; - snake->pausepressed = false; - snake->time = 0; - snake->nextupdate = SNAKE_SPEED; - snake->gameover = false; - snake->background = M_RandomKey(sizeof(snake_backgrounds) / sizeof(*snake_backgrounds)); - - snake->snakelength = 1; - snake->snakebonus = SNAKE_BONUS_NONE; - snake->snakex[0] = M_RandomKey(SNAKE_NUM_BLOCKS_X); - snake->snakey[0] = M_RandomKey(SNAKE_NUM_BLOCKS_Y); - snake->snakedir[0] = 0; - snake->snakedir[1] = 0; - - snake->applex = M_RandomKey(SNAKE_NUM_BLOCKS_X); - snake->appley = M_RandomKey(SNAKE_NUM_BLOCKS_Y); - - snake->bonustype = SNAKE_BONUS_NONE; -} - -static UINT8 Snake_GetOppositeDir(UINT8 dir) -{ - if (dir == 1 || dir == 3) - return dir + 1; - else if (dir == 2 || dir == 4) - return dir - 1; - else - return 12 + 5 - dir; -} - -static void Snake_FindFreeSlot(UINT8 *freex, UINT8 *freey, UINT8 headx, UINT8 heady) -{ - UINT8 x, y; - UINT16 i; - - do - { - x = M_RandomKey(SNAKE_NUM_BLOCKS_X); - y = M_RandomKey(SNAKE_NUM_BLOCKS_Y); - - for (i = 0; i < snake->snakelength; i++) - if (x == snake->snakex[i] && y == snake->snakey[i]) - break; - } while (i < snake->snakelength || (x == headx && y == heady) - || (x == snake->applex && y == snake->appley) - || (snake->bonustype != SNAKE_BONUS_NONE && x == snake->bonusx && y == snake->bonusy)); - - *freex = x; - *freey = y; -} - -static void Snake_Handle(void) -{ - UINT8 x, y; - UINT8 oldx, oldy; - UINT16 i; - UINT16 joystate = 0; - - // Handle retry - if (snake->gameover && (G_PlayerInputDown(0, GC_JUMP) || gamekeydown[KEY_ENTER])) - { - Snake_Initialise(); - snake->pausepressed = true; // Avoid accidental pause on respawn - } - - // Handle pause - if (G_PlayerInputDown(0, GC_PAUSE) || gamekeydown[KEY_ENTER]) - { - if (!snake->pausepressed) - snake->paused = !snake->paused; - snake->pausepressed = true; - } - else - snake->pausepressed = false; - - if (snake->paused) - return; - - snake->time++; - - x = snake->snakex[0]; - y = snake->snakey[0]; - oldx = snake->snakex[1]; - oldy = snake->snakey[1]; - - // Update direction - if (G_PlayerInputDown(0, GC_STRAFELEFT) || gamekeydown[KEY_LEFTARROW] || joystate == 3) - { - if (snake->snakelength < 2 || x <= oldx) - snake->snakedir[0] = 1; - } - else if (G_PlayerInputDown(0, GC_STRAFERIGHT) || gamekeydown[KEY_RIGHTARROW] || joystate == 4) - { - if (snake->snakelength < 2 || x >= oldx) - snake->snakedir[0] = 2; - } - else if (G_PlayerInputDown(0, GC_FORWARD) || gamekeydown[KEY_UPARROW] || joystate == 1) - { - if (snake->snakelength < 2 || y <= oldy) - snake->snakedir[0] = 3; - } - else if (G_PlayerInputDown(0, GC_BACKWARD) || gamekeydown[KEY_DOWNARROW] || joystate == 2) - { - if (snake->snakelength < 2 || y >= oldy) - snake->snakedir[0] = 4; - } - - if (snake->snakebonustime) - { - snake->snakebonustime--; - if (!snake->snakebonustime) - snake->snakebonus = SNAKE_BONUS_NONE; - } - - snake->nextupdate--; - if (snake->nextupdate) - return; - if (snake->snakebonus == SNAKE_BONUS_SLOW) - snake->nextupdate = SNAKE_SPEED * 2; - else if (snake->snakebonus == SNAKE_BONUS_FAST) - snake->nextupdate = SNAKE_SPEED * 2 / 3; - else - snake->nextupdate = SNAKE_SPEED; - - if (snake->gameover) - return; - - // Find new position - switch (snake->snakedir[0]) - { - case 1: - if (x > 0) - x--; - else - snake->gameover = true; - break; - case 2: - if (x < SNAKE_NUM_BLOCKS_X - 1) - x++; - else - snake->gameover = true; - break; - case 3: - if (y > 0) - y--; - else - snake->gameover = true; - break; - case 4: - if (y < SNAKE_NUM_BLOCKS_Y - 1) - y++; - else - snake->gameover = true; - break; - } - - // Check collision with snake - if (snake->snakebonus != SNAKE_BONUS_GHOST) - for (i = 1; i < snake->snakelength - 1; i++) - if (x == snake->snakex[i] && y == snake->snakey[i]) - { - if (snake->snakebonus == SNAKE_BONUS_SCISSORS) - { - snake->snakebonus = SNAKE_BONUS_NONE; - snake->snakelength = i; - S_StartSound(NULL, sfx_adderr); - } - else - snake->gameover = true; - } - - if (snake->gameover) - { - S_StartSound(NULL, sfx_lose); - return; - } - - // Check collision with apple - if (x == snake->applex && y == snake->appley) - { - if (snake->snakelength + 3 < SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y) - { - snake->snakelength++; - snake->snakex [snake->snakelength - 1] = snake->snakex [snake->snakelength - 2]; - snake->snakey [snake->snakelength - 1] = snake->snakey [snake->snakelength - 2]; - snake->snakedir[snake->snakelength - 1] = snake->snakedir[snake->snakelength - 2]; - } - - // Spawn new apple - Snake_FindFreeSlot(&snake->applex, &snake->appley, x, y); - - // Spawn new bonus - if (!(snake->snakelength % 5)) - { - do - { - snake->bonustype = M_RandomKey(SNAKE_NUM_BONUSES - 1) + 1; - } while (snake->snakelength > SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y * 3 / 4 - && (snake->bonustype == SNAKE_BONUS_EGGMAN || snake->bonustype == SNAKE_BONUS_FAST || snake->bonustype == SNAKE_BONUS_REVERSE)); - - Snake_FindFreeSlot(&snake->bonusx, &snake->bonusy, x, y); - } - - S_StartSound(NULL, sfx_s3k6b); - } - - if (snake->snakelength > 1 && snake->snakedir[0]) - { - UINT8 dir = snake->snakedir[0]; - - oldx = snake->snakex[1]; - oldy = snake->snakey[1]; - - // Move - for (i = snake->snakelength - 1; i > 0; i--) - { - snake->snakex[i] = snake->snakex[i - 1]; - snake->snakey[i] = snake->snakey[i - 1]; - snake->snakedir[i] = snake->snakedir[i - 1]; - } - - // Handle corners - if (x < oldx && dir == 3) - dir = 5; - else if (x > oldx && dir == 3) - dir = 6; - else if (x < oldx && dir == 4) - dir = 7; - else if (x > oldx && dir == 4) - dir = 8; - else if (y < oldy && dir == 1) - dir = 9; - else if (y < oldy && dir == 2) - dir = 10; - else if (y > oldy && dir == 1) - dir = 11; - else if (y > oldy && dir == 2) - dir = 12; - snake->snakedir[1] = dir; - } - - snake->snakex[0] = x; - snake->snakey[0] = y; - - // Check collision with bonus - if (snake->bonustype != SNAKE_BONUS_NONE && x == snake->bonusx && y == snake->bonusy) - { - S_StartSound(NULL, sfx_ncchip); - - switch (snake->bonustype) - { - case SNAKE_BONUS_SLOW: - snake->snakebonus = SNAKE_BONUS_SLOW; - snake->snakebonustime = 20 * TICRATE; - break; - case SNAKE_BONUS_FAST: - snake->snakebonus = SNAKE_BONUS_FAST; - snake->snakebonustime = 20 * TICRATE; - break; - case SNAKE_BONUS_GHOST: - snake->snakebonus = SNAKE_BONUS_GHOST; - snake->snakebonustime = 10 * TICRATE; - break; - case SNAKE_BONUS_NUKE: - for (i = 0; i < snake->snakelength; i++) - { - snake->snakex [i] = snake->snakex [0]; - snake->snakey [i] = snake->snakey [0]; - snake->snakedir[i] = snake->snakedir[0]; - } - - S_StartSound(NULL, sfx_bkpoof); - break; - case SNAKE_BONUS_SCISSORS: - snake->snakebonus = SNAKE_BONUS_SCISSORS; - snake->snakebonustime = 60 * TICRATE; - break; - case SNAKE_BONUS_REVERSE: - for (i = 0; i < (snake->snakelength + 1) / 2; i++) - { - UINT16 i2 = snake->snakelength - 1 - i; - UINT8 tmpx = snake->snakex [i]; - UINT8 tmpy = snake->snakey [i]; - UINT8 tmpdir = snake->snakedir[i]; - - // Swap first segment with last segment - snake->snakex [i] = snake->snakex [i2]; - snake->snakey [i] = snake->snakey [i2]; - snake->snakedir[i] = Snake_GetOppositeDir(snake->snakedir[i2]); - snake->snakex [i2] = tmpx; - snake->snakey [i2] = tmpy; - snake->snakedir[i2] = Snake_GetOppositeDir(tmpdir); - } - - snake->snakedir[0] = 0; - - S_StartSound(NULL, sfx_gravch); - break; - default: - if (snake->snakebonus != SNAKE_BONUS_GHOST) - { - snake->gameover = true; - S_StartSound(NULL, sfx_lose); - } - } - - snake->bonustype = SNAKE_BONUS_NONE; - } -} - -static void Snake_Draw(void) -{ - INT16 i; - - // Background - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); - - V_DrawFlatFill( - SNAKE_LEFT_X + SNAKE_BORDER_SIZE, - SNAKE_TOP_Y + SNAKE_BORDER_SIZE, - SNAKE_MAP_WIDTH, - SNAKE_MAP_HEIGHT, - W_GetNumForName(snake_backgrounds[snake->background]) - ); - - // Borders - V_DrawFill(SNAKE_LEFT_X, SNAKE_TOP_Y, SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_BORDER_SIZE, 242); // Top - V_DrawFill(SNAKE_LEFT_X + SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_TOP_Y, SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, 242); // Right - V_DrawFill(SNAKE_LEFT_X + SNAKE_BORDER_SIZE, SNAKE_TOP_Y + SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_BORDER_SIZE, 242); // Bottom - V_DrawFill(SNAKE_LEFT_X, SNAKE_TOP_Y + SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, 242); // Left - - // Apple - V_DrawFixedPatch( - (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->applex * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, - (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->appley * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, - FRACUNIT / 4, - 0, - W_CachePatchLongName("DL_APPLE", PU_HUDGFX), - NULL - ); - - // Bonus - if (snake->bonustype != SNAKE_BONUS_NONE) - V_DrawFixedPatch( - (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->bonusx * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2 ) * FRACUNIT, - (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->bonusy * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2 + 4) * FRACUNIT, - FRACUNIT / 2, - 0, - W_CachePatchLongName(snake_bonuspatches[snake->bonustype], PU_HUDGFX), - NULL - ); - - // Snake - if (!snake->gameover || snake->time % 8 < 8 / 2) // Blink if game over - { - for (i = snake->snakelength - 1; i >= 0; i--) - { - const char *patchname; - UINT8 dir = snake->snakedir[i]; - - if (i == 0) // Head - { - switch (dir) - { - case 1: patchname = "DL_SNAKEHEAD_L"; break; - case 2: patchname = "DL_SNAKEHEAD_R"; break; - case 3: patchname = "DL_SNAKEHEAD_T"; break; - case 4: patchname = "DL_SNAKEHEAD_B"; break; - default: patchname = "DL_SNAKEHEAD_M"; - } - } - else // Body - { - switch (dir) - { - case 1: patchname = "DL_SNAKEBODY_L"; break; - case 2: patchname = "DL_SNAKEBODY_R"; break; - case 3: patchname = "DL_SNAKEBODY_T"; break; - case 4: patchname = "DL_SNAKEBODY_B"; break; - case 5: patchname = "DL_SNAKEBODY_LT"; break; - case 6: patchname = "DL_SNAKEBODY_RT"; break; - case 7: patchname = "DL_SNAKEBODY_LB"; break; - case 8: patchname = "DL_SNAKEBODY_RB"; break; - case 9: patchname = "DL_SNAKEBODY_TL"; break; - case 10: patchname = "DL_SNAKEBODY_TR"; break; - case 11: patchname = "DL_SNAKEBODY_BL"; break; - case 12: patchname = "DL_SNAKEBODY_BR"; break; - default: patchname = "DL_SNAKEBODY_B"; - } - } - - V_DrawFixedPatch( - (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->snakex[i] * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, - (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->snakey[i] * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, - i == 0 && dir == 0 ? FRACUNIT / 5 : FRACUNIT / 2, - snake->snakebonus == SNAKE_BONUS_GHOST ? V_TRANSLUCENT : 0, - W_CachePatchLongName(patchname, PU_HUDGFX), - NULL - ); - } - } - - // Length - V_DrawString(SNAKE_RIGHT_X + 4, SNAKE_TOP_Y, V_MONOSPACE, va("%u", snake->snakelength)); - - // Bonus - if (snake->snakebonus != SNAKE_BONUS_NONE - && (snake->snakebonustime >= 3 * TICRATE || snake->time % 4 < 4 / 2)) - V_DrawFixedPatch( - (SNAKE_RIGHT_X + 10) * FRACUNIT, - (SNAKE_TOP_Y + 24) * FRACUNIT, - FRACUNIT / 2, - 0, - W_CachePatchLongName(snake_bonuspatches[snake->snakebonus], PU_HUDGFX), - NULL - ); -} +static void *snake = NULL; static void CL_DrawConnectionStatusBox(void) { @@ -1167,7 +670,7 @@ static inline void CL_DrawConnectionStatus(void) char *filename; if (snake) - Snake_Draw(); + Snake_Draw(snake); // Draw the bottom box. CL_DrawConnectionStatusBox(); @@ -1213,7 +716,7 @@ static inline void CL_DrawConnectionStatus(void) else { if (snake) - Snake_Draw(); + Snake_Draw(snake); CL_DrawConnectionStatusBox(); V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, @@ -1950,7 +1453,7 @@ static void M_ConfirmConnect(event_t *ev) if (CL_SendFileRequest()) { cl_mode = CL_DOWNLOADFILES; - Snake_Initialise(); + Snake_Allocate(&snake); } } else @@ -2300,13 +1803,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic if (waitmore) break; // exit the case -#ifndef NONET - if (snake) - { - free(snake); - snake = NULL; - } -#endif + Snake_Free(&snake); cl_mode = CL_LOADFILES; break; @@ -2401,13 +1898,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic CONS_Printf(M_GetText("Network game synchronization aborted.\n")); M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); -#ifndef NONET - if (snake) - { - free(snake); - snake = NULL; - } -#endif + Snake_Free(&snake); D_QuitNetGame(); CL_Reset(); @@ -2417,7 +1908,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic } #ifndef NONET else if (cl_mode == CL_DOWNLOADFILES && snake) - Snake_Handle(); + Snake_Update(snake); #endif if (client && (cl_mode == CL_DOWNLOADFILES || cl_mode == CL_DOWNLOADSAVEGAME)) diff --git a/src/snake.c b/src/snake.c new file mode 100644 index 000000000..2c80adeb9 --- /dev/null +++ b/src/snake.c @@ -0,0 +1,535 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2023-2023 by Louis-Antoine de Moulins de Rochefort. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file snake.c +/// \brief Snake minigame for the download screen. + +#include "snake.h" +#include "g_input.h" +#include "m_random.h" +#include "s_sound.h" +#include "screen.h" +#include "v_video.h" +#include "w_wad.h" +#include "z_zone.h" + +#define SNAKE_SPEED 5 + +#define SNAKE_NUM_BLOCKS_X 20 +#define SNAKE_NUM_BLOCKS_Y 10 +#define SNAKE_BLOCK_SIZE 12 +#define SNAKE_BORDER_SIZE 12 + +#define SNAKE_MAP_WIDTH (SNAKE_NUM_BLOCKS_X * SNAKE_BLOCK_SIZE) +#define SNAKE_MAP_HEIGHT (SNAKE_NUM_BLOCKS_Y * SNAKE_BLOCK_SIZE) + +#define SNAKE_LEFT_X ((BASEVIDWIDTH - SNAKE_MAP_WIDTH) / 2 - SNAKE_BORDER_SIZE) +#define SNAKE_RIGHT_X (SNAKE_LEFT_X + SNAKE_MAP_WIDTH + SNAKE_BORDER_SIZE * 2 - 1) +#define SNAKE_BOTTOM_Y (BASEVIDHEIGHT - 48) +#define SNAKE_TOP_Y (SNAKE_BOTTOM_Y - SNAKE_MAP_HEIGHT - SNAKE_BORDER_SIZE * 2 + 1) + +enum snake_bonustype_s { + SNAKE_BONUS_NONE = 0, + SNAKE_BONUS_SLOW, + SNAKE_BONUS_FAST, + SNAKE_BONUS_GHOST, + SNAKE_BONUS_NUKE, + SNAKE_BONUS_SCISSORS, + SNAKE_BONUS_REVERSE, + SNAKE_BONUS_EGGMAN, + SNAKE_NUM_BONUSES, +}; + +typedef struct snake_s +{ + boolean paused; + boolean pausepressed; + tic_t time; + tic_t nextupdate; + boolean gameover; + UINT8 background; + + UINT16 snakelength; + enum snake_bonustype_s snakebonus; + tic_t snakebonustime; + UINT8 snakex[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; + UINT8 snakey[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; + UINT8 snakedir[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; + + UINT8 applex; + UINT8 appley; + + enum snake_bonustype_s bonustype; + UINT8 bonusx; + UINT8 bonusy; +} snake_t; + +static const char *snake_bonuspatches[] = { + NULL, + "DL_SLOW", + "TVSSC0", + "TVIVC0", + "TVARC0", + "DL_SCISSORS", + "TVRCC0", + "TVEGC0", +}; + +static const char *snake_backgrounds[] = { + "RVPUMICF", + "FRSTRCKF", + "TAR", + "MMFLRB4", + "RVDARKF1", + "RVZWALF1", + "RVZWALF4", + "RVZWALF5", + "RVZGRS02", + "RVZGRS04", +}; + +static void Snake_Initialise(snake_t *snake) +{ + snake->paused = false; + snake->pausepressed = false; + snake->time = 0; + snake->nextupdate = SNAKE_SPEED; + snake->gameover = false; + snake->background = M_RandomKey(sizeof(snake_backgrounds) / sizeof(*snake_backgrounds)); + + snake->snakelength = 1; + snake->snakebonus = SNAKE_BONUS_NONE; + snake->snakex[0] = M_RandomKey(SNAKE_NUM_BLOCKS_X); + snake->snakey[0] = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + snake->snakedir[0] = 0; + snake->snakedir[1] = 0; + + snake->applex = M_RandomKey(SNAKE_NUM_BLOCKS_X); + snake->appley = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + + snake->bonustype = SNAKE_BONUS_NONE; +} + +static UINT8 Snake_GetOppositeDir(UINT8 dir) +{ + if (dir == 1 || dir == 3) + return dir + 1; + else if (dir == 2 || dir == 4) + return dir - 1; + else + return 12 + 5 - dir; +} + +static void Snake_FindFreeSlot(snake_t *snake, UINT8 *freex, UINT8 *freey, UINT8 headx, UINT8 heady) +{ + UINT8 x, y; + UINT16 i; + + do + { + x = M_RandomKey(SNAKE_NUM_BLOCKS_X); + y = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + + for (i = 0; i < snake->snakelength; i++) + if (x == snake->snakex[i] && y == snake->snakey[i]) + break; + } while (i < snake->snakelength || (x == headx && y == heady) + || (x == snake->applex && y == snake->appley) + || (snake->bonustype != SNAKE_BONUS_NONE && x == snake->bonusx && y == snake->bonusy)); + + *freex = x; + *freey = y; +} + +void Snake_Allocate(void **opaque) +{ + if (*opaque) + Snake_Free(opaque); + *opaque = malloc(sizeof(snake_t)); + Snake_Initialise(*opaque); +} + +void Snake_Update(void *opaque) +{ + UINT8 x, y; + UINT8 oldx, oldy; + UINT16 i; + UINT16 joystate = 0; + + snake_t *snake = opaque; + + // Handle retry + if (snake->gameover && (G_PlayerInputDown(0, GC_JUMP) || gamekeydown[KEY_ENTER])) + { + Snake_Initialise(snake); + snake->pausepressed = true; // Avoid accidental pause on respawn + } + + // Handle pause + if (G_PlayerInputDown(0, GC_PAUSE) || gamekeydown[KEY_ENTER]) + { + if (!snake->pausepressed) + snake->paused = !snake->paused; + snake->pausepressed = true; + } + else + snake->pausepressed = false; + + if (snake->paused) + return; + + snake->time++; + + x = snake->snakex[0]; + y = snake->snakey[0]; + oldx = snake->snakex[1]; + oldy = snake->snakey[1]; + + // Update direction + if (G_PlayerInputDown(0, GC_STRAFELEFT) || gamekeydown[KEY_LEFTARROW] || joystate == 3) + { + if (snake->snakelength < 2 || x <= oldx) + snake->snakedir[0] = 1; + } + else if (G_PlayerInputDown(0, GC_STRAFERIGHT) || gamekeydown[KEY_RIGHTARROW] || joystate == 4) + { + if (snake->snakelength < 2 || x >= oldx) + snake->snakedir[0] = 2; + } + else if (G_PlayerInputDown(0, GC_FORWARD) || gamekeydown[KEY_UPARROW] || joystate == 1) + { + if (snake->snakelength < 2 || y <= oldy) + snake->snakedir[0] = 3; + } + else if (G_PlayerInputDown(0, GC_BACKWARD) || gamekeydown[KEY_DOWNARROW] || joystate == 2) + { + if (snake->snakelength < 2 || y >= oldy) + snake->snakedir[0] = 4; + } + + if (snake->snakebonustime) + { + snake->snakebonustime--; + if (!snake->snakebonustime) + snake->snakebonus = SNAKE_BONUS_NONE; + } + + snake->nextupdate--; + if (snake->nextupdate) + return; + if (snake->snakebonus == SNAKE_BONUS_SLOW) + snake->nextupdate = SNAKE_SPEED * 2; + else if (snake->snakebonus == SNAKE_BONUS_FAST) + snake->nextupdate = SNAKE_SPEED * 2 / 3; + else + snake->nextupdate = SNAKE_SPEED; + + if (snake->gameover) + return; + + // Find new position + switch (snake->snakedir[0]) + { + case 1: + if (x > 0) + x--; + else + snake->gameover = true; + break; + case 2: + if (x < SNAKE_NUM_BLOCKS_X - 1) + x++; + else + snake->gameover = true; + break; + case 3: + if (y > 0) + y--; + else + snake->gameover = true; + break; + case 4: + if (y < SNAKE_NUM_BLOCKS_Y - 1) + y++; + else + snake->gameover = true; + break; + } + + // Check collision with snake + if (snake->snakebonus != SNAKE_BONUS_GHOST) + for (i = 1; i < snake->snakelength - 1; i++) + if (x == snake->snakex[i] && y == snake->snakey[i]) + { + if (snake->snakebonus == SNAKE_BONUS_SCISSORS) + { + snake->snakebonus = SNAKE_BONUS_NONE; + snake->snakelength = i; + S_StartSound(NULL, sfx_adderr); + } + else + snake->gameover = true; + } + + if (snake->gameover) + { + S_StartSound(NULL, sfx_lose); + return; + } + + // Check collision with apple + if (x == snake->applex && y == snake->appley) + { + if (snake->snakelength + 3 < SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y) + { + snake->snakelength++; + snake->snakex [snake->snakelength - 1] = snake->snakex [snake->snakelength - 2]; + snake->snakey [snake->snakelength - 1] = snake->snakey [snake->snakelength - 2]; + snake->snakedir[snake->snakelength - 1] = snake->snakedir[snake->snakelength - 2]; + } + + // Spawn new apple + Snake_FindFreeSlot(snake, &snake->applex, &snake->appley, x, y); + + // Spawn new bonus + if (!(snake->snakelength % 5)) + { + do + { + snake->bonustype = M_RandomKey(SNAKE_NUM_BONUSES - 1) + 1; + } while (snake->snakelength > SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y * 3 / 4 + && (snake->bonustype == SNAKE_BONUS_EGGMAN || snake->bonustype == SNAKE_BONUS_FAST || snake->bonustype == SNAKE_BONUS_REVERSE)); + + Snake_FindFreeSlot(snake, &snake->bonusx, &snake->bonusy, x, y); + } + + S_StartSound(NULL, sfx_s3k6b); + } + + if (snake->snakelength > 1 && snake->snakedir[0]) + { + UINT8 dir = snake->snakedir[0]; + + oldx = snake->snakex[1]; + oldy = snake->snakey[1]; + + // Move + for (i = snake->snakelength - 1; i > 0; i--) + { + snake->snakex[i] = snake->snakex[i - 1]; + snake->snakey[i] = snake->snakey[i - 1]; + snake->snakedir[i] = snake->snakedir[i - 1]; + } + + // Handle corners + if (x < oldx && dir == 3) + dir = 5; + else if (x > oldx && dir == 3) + dir = 6; + else if (x < oldx && dir == 4) + dir = 7; + else if (x > oldx && dir == 4) + dir = 8; + else if (y < oldy && dir == 1) + dir = 9; + else if (y < oldy && dir == 2) + dir = 10; + else if (y > oldy && dir == 1) + dir = 11; + else if (y > oldy && dir == 2) + dir = 12; + snake->snakedir[1] = dir; + } + + snake->snakex[0] = x; + snake->snakey[0] = y; + + // Check collision with bonus + if (snake->bonustype != SNAKE_BONUS_NONE && x == snake->bonusx && y == snake->bonusy) + { + S_StartSound(NULL, sfx_ncchip); + + switch (snake->bonustype) + { + case SNAKE_BONUS_SLOW: + snake->snakebonus = SNAKE_BONUS_SLOW; + snake->snakebonustime = 20 * TICRATE; + break; + case SNAKE_BONUS_FAST: + snake->snakebonus = SNAKE_BONUS_FAST; + snake->snakebonustime = 20 * TICRATE; + break; + case SNAKE_BONUS_GHOST: + snake->snakebonus = SNAKE_BONUS_GHOST; + snake->snakebonustime = 10 * TICRATE; + break; + case SNAKE_BONUS_NUKE: + for (i = 0; i < snake->snakelength; i++) + { + snake->snakex [i] = snake->snakex [0]; + snake->snakey [i] = snake->snakey [0]; + snake->snakedir[i] = snake->snakedir[0]; + } + + S_StartSound(NULL, sfx_bkpoof); + break; + case SNAKE_BONUS_SCISSORS: + snake->snakebonus = SNAKE_BONUS_SCISSORS; + snake->snakebonustime = 60 * TICRATE; + break; + case SNAKE_BONUS_REVERSE: + for (i = 0; i < (snake->snakelength + 1) / 2; i++) + { + UINT16 i2 = snake->snakelength - 1 - i; + UINT8 tmpx = snake->snakex [i]; + UINT8 tmpy = snake->snakey [i]; + UINT8 tmpdir = snake->snakedir[i]; + + // Swap first segment with last segment + snake->snakex [i] = snake->snakex [i2]; + snake->snakey [i] = snake->snakey [i2]; + snake->snakedir[i] = Snake_GetOppositeDir(snake->snakedir[i2]); + snake->snakex [i2] = tmpx; + snake->snakey [i2] = tmpy; + snake->snakedir[i2] = Snake_GetOppositeDir(tmpdir); + } + + snake->snakedir[0] = 0; + + S_StartSound(NULL, sfx_gravch); + break; + default: + if (snake->snakebonus != SNAKE_BONUS_GHOST) + { + snake->gameover = true; + S_StartSound(NULL, sfx_lose); + } + } + + snake->bonustype = SNAKE_BONUS_NONE; + } +} + +void Snake_Draw(void *opaque) +{ + INT16 i; + + snake_t *snake = opaque; + + // Background + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); + + V_DrawFlatFill( + SNAKE_LEFT_X + SNAKE_BORDER_SIZE, + SNAKE_TOP_Y + SNAKE_BORDER_SIZE, + SNAKE_MAP_WIDTH, + SNAKE_MAP_HEIGHT, + W_GetNumForName(snake_backgrounds[snake->background]) + ); + + // Borders + V_DrawFill(SNAKE_LEFT_X, SNAKE_TOP_Y, SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_BORDER_SIZE, 242); // Top + V_DrawFill(SNAKE_LEFT_X + SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_TOP_Y, SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, 242); // Right + V_DrawFill(SNAKE_LEFT_X + SNAKE_BORDER_SIZE, SNAKE_TOP_Y + SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_BORDER_SIZE, 242); // Bottom + V_DrawFill(SNAKE_LEFT_X, SNAKE_TOP_Y + SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, 242); // Left + + // Apple + V_DrawFixedPatch( + (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->applex * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->appley * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + FRACUNIT / 4, + 0, + W_CachePatchLongName("DL_APPLE", PU_HUDGFX), + NULL + ); + + // Bonus + if (snake->bonustype != SNAKE_BONUS_NONE) + V_DrawFixedPatch( + (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->bonusx * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2 ) * FRACUNIT, + (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->bonusy * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2 + 4) * FRACUNIT, + FRACUNIT / 2, + 0, + W_CachePatchLongName(snake_bonuspatches[snake->bonustype], PU_HUDGFX), + NULL + ); + + // Snake + if (!snake->gameover || snake->time % 8 < 8 / 2) // Blink if game over + { + for (i = snake->snakelength - 1; i >= 0; i--) + { + const char *patchname; + UINT8 dir = snake->snakedir[i]; + + if (i == 0) // Head + { + switch (dir) + { + case 1: patchname = "DL_SNAKEHEAD_L"; break; + case 2: patchname = "DL_SNAKEHEAD_R"; break; + case 3: patchname = "DL_SNAKEHEAD_T"; break; + case 4: patchname = "DL_SNAKEHEAD_B"; break; + default: patchname = "DL_SNAKEHEAD_M"; + } + } + else // Body + { + switch (dir) + { + case 1: patchname = "DL_SNAKEBODY_L"; break; + case 2: patchname = "DL_SNAKEBODY_R"; break; + case 3: patchname = "DL_SNAKEBODY_T"; break; + case 4: patchname = "DL_SNAKEBODY_B"; break; + case 5: patchname = "DL_SNAKEBODY_LT"; break; + case 6: patchname = "DL_SNAKEBODY_RT"; break; + case 7: patchname = "DL_SNAKEBODY_LB"; break; + case 8: patchname = "DL_SNAKEBODY_RB"; break; + case 9: patchname = "DL_SNAKEBODY_TL"; break; + case 10: patchname = "DL_SNAKEBODY_TR"; break; + case 11: patchname = "DL_SNAKEBODY_BL"; break; + case 12: patchname = "DL_SNAKEBODY_BR"; break; + default: patchname = "DL_SNAKEBODY_B"; + } + } + + V_DrawFixedPatch( + (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->snakex[i] * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->snakey[i] * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + i == 0 && dir == 0 ? FRACUNIT / 5 : FRACUNIT / 2, + snake->snakebonus == SNAKE_BONUS_GHOST ? V_TRANSLUCENT : 0, + W_CachePatchLongName(patchname, PU_HUDGFX), + NULL + ); + } + } + + // Length + V_DrawString(SNAKE_RIGHT_X + 4, SNAKE_TOP_Y, V_MONOSPACE, va("%u", snake->snakelength)); + + // Bonus + if (snake->snakebonus != SNAKE_BONUS_NONE + && (snake->snakebonustime >= 3 * TICRATE || snake->time % 4 < 4 / 2)) + V_DrawFixedPatch( + (SNAKE_RIGHT_X + 10) * FRACUNIT, + (SNAKE_TOP_Y + 24) * FRACUNIT, + FRACUNIT / 2, + 0, + W_CachePatchLongName(snake_bonuspatches[snake->snakebonus], PU_HUDGFX), + NULL + ); +} + +void Snake_Free(void **opaque) +{ + if (*opaque) + { + free(opaque); + *opaque = NULL; + } +} diff --git a/src/snake.h b/src/snake.h new file mode 100644 index 000000000..a3106bb0f --- /dev/null +++ b/src/snake.h @@ -0,0 +1,20 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2023-2023 by Louis-Antoine de Moulins de Rochefort. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file snake.h +/// \brief Snake minigame for the download screen. + +#ifndef __SNAKE__ +#define __SNAKE__ + +void Snake_Allocate(void **opaque); +void Snake_Update(void *opaque); +void Snake_Draw(void *opaque); +void Snake_Free(void **opaque); + +#endif From 33c76453e11bc06d4ec9b8c26937dc443581c8f4 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Wed, 28 Dec 2022 18:50:00 +0100 Subject: [PATCH 24/96] Remove snake_ prefix --- src/snake.c | 198 ++++++++++++++++++++++++++-------------------------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/src/snake.c b/src/snake.c index 2c80adeb9..21e79401d 100644 --- a/src/snake.c +++ b/src/snake.c @@ -18,31 +18,31 @@ #include "w_wad.h" #include "z_zone.h" -#define SNAKE_SPEED 5 +#define SPEED 5 -#define SNAKE_NUM_BLOCKS_X 20 -#define SNAKE_NUM_BLOCKS_Y 10 -#define SNAKE_BLOCK_SIZE 12 -#define SNAKE_BORDER_SIZE 12 +#define NUM_BLOCKS_X 20 +#define NUM_BLOCKS_Y 10 +#define BLOCK_SIZE 12 +#define BORDER_SIZE 12 -#define SNAKE_MAP_WIDTH (SNAKE_NUM_BLOCKS_X * SNAKE_BLOCK_SIZE) -#define SNAKE_MAP_HEIGHT (SNAKE_NUM_BLOCKS_Y * SNAKE_BLOCK_SIZE) +#define MAP_WIDTH (NUM_BLOCKS_X * BLOCK_SIZE) +#define MAP_HEIGHT (NUM_BLOCKS_Y * BLOCK_SIZE) -#define SNAKE_LEFT_X ((BASEVIDWIDTH - SNAKE_MAP_WIDTH) / 2 - SNAKE_BORDER_SIZE) -#define SNAKE_RIGHT_X (SNAKE_LEFT_X + SNAKE_MAP_WIDTH + SNAKE_BORDER_SIZE * 2 - 1) -#define SNAKE_BOTTOM_Y (BASEVIDHEIGHT - 48) -#define SNAKE_TOP_Y (SNAKE_BOTTOM_Y - SNAKE_MAP_HEIGHT - SNAKE_BORDER_SIZE * 2 + 1) +#define LEFT_X ((BASEVIDWIDTH - MAP_WIDTH) / 2 - BORDER_SIZE) +#define RIGHT_X (LEFT_X + MAP_WIDTH + BORDER_SIZE * 2 - 1) +#define BOTTOM_Y (BASEVIDHEIGHT - 48) +#define TOP_Y (BOTTOM_Y - MAP_HEIGHT - BORDER_SIZE * 2 + 1) -enum snake_bonustype_s { - SNAKE_BONUS_NONE = 0, - SNAKE_BONUS_SLOW, - SNAKE_BONUS_FAST, - SNAKE_BONUS_GHOST, - SNAKE_BONUS_NUKE, - SNAKE_BONUS_SCISSORS, - SNAKE_BONUS_REVERSE, - SNAKE_BONUS_EGGMAN, - SNAKE_NUM_BONUSES, +enum bonustype_s { + BONUS_NONE = 0, + BONUS_SLOW, + BONUS_FAST, + BONUS_GHOST, + BONUS_NUKE, + BONUS_SCISSORS, + BONUS_REVERSE, + BONUS_EGGMAN, + NUM_BONUSES, }; typedef struct snake_s @@ -55,21 +55,21 @@ typedef struct snake_s UINT8 background; UINT16 snakelength; - enum snake_bonustype_s snakebonus; + enum bonustype_s snakebonus; tic_t snakebonustime; - UINT8 snakex[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; - UINT8 snakey[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; - UINT8 snakedir[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; + UINT8 snakex[NUM_BLOCKS_X * NUM_BLOCKS_Y]; + UINT8 snakey[NUM_BLOCKS_X * NUM_BLOCKS_Y]; + UINT8 snakedir[NUM_BLOCKS_X * NUM_BLOCKS_Y]; UINT8 applex; UINT8 appley; - enum snake_bonustype_s bonustype; + enum bonustype_s bonustype; UINT8 bonusx; UINT8 bonusy; } snake_t; -static const char *snake_bonuspatches[] = { +static const char *bonuspatches[] = { NULL, "DL_SLOW", "TVSSC0", @@ -80,7 +80,7 @@ static const char *snake_bonuspatches[] = { "TVEGC0", }; -static const char *snake_backgrounds[] = { +static const char *backgrounds[] = { "RVPUMICF", "FRSTRCKF", "TAR", @@ -93,29 +93,29 @@ static const char *snake_backgrounds[] = { "RVZGRS04", }; -static void Snake_Initialise(snake_t *snake) +static void Initialise(snake_t *snake) { snake->paused = false; snake->pausepressed = false; snake->time = 0; - snake->nextupdate = SNAKE_SPEED; + snake->nextupdate = SPEED; snake->gameover = false; - snake->background = M_RandomKey(sizeof(snake_backgrounds) / sizeof(*snake_backgrounds)); + snake->background = M_RandomKey(sizeof(backgrounds) / sizeof(*backgrounds)); snake->snakelength = 1; - snake->snakebonus = SNAKE_BONUS_NONE; - snake->snakex[0] = M_RandomKey(SNAKE_NUM_BLOCKS_X); - snake->snakey[0] = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + snake->snakebonus = BONUS_NONE; + snake->snakex[0] = M_RandomKey(NUM_BLOCKS_X); + snake->snakey[0] = M_RandomKey(NUM_BLOCKS_Y); snake->snakedir[0] = 0; snake->snakedir[1] = 0; - snake->applex = M_RandomKey(SNAKE_NUM_BLOCKS_X); - snake->appley = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + snake->applex = M_RandomKey(NUM_BLOCKS_X); + snake->appley = M_RandomKey(NUM_BLOCKS_Y); - snake->bonustype = SNAKE_BONUS_NONE; + snake->bonustype = BONUS_NONE; } -static UINT8 Snake_GetOppositeDir(UINT8 dir) +static UINT8 GetOppositeDir(UINT8 dir) { if (dir == 1 || dir == 3) return dir + 1; @@ -125,22 +125,22 @@ static UINT8 Snake_GetOppositeDir(UINT8 dir) return 12 + 5 - dir; } -static void Snake_FindFreeSlot(snake_t *snake, UINT8 *freex, UINT8 *freey, UINT8 headx, UINT8 heady) +static void FindFreeSlot(snake_t *snake, UINT8 *freex, UINT8 *freey, UINT8 headx, UINT8 heady) { UINT8 x, y; UINT16 i; do { - x = M_RandomKey(SNAKE_NUM_BLOCKS_X); - y = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + x = M_RandomKey(NUM_BLOCKS_X); + y = M_RandomKey(NUM_BLOCKS_Y); for (i = 0; i < snake->snakelength; i++) if (x == snake->snakex[i] && y == snake->snakey[i]) break; } while (i < snake->snakelength || (x == headx && y == heady) || (x == snake->applex && y == snake->appley) - || (snake->bonustype != SNAKE_BONUS_NONE && x == snake->bonusx && y == snake->bonusy)); + || (snake->bonustype != BONUS_NONE && x == snake->bonusx && y == snake->bonusy)); *freex = x; *freey = y; @@ -151,7 +151,7 @@ void Snake_Allocate(void **opaque) if (*opaque) Snake_Free(opaque); *opaque = malloc(sizeof(snake_t)); - Snake_Initialise(*opaque); + Initialise(*opaque); } void Snake_Update(void *opaque) @@ -166,7 +166,7 @@ void Snake_Update(void *opaque) // Handle retry if (snake->gameover && (G_PlayerInputDown(0, GC_JUMP) || gamekeydown[KEY_ENTER])) { - Snake_Initialise(snake); + Initialise(snake); snake->pausepressed = true; // Avoid accidental pause on respawn } @@ -216,18 +216,18 @@ void Snake_Update(void *opaque) { snake->snakebonustime--; if (!snake->snakebonustime) - snake->snakebonus = SNAKE_BONUS_NONE; + snake->snakebonus = BONUS_NONE; } snake->nextupdate--; if (snake->nextupdate) return; - if (snake->snakebonus == SNAKE_BONUS_SLOW) - snake->nextupdate = SNAKE_SPEED * 2; - else if (snake->snakebonus == SNAKE_BONUS_FAST) - snake->nextupdate = SNAKE_SPEED * 2 / 3; + if (snake->snakebonus == BONUS_SLOW) + snake->nextupdate = SPEED * 2; + else if (snake->snakebonus == BONUS_FAST) + snake->nextupdate = SPEED * 2 / 3; else - snake->nextupdate = SNAKE_SPEED; + snake->nextupdate = SPEED; if (snake->gameover) return; @@ -242,7 +242,7 @@ void Snake_Update(void *opaque) snake->gameover = true; break; case 2: - if (x < SNAKE_NUM_BLOCKS_X - 1) + if (x < NUM_BLOCKS_X - 1) x++; else snake->gameover = true; @@ -254,7 +254,7 @@ void Snake_Update(void *opaque) snake->gameover = true; break; case 4: - if (y < SNAKE_NUM_BLOCKS_Y - 1) + if (y < NUM_BLOCKS_Y - 1) y++; else snake->gameover = true; @@ -262,13 +262,13 @@ void Snake_Update(void *opaque) } // Check collision with snake - if (snake->snakebonus != SNAKE_BONUS_GHOST) + if (snake->snakebonus != BONUS_GHOST) for (i = 1; i < snake->snakelength - 1; i++) if (x == snake->snakex[i] && y == snake->snakey[i]) { - if (snake->snakebonus == SNAKE_BONUS_SCISSORS) + if (snake->snakebonus == BONUS_SCISSORS) { - snake->snakebonus = SNAKE_BONUS_NONE; + snake->snakebonus = BONUS_NONE; snake->snakelength = i; S_StartSound(NULL, sfx_adderr); } @@ -285,7 +285,7 @@ void Snake_Update(void *opaque) // Check collision with apple if (x == snake->applex && y == snake->appley) { - if (snake->snakelength + 3 < SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y) + if (snake->snakelength + 3 < NUM_BLOCKS_X * NUM_BLOCKS_Y) { snake->snakelength++; snake->snakex [snake->snakelength - 1] = snake->snakex [snake->snakelength - 2]; @@ -294,18 +294,18 @@ void Snake_Update(void *opaque) } // Spawn new apple - Snake_FindFreeSlot(snake, &snake->applex, &snake->appley, x, y); + FindFreeSlot(snake, &snake->applex, &snake->appley, x, y); // Spawn new bonus if (!(snake->snakelength % 5)) { do { - snake->bonustype = M_RandomKey(SNAKE_NUM_BONUSES - 1) + 1; - } while (snake->snakelength > SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y * 3 / 4 - && (snake->bonustype == SNAKE_BONUS_EGGMAN || snake->bonustype == SNAKE_BONUS_FAST || snake->bonustype == SNAKE_BONUS_REVERSE)); + snake->bonustype = M_RandomKey(NUM_BONUSES - 1) + 1; + } while (snake->snakelength > NUM_BLOCKS_X * NUM_BLOCKS_Y * 3 / 4 + && (snake->bonustype == BONUS_EGGMAN || snake->bonustype == BONUS_FAST || snake->bonustype == BONUS_REVERSE)); - Snake_FindFreeSlot(snake, &snake->bonusx, &snake->bonusy, x, y); + FindFreeSlot(snake, &snake->bonusx, &snake->bonusy, x, y); } S_StartSound(NULL, sfx_s3k6b); @@ -350,25 +350,25 @@ void Snake_Update(void *opaque) snake->snakey[0] = y; // Check collision with bonus - if (snake->bonustype != SNAKE_BONUS_NONE && x == snake->bonusx && y == snake->bonusy) + if (snake->bonustype != BONUS_NONE && x == snake->bonusx && y == snake->bonusy) { S_StartSound(NULL, sfx_ncchip); switch (snake->bonustype) { - case SNAKE_BONUS_SLOW: - snake->snakebonus = SNAKE_BONUS_SLOW; + case BONUS_SLOW: + snake->snakebonus = BONUS_SLOW; snake->snakebonustime = 20 * TICRATE; break; - case SNAKE_BONUS_FAST: - snake->snakebonus = SNAKE_BONUS_FAST; + case BONUS_FAST: + snake->snakebonus = BONUS_FAST; snake->snakebonustime = 20 * TICRATE; break; - case SNAKE_BONUS_GHOST: - snake->snakebonus = SNAKE_BONUS_GHOST; + case BONUS_GHOST: + snake->snakebonus = BONUS_GHOST; snake->snakebonustime = 10 * TICRATE; break; - case SNAKE_BONUS_NUKE: + case BONUS_NUKE: for (i = 0; i < snake->snakelength; i++) { snake->snakex [i] = snake->snakex [0]; @@ -378,11 +378,11 @@ void Snake_Update(void *opaque) S_StartSound(NULL, sfx_bkpoof); break; - case SNAKE_BONUS_SCISSORS: - snake->snakebonus = SNAKE_BONUS_SCISSORS; + case BONUS_SCISSORS: + snake->snakebonus = BONUS_SCISSORS; snake->snakebonustime = 60 * TICRATE; break; - case SNAKE_BONUS_REVERSE: + case BONUS_REVERSE: for (i = 0; i < (snake->snakelength + 1) / 2; i++) { UINT16 i2 = snake->snakelength - 1 - i; @@ -393,10 +393,10 @@ void Snake_Update(void *opaque) // Swap first segment with last segment snake->snakex [i] = snake->snakex [i2]; snake->snakey [i] = snake->snakey [i2]; - snake->snakedir[i] = Snake_GetOppositeDir(snake->snakedir[i2]); + snake->snakedir[i] = GetOppositeDir(snake->snakedir[i2]); snake->snakex [i2] = tmpx; snake->snakey [i2] = tmpy; - snake->snakedir[i2] = Snake_GetOppositeDir(tmpdir); + snake->snakedir[i2] = GetOppositeDir(tmpdir); } snake->snakedir[0] = 0; @@ -404,14 +404,14 @@ void Snake_Update(void *opaque) S_StartSound(NULL, sfx_gravch); break; default: - if (snake->snakebonus != SNAKE_BONUS_GHOST) + if (snake->snakebonus != BONUS_GHOST) { snake->gameover = true; S_StartSound(NULL, sfx_lose); } } - snake->bonustype = SNAKE_BONUS_NONE; + snake->bonustype = BONUS_NONE; } } @@ -425,23 +425,23 @@ void Snake_Draw(void *opaque) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); V_DrawFlatFill( - SNAKE_LEFT_X + SNAKE_BORDER_SIZE, - SNAKE_TOP_Y + SNAKE_BORDER_SIZE, - SNAKE_MAP_WIDTH, - SNAKE_MAP_HEIGHT, - W_GetNumForName(snake_backgrounds[snake->background]) + LEFT_X + BORDER_SIZE, + TOP_Y + BORDER_SIZE, + MAP_WIDTH, + MAP_HEIGHT, + W_GetNumForName(backgrounds[snake->background]) ); // Borders - V_DrawFill(SNAKE_LEFT_X, SNAKE_TOP_Y, SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_BORDER_SIZE, 242); // Top - V_DrawFill(SNAKE_LEFT_X + SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_TOP_Y, SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, 242); // Right - V_DrawFill(SNAKE_LEFT_X + SNAKE_BORDER_SIZE, SNAKE_TOP_Y + SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_BORDER_SIZE, 242); // Bottom - V_DrawFill(SNAKE_LEFT_X, SNAKE_TOP_Y + SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, 242); // Left + V_DrawFill(LEFT_X, TOP_Y, BORDER_SIZE + MAP_WIDTH, BORDER_SIZE, 242); // Top + V_DrawFill(LEFT_X + BORDER_SIZE + MAP_WIDTH, TOP_Y, BORDER_SIZE, BORDER_SIZE + MAP_HEIGHT, 242); // Right + V_DrawFill(LEFT_X + BORDER_SIZE, TOP_Y + BORDER_SIZE + MAP_HEIGHT, BORDER_SIZE + MAP_WIDTH, BORDER_SIZE, 242); // Bottom + V_DrawFill(LEFT_X, TOP_Y + BORDER_SIZE, BORDER_SIZE, BORDER_SIZE + MAP_HEIGHT, 242); // Left // Apple V_DrawFixedPatch( - (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->applex * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, - (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->appley * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + (LEFT_X + BORDER_SIZE + snake->applex * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT, + (TOP_Y + BORDER_SIZE + snake->appley * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT, FRACUNIT / 4, 0, W_CachePatchLongName("DL_APPLE", PU_HUDGFX), @@ -449,13 +449,13 @@ void Snake_Draw(void *opaque) ); // Bonus - if (snake->bonustype != SNAKE_BONUS_NONE) + if (snake->bonustype != BONUS_NONE) V_DrawFixedPatch( - (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->bonusx * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2 ) * FRACUNIT, - (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->bonusy * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2 + 4) * FRACUNIT, + (LEFT_X + BORDER_SIZE + snake->bonusx * BLOCK_SIZE + BLOCK_SIZE / 2 ) * FRACUNIT, + (TOP_Y + BORDER_SIZE + snake->bonusy * BLOCK_SIZE + BLOCK_SIZE / 2 + 4) * FRACUNIT, FRACUNIT / 2, 0, - W_CachePatchLongName(snake_bonuspatches[snake->bonustype], PU_HUDGFX), + W_CachePatchLongName(bonuspatches[snake->bonustype], PU_HUDGFX), NULL ); @@ -499,10 +499,10 @@ void Snake_Draw(void *opaque) } V_DrawFixedPatch( - (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->snakex[i] * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, - (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->snakey[i] * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + (LEFT_X + BORDER_SIZE + snake->snakex[i] * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT, + (TOP_Y + BORDER_SIZE + snake->snakey[i] * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT, i == 0 && dir == 0 ? FRACUNIT / 5 : FRACUNIT / 2, - snake->snakebonus == SNAKE_BONUS_GHOST ? V_TRANSLUCENT : 0, + snake->snakebonus == BONUS_GHOST ? V_TRANSLUCENT : 0, W_CachePatchLongName(patchname, PU_HUDGFX), NULL ); @@ -510,17 +510,17 @@ void Snake_Draw(void *opaque) } // Length - V_DrawString(SNAKE_RIGHT_X + 4, SNAKE_TOP_Y, V_MONOSPACE, va("%u", snake->snakelength)); + V_DrawString(RIGHT_X + 4, TOP_Y, V_MONOSPACE, va("%u", snake->snakelength)); // Bonus - if (snake->snakebonus != SNAKE_BONUS_NONE + if (snake->snakebonus != BONUS_NONE && (snake->snakebonustime >= 3 * TICRATE || snake->time % 4 < 4 / 2)) V_DrawFixedPatch( - (SNAKE_RIGHT_X + 10) * FRACUNIT, - (SNAKE_TOP_Y + 24) * FRACUNIT, + (RIGHT_X + 10) * FRACUNIT, + (TOP_Y + 24) * FRACUNIT, FRACUNIT / 2, 0, - W_CachePatchLongName(snake_bonuspatches[snake->snakebonus], PU_HUDGFX), + W_CachePatchLongName(bonuspatches[snake->snakebonus], PU_HUDGFX), NULL ); } From 262ed6b7f34440ec292c139e7977c0af18366404 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Thu, 29 Dec 2022 10:23:12 +0100 Subject: [PATCH 25/96] Split packet handling switch into functions --- src/d_clisrv.c | 1111 ++++++++++++++++++++++++------------------------ src/d_netfil.c | 49 ++- src/d_netfil.h | 8 +- 3 files changed, 605 insertions(+), 563 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index be10e4f9b..d3f6854c7 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3677,8 +3677,531 @@ static void HandleServerInfo(SINT8 node) } #endif -static void PT_WillResendGamestate(void) +// Helper function for packets that should only be sent by the server +// If it is NOT from the server, bail out and close the connection! +static boolean ServerOnly(SINT8 node) { + if (node == servernode) + return false; + + Net_CloseConnection(node); + return true; +} + +static void PT_AskInfoViaMS(SINT8 node) +{ + Net_CloseConnection(node); +} + +static void PT_TellFilesNeeded(SINT8 node) +{ + if (server && serverrunning) + { + UINT8 *p; + INT32 firstfile = netbuffer->u.filesneedednum; + + netbuffer->packettype = PT_MOREFILESNEEDED; + netbuffer->u.filesneededcfg.first = firstfile; + netbuffer->u.filesneededcfg.more = 0; + + p = PutFileNeeded(firstfile); + + HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); + } + else // Shouldn't get this if you aren't the server...? + Net_CloseConnection(node); +} + +static void PT_MoreFilesNeeded(SINT8 node) +{ + if (server && serverrunning) + { // But wait I thought I'm the server? + Net_CloseConnection(node); + return; + } + if (ServerOnly(node)) + return; + if (cl_mode == CL_ASKFULLFILELIST && netbuffer->u.filesneededcfg.first == fileneedednum) + { + D_ParseFileneeded(netbuffer->u.filesneededcfg.num, netbuffer->u.filesneededcfg.files, netbuffer->u.filesneededcfg.first); + if (!netbuffer->u.filesneededcfg.more) + cl_lastcheckedfilecount = UINT16_MAX; // Got the whole file list + } +} + +static void PT_AskInfo(SINT8 node) +{ + if (server && serverrunning) + { + SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time)); + SV_SendPlayerInfo(node); // Send extra info + } + Net_CloseConnection(node); +} + +// Negative response of client join request +static void PT_ServerRefuse(SINT8 node) +{ + if (server && serverrunning) + { // But wait I thought I'm the server? + Net_CloseConnection(node); + return; + } + if (ServerOnly(node)) + return; + if (cl_mode == CL_WAITJOINRESPONSE) + { + // Save the reason so it can be displayed after quitting the netgame + char *reason = strdup(netbuffer->u.serverrefuse.reason); + if (!reason) + I_Error("Out of memory!\n"); + + if (strstr(reason, "Maximum players reached")) + { + serverisfull = true; + //Special timeout for when refusing due to player cap. The client will wait 3 seconds between join requests when waiting for a slot, so we need this to be much longer + //We set it back to the value of cv_nettimeout.value in CL_Reset + connectiontimeout = NEWTICRATE*7; + cl_mode = CL_ASKJOIN; + free(reason); + return; + } + + M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"), + reason), NULL, MM_NOTHING); + + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + + free(reason); + + // Will be reset by caller. Signals refusal. + cl_mode = CL_ABORTED; + } +} + +// Positive response of client join request +static void PT_ServerCFG(SINT8 node) +{ + if (server && serverrunning && node != servernode) + { // but wait I thought I'm the server? + Net_CloseConnection(node); + return; + } + if (ServerOnly(node)) + return; + /// \note how would this happen? and is it doing the right thing if it does? + if (cl_mode != CL_WAITJOINRESPONSE) + return; + + if (client) + { + maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); + G_SetGametype(netbuffer->u.servercfg.gametype); + modifiedgame = netbuffer->u.servercfg.modifiedgame; + memcpy(server_context, netbuffer->u.servercfg.server_context, 8); + } + + nodeingame[(UINT8)servernode] = true; + serverplayer = netbuffer->u.servercfg.serverplayer; + doomcom->numslots = SHORT(netbuffer->u.servercfg.totalslotnum); + mynode = netbuffer->u.servercfg.clientnode; + if (serverplayer >= 0) + playernode[(UINT8)serverplayer] = servernode; + + if (netgame) +#ifndef NONET + CONS_Printf(M_GetText("Join accepted, waiting for complete game state...\n")); +#else + CONS_Printf(M_GetText("Join accepted, waiting for next level change...\n")); +#endif + DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode)); + +#ifndef NONET + /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? + /// Shouldn't them be downloaded even at intermission time? + /// Also, according to HandleConnect, the server will send the savegame even during intermission... + if (netbuffer->u.servercfg.gamestate == GS_LEVEL/* || + netbuffer->u.servercfg.gamestate == GS_INTERMISSION*/) + cl_mode = CL_DOWNLOADSAVEGAME; + else +#endif + cl_mode = CL_CONNECTED; +} + +static void PT_ClientCmd(SINT8 node, INT32 netconsole) +{ + tic_t realend, realstart; + + if (client) + return; + + // To save bytes, only the low byte of tic numbers are sent + // Use ExpandTics to figure out what the rest of the bytes are + realstart = ExpandTics(netbuffer->u.clientpak.client_tic, node); + realend = ExpandTics(netbuffer->u.clientpak.resendfrom, node); + + if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS + || netbuffer->packettype == PT_NODEKEEPALIVEMIS + || supposedtics[node] < realend) + { + supposedtics[node] = realend; + } + // Discard out of order packet + if (nettics[node] > realend) + { + DEBFILE(va("out of order ticcmd discarded nettics = %u\n", nettics[node])); + return; + } + + // Update the nettics + nettics[node] = realend; + + // Don't do anything for packets of type NODEKEEPALIVE? + if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE + || netbuffer->packettype == PT_NODEKEEPALIVEMIS) + return; + + // As long as clients send valid ticcmds, the server can keep running, so reset the timeout + /// \todo Use a separate cvar for that kind of timeout? + freezetimeout[node] = I_GetTime() + connectiontimeout; + + // Copy ticcmd + G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); + + // Check ticcmd for "speed hacks" + if (netcmds[maketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE + || netcmds[maketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].sidemove < -MAXPLMOVE) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), netconsole); + //D_Clearticcmd(k); + + SendKick(netconsole, KICK_MSG_CON_FAIL); + return; + } + + // Splitscreen cmd + if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) + && nodetoplayer2[node] >= 0) + G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], + &netbuffer->u.client2pak.cmd2, 1); + + // Check player consistancy during the level + if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL + && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) +#ifndef NONET + && !SV_ResendingSavegameToAnyone() +#endif + && !resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime()) + { + if (cv_resynchattempts.value) + { + // Tell the client we are about to resend them the gamestate + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + HSendPacket(node, true, 0, 0); + + resendingsavegame[node] = true; + + if (cv_blamecfail.value) + CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), + netconsole+1, player_names[netconsole], + consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy)); + DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", + netconsole, realstart, consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy))); + return; + } + else + { + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", + netconsole, realstart, consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy))); + return; + } + } +} + +static void PT_TextCmd(SINT8 node, INT32 netconsole) +{ + if (client) + return; + + // splitscreen special + if (netbuffer->packettype == PT_TEXTCMD2) + netconsole = nodetoplayer2[node]; + + if (netconsole < 0 || netconsole >= MAXPLAYERS) + Net_UnAcknowledgePacket(node); + else + { + size_t j; + tic_t tic = maketic; + UINT8 *textcmd; + + // ignore if the textcmd has a reported size of zero + // this shouldn't be sent at all + if (!netbuffer->u.textcmd[0]) + { + DEBFILE(va("GetPacket: Textcmd with size 0 detected! (node %u, player %d)\n", + node, netconsole)); + Net_UnAcknowledgePacket(node); + return; + } + + // ignore if the textcmd size var is actually larger than it should be + // BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength + if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1) + { + DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n", + netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1), + node, netconsole)); + Net_UnAcknowledgePacket(node); + return; + } + + // check if tic that we are making isn't too large else we cannot send it :( + // doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time + j = software_MAXPACKETLENGTH + - (netbuffer->u.textcmd[0]+2+BASESERVERTICSSIZE + + (doomcom->numslots+1)*sizeof(ticcmd_t)); + + // search a tic that have enougth space in the ticcmd + while ((textcmd = D_GetExistingTextcmd(tic, netconsole)), + (TotalTextCmdPerTic(tic) > j || netbuffer->u.textcmd[0] + (textcmd ? textcmd[0] : 0) > MAXTEXTCMD) + && tic < firstticstosend + BACKUPTICS) + tic++; + + if (tic >= firstticstosend + BACKUPTICS) + { + DEBFILE(va("GetPacket: Textcmd too long (max %s, used %s, mak %d, " + "tosend %u, node %u, player %d)\n", sizeu1(j), sizeu2(TotalTextCmdPerTic(maketic)), + maketic, firstticstosend, node, netconsole)); + Net_UnAcknowledgePacket(node); + return; + } + + // Make sure we have a buffer + if (!textcmd) textcmd = D_GetTextcmd(tic, netconsole); + + DEBFILE(va("textcmd put in tic %u at position %d (player %d) ftts %u mk %u\n", + tic, textcmd[0]+1, netconsole, firstticstosend, maketic)); + + M_Memcpy(&textcmd[textcmd[0]+1], netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]); + textcmd[0] += (UINT8)netbuffer->u.textcmd[0]; + } +} + +static void PT_Login(SINT8 node, INT32 netconsole) +{ + (void)node; + + if (client) + return; + +#ifndef NOMD5 + UINT8 finalmd5[16];/* Well, it's the cool thing to do? */ + + if (doomcom->datalength < 16)/* ignore partial sends */ + return; + + if (!adminpasswordset) + { + CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[netconsole]); + return; + } + + // Do the final pass to compare with the sent md5 + D_MD5PasswordPass(adminpassmd5, 16, va("PNUM%02d", netconsole), &finalmd5); + + if (!memcmp(netbuffer->u.md5sum, finalmd5, 16)) + { + CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[netconsole]); + COM_BufInsertText(va("promote %d\n", netconsole)); // do this immediately + } + else + CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[netconsole]); +#else + (void)netconsole; +#endif +} + +static void PT_ClientQuit(SINT8 node, INT32 netconsole) +{ + if (client) + return; + + if (!nodeingame[node]) + { + Net_CloseConnection(node); + return; + } + + // nodeingame will be put false in the execution of kick command + // this allow to send some packets to the quitting client to have their ack back + nodewaiting[node] = 0; + if (netconsole != -1 && playeringame[netconsole]) + { + UINT8 kickmsg; + + if (netbuffer->packettype == PT_NODETIMEOUT) + kickmsg = KICK_MSG_TIMEOUT; + else + kickmsg = KICK_MSG_PLAYER_QUIT; + kickmsg |= KICK_MSG_KEEP_BODY; + + SendKick(netconsole, kickmsg); + nodetoplayer[node] = -1; + + if (nodetoplayer2[node] != -1 && nodetoplayer2[node] >= 0 + && playeringame[(UINT8)nodetoplayer2[node]]) + { + SendKick(nodetoplayer2[node], kickmsg); + nodetoplayer2[node] = -1; + } + } + Net_CloseConnection(node); + nodeingame[node] = false; +} + +static void PT_CanReceiveGamestate(SINT8 node) +{ +#ifndef NONET + if (client || sendingsavegame[node]) + return; + + CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[nodetoplayer[node]]); + + SV_SendSaveGame(node, true); // Resend a complete game state + resendingsavegame[node] = true; +#else + (void)node; +#endif +} + +static void PT_AskLuaFile(SINT8 node) +{ + if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_ASKED) + AddLuaFileToSendQueue(node, luafiletransfers->realfilename); +} + +static void PT_HasLuaFile(SINT8 node) +{ + if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_SENDING) + SV_HandleLuaFileSent(node); +} + +static void PT_ReceivedGamestate(SINT8 node) +{ + sendingsavegame[node] = false; + resendingsavegame[node] = false; + savegameresendcooldown[node] = I_GetTime() + 5 * TICRATE; +} + +static void PT_ServerTics(SINT8 node, INT32 netconsole) +{ + UINT8 *pak, *txtpak, numtxtpak; + tic_t realend, realstart; + + if (!nodeingame[node]) + { + // Do not remove my own server (we have just get a out of order packet) + if (node != servernode) + { + DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype)); + Net_CloseConnection(node); + } + return; + } + + // Only accept PT_SERVERTICS from the server. + if (node != servernode) + { + CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_SERVERTICS", node); + if (server) + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + return; + } + + realstart = netbuffer->u.serverpak.starttic; + realend = realstart + netbuffer->u.serverpak.numtics; + + txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots + * netbuffer->u.serverpak.numtics]; + + if (realend > gametic + CLIENTBACKUPTICS) + realend = gametic + CLIENTBACKUPTICS; + cl_packetmissed = realstart > neededtic; + + if (realstart <= neededtic && realend > neededtic) + { + tic_t i, j; + pak = (UINT8 *)&netbuffer->u.serverpak.cmds; + + for (i = realstart; i < realend; i++) + { + // clear first + D_Clearticcmd(i); + + // copy the tics + pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak, + netbuffer->u.serverpak.numslots*sizeof (ticcmd_t)); + + // copy the textcmds + numtxtpak = *txtpak++; + for (j = 0; j < numtxtpak; j++) + { + INT32 k = *txtpak++; // playernum + const size_t txtsize = txtpak[0]+1; + + if (i >= gametic) // Don't copy old net commands + M_Memcpy(D_GetTextcmd(i, k), txtpak, txtsize); + txtpak += txtsize; + } + } + + neededtic = realend; + } + else + { + DEBFILE(va("frame not in bound: %u\n", neededtic)); + /*if (realend < neededtic - 2 * TICRATE || neededtic + 2 * TICRATE < realstart) + I_Error("Received an out of order PT_SERVERTICS packet!\n" + "Got tics %d-%d, needed tic %d\n\n" + "Please report this crash on the Master Board,\n" + "IRC or Discord so it can be fixed.\n", (INT32)realstart, (INT32)realend, (INT32)neededtic);*/ + } +} + +static void PT_Ping(SINT8 node, INT32 netconsole) +{ + // Only accept PT_PING from the server. + if (node != servernode) + { + CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_PING", node); + if (server) + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + return; + } + + //Update client ping table from the server. + if (client) + { + UINT8 i; + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i]) + playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i]; + + servermaxping = (tic_t)netbuffer->u.pingtable[MAXPLAYERS]; + } +} + +static void PT_WillResendGamestate(SINT8 node) +{ + (void)node; + #ifndef NONET char tmpsave[256]; @@ -3705,19 +4228,12 @@ static void PT_WillResendGamestate(void) #endif } -static void PT_CanReceiveGamestate(SINT8 node) +static void PT_SendingLuaFile(SINT8 node) { -#ifndef NONET - if (client || sendingsavegame[node]) - return; - - CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[nodetoplayer[node]]); - - SV_SendSaveGame(node, true); // Resend a complete game state - resendingsavegame[node] = true; -#else (void)node; -#endif + + if (client) + CL_PrepareDownloadLuaFile(); } /** Handles a packet received from a node that isn't in game @@ -3733,202 +4249,27 @@ static void HandlePacketFromAwayNode(SINT8 node) if (node != servernode) DEBFILE(va("Received packet from unknown host %d\n", node)); -// macro for packets that should only be sent by the server -// if it is NOT from the server, bail out and close the connection! -#define SERVERONLY \ - if (node != servernode) \ - { \ - Net_CloseConnection(node); \ - break; \ - } switch (netbuffer->packettype) { - case PT_ASKINFOVIAMS: - Net_CloseConnection(node); - break; - - case PT_TELLFILESNEEDED: - if (server && serverrunning) - { - UINT8 *p; - INT32 firstfile = netbuffer->u.filesneedednum; - - netbuffer->packettype = PT_MOREFILESNEEDED; - netbuffer->u.filesneededcfg.first = firstfile; - netbuffer->u.filesneededcfg.more = 0; - - p = PutFileNeeded(firstfile); - - HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); - } - else // Shouldn't get this if you aren't the server...? - Net_CloseConnection(node); - break; - - case PT_MOREFILESNEEDED: - if (server && serverrunning) - { // But wait I thought I'm the server? - Net_CloseConnection(node); - break; - } - SERVERONLY - if (cl_mode == CL_ASKFULLFILELIST && netbuffer->u.filesneededcfg.first == fileneedednum) - { - D_ParseFileneeded(netbuffer->u.filesneededcfg.num, netbuffer->u.filesneededcfg.files, netbuffer->u.filesneededcfg.first); - if (!netbuffer->u.filesneededcfg.more) - cl_lastcheckedfilecount = UINT16_MAX; // Got the whole file list - } - break; - - case PT_ASKINFO: - if (server && serverrunning) - { - SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time)); - SV_SendPlayerInfo(node); // Send extra info - } - Net_CloseConnection(node); - break; - - case PT_SERVERREFUSE: // Negative response of client join request - if (server && serverrunning) - { // But wait I thought I'm the server? - Net_CloseConnection(node); - break; - } - SERVERONLY - if (cl_mode == CL_WAITJOINRESPONSE) - { - // Save the reason so it can be displayed after quitting the netgame - char *reason = strdup(netbuffer->u.serverrefuse.reason); - if (!reason) - I_Error("Out of memory!\n"); - - if (strstr(reason, "Maximum players reached")) - { - serverisfull = true; - //Special timeout for when refusing due to player cap. The client will wait 3 seconds between join requests when waiting for a slot, so we need this to be much longer - //We set it back to the value of cv_nettimeout.value in CL_Reset - connectiontimeout = NEWTICRATE*7; - cl_mode = CL_ASKJOIN; - free(reason); - break; - } - - M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"), - reason), NULL, MM_NOTHING); - - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - - free(reason); - - // Will be reset by caller. Signals refusal. - cl_mode = CL_ABORTED; - } - break; - - case PT_SERVERCFG: // Positive response of client join request - { - if (server && serverrunning && node != servernode) - { // but wait I thought I'm the server? - Net_CloseConnection(node); - break; - } - SERVERONLY - /// \note how would this happen? and is it doing the right thing if it does? - if (cl_mode != CL_WAITJOINRESPONSE) - break; - - if (client) - { - maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); - G_SetGametype(netbuffer->u.servercfg.gametype); - modifiedgame = netbuffer->u.servercfg.modifiedgame; - memcpy(server_context, netbuffer->u.servercfg.server_context, 8); - } - - nodeingame[(UINT8)servernode] = true; - serverplayer = netbuffer->u.servercfg.serverplayer; - doomcom->numslots = SHORT(netbuffer->u.servercfg.totalslotnum); - mynode = netbuffer->u.servercfg.clientnode; - if (serverplayer >= 0) - playernode[(UINT8)serverplayer] = servernode; - - if (netgame) -#ifndef NONET - CONS_Printf(M_GetText("Join accepted, waiting for complete game state...\n")); -#else - CONS_Printf(M_GetText("Join accepted, waiting for next level change...\n")); -#endif - DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode)); - -#ifndef NONET - /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? - /// Shouldn't them be downloaded even at intermission time? - /// Also, according to HandleConnect, the server will send the savegame even during intermission... - if (netbuffer->u.servercfg.gamestate == GS_LEVEL/* || - netbuffer->u.servercfg.gamestate == GS_INTERMISSION*/) - cl_mode = CL_DOWNLOADSAVEGAME; - else -#endif - cl_mode = CL_CONNECTED; - break; - } - - // Handled in d_netfil.c - case PT_FILEFRAGMENT: - if (server) - { // But wait I thought I'm the server? - Net_CloseConnection(node); - break; - } - SERVERONLY - PT_FileFragment(); - break; - - case PT_FILEACK: - if (server) - PT_FileAck(); - break; - - case PT_FILERECEIVED: - if (server) - PT_FileReceived(); - break; - - case PT_REQUESTFILE: - if (server) - { - if (!cv_downloading.value || !PT_RequestFile(node)) - Net_CloseConnection(node); // close connection if one of the requested files could not be sent, or you disabled downloading anyway - } - else - Net_CloseConnection(node); // nope - break; - - case PT_NODETIMEOUT: - case PT_CLIENTQUIT: - if (server) - Net_CloseConnection(node); - break; - - case PT_CLIENTCMD: - break; // This is not an "unknown packet" - - case PT_SERVERTICS: - // Do not remove my own server (we have just get a out of order packet) - if (node == servernode) - break; - /* FALLTHRU */ + case PT_ASKINFOVIAMS : PT_AskInfoViaMS (node ); break; + case PT_TELLFILESNEEDED: PT_TellFilesNeeded(node ); break; + case PT_MOREFILESNEEDED: PT_MoreFilesNeeded(node ); break; + case PT_ASKINFO : PT_AskInfo (node ); break; + case PT_SERVERREFUSE : PT_ServerRefuse (node ); break; + case PT_SERVERCFG : PT_ServerCFG (node ); break; + case PT_FILEFRAGMENT : PT_FileFragment (node, -1); break; + case PT_FILEACK : PT_FileAck (node ); break; + case PT_FILERECEIVED : PT_FileReceived (node ); break; + case PT_REQUESTFILE : PT_RequestFile (node ); break; + case PT_NODETIMEOUT : PT_ClientQuit (node, -1); break; + case PT_CLIENTQUIT : PT_ClientQuit (node, -1); break; + case PT_SERVERTICS : PT_ServerTics (node, -1); break; + case PT_CLIENTCMD : break; // This is not an "unknown packet" default: DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype)); Net_CloseConnection(node); - break; // Ignore it - } -#undef SERVERONLY } /** Handles a packet received from a node that is in game @@ -3942,13 +4283,6 @@ static void HandlePacketFromAwayNode(SINT8 node) static void HandlePacketFromPlayer(SINT8 node) { INT32 netconsole; - tic_t realend, realstart; - UINT8 *pak, *txtpak, numtxtpak; -#ifndef NOMD5 - UINT8 finalmd5[16];/* Well, it's the cool thing to do? */ -#endif - - txtpak = NULL; if (dedicated && node == 0) netconsole = 0; @@ -3961,358 +4295,39 @@ static void HandlePacketFromPlayer(SINT8 node) switch (netbuffer->packettype) { -// -------------------------------------------- SERVER RECEIVE ---------- + // SERVER RECEIVE case PT_CLIENTCMD: case PT_CLIENT2CMD: case PT_CLIENTMIS: case PT_CLIENT2MIS: case PT_NODEKEEPALIVE: case PT_NODEKEEPALIVEMIS: - if (client) - break; - - // To save bytes, only the low byte of tic numbers are sent - // Use ExpandTics to figure out what the rest of the bytes are - realstart = ExpandTics(netbuffer->u.clientpak.client_tic, node); - realend = ExpandTics(netbuffer->u.clientpak.resendfrom, node); - - if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS - || netbuffer->packettype == PT_NODEKEEPALIVEMIS - || supposedtics[node] < realend) - { - supposedtics[node] = realend; - } - // Discard out of order packet - if (nettics[node] > realend) - { - DEBFILE(va("out of order ticcmd discarded nettics = %u\n", nettics[node])); - break; - } - - // Update the nettics - nettics[node] = realend; - - // Don't do anything for packets of type NODEKEEPALIVE? - if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE - || netbuffer->packettype == PT_NODEKEEPALIVEMIS) - break; - - // As long as clients send valid ticcmds, the server can keep running, so reset the timeout - /// \todo Use a separate cvar for that kind of timeout? - freezetimeout[node] = I_GetTime() + connectiontimeout; - - // Copy ticcmd - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); - - // Check ticcmd for "speed hacks" - if (netcmds[maketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE - || netcmds[maketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].sidemove < -MAXPLMOVE) - { - CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), netconsole); - //D_Clearticcmd(k); - - SendKick(netconsole, KICK_MSG_CON_FAIL); - break; - } - - // Splitscreen cmd - if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) - && nodetoplayer2[node] >= 0) - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], - &netbuffer->u.client2pak.cmd2, 1); - - // Check player consistancy during the level - if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL - && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) -#ifndef NONET - && !SV_ResendingSavegameToAnyone() -#endif - && !resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime()) - { - if (cv_resynchattempts.value) - { - // Tell the client we are about to resend them the gamestate - netbuffer->packettype = PT_WILLRESENDGAMESTATE; - HSendPacket(node, true, 0, 0); - - resendingsavegame[node] = true; - - if (cv_blamecfail.value) - CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), - netconsole+1, player_names[netconsole], - consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy)); - DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", - netconsole, realstart, consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy))); - break; - } - else - { - SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", - netconsole, realstart, consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy))); - break; - } - } + PT_ClientCmd(node, netconsole); break; - case PT_TEXTCMD2: // splitscreen special - netconsole = nodetoplayer2[node]; - /* FALLTHRU */ - case PT_TEXTCMD: - if (client) - break; + case PT_TEXTCMD : PT_TextCmd (node, netconsole); break; + case PT_TEXTCMD2 : PT_TextCmd (node, netconsole); break; + case PT_LOGIN : PT_Login (node, netconsole); break; + case PT_NODETIMEOUT : PT_ClientQuit (node, netconsole); break; + case PT_CLIENTQUIT : PT_ClientQuit (node, netconsole); break; + case PT_CANRECEIVEGAMESTATE: PT_CanReceiveGamestate(node ); break; + case PT_ASKLUAFILE : PT_AskLuaFile (node ); break; + case PT_HASLUAFILE : PT_HasLuaFile (node ); break; + case PT_RECEIVEDGAMESTATE : PT_ReceivedGamestate (node ); break; - if (netconsole < 0 || netconsole >= MAXPLAYERS) - Net_UnAcknowledgePacket(node); - else - { - size_t j; - tic_t tic = maketic; - UINT8 *textcmd; + // CLIENT RECEIVE + case PT_SERVERTICS : PT_ServerTics (node, netconsole); break; + case PT_PING : PT_Ping (node, netconsole); break; + case PT_FILEFRAGMENT : PT_FileFragment (node, netconsole); break; + case PT_FILEACK : PT_FileAck (node ); break; + case PT_FILERECEIVED : PT_FileReceived (node ); break; + case PT_WILLRESENDGAMESTATE: PT_WillResendGamestate(node ); break; + case PT_SENDINGLUAFILE : PT_SendingLuaFile (node ); break; + case PT_SERVERCFG : break; - // ignore if the textcmd has a reported size of zero - // this shouldn't be sent at all - if (!netbuffer->u.textcmd[0]) - { - DEBFILE(va("GetPacket: Textcmd with size 0 detected! (node %u, player %d)\n", - node, netconsole)); - Net_UnAcknowledgePacket(node); - break; - } - - // ignore if the textcmd size var is actually larger than it should be - // BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength - if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1) - { - DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n", - netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1), - node, netconsole)); - Net_UnAcknowledgePacket(node); - break; - } - - // check if tic that we are making isn't too large else we cannot send it :( - // doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time - j = software_MAXPACKETLENGTH - - (netbuffer->u.textcmd[0]+2+BASESERVERTICSSIZE - + (doomcom->numslots+1)*sizeof(ticcmd_t)); - - // search a tic that have enougth space in the ticcmd - while ((textcmd = D_GetExistingTextcmd(tic, netconsole)), - (TotalTextCmdPerTic(tic) > j || netbuffer->u.textcmd[0] + (textcmd ? textcmd[0] : 0) > MAXTEXTCMD) - && tic < firstticstosend + BACKUPTICS) - tic++; - - if (tic >= firstticstosend + BACKUPTICS) - { - DEBFILE(va("GetPacket: Textcmd too long (max %s, used %s, mak %d, " - "tosend %u, node %u, player %d)\n", sizeu1(j), sizeu2(TotalTextCmdPerTic(maketic)), - maketic, firstticstosend, node, netconsole)); - Net_UnAcknowledgePacket(node); - break; - } - - // Make sure we have a buffer - if (!textcmd) textcmd = D_GetTextcmd(tic, netconsole); - - DEBFILE(va("textcmd put in tic %u at position %d (player %d) ftts %u mk %u\n", - tic, textcmd[0]+1, netconsole, firstticstosend, maketic)); - - M_Memcpy(&textcmd[textcmd[0]+1], netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]); - textcmd[0] += (UINT8)netbuffer->u.textcmd[0]; - } - break; - case PT_LOGIN: - if (client) - break; - -#ifndef NOMD5 - if (doomcom->datalength < 16)/* ignore partial sends */ - break; - - if (!adminpasswordset) - { - CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[netconsole]); - break; - } - - // Do the final pass to compare with the sent md5 - D_MD5PasswordPass(adminpassmd5, 16, va("PNUM%02d", netconsole), &finalmd5); - - if (!memcmp(netbuffer->u.md5sum, finalmd5, 16)) - { - CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[netconsole]); - COM_BufInsertText(va("promote %d\n", netconsole)); // do this immediately - } - else - CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[netconsole]); -#endif - break; - case PT_NODETIMEOUT: - case PT_CLIENTQUIT: - if (client) - break; - - // nodeingame will be put false in the execution of kick command - // this allow to send some packets to the quitting client to have their ack back - nodewaiting[node] = 0; - if (netconsole != -1 && playeringame[netconsole]) - { - UINT8 kickmsg; - - if (netbuffer->packettype == PT_NODETIMEOUT) - kickmsg = KICK_MSG_TIMEOUT; - else - kickmsg = KICK_MSG_PLAYER_QUIT; - kickmsg |= KICK_MSG_KEEP_BODY; - - SendKick(netconsole, kickmsg); - nodetoplayer[node] = -1; - - if (nodetoplayer2[node] != -1 && nodetoplayer2[node] >= 0 - && playeringame[(UINT8)nodetoplayer2[node]]) - { - SendKick(nodetoplayer2[node], kickmsg); - nodetoplayer2[node] = -1; - } - } - Net_CloseConnection(node); - nodeingame[node] = false; - break; - case PT_CANRECEIVEGAMESTATE: - PT_CanReceiveGamestate(node); - break; - case PT_ASKLUAFILE: - if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_ASKED) - AddLuaFileToSendQueue(node, luafiletransfers->realfilename); - break; - case PT_HASLUAFILE: - if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_SENDING) - SV_HandleLuaFileSent(node); - break; - case PT_RECEIVEDGAMESTATE: - sendingsavegame[node] = false; - resendingsavegame[node] = false; - savegameresendcooldown[node] = I_GetTime() + 5 * TICRATE; - break; -// -------------------------------------------- CLIENT RECEIVE ---------- - case PT_SERVERTICS: - // Only accept PT_SERVERTICS from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_SERVERTICS", node); - if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - break; - } - - realstart = netbuffer->u.serverpak.starttic; - realend = realstart + netbuffer->u.serverpak.numtics; - - if (!txtpak) - txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots - * netbuffer->u.serverpak.numtics]; - - if (realend > gametic + CLIENTBACKUPTICS) - realend = gametic + CLIENTBACKUPTICS; - cl_packetmissed = realstart > neededtic; - - if (realstart <= neededtic && realend > neededtic) - { - tic_t i, j; - pak = (UINT8 *)&netbuffer->u.serverpak.cmds; - - for (i = realstart; i < realend; i++) - { - // clear first - D_Clearticcmd(i); - - // copy the tics - pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak, - netbuffer->u.serverpak.numslots*sizeof (ticcmd_t)); - - // copy the textcmds - numtxtpak = *txtpak++; - for (j = 0; j < numtxtpak; j++) - { - INT32 k = *txtpak++; // playernum - const size_t txtsize = txtpak[0]+1; - - if (i >= gametic) // Don't copy old net commands - M_Memcpy(D_GetTextcmd(i, k), txtpak, txtsize); - txtpak += txtsize; - } - } - - neededtic = realend; - } - else - { - DEBFILE(va("frame not in bound: %u\n", neededtic)); - /*if (realend < neededtic - 2 * TICRATE || neededtic + 2 * TICRATE < realstart) - I_Error("Received an out of order PT_SERVERTICS packet!\n" - "Got tics %d-%d, needed tic %d\n\n" - "Please report this crash on the Master Board,\n" - "IRC or Discord so it can be fixed.\n", (INT32)realstart, (INT32)realend, (INT32)neededtic);*/ - } - break; - case PT_PING: - // Only accept PT_PING from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_PING", node); - if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - break; - } - - //Update client ping table from the server. - if (client) - { - UINT8 i; - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i]; - - servermaxping = (tic_t)netbuffer->u.pingtable[MAXPLAYERS]; - } - - break; - case PT_SERVERCFG: - break; - case PT_FILEFRAGMENT: - // Only accept PT_FILEFRAGMENT from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_FILEFRAGMENT", node); - if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - break; - } - if (client) - PT_FileFragment(); - break; - case PT_FILEACK: - if (server) - PT_FileAck(); - break; - case PT_FILERECEIVED: - if (server) - PT_FileReceived(); - break; - case PT_WILLRESENDGAMESTATE: - PT_WillResendGamestate(); - break; - case PT_SENDINGLUAFILE: - if (client) - CL_PrepareDownloadLuaFile(); - break; default: DEBFILE(va("UNKNOWN PACKET TYPE RECEIVED %d from host %d\n", netbuffer->packettype, node)); - } // end switch + } } /** Handles all received packets, if any diff --git a/src/d_netfil.c b/src/d_netfil.c index edbef30bb..7c9ed54d8 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -413,12 +413,17 @@ boolean CL_SendFileRequest(void) } // get request filepak and put it on the send queue -// returns false if a requested file was not found or cannot be sent -boolean PT_RequestFile(INT32 node) +void PT_RequestFile(SINT8 node) { UINT8 *p = netbuffer->u.textcmd; UINT8 id; + if (client || !cv_downloading.value) + { + Net_CloseConnection(node); // close connection if you are not the server or disabled downloading + return; + } + while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow { id = READUINT8(p); @@ -428,11 +433,12 @@ boolean PT_RequestFile(INT32 node) if (!AddFileToSendQueue(node, id)) { SV_AbortSendFiles(node); - return false; // don't read the rest of the files + Net_CloseConnection(node); // close connection if one of the requested files could not be sent + return; // don't read the rest of the files } } - return true; // no problems with any files + return; // no problems with any files } /** Checks if the files needed aren't already loaded or on the disk @@ -1137,13 +1143,15 @@ void FileSendTicker(void) } } -void PT_FileAck(void) +void PT_FileAck(SINT8 node) { fileack_pak *packet = &netbuffer->u.fileack; - INT32 node = doomcom->remotenode; filetran_t *trans = &transfer[node]; INT32 i, j; + if (client) + return; + // Wrong file id? Ignore it, it's probably a late packet if (!(trans->txlist && packet->fileid == trans->txlist->fileid)) return; @@ -1190,12 +1198,12 @@ void PT_FileAck(void) } } -void PT_FileReceived(void) +void PT_FileReceived(SINT8 node) { - filetx_t *trans = transfer[doomcom->remotenode].txlist; + filetx_t *trans = transfer[node].txlist; - if (trans && netbuffer->u.filereceived == trans->fileid) - SV_EndFileSend(doomcom->remotenode); + if (server && trans && netbuffer->u.filereceived == trans->fileid) + SV_EndFileSend(node); } static void SendAckPacket(fileack_pak *packet, UINT8 fileid) @@ -1281,8 +1289,27 @@ void FileReceiveTicker(void) } } -void PT_FileFragment(void) +void PT_FileFragment(SINT8 node, INT32 netconsole) { + if (nodeingame[node]) + { + // Only accept PT_FILEFRAGMENT from the server. + if (node != servernode) + { + CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_FILEFRAGMENT", node); + if (server) + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + return; + } + if (server) + return; + } + else if (server || node != servernode) + { + Net_CloseConnection(node); + return; + } + INT32 filenum = netbuffer->u.filetxpak.fileid; fileneeded_t *file = &fileneeded[filenum]; UINT32 fragmentpos = LONG(netbuffer->u.filetxpak.position); diff --git a/src/d_netfil.h b/src/d_netfil.h index f778a518f..5c7f4ef49 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -90,16 +90,16 @@ void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemet UINT8 fileid); void FileSendTicker(void); -void PT_FileAck(void); -void PT_FileReceived(void); +void PT_FileAck(SINT8 node); +void PT_FileReceived(SINT8 node); boolean SendingFile(INT32 node); void FileReceiveTicker(void); -void PT_FileFragment(void); +void PT_FileFragment(SINT8 node, INT32 netconsole); boolean CL_CheckDownloadable(void); boolean CL_SendFileRequest(void); -boolean PT_RequestFile(INT32 node); +void PT_RequestFile(SINT8 node); typedef enum { From e6e9eef0e2a2ba3a36c6d7159748fb9485938b17 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Thu, 29 Dec 2022 15:52:45 +0100 Subject: [PATCH 26/96] Merge node arrays into a structure --- src/d_clisrv.c | 202 ++++++++++++++++++++++++------------------------- src/d_net.h | 23 +++++- src/d_netfil.c | 4 +- src/i_tcp.c | 14 ++-- 4 files changed, 125 insertions(+), 118 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index d3f6854c7..e311bf15a 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -84,6 +84,8 @@ boolean serverrunning = false; INT32 serverplayer = 0; char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support) +netnode_t netnodes[MAXNETNODES]; + // Server specific vars UINT8 playernode[MAXPLAYERS]; char playeraddress[MAXPLAYERS][64]; @@ -91,10 +93,6 @@ char playeraddress[MAXPLAYERS][64]; // Minimum timeout for sending the savegame // The actual timeout will be longer depending on the savegame length tic_t jointimeout = (10*TICRATE); -static boolean sendingsavegame[MAXNETNODES]; // Are we sending the savegame? -static boolean resendingsavegame[MAXNETNODES]; // Are we resending the savegame? -static tic_t savegameresendcooldown[MAXNETNODES]; // How long before we can resend again? -static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout? // Incremented by cv_joindelay when a client joins, decremented each tic. // If higher than cv_joindelay * 2 (3 joins in a short timespan), joins are temporarily disabled. @@ -103,14 +101,8 @@ static tic_t joindelay = 0; UINT16 pingmeasurecount = 1; UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone. UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values. -SINT8 nodetoplayer[MAXNETNODES]; -SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen) -UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen -boolean nodeingame[MAXNETNODES]; // set false as nodes leave game tic_t servermaxping = 800; // server's max ping. Defaults to 800 -static tic_t nettics[MAXNETNODES]; // what tic the client have received -static tic_t supposedtics[MAXNETNODES]; // nettics prevision for smaller packet -static UINT8 nodewaiting[MAXNETNODES]; + static tic_t firstticstosend; // min of the nettics static tic_t tictoclear = 0; // optimize d_clearticcmd static tic_t maketic; @@ -218,14 +210,14 @@ tic_t ExpandTics(INT32 low, INT32 node) { INT32 delta; - delta = low - (nettics[node] & UINT8_MAX); + delta = low - (netnodes[node].tic & UINT8_MAX); if (delta >= -64 && delta <= 64) - return (nettics[node] & ~UINT8_MAX) + low; + return (netnodes[node].tic & ~UINT8_MAX) + low; else if (delta > 64) - return (nettics[node] & ~UINT8_MAX) - 256 + low; + return (netnodes[node].tic & ~UINT8_MAX) - 256 + low; else //if (delta < -64) - return (nettics[node] & ~UINT8_MAX) + 256 + low; + return (netnodes[node].tic & ~UINT8_MAX) + 256 + low; } // ----------------------------------------------------------------- @@ -999,7 +991,7 @@ static boolean SV_ResendingSavegameToAnyone(void) INT32 i; for (i = 0; i < MAXNETNODES; i++) - if (resendingsavegame[i]) + if (netnodes[i].resendingsavegame) return true; return false; } @@ -1068,8 +1060,8 @@ static void SV_SendSaveGame(INT32 node, boolean resending) save_p = NULL; // Remember when we started sending the savegame so we can handle timeouts - sendingsavegame[node] = true; - freezetimeout[node] = I_GetTime() + jointimeout + length / 1024; // 1 extra tic for each kilobyte + netnodes[node].sendingsavegame = true; + netnodes[node].freezetimeout = I_GetTime() + jointimeout + length / 1024; // 1 extra tic for each kilobyte } #ifdef DUMPCONSISTENCY @@ -2034,7 +2026,7 @@ static void CL_ConnectToServer(void) { pnumnodes = 0; for (i = 0; i < MAXNETNODES; i++) - if (nodeingame[i]) + if (netnodes[i].ingame) pnumnodes++; } } @@ -2316,10 +2308,10 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason) if (server && !demoplayback && playernode[playernum] != UINT8_MAX) { INT32 node = playernode[playernum]; - playerpernode[node]--; - if (playerpernode[node] <= 0) + netnodes[node].numplayers--; + if (netnodes[node].numplayers <= 0) { - nodeingame[node] = false; + netnodes[node].ingame = false; Net_CloseConnection(node); ResetNode(node); } @@ -2431,7 +2423,7 @@ void CL_Reset(void) if (servernode > 0 && servernode < MAXNETNODES) { - nodeingame[(UINT8)servernode] = false; + netnodes[(UINT8)servernode].ingame = false; Net_CloseConnection(servernode); } D_CloseConnection(); // netgame = false @@ -2674,7 +2666,7 @@ static void Command_Kick(void) // Special case if we are trying to kick a player who is downloading the game state: // trigger a timeout instead of kicking them, because a kick would only // take effect after they have finished downloading - if (server && playernode[pn] != UINT8_MAX && sendingsavegame[playernode[pn]]) + if (server && playernode[pn] != UINT8_MAX && netnodes[playernode[pn]].sendingsavegame) { Net_ConnectionTimeout(playernode[pn]); return; @@ -2763,8 +2755,8 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) // Is playernum authorized to make this kick? if (playernum != serverplayer && !IsPlayerAdmin(playernum) - && !(playernode[playernum] != UINT8_MAX && playerpernode[playernode[playernum]] == 2 - && nodetoplayer2[playernode[playernum]] == pnum)) + && !(playernode[playernum] != UINT8_MAX && netnodes[playernode[playernum]].numplayers == 2 + && netnodes[playernode[playernum]].player2 == pnum)) { // We received a kick command from someone who isn't the // server or admin, and who isn't in splitscreen removing @@ -2802,10 +2794,10 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) "\n" "If you think this is a bug, please report it, including all of the details above.\n", playernum, pnum, - playernode[playernum], playerpernode[playernode[playernum]], - nodetoplayer2[playernode[playernum]], - playernode[pnum], playerpernode[playernode[pnum]], - nodetoplayer2[playernode[pnum]]); + playernode[playernum], netnodes[playernode[playernum]].numplayers, + netnodes[playernode[playernum]].player2, + playernode[pnum], netnodes[playernode[pnum]].numplayers, + netnodes[playernode[pnum]].player2); */ pnum = playernum; msg = KICK_MSG_CON_FAIL; @@ -2926,10 +2918,10 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) if (server && !demoplayback && playernode[pnum] != UINT8_MAX) { INT32 node = playernode[pnum]; - playerpernode[node]--; - if (playerpernode[node] <= 0) + netnodes[node].numplayers--; + if (netnodes[node].numplayers <= 0) { - nodeingame[node] = false; + netnodes[node].ingame = false; Net_CloseConnection(node); ResetNode(node); } @@ -3017,19 +3009,19 @@ void D_ClientServerInit(void) static void ResetNode(INT32 node) { - nodeingame[node] = false; - nodewaiting[node] = 0; + netnodes[node].ingame = false; + netnodes[node].numplayerswaiting = 0; - nettics[node] = gametic; - supposedtics[node] = gametic; + netnodes[node].tic = gametic; + netnodes[node].supposedtic = gametic; - nodetoplayer[node] = -1; - nodetoplayer2[node] = -1; - playerpernode[node] = 0; + netnodes[node].player = -1; + netnodes[node].player2 = -1; + netnodes[node].numplayers = 0; - sendingsavegame[node] = false; - resendingsavegame[node] = false; - savegameresendcooldown[node] = 0; + netnodes[node].sendingsavegame = false; + netnodes[node].resendingsavegame = false; + netnodes[node].savegameresendcooldown = 0; } void SV_ResetServer(void) @@ -3067,7 +3059,7 @@ void SV_ResetServer(void) if (dedicated) { - nodeingame[0] = true; + netnodes[0].ingame = true; serverplayer = 0; } else @@ -3130,14 +3122,14 @@ void D_QuitNetGame(void) netbuffer->packettype = PT_SERVERSHUTDOWN; for (i = 0; i < MAXNETNODES; i++) - if (nodeingame[i]) + if (netnodes[i].ingame) HSendPacket(i, true, 0, 0); #ifdef MASTERSERVER if (serverrunning && ms_RoomId > 0) UnregisterServer(); #endif } - else if (servernode > 0 && servernode < MAXNETNODES && nodeingame[(UINT8)servernode]) + else if (servernode > 0 && servernode < MAXNETNODES && netnodes[(UINT8)servernode].ingame) { netbuffer->packettype = PT_CLIENTQUIT; HSendPacket(servernode, true, 0, 0); @@ -3161,12 +3153,12 @@ void D_QuitNetGame(void) // Adds a node to the game (player will follow at map change or at savegame....) static inline void SV_AddNode(INT32 node) { - nettics[node] = gametic; - supposedtics[node] = gametic; + netnodes[node].tic = gametic; + netnodes[node].supposedtic = gametic; // little hack because the server connects to itself and puts // nodeingame when connected not here if (node) - nodeingame[node] = true; + netnodes[node].ingame = true; } // Xcmd XD_ADDPLAYER @@ -3311,7 +3303,7 @@ static boolean SV_AddWaitingPlayers(const char *name, const char *name2) for (node = 0; node < MAXNETNODES; node++) { // splitscreen can allow 2 player in one node - for (; nodewaiting[node] > 0; nodewaiting[node]--) + for (; netnodes[node].numplayerswaiting > 0; netnodes[node].numplayerswaiting--) { newplayer = true; @@ -3325,7 +3317,7 @@ static boolean SV_AddWaitingPlayers(const char *name, const char *name2) if (playeringame[newplayernum]) continue; for (n = 0; n < MAXNETNODES; n++) - if (nodetoplayer[n] == newplayernum || nodetoplayer2[n] == newplayernum) + if (netnodes[n].player == newplayernum || netnodes[n].player2 == newplayernum) break; if (n == MAXNETNODES) break; @@ -3341,18 +3333,18 @@ static boolean SV_AddWaitingPlayers(const char *name, const char *name2) p = buf + 2; buf[0] = (UINT8)node; buf[1] = newplayernum; - if (playerpernode[node] < 1) + if (netnodes[node].numplayers < 1) { - nodetoplayer[node] = newplayernum; + netnodes[node].player = newplayernum; WRITESTRINGN(p, name, MAXPLAYERNAME); } else { - nodetoplayer2[node] = newplayernum; + netnodes[node].player2 = newplayernum; buf[1] |= 0x80; WRITESTRINGN(p, name2, MAXPLAYERNAME); } - playerpernode[node]++; + netnodes[node].numplayers++; SendNetXCmd(XD_ADDPLAYER, &buf, p - buf); @@ -3571,7 +3563,7 @@ static void HandleConnect(SINT8 node) boolean newnode = false; #endif - for (i = 0; i < netbuffer->u.clientcfg.localplayers - playerpernode[node]; i++) + for (i = 0; i < netbuffer->u.clientcfg.localplayers - netnodes[node].numplayers; i++) { strlcpy(names[i], netbuffer->u.clientcfg.names[i], MAXPLAYERNAME + 1); if (!EnsurePlayerNameIsGood(names[i], rejoinernum)) @@ -3582,8 +3574,8 @@ static void HandleConnect(SINT8 node) } // client authorised to join - nodewaiting[node] = (UINT8)(netbuffer->u.clientcfg.localplayers - playerpernode[node]); - if (!nodeingame[node]) + netnodes[node].numplayerswaiting = (UINT8)(netbuffer->u.clientcfg.localplayers - netnodes[node].numplayers); + if (!netnodes[node].ingame) { gamestate_t backupstate = gamestate; #ifndef NONET @@ -3608,7 +3600,7 @@ static void HandleConnect(SINT8 node) DEBFILE("new node joined\n"); } #ifndef NONET - if (nodewaiting[node]) + if (netnodes[node].numplayerswaiting) { if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) && newnode) { @@ -3803,7 +3795,7 @@ static void PT_ServerCFG(SINT8 node) memcpy(server_context, netbuffer->u.servercfg.server_context, 8); } - nodeingame[(UINT8)servernode] = true; + netnodes[(UINT8)servernode].ingame = true; serverplayer = netbuffer->u.servercfg.serverplayer; doomcom->numslots = SHORT(netbuffer->u.servercfg.totalslotnum); mynode = netbuffer->u.servercfg.clientnode; @@ -3844,19 +3836,19 @@ static void PT_ClientCmd(SINT8 node, INT32 netconsole) if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS || netbuffer->packettype == PT_NODEKEEPALIVEMIS - || supposedtics[node] < realend) + || netnodes[node].supposedtic < realend) { - supposedtics[node] = realend; + netnodes[node].supposedtic = realend; } // Discard out of order packet - if (nettics[node] > realend) + if (netnodes[node].tic > realend) { - DEBFILE(va("out of order ticcmd discarded nettics = %u\n", nettics[node])); + DEBFILE(va("out of order ticcmd discarded nettics = %u\n", netnodes[node].tic)); return; } // Update the nettics - nettics[node] = realend; + netnodes[node].tic = realend; // Don't do anything for packets of type NODEKEEPALIVE? if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE @@ -3865,7 +3857,7 @@ static void PT_ClientCmd(SINT8 node, INT32 netconsole) // As long as clients send valid ticcmds, the server can keep running, so reset the timeout /// \todo Use a separate cvar for that kind of timeout? - freezetimeout[node] = I_GetTime() + connectiontimeout; + netnodes[node].freezetimeout = I_GetTime() + connectiontimeout; // Copy ticcmd G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); @@ -3883,8 +3875,8 @@ static void PT_ClientCmd(SINT8 node, INT32 netconsole) // Splitscreen cmd if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) - && nodetoplayer2[node] >= 0) - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], + && netnodes[node].player2 >= 0) + G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)netnodes[node].player2], &netbuffer->u.client2pak.cmd2, 1); // Check player consistancy during the level @@ -3893,7 +3885,7 @@ static void PT_ClientCmd(SINT8 node, INT32 netconsole) #ifndef NONET && !SV_ResendingSavegameToAnyone() #endif - && !resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime()) + && !netnodes[node].resendingsavegame && netnodes[node].savegameresendcooldown <= I_GetTime()) { if (cv_resynchattempts.value) { @@ -3901,7 +3893,7 @@ static void PT_ClientCmd(SINT8 node, INT32 netconsole) netbuffer->packettype = PT_WILLRESENDGAMESTATE; HSendPacket(node, true, 0, 0); - resendingsavegame[node] = true; + netnodes[node].resendingsavegame = true; if (cv_blamecfail.value) CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), @@ -3931,7 +3923,7 @@ static void PT_TextCmd(SINT8 node, INT32 netconsole) // splitscreen special if (netbuffer->packettype == PT_TEXTCMD2) - netconsole = nodetoplayer2[node]; + netconsole = netnodes[node].player2; if (netconsole < 0 || netconsole >= MAXPLAYERS) Net_UnAcknowledgePacket(node); @@ -4033,7 +4025,7 @@ static void PT_ClientQuit(SINT8 node, INT32 netconsole) if (client) return; - if (!nodeingame[node]) + if (!netnodes[node].ingame) { Net_CloseConnection(node); return; @@ -4041,7 +4033,7 @@ static void PT_ClientQuit(SINT8 node, INT32 netconsole) // nodeingame will be put false in the execution of kick command // this allow to send some packets to the quitting client to have their ack back - nodewaiting[node] = 0; + netnodes[node].numplayerswaiting = 0; if (netconsole != -1 && playeringame[netconsole]) { UINT8 kickmsg; @@ -4053,29 +4045,29 @@ static void PT_ClientQuit(SINT8 node, INT32 netconsole) kickmsg |= KICK_MSG_KEEP_BODY; SendKick(netconsole, kickmsg); - nodetoplayer[node] = -1; + netnodes[node].player = -1; - if (nodetoplayer2[node] != -1 && nodetoplayer2[node] >= 0 - && playeringame[(UINT8)nodetoplayer2[node]]) + if (netnodes[node].player2 != -1 && netnodes[node].player2 >= 0 + && playeringame[(UINT8)netnodes[node].player2]) { - SendKick(nodetoplayer2[node], kickmsg); - nodetoplayer2[node] = -1; + SendKick(netnodes[node].player2, kickmsg); + netnodes[node].player2 = -1; } } Net_CloseConnection(node); - nodeingame[node] = false; + netnodes[node].ingame = false; } static void PT_CanReceiveGamestate(SINT8 node) { #ifndef NONET - if (client || sendingsavegame[node]) + if (client || netnodes[node].sendingsavegame) return; - CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[nodetoplayer[node]]); + CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[netnodes[node].player]); SV_SendSaveGame(node, true); // Resend a complete game state - resendingsavegame[node] = true; + netnodes[node].resendingsavegame = true; #else (void)node; #endif @@ -4095,9 +4087,9 @@ static void PT_HasLuaFile(SINT8 node) static void PT_ReceivedGamestate(SINT8 node) { - sendingsavegame[node] = false; - resendingsavegame[node] = false; - savegameresendcooldown[node] = I_GetTime() + 5 * TICRATE; + netnodes[node].sendingsavegame = false; + netnodes[node].resendingsavegame = false; + netnodes[node].savegameresendcooldown = I_GetTime() + 5 * TICRATE; } static void PT_ServerTics(SINT8 node, INT32 netconsole) @@ -4105,7 +4097,7 @@ static void PT_ServerTics(SINT8 node, INT32 netconsole) UINT8 *pak, *txtpak, numtxtpak; tic_t realend, realstart; - if (!nodeingame[node]) + if (!netnodes[node].ingame) { // Do not remove my own server (we have just get a out of order packet) if (node != servernode) @@ -4287,7 +4279,7 @@ static void HandlePacketFromPlayer(SINT8 node) if (dedicated && node == 0) netconsole = 0; else - netconsole = nodetoplayer[node]; + netconsole = netnodes[node].player; #ifdef PARANOIA if (netconsole >= MAXPLAYERS) I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole); @@ -4376,7 +4368,7 @@ static void GetPackets(void) continue; // We do nothing with PLAYERINFO, that's for the MS browser. // Packet received from someone already playing - if (nodeingame[node]) + if (netnodes[node].ingame) HandlePacketFromPlayer(node); // Packet received from someone not playing else @@ -4572,13 +4564,13 @@ static void SV_SendTics(void) // send to all client but not to me // for each node create a packet with x tics and send it - // x is computed using supposedtics[n], max packet size and maketic + // x is computed using netnodes[n].supposedtic, max packet size and maketic for (n = 1; n < MAXNETNODES; n++) - if (nodeingame[n]) + if (netnodes[n].ingame) { - // assert supposedtics[n]>=nettics[n] - realfirsttic = supposedtics[n]; - lasttictosend = min(maketic, nettics[n] + CLIENTBACKUPTICS); + // assert netnodes[n].supposedtic>=netnodes[n].tic + realfirsttic = netnodes[n].supposedtic; + lasttictosend = min(maketic, netnodes[n].tic + CLIENTBACKUPTICS); if (realfirsttic >= lasttictosend) { @@ -4587,8 +4579,8 @@ static void SV_SendTics(void) // packet detection work when we have received packet with firsttic > neededtic // (getpacket servertics case) DEBFILE(va("Nothing to send node %u mak=%u sup=%u net=%u \n", - n, maketic, supposedtics[n], nettics[n])); - realfirsttic = nettics[n]; + n, maketic, netnodes[n].supposedtic, netnodes[n].tic)); + realfirsttic = netnodes[n].tic; if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3) // all tic are ok continue; @@ -4666,13 +4658,13 @@ static void SV_SendTics(void) HSendPacket(n, false, 0, packsize); // when tic are too large, only one tic is sent so don't go backward! if (lasttictosend-doomcom->extratics > realfirsttic) - supposedtics[n] = lasttictosend-doomcom->extratics; + netnodes[n].supposedtic = lasttictosend-doomcom->extratics; else - supposedtics[n] = lasttictosend; - if (supposedtics[n] < nettics[n]) supposedtics[n] = nettics[n]; + netnodes[n].supposedtic = lasttictosend; + if (netnodes[n].supposedtic < netnodes[n].tic) netnodes[n].supposedtic = netnodes[n].tic; } // node 0 is me! - supposedtics[0] = maketic; + netnodes[0].supposedtic = maketic; } // @@ -4915,7 +4907,7 @@ static inline void PingUpdate(void) //send out our ping packets for (i = 0; i < MAXNETNODES; i++) - if (nodeingame[i]) + if (netnodes[i].ingame) HSendPacket(i, true, 0, sizeof(INT32) * (MAXPLAYERS+1)); pingmeasurecount = 1; //Reset count @@ -4993,11 +4985,11 @@ void NetUpdate(void) firstticstosend = gametic; for (i = 0; i < MAXNETNODES; i++) - if (nodeingame[i] && nettics[i] < firstticstosend) + if (netnodes[i].ingame && netnodes[i].tic < firstticstosend) { - firstticstosend = nettics[i]; + firstticstosend = netnodes[i].tic; - if (maketic + 1 >= nettics[i] + BACKUPTICS) + if (maketic + 1 >= netnodes[i].tic + BACKUPTICS) Net_ConnectionTimeout(i); } @@ -5025,7 +5017,7 @@ void NetUpdate(void) if (server) { for (i = 1; i < MAXNETNODES; i++) - if (nodeingame[i] && freezetimeout[i] < I_GetTime()) + if (netnodes[i].ingame && netnodes[i].freezetimeout < I_GetTime()) Net_ConnectionTimeout(i); // In case the cvar value was lowered @@ -5066,7 +5058,7 @@ INT32 D_NumPlayers(void) tic_t GetLag(INT32 node) { - return gametic - nettics[node]; + return gametic - netnodes[node].tic; } void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest) diff --git a/src/d_net.h b/src/d_net.h index 5baa593a0..9eee53894 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -37,10 +37,25 @@ boolean Net_GetNetStat(void); extern INT32 getbytes; extern INT64 sendbytes; // Realtime updated -extern SINT8 nodetoplayer[MAXNETNODES]; -extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen) -extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen -extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game +typedef struct netnode_s +{ + boolean ingame; // set false as nodes leave game + tic_t freezetimeout; // Until when can this node freeze the server before getting a timeout? + + SINT8 player; + SINT8 player2; // say the numplayer for this node if any (splitscreen) + UINT8 numplayers; // used specialy for scplitscreen + UINT8 numplayerswaiting; + + tic_t tic; // what tic the client have received + tic_t supposedtic; // nettics prevision for smaller packet + + boolean sendingsavegame; // Are we sending the savegame? + boolean resendingsavegame; // Are we resending the savegame? + tic_t savegameresendcooldown; // How long before we can resend again? +} netnode_t; + +extern netnode_t netnodes[MAXNETNODES]; extern boolean serverrunning; diff --git a/src/d_netfil.c b/src/d_netfil.c index 7c9ed54d8..1fee1df81 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -667,7 +667,7 @@ void SV_PrepareSendLuaFile(void) // Set status to "waiting" for everyone for (i = 0; i < MAXNETNODES; i++) - luafiletransfers->nodestatus[i] = (nodeingame[i] ? LFTNS_WAITING : LFTNS_NONE); + luafiletransfers->nodestatus[i] = (netnodes[i].ingame ? LFTNS_WAITING : LFTNS_NONE); if (FIL_ReadFileOK(luafiletransfers->realfilename)) { @@ -1291,7 +1291,7 @@ void FileReceiveTicker(void) void PT_FileFragment(SINT8 node, INT32 netconsole) { - if (nodeingame[node]) + if (netnodes[node].ingame) { // Only accept PT_FILEFRAGMENT from the server. if (node != servernode) diff --git a/src/i_tcp.c b/src/i_tcp.c index 8838ba725..00aebddd3 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -449,7 +449,7 @@ static void cleanupnodes(void) // Why can't I start at zero? for (j = 1; j < MAXNETNODES; j++) - if (!(nodeingame[j] || SendingFile(j))) + if (!(netnodes[j].ingame || SendingFile(j))) nodeconnected[j] = false; } @@ -473,7 +473,7 @@ static SINT8 getfreenode(void) */ /*I_Error("No more free nodes!!1!11!11!!1111\n"); for (j = 1; j < MAXNETNODES; j++) - if (!nodeingame[j]) + if (!netnodes[j].ingame) return j;*/ return -1; @@ -488,24 +488,24 @@ void Command_Numnodes(void) for (i = 1; i < MAXNETNODES; i++) { - if (!(nodeconnected[i] || nodeingame[i])) + if (!(nodeconnected[i] || netnodes[i].ingame)) continue; if (nodeconnected[i]) connected++; - if (nodeingame[i]) + if (netnodes[i].ingame) ingame++; CONS_Printf("%2d - ", i); - if (nodetoplayer[i] != -1) - CONS_Printf("player %.2d", nodetoplayer[i]); + if (netnodes[i].player != -1) + CONS_Printf("player %.2d", netnodes[i].player); else CONS_Printf(" "); if (nodeconnected[i]) CONS_Printf(" - connected"); else CONS_Printf(" - "); - if (nodeingame[i]) + if (netnodes[i].ingame) CONS_Printf(" - ingame"); else CONS_Printf(" - "); From dc716d9ecee9aabcc7724b1a59c3ee544bd3f8b9 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Thu, 29 Dec 2022 20:45:56 +0100 Subject: [PATCH 27/96] Cleanup ResetNode --- src/d_clisrv.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index e311bf15a..3ab0df1d0 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2278,7 +2278,12 @@ static void Command_connect(void) } #endif -static void ResetNode(INT32 node); +static void ResetNode(INT32 node) +{ + memset(&netnodes[node], 0, sizeof(*netnodes)); + netnodes[node].player = -1; + netnodes[node].player2 = -1; +} // // CL_ClearPlayer @@ -3007,23 +3012,6 @@ void D_ClientServerInit(void) SV_SpawnServer(); } -static void ResetNode(INT32 node) -{ - netnodes[node].ingame = false; - netnodes[node].numplayerswaiting = 0; - - netnodes[node].tic = gametic; - netnodes[node].supposedtic = gametic; - - netnodes[node].player = -1; - netnodes[node].player2 = -1; - netnodes[node].numplayers = 0; - - netnodes[node].sendingsavegame = false; - netnodes[node].resendingsavegame = false; - netnodes[node].savegameresendcooldown = 0; -} - void SV_ResetServer(void) { INT32 i; From 2b2797ec665102fbd3224f93e358c686e145e001 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Thu, 29 Dec 2022 20:48:17 +0100 Subject: [PATCH 28/96] Move player-node unlinking to a function --- src/d_clisrv.c | 48 ++++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 3ab0df1d0..1fee20a3f 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2298,6 +2298,24 @@ void CL_ClearPlayer(INT32 playernum) memset(playeraddress[playernum], 0, sizeof(*playeraddress)); } +static void UnlinkPlayerFromNode(INT32 playernum) +{ + INT32 node = playernode[playernum]; + + if (node == UINT8_MAX) + return; + + playernode[playernum] = UINT8_MAX; + + netnodes[node].numplayers--; + if (netnodes[node].numplayers <= 0) + { + netnodes[node].ingame = false; + Net_CloseConnection(node); + ResetNode(node); + } +} + // // CL_RemovePlayer // @@ -2310,17 +2328,8 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason) if (!playeringame[playernum]) return; - if (server && !demoplayback && playernode[playernum] != UINT8_MAX) - { - INT32 node = playernode[playernum]; - netnodes[node].numplayers--; - if (netnodes[node].numplayers <= 0) - { - netnodes[node].ingame = false; - Net_CloseConnection(node); - ResetNode(node); - } - } + if (server) + UnlinkPlayerFromNode(playernum); if (gametyperules & GTR_TEAMFLAGS) P_PlayerFlagBurst(&players[playernum], false); // Don't take the flag with you! @@ -2392,7 +2401,6 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason) // remove avatar of player playeringame[playernum] = false; - playernode[playernum] = UINT8_MAX; while (!playeringame[doomcom->numslots-1] && doomcom->numslots > 1) doomcom->numslots--; @@ -2920,20 +2928,8 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) } else if (keepbody) { - if (server && !demoplayback && playernode[pnum] != UINT8_MAX) - { - INT32 node = playernode[pnum]; - netnodes[node].numplayers--; - if (netnodes[node].numplayers <= 0) - { - netnodes[node].ingame = false; - Net_CloseConnection(node); - ResetNode(node); - } - } - - playernode[pnum] = UINT8_MAX; - + if (server) + UnlinkPlayerFromNode(pnum); players[pnum].quittime = 1; } else From dc3995753984f34b30b9973551b103ba6b9564e2 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Thu, 29 Dec 2022 21:28:53 +0100 Subject: [PATCH 29/96] Move sphere redistribution to its own function --- src/d_clisrv.c | 106 ++++++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 50 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 1fee20a3f..eee820db2 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2316,6 +2316,61 @@ static void UnlinkPlayerFromNode(INT32 playernum) } } +// If in a special stage, redistribute the player's +// spheres across the remaining players. +// I feel like this shouldn't even be in this file at all, but well. +static void RedistributeSpecialStageSpheres(INT32 playernum) +{ + INT32 i, count, sincrement, spheres, rincrement, rings; + + if (!G_IsSpecialStage(gamemap)) + return; + + for (i = 0, count = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + count++; + } + + count--; + sincrement = spheres = players[playernum].spheres; + rincrement = rings = players[playernum].rings; + + if (count) + { + sincrement /= count; + rincrement /= count; + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && i != playernum) + { + if (spheres < 2*sincrement) + { + P_GivePlayerSpheres(&players[i], spheres); + spheres = 0; + } + else + { + P_GivePlayerSpheres(&players[i], sincrement); + spheres -= sincrement; + } + + if (rings < 2*rincrement) + { + P_GivePlayerRings(&players[i], rings); + rings = 0; + } + else + { + P_GivePlayerRings(&players[i], rincrement); + rings -= rincrement; + } + } + } +} + // // CL_RemovePlayer // @@ -2334,56 +2389,7 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason) if (gametyperules & GTR_TEAMFLAGS) P_PlayerFlagBurst(&players[playernum], false); // Don't take the flag with you! - // If in a special stage, redistribute the player's spheres across - // the remaining players. - if (G_IsSpecialStage(gamemap)) - { - INT32 i, count, sincrement, spheres, rincrement, rings; - - for (i = 0, count = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i]) - count++; - } - - count--; - sincrement = spheres = players[playernum].spheres; - rincrement = rings = players[playernum].rings; - - if (count) - { - sincrement /= count; - rincrement /= count; - } - - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && i != playernum) - { - if (spheres < 2*sincrement) - { - P_GivePlayerSpheres(&players[i], spheres); - spheres = 0; - } - else - { - P_GivePlayerSpheres(&players[i], sincrement); - spheres -= sincrement; - } - - if (rings < 2*rincrement) - { - P_GivePlayerRings(&players[i], rings); - rings = 0; - } - else - { - P_GivePlayerRings(&players[i], rincrement); - rings -= rincrement; - } - } - } - } + RedistributeSpecialStageSpheres(playernum); LUA_HookPlayerQuit(&players[playernum], reason); // Lua hook for player quitting From 6806fbce4582f1f2e69afd95b3fda2203a3444f3 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Thu, 29 Dec 2022 22:16:08 +0100 Subject: [PATCH 30/96] Fix sphere redistribution --- src/d_clisrv.c | 54 +++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index eee820db2..432001b80 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2333,39 +2333,39 @@ static void RedistributeSpecialStageSpheres(INT32 playernum) } count--; - sincrement = spheres = players[playernum].spheres; - rincrement = rings = players[playernum].rings; + spheres = players[playernum].spheres; + rings = players[playernum].rings; - if (count) + while (count && (spheres || rings)) { - sincrement /= count; - rincrement /= count; - } + sincrement = max(spheres / count, 1); + rincrement = max(rings / count, 1); - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && i != playernum) + for (i = 0; i < MAXPLAYERS; i++) { - if (spheres < 2*sincrement) + if (playeringame[i] && i != playernum) { - P_GivePlayerSpheres(&players[i], spheres); - spheres = 0; - } - else - { - P_GivePlayerSpheres(&players[i], sincrement); - spheres -= sincrement; - } + if (spheres < sincrement) + { + P_GivePlayerSpheres(&players[i], spheres); + spheres = 0; + } + else + { + P_GivePlayerSpheres(&players[i], sincrement); + spheres -= sincrement; + } - if (rings < 2*rincrement) - { - P_GivePlayerRings(&players[i], rings); - rings = 0; - } - else - { - P_GivePlayerRings(&players[i], rincrement); - rings -= rincrement; + if (rings < rincrement) + { + P_GivePlayerRings(&players[i], rings); + rings = 0; + } + else + { + P_GivePlayerRings(&players[i], rincrement); + rings -= rincrement; + } } } } From 36613d58e9177f868a400a15d53f4600e8d6d36e Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Thu, 29 Dec 2022 22:30:26 +0100 Subject: [PATCH 31/96] Cleanup sphere redistribution --- src/d_clisrv.c | 57 ++++++++++++++++---------------------------------- 1 file changed, 18 insertions(+), 39 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 432001b80..1b344a0de 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2321,52 +2321,31 @@ static void UnlinkPlayerFromNode(INT32 playernum) // I feel like this shouldn't even be in this file at all, but well. static void RedistributeSpecialStageSpheres(INT32 playernum) { - INT32 i, count, sincrement, spheres, rincrement, rings; - - if (!G_IsSpecialStage(gamemap)) + if (!G_IsSpecialStage(gamemap) || D_NumPlayers() <= 1) return; - for (i = 0, count = 0; i < MAXPLAYERS; i++) + INT32 count = D_NumPlayers() - 1; + INT32 spheres = players[playernum].spheres; + INT32 rings = players[playernum].rings; + + while (spheres || rings) { - if (playeringame[i]) - count++; - } - - count--; - spheres = players[playernum].spheres; - rings = players[playernum].rings; - - while (count && (spheres || rings)) - { - sincrement = max(spheres / count, 1); - rincrement = max(rings / count, 1); + INT32 sincrement = max(spheres / count, 1); + INT32 rincrement = max(rings / count, 1); + INT32 i, n; for (i = 0; i < MAXPLAYERS; i++) { - if (playeringame[i] && i != playernum) - { - if (spheres < sincrement) - { - P_GivePlayerSpheres(&players[i], spheres); - spheres = 0; - } - else - { - P_GivePlayerSpheres(&players[i], sincrement); - spheres -= sincrement; - } + if (!playeringame[i] || i == playernum) + continue; - if (rings < rincrement) - { - P_GivePlayerRings(&players[i], rings); - rings = 0; - } - else - { - P_GivePlayerRings(&players[i], rincrement); - rings -= rincrement; - } - } + n = min(spheres, sincrement); + P_GivePlayerSpheres(&players[i], n); + spheres -= n; + + n = min(rings, rincrement); + P_GivePlayerRings(&players[i], n); + rings -= n; } } } From ba91520eab98474c949c6937523bad2bb98b2fc3 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Fri, 30 Dec 2022 00:24:06 +0100 Subject: [PATCH 32/96] Remove useless return value for SV_AddWaitingPlayers --- src/d_clisrv.c | 12 +++--------- src/d_clisrv.h | 2 +- src/d_netcmd.c | 3 +-- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 1b344a0de..0c6960236 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3262,9 +3262,9 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) LUA_HookInt(newplayernum, HOOK(PlayerJoin)); } -static boolean SV_AddWaitingPlayers(const char *name, const char *name2) +static void SV_AddWaitingPlayers(const char *name, const char *name2) { - INT32 node, n, newplayer = false; + INT32 node, n; UINT8 buf[2 + MAXPLAYERNAME]; UINT8 *p; INT32 newplayernum; @@ -3274,8 +3274,6 @@ static boolean SV_AddWaitingPlayers(const char *name, const char *name2) // splitscreen can allow 2 player in one node for (; netnodes[node].numplayerswaiting > 0; netnodes[node].numplayerswaiting--) { - newplayer = true; - newplayernum = FindRejoinerNum(node); if (newplayernum == -1) { @@ -3320,8 +3318,6 @@ static boolean SV_AddWaitingPlayers(const char *name, const char *name2) DEBFILE(va("Server added player %d node %d\n", newplayernum, node)); } } - - return newplayer; } void CL_AddSplitscreenPlayer(void) @@ -3344,7 +3340,7 @@ boolean Playing(void) return (server && serverrunning) || (client && cl_mode == CL_CONNECTED); } -boolean SV_SpawnServer(void) +void SV_SpawnServer(void) { if (demoplayback) G_StopDemo(); // reset engine parameter @@ -3371,8 +3367,6 @@ boolean SV_SpawnServer(void) CL_ConnectToServer(); else doomcom->numslots = 1; } - - return SV_AddWaitingPlayers(cv_playername.zstring, cv_playername2.zstring); } void SV_StopServer(void) diff --git a/src/d_clisrv.h b/src/d_clisrv.h index e07864122..b3ee95c0c 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -412,7 +412,7 @@ void SendKick(UINT8 playernum, UINT8 msg); void NetUpdate(void); void SV_StartSinglePlayerServer(void); -boolean SV_SpawnServer(void); +void SV_SpawnServer(void); void SV_StopServer(void); void SV_ResetServer(void); void CL_AddSplitscreenPlayer(void); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 5f02bc2de..243501ba4 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1850,8 +1850,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese // reset players if there is a new one if (!IsPlayerAdmin(consoleplayer)) { - if (SV_SpawnServer()) - buf[0] &= ~(1<<1); + SV_SpawnServer(); if (!Playing()) // you failed to start a server somehow, so cancel the map change return; } From f27de6c324cab56a3ac17117b39e014717b22f0e Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Fri, 30 Dec 2022 01:48:26 +0100 Subject: [PATCH 33/96] Remove useless condition --- src/d_clisrv.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 0c6960236..bc0992539 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3563,17 +3563,14 @@ static void HandleConnect(SINT8 node) DEBFILE("new node joined\n"); } #ifndef NONET - if (netnodes[node].numplayerswaiting) + if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) && newnode) { - if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) && newnode) - { - SV_SendSaveGame(node, false); // send a complete game state - DEBFILE("send savegame\n"); - } - SV_AddWaitingPlayers(names[0], names[1]); - joindelay += cv_joindelay.value * TICRATE; - player_joining = true; + SV_SendSaveGame(node, false); // send a complete game state + DEBFILE("send savegame\n"); } + SV_AddWaitingPlayers(names[0], names[1]); + joindelay += cv_joindelay.value * TICRATE; + player_joining = true; #endif } } From 388505db62ff627dcd25a2911c45a3188010861d Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Fri, 30 Dec 2022 02:46:59 +0100 Subject: [PATCH 34/96] Remove unneeded numplayerswaiting field --- src/d_clisrv.c | 98 ++++++++++++++++++++++++-------------------------- src/d_net.h | 1 - 2 files changed, 47 insertions(+), 52 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index bc0992539..7aafdf539 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3262,62 +3262,54 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) LUA_HookInt(newplayernum, HOOK(PlayerJoin)); } -static void SV_AddWaitingPlayers(const char *name, const char *name2) +static void SV_AddPlayer(SINT8 node, const char *name) { - INT32 node, n; + INT32 n; UINT8 buf[2 + MAXPLAYERNAME]; UINT8 *p; INT32 newplayernum; - for (node = 0; node < MAXNETNODES; node++) + newplayernum = FindRejoinerNum(node); + if (newplayernum == -1) { - // splitscreen can allow 2 player in one node - for (; netnodes[node].numplayerswaiting > 0; netnodes[node].numplayerswaiting--) + // search for a free playernum + // we can't use playeringame since it is not updated here + for (newplayernum = dedicated ? 1 : 0; newplayernum < MAXPLAYERS; newplayernum++) { - newplayernum = FindRejoinerNum(node); - if (newplayernum == -1) - { - // search for a free playernum - // we can't use playeringame since it is not updated here - for (newplayernum = dedicated ? 1 : 0; newplayernum < MAXPLAYERS; newplayernum++) - { - if (playeringame[newplayernum]) - continue; - for (n = 0; n < MAXNETNODES; n++) - if (netnodes[n].player == newplayernum || netnodes[n].player2 == newplayernum) - break; - if (n == MAXNETNODES) - break; - } - } - - // should never happen since we check the playernum - // before accepting the join - I_Assert(newplayernum < MAXPLAYERS); - - playernode[newplayernum] = (UINT8)node; - - p = buf + 2; - buf[0] = (UINT8)node; - buf[1] = newplayernum; - if (netnodes[node].numplayers < 1) - { - netnodes[node].player = newplayernum; - WRITESTRINGN(p, name, MAXPLAYERNAME); - } - else - { - netnodes[node].player2 = newplayernum; - buf[1] |= 0x80; - WRITESTRINGN(p, name2, MAXPLAYERNAME); - } - netnodes[node].numplayers++; - - SendNetXCmd(XD_ADDPLAYER, &buf, p - buf); - - DEBFILE(va("Server added player %d node %d\n", newplayernum, node)); + if (playeringame[newplayernum]) + continue; + for (n = 0; n < MAXNETNODES; n++) + if (netnodes[n].player == newplayernum || netnodes[n].player2 == newplayernum) + break; + if (n == MAXNETNODES) + break; } } + + // should never happen since we check the playernum + // before accepting the join + I_Assert(newplayernum < MAXPLAYERS); + + playernode[newplayernum] = (UINT8)node; + + p = buf + 2; + buf[0] = (UINT8)node; + buf[1] = newplayernum; + if (netnodes[node].numplayers < 1) + { + netnodes[node].player = newplayernum; + } + else + { + netnodes[node].player2 = newplayernum; + buf[1] |= 0x80; + } + WRITESTRINGN(p, name, MAXPLAYERNAME); + netnodes[node].numplayers++; + + SendNetXCmd(XD_ADDPLAYER, &buf, p - buf); + + DEBFILE(va("Server added player %d node %d\n", newplayernum, node)); } void CL_AddSplitscreenPlayer(void) @@ -3522,11 +3514,12 @@ static void HandleConnect(SINT8 node) SV_SendRefuse(node, refuse); else { + INT32 numplayers = netbuffer->u.clientcfg.localplayers; #ifndef NONET boolean newnode = false; #endif - for (i = 0; i < netbuffer->u.clientcfg.localplayers - netnodes[node].numplayers; i++) + for (i = 0; i < numplayers; i++) { strlcpy(names[i], netbuffer->u.clientcfg.names[i], MAXPLAYERNAME + 1); if (!EnsurePlayerNameIsGood(names[i], rejoinernum)) @@ -3537,7 +3530,6 @@ static void HandleConnect(SINT8 node) } // client authorised to join - netnodes[node].numplayerswaiting = (UINT8)(netbuffer->u.clientcfg.localplayers - netnodes[node].numplayers); if (!netnodes[node].ingame) { gamestate_t backupstate = gamestate; @@ -3568,7 +3560,12 @@ static void HandleConnect(SINT8 node) SV_SendSaveGame(node, false); // send a complete game state DEBFILE("send savegame\n"); } - SV_AddWaitingPlayers(names[0], names[1]); + + // Splitscreen can allow 2 players in one node + SV_AddPlayer(node, names[0]); + if (numplayers > 1) + SV_AddPlayer(node, names[1]); + joindelay += cv_joindelay.value * TICRATE; player_joining = true; #endif @@ -3993,7 +3990,6 @@ static void PT_ClientQuit(SINT8 node, INT32 netconsole) // nodeingame will be put false in the execution of kick command // this allow to send some packets to the quitting client to have their ack back - netnodes[node].numplayerswaiting = 0; if (netconsole != -1 && playeringame[netconsole]) { UINT8 kickmsg; diff --git a/src/d_net.h b/src/d_net.h index 9eee53894..c6c9e2894 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -45,7 +45,6 @@ typedef struct netnode_s SINT8 player; SINT8 player2; // say the numplayer for this node if any (splitscreen) UINT8 numplayers; // used specialy for scplitscreen - UINT8 numplayerswaiting; tic_t tic; // what tic the client have received tic_t supposedtic; // nettics prevision for smaller packet From 0a0da81007de48797e09ff302dc8009ab6997b73 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Fri, 30 Dec 2022 07:52:19 +0100 Subject: [PATCH 35/96] Fix typo --- src/p_setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index cd9185484..eedda1b08 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4910,9 +4910,9 @@ static void P_ConvertBinaryLinedefTypes(void) case 331: // Player skin - continuous case 332: // Player skin - each time case 333: // Player skin - once - if (lines[i].special == 303) + if (lines[i].special == 333) lines[i].args[0] = TMT_ONCE; - else if (lines[i].special == 302) + else if (lines[i].special == 332) lines[i].args[0] = (lines[i].flags & ML_BOUNCY) ? TMT_EACHTIMEENTERANDEXIT : TMT_EACHTIMEENTER; else lines[i].args[0] = TMT_CONTINUOUS; From d561b5a0bf08a6dfa616640bf7c2eed74efed7e5 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Fri, 30 Dec 2022 13:10:01 +0100 Subject: [PATCH 36/96] Remove broken joinnextround console variable --- src/d_clisrv.c | 6 ------ src/d_clisrv.h | 2 +- src/d_netcmd.c | 1 - 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 7aafdf539..31a19001a 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2925,7 +2925,6 @@ static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, N consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL); consvar_t cv_allownewplayer = CVAR_INIT ("allowjoin", "On", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); -consvar_t cv_joinnextround = CVAR_INIT ("joinnextround", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); /// \todo not done static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}}; consvar_t cv_maxplayers = CVAR_INIT ("maxplayers", "8", CV_SAVE|CV_NETVAR, maxplayers_cons_t, NULL); static CV_PossibleValue_t joindelay_cons_t[] = {{1, "MIN"}, {3600, "MAX"}, {0, "Off"}, {0, NULL}}; @@ -3532,17 +3531,13 @@ static void HandleConnect(SINT8 node) // client authorised to join if (!netnodes[node].ingame) { - gamestate_t backupstate = gamestate; #ifndef NONET newnode = true; #endif SV_AddNode(node); - if (cv_joinnextround.value && gameaction == ga_nothing) - G_SetGamestate(GS_WAITINGPLAYERS); if (!SV_SendServerConfig(node)) { - G_SetGamestate(backupstate); /// \note Shouldn't SV_SendRefuse be called before ResetNode? ResetNode(node); SV_SendRefuse(node, M_GetText("Server couldn't send info, please try again")); @@ -3551,7 +3546,6 @@ static void HandleConnect(SINT8 node) } //if (gamestate != GS_LEVEL) // GS_INTERMISSION, etc? // SV_SendPlayerConfigs(node); // send bare minimum player info - G_SetGamestate(backupstate); DEBFILE("new node joined\n"); } #ifndef NONET diff --git a/src/d_clisrv.h b/src/d_clisrv.h index b3ee95c0c..99d859924 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -394,7 +394,7 @@ extern UINT32 realpingtable[MAXPLAYERS]; extern UINT32 playerpingtable[MAXPLAYERS]; extern tic_t servermaxping; -extern consvar_t cv_netticbuffer, cv_allownewplayer, cv_joinnextround, cv_maxplayers, cv_joindelay, cv_rejointimeout; +extern consvar_t cv_netticbuffer, cv_allownewplayer, cv_maxplayers, cv_joindelay, cv_rejointimeout; extern consvar_t cv_resynchattempts, cv_blamecfail; extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 243501ba4..64f478ff7 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -630,7 +630,6 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_downloadspeed); #ifndef NONET CV_RegisterVar(&cv_allownewplayer); - CV_RegisterVar(&cv_joinnextround); CV_RegisterVar(&cv_showjoinaddress); CV_RegisterVar(&cv_blamecfail); #endif From c9dc44c2f6f53d7a34d2decd89cbfa5624e51514 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Fri, 30 Dec 2022 14:01:03 +0100 Subject: [PATCH 37/96] Cleanup HandleConnect --- src/d_clisrv.c | 96 +++++++++++++++++++++----------------------------- 1 file changed, 41 insertions(+), 55 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 31a19001a..699c372d7 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3501,69 +3501,55 @@ ConnectionRefused (SINT8 node, INT32 rejoinernum) static void HandleConnect(SINT8 node) { char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1]; + INT32 numplayers = netbuffer->u.clientcfg.localplayers; INT32 rejoinernum; INT32 i; - const char *refuse; rejoinernum = FindRejoinerNum(node); - refuse = ConnectionRefused(node, rejoinernum); - + const char *refuse = ConnectionRefused(node, rejoinernum); if (refuse) - SV_SendRefuse(node, refuse); - else { - INT32 numplayers = netbuffer->u.clientcfg.localplayers; -#ifndef NONET - boolean newnode = false; -#endif - - for (i = 0; i < numplayers; i++) - { - strlcpy(names[i], netbuffer->u.clientcfg.names[i], MAXPLAYERNAME + 1); - if (!EnsurePlayerNameIsGood(names[i], rejoinernum)) - { - SV_SendRefuse(node, "Bad player name"); - return; - } - } - - // client authorised to join - if (!netnodes[node].ingame) - { -#ifndef NONET - newnode = true; -#endif - SV_AddNode(node); - - if (!SV_SendServerConfig(node)) - { - /// \note Shouldn't SV_SendRefuse be called before ResetNode? - ResetNode(node); - SV_SendRefuse(node, M_GetText("Server couldn't send info, please try again")); - /// \todo fix this !!! - return; // restart the while - } - //if (gamestate != GS_LEVEL) // GS_INTERMISSION, etc? - // SV_SendPlayerConfigs(node); // send bare minimum player info - DEBFILE("new node joined\n"); - } -#ifndef NONET - if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) && newnode) - { - SV_SendSaveGame(node, false); // send a complete game state - DEBFILE("send savegame\n"); - } - - // Splitscreen can allow 2 players in one node - SV_AddPlayer(node, names[0]); - if (numplayers > 1) - SV_AddPlayer(node, names[1]); - - joindelay += cv_joindelay.value * TICRATE; - player_joining = true; -#endif + SV_SendRefuse(node, refuse); + return; } + + for (i = 0; i < numplayers; i++) + { + strlcpy(names[i], netbuffer->u.clientcfg.names[i], MAXPLAYERNAME + 1); + if (!EnsurePlayerNameIsGood(names[i], rejoinernum)) + { + SV_SendRefuse(node, "Bad player name"); + return; + } + } + + SV_AddNode(node); + + if (!SV_SendServerConfig(node)) + { + /// \note Shouldn't SV_SendRefuse be called before ResetNode? + ResetNode(node); + SV_SendRefuse(node, M_GetText("Server couldn't send info, please try again")); + /// \todo fix this !!! + return; // restart the while + } + DEBFILE("new node joined\n"); + +#ifndef NONET + if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) + { + SV_SendSaveGame(node, false); // send a complete game state + DEBFILE("send savegame\n"); + } + + // Splitscreen can allow 2 players in one node + for (i = 0; i < numplayers; i++) + SV_AddPlayer(node, names[i]); + + joindelay += cv_joindelay.value * TICRATE; + player_joining = true; +#endif } /** Called when a PT_SERVERSHUTDOWN packet is received From 6ae44fe91d7fb5149db1bec4e255fdb17fb165fe Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Fri, 30 Dec 2022 14:01:37 +0100 Subject: [PATCH 38/96] Rename ConnectionRefused to be more descriptive --- src/d_clisrv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 699c372d7..d7d02f9bb 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3422,7 +3422,7 @@ static size_t TotalTextCmdPerTic(tic_t tic) } static const char * -ConnectionRefused (SINT8 node, INT32 rejoinernum) +GetRefuseMessage (SINT8 node, INT32 rejoinernum) { clientconfig_pak *cc = &netbuffer->u.clientcfg; @@ -3507,7 +3507,7 @@ static void HandleConnect(SINT8 node) rejoinernum = FindRejoinerNum(node); - const char *refuse = ConnectionRefused(node, rejoinernum); + const char *refuse = GetRefuseMessage(node, rejoinernum); if (refuse) { SV_SendRefuse(node, refuse); From e519f306fbc36b1f595defd8989ae37bb6672eb4 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Fri, 30 Dec 2022 14:03:32 +0100 Subject: [PATCH 39/96] Ignore duplicate PT_CLIENTJOIN packets --- src/d_clisrv.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index d7d02f9bb..b25e34c56 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3505,6 +3505,10 @@ static void HandleConnect(SINT8 node) INT32 rejoinernum; INT32 i; + // Ignore duplicate packets + if (netnodes[node].ingame) + return; + rejoinernum = FindRejoinerNum(node); const char *refuse = GetRefuseMessage(node, rejoinernum); From 05d232c02909a8afca406a0b75a89bfe2fce1ef7 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Fri, 30 Dec 2022 15:07:57 +0100 Subject: [PATCH 40/96] Delete netcode Just kidding, I just deleted NONET --- src/Makefile | 1 - src/Makefile.d/features.mk | 4 +- src/Makefile.d/win32.mk | 2 - src/d_clisrv.c | 85 +------------ src/d_clisrv.h | 2 - src/d_net.c | 48 -------- src/d_net.h | 2 - src/d_netcmd.c | 2 - src/d_netfil.c | 6 - src/d_netfil.h | 2 - src/deh_tables.c | 2 +- src/doomdef.h | 3 +- src/hu_stuff.c | 31 ----- src/i_tcp.c | 238 ++++++++++++++----------------------- src/m_menu.c | 55 --------- src/m_menu.h | 2 +- src/mserv.c | 6 - src/sdl/i_system.c | 4 - 18 files changed, 96 insertions(+), 399 deletions(-) diff --git a/src/Makefile b/src/Makefile index 7571c8089..cec5dc88f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -64,7 +64,6 @@ # # Netplay incompatible # -------------------- -# NONET=1 - Disable online capability. # NOMD5=1 - Disable MD5 checksum (validation tool). # NOPOSTPROCESSING=1 - ? # MOBJCONSISTANCY=1 - ?? diff --git a/src/Makefile.d/features.mk b/src/Makefile.d/features.mk index 8ba33383b..9acbb4d86 100644 --- a/src/Makefile.d/features.mk +++ b/src/Makefile.d/features.mk @@ -3,7 +3,7 @@ # passthru_opts+=\ - NONET NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\ + NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\ MOBJCONSISTANCY PACKETDROP ZDEBUG\ HAVE_MINIUPNPC\ @@ -46,13 +46,11 @@ sources+=apng.c endif endif -ifndef NONET ifndef NOCURL CURLCONFIG?=curl-config $(eval $(call Configure,CURL,$(CURLCONFIG))) opts+=-DHAVE_CURL endif -endif ifdef HAVE_MINIUPNPC libs+=-lminiupnpc diff --git a/src/Makefile.d/win32.mk b/src/Makefile.d/win32.mk index 0e48ed683..e7269e1e7 100644 --- a/src/Makefile.d/win32.mk +++ b/src/Makefile.d/win32.mk @@ -35,12 +35,10 @@ libs+=-lws2_32 endif endif -ifndef NONET ifndef MINGW64 # miniupnc is broken with MINGW64 opts+=-I../libs -DSTATIC_MINIUPNPC libs+=-L../libs/miniupnpc/mingw$(32) -lws2_32 -liphlpapi endif -endif ifndef MINGW64 32=32 diff --git a/src/d_clisrv.c b/src/d_clisrv.c index b25e34c56..cb1ccd539 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -53,12 +53,10 @@ // aaaaaa #include "i_gamepad.h" -#ifndef NONET // cl loading screen #include "v_video.h" #include "f_finale.h" #include "snake.h" -#endif // // NETWORKING @@ -535,7 +533,6 @@ static cl_mode_t cl_mode = CL_SEARCHING; static UINT16 cl_lastcheckedfilecount = 0; // used for full file list -#ifndef NONET static void *snake = NULL; static void CL_DrawConnectionStatusBox(void) @@ -716,7 +713,6 @@ static inline void CL_DrawConnectionStatus(void) } } } -#endif static boolean CL_AskFileList(INT32 firstfile) { @@ -983,7 +979,6 @@ static boolean SV_SendServerConfig(INT32 node) return waspacketsent; } -#ifndef NONET #define SAVEGAMESIZE (768*1024) static boolean SV_ResendingSavegameToAnyone(void) @@ -1210,9 +1205,7 @@ static void CL_ReloadReceivedSavegame(void) CONS_Printf(M_GetText("Game state reloaded\n")); } -#endif -#ifndef NONET static void SendAskInfo(INT32 node) { const tic_t asktime = I_GetTime(); @@ -1430,12 +1423,8 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room) #endif/*MASTERSERVER*/ } -#endif // ifndef NONET - static void M_ConfirmConnect(event_t *ev) { -#ifndef NONET - if (ev->type == ev_keydown || ev->type == ev_gamepad_down) { if ((ev->type == ev_keydown && (ev->key == ' ' || ev->key == 'y' || ev->key == KEY_ENTER)) || (ev->type == ev_gamepad_down && ev->which == 0 && ev->key == GAMEPAD_BUTTON_A)) @@ -1459,9 +1448,6 @@ static void M_ConfirmConnect(event_t *ev) M_ClearMenus(true); } } -#else - (void)ev; -#endif } static boolean CL_FinishedFileList(void) @@ -1541,7 +1527,6 @@ static boolean CL_FinishedFileList(void) return false; } -#ifndef NONET downloadcompletednum = 0; downloadcompletedsize = 0; totalfilesrequestednum = 0; @@ -1561,7 +1546,6 @@ static boolean CL_FinishedFileList(void) downloadsize = Z_StrDup(va("%uM",totalfilesrequestedsize>>20)); else downloadsize = Z_StrDup(va("%uK",totalfilesrequestedsize>>10)); -#endif if (serverisfull) M_StartMessage(va(M_GetText( @@ -1586,7 +1570,6 @@ static boolean CL_FinishedFileList(void) return true; } -#ifndef NONET static const char * InvalidServerReason (serverinfo_pak *info) { #define EOT "\nPress ESC\n" @@ -1650,7 +1633,6 @@ static const char * InvalidServerReason (serverinfo_pak *info) #undef EOT } -#endif // ifndef NONET /** Called by CL_ServerConnectionTicker * @@ -1662,7 +1644,6 @@ static const char * InvalidServerReason (serverinfo_pak *info) */ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) { -#ifndef NONET INT32 i; // serverlist is updated by GetPacket function @@ -1732,11 +1713,6 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) SendAskInfo(servernode); *asksent = I_GetTime(); } -#else - (void)asksent; - // No netgames, so we skip this state. - cl_mode = CL_ASKJOIN; -#endif // ifndef NONET/else return true; } @@ -1756,10 +1732,6 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic boolean waitmore; INT32 i; -#ifdef NONET - (void)tmpsave; -#endif - switch (cl_mode) { case CL_SEARCHING: @@ -1824,12 +1796,12 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic ), NULL, MM_NOTHING); return false; } -#ifndef NONET + // prepare structures to save the file // WARNING: this can be useless in case of server not in GS_LEVEL // but since the network layer doesn't provide ordered packets... CL_PrepareDownloadSaveGame(tmpsave); -#endif + if (I_GetTime() >= *asksent && CL_SendJoin()) { *asksent = I_GetTime() + NEWTICRATE*3; @@ -1842,7 +1814,6 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic cl_mode = CL_ASKJOIN; } break; -#ifndef NONET case CL_DOWNLOADSAVEGAME: // At this state, the first (and only) needed file is the gamestate if (fileneeded[0].status == FS_FOUND) @@ -1853,7 +1824,6 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic } // don't break case continue to CL_CONNECTED else break; -#endif case CL_CONNECTED: case CL_CONFIRMCONNECT: //logic is handled by M_ConfirmConnect @@ -1898,10 +1868,8 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic memset(gamekeydown, 0, NUMKEYS); return false; } -#ifndef NONET else if (cl_mode == CL_DOWNLOADFILES && snake) Snake_Update(snake); -#endif if (client && (cl_mode == CL_DOWNLOADFILES || cl_mode == CL_DOWNLOADSAVEGAME)) FileReceiveTicker(); @@ -1912,7 +1880,6 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic //FileSendTicker(); *oldtic = I_GetTime(); -#ifndef NONET if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED) { if (!snake) @@ -1935,10 +1902,6 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic S_UpdateSounds(); S_UpdateClosedCaptions(); } -#else - CON_Drawer(); - I_UpdateNoVsync(); -#endif } else { @@ -1958,22 +1921,18 @@ static void CL_ConnectToServer(void) { INT32 pnumnodes, nodewaited = doomcom->numnodes, i; tic_t oldtic; -#ifndef NONET tic_t asksent; char tmpsave[256]; sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); lastfilenum = -1; -#endif cl_mode = CL_SEARCHING; -#ifndef NONET // Don't get a corrupt savegame error because tmpsave already exists if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1) I_Error("Can't delete %s\n", tmpsave); -#endif if (netgame) { @@ -1994,7 +1953,6 @@ static void CL_ConnectToServer(void) pnumnodes = 1; oldtic = I_GetTime() - 1; -#ifndef NONET asksent = (tic_t) - TICRATE; firstconnectattempttime = I_GetTime(); @@ -2010,16 +1968,11 @@ static void CL_ConnectToServer(void) serverlist[i].info.version%100, serverlist[i].info.subversion); } SL_ClearServerList(servernode); -#endif do { // If the connection was aborted for some reason, leave -#ifndef NONET if (!CL_ServerConnectionTicker(tmpsave, &oldtic, &asksent)) -#else - if (!CL_ServerConnectionTicker((char*)NULL, &oldtic, (tic_t *)NULL)) -#endif return; if (server) @@ -2037,7 +1990,6 @@ static void CL_ConnectToServer(void) displayplayer = consoleplayer; } -#ifndef NONET typedef struct banreason_s { char *reason; @@ -2276,7 +2228,6 @@ static void Command_connect(void) botskin = 0; CL_ConnectToServer(); } -#endif static void ResetNode(INT32 node) { @@ -2437,10 +2388,8 @@ void CL_Reset(void) FreeFileNeeded(); fileneedednum = 0; -#ifndef NONET totalfilesrequestednum = 0; totalfilesrequestedsize = 0; -#endif firstconnectattempttime = 0; serverisfull = false; connectiontimeout = (tic_t)cv_nettimeout.value; //reset this temporary hack @@ -2448,7 +2397,6 @@ void CL_Reset(void) // D_StartTitle should get done now, but the calling function will handle it } -#ifndef NONET static void Command_GetPlayerNum(void) { INT32 i; @@ -2726,7 +2674,6 @@ static void Command_ResendGamestate(void) return; } } -#endif static void Got_KickCmd(UINT8 **p, INT32 playernum) { @@ -2810,10 +2757,8 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) { if (I_Ban && !I_Ban(playernode[(INT32)pnum])) CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n")); -#ifndef NONET else Ban_Add(reason); -#endif } switch (msg) @@ -2953,7 +2898,6 @@ void D_ClientServerInit(void) DEBFILE(va("- - -== SRB2 v%d.%.2d.%d "VERSIONSTRING" debugfile ==- - -\n", VERSION/100, VERSION%100, SUBVERSION)); -#ifndef NONET COM_AddCommand("getplayernum", Command_GetPlayerNum); COM_AddCommand("kick", Command_Kick); COM_AddCommand("ban", Command_Ban); @@ -2970,17 +2914,14 @@ void D_ClientServerInit(void) #endif #ifdef _DEBUG COM_AddCommand("numnodes", Command_Numnodes); -#endif #endif RegisterNetXCmd(XD_KICK, Got_KickCmd); RegisterNetXCmd(XD_ADDPLAYER, Got_AddPlayer); -#ifndef NONET #ifdef DUMPCONSISTENCY CV_RegisterVar(&cv_dumpconsistency); #endif Ban_Load_File(false); -#endif gametic = 0; localgametic = 0; @@ -3540,7 +3481,6 @@ static void HandleConnect(SINT8 node) } DEBFILE("new node joined\n"); -#ifndef NONET if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) { SV_SendSaveGame(node, false); // send a complete game state @@ -3553,7 +3493,6 @@ static void HandleConnect(SINT8 node) joindelay += cv_joindelay.value * TICRATE; player_joining = true; -#endif } /** Called when a PT_SERVERSHUTDOWN packet is received @@ -3586,7 +3525,6 @@ static void HandleTimeout(SINT8 node) M_StartMessage(M_GetText("Server Timeout\n\nPress Esc\n"), NULL, MM_NOTHING); } -#ifndef NONET /** Called when a PT_SERVERINFO packet is received * * \param node The packet sender @@ -3608,7 +3546,6 @@ static void HandleServerInfo(SINT8 node) SL_InsertServer(&netbuffer->u.serverinfo, node); } -#endif // Helper function for packets that should only be sent by the server // If it is NOT from the server, bail out and close the connection! @@ -3744,14 +3681,9 @@ static void PT_ServerCFG(SINT8 node) playernode[(UINT8)serverplayer] = servernode; if (netgame) -#ifndef NONET CONS_Printf(M_GetText("Join accepted, waiting for complete game state...\n")); -#else - CONS_Printf(M_GetText("Join accepted, waiting for next level change...\n")); -#endif DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode)); -#ifndef NONET /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? /// Shouldn't them be downloaded even at intermission time? /// Also, according to HandleConnect, the server will send the savegame even during intermission... @@ -3759,7 +3691,6 @@ static void PT_ServerCFG(SINT8 node) netbuffer->u.servercfg.gamestate == GS_INTERMISSION*/) cl_mode = CL_DOWNLOADSAVEGAME; else -#endif cl_mode = CL_CONNECTED; } @@ -3823,9 +3754,7 @@ static void PT_ClientCmd(SINT8 node, INT32 netconsole) // Check player consistancy during the level if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) -#ifndef NONET && !SV_ResendingSavegameToAnyone() -#endif && !netnodes[node].resendingsavegame && netnodes[node].savegameresendcooldown <= I_GetTime()) { if (cv_resynchattempts.value) @@ -4000,7 +3929,6 @@ static void PT_ClientQuit(SINT8 node, INT32 netconsole) static void PT_CanReceiveGamestate(SINT8 node) { -#ifndef NONET if (client || netnodes[node].sendingsavegame) return; @@ -4008,9 +3936,6 @@ static void PT_CanReceiveGamestate(SINT8 node) SV_SendSaveGame(node, true); // Resend a complete game state netnodes[node].resendingsavegame = true; -#else - (void)node; -#endif } static void PT_AskLuaFile(SINT8 node) @@ -4134,7 +4059,6 @@ static void PT_WillResendGamestate(SINT8 node) { (void)node; -#ifndef NONET char tmpsave[256]; if (server || cl_redownloadinggamestate) @@ -4157,7 +4081,6 @@ static void PT_WillResendGamestate(SINT8 node) CL_PrepareDownloadSaveGame(tmpsave); cl_redownloadinggamestate = true; -#endif } static void PT_SendingLuaFile(SINT8 node) @@ -4296,13 +4219,11 @@ static void GetPackets(void) } } -#ifndef NONET if (netbuffer->packettype == PT_SERVERINFO) { HandleServerInfo(node); continue; } -#endif if (netbuffer->packettype == PT_PLAYERINFO) continue; // We do nothing with PLAYERINFO, that's for the MS browser. @@ -4906,11 +4827,9 @@ void NetUpdate(void) if (client) { -#ifndef NONET // If the client just finished redownloading the game state, load it if (cl_redownloadinggamestate && fileneeded[0].status == FS_FOUND) CL_ReloadReceivedSavegame(); -#endif CL_SendClientCmd(); // Send tic cmd hu_redownloadinggamestate = cl_redownloadinggamestate; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 99d859924..0d6add13a 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -437,11 +437,9 @@ boolean TryRunTics(tic_t realtic); /*boolean AddLmpExtradata(UINT8 **demo_p, INT32 playernum); void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum);*/ -#ifndef NONET // translate a playername in a player number return -1 if not found and // print a error message in the console SINT8 nametonum(const char *name); -#endif extern char motd[254], server_context[8]; extern UINT8 playernode[MAXPLAYERS]; diff --git a/src/d_net.c b/src/d_net.c index a7e1eb16d..9e3759d32 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -138,7 +138,6 @@ boolean Net_GetNetStat(void) #define URGENTFREESLOTNUM 10 #define ACKTOSENDTIMEOUT (TICRATE/11) -#ifndef NONET typedef struct { UINT8 acknum; @@ -152,7 +151,6 @@ typedef struct doomdata_t data; } pak; } ackpak_t; -#endif typedef enum { @@ -160,10 +158,8 @@ typedef enum NF_TIMEOUT = 2, // Flag is set when the node got a timeout } node_flags_t; -#ifndef NONET // Table of packets that were not acknowleged can be resent (the sender window) static ackpak_t ackpak[MAXACKPACKETS]; -#endif typedef struct { @@ -191,7 +187,6 @@ typedef struct static node_t nodes[MAXNETNODES]; #define NODETIMEOUT 14 -#ifndef NONET // return <0 if a < b (mod 256) // 0 if a = n (mod 256) // >0 if a > b (mod 256) @@ -426,21 +421,15 @@ static boolean Processackpak(void) } return goodpacket; } -#endif // send special packet with only ack on it void Net_SendAcks(INT32 node) { -#ifdef NONET - (void)node; -#else netbuffer->packettype = PT_NOTHING; M_Memcpy(netbuffer->u.textcmd, nodes[node].acktosend, MAXACKTOSEND); HSendPacket(node, false, 0, MAXACKTOSEND); -#endif } -#ifndef NONET static void GotAcks(void) { INT32 i, j; @@ -463,7 +452,6 @@ static void GotAcks(void) } } } -#endif void Net_ConnectionTimeout(INT32 node) { @@ -489,7 +477,6 @@ void Net_ConnectionTimeout(INT32 node) // Resend the data if needed void Net_AckTicker(void) { -#ifndef NONET INT32 i; for (i = 0; i < MAXACKPACKETS; i++) @@ -536,16 +523,12 @@ void Net_AckTicker(void) } } } -#endif } // Remove last packet received ack before resending the ackreturn // (the higher layer doesn't have room, or something else ....) void Net_UnAcknowledgePacket(INT32 node) { -#ifdef NONET - (void)node; -#else INT32 hm1 = (nodes[node].acktosend_head-1+MAXACKTOSEND) % MAXACKTOSEND; DEBFILE(va("UnAcknowledge node %d\n", node)); if (!node) @@ -577,10 +560,8 @@ void Net_UnAcknowledgePacket(INT32 node) if (!nodes[node].firstacktosend) nodes[node].firstacktosend = 1; } -#endif } -#ifndef NONET /** Checks if all acks have been received * * \return True if all acks have been received @@ -596,7 +577,6 @@ static boolean Net_AllAcksReceived(void) return true; } -#endif /** Waits for all ackreturns * @@ -605,9 +585,6 @@ static boolean Net_AllAcksReceived(void) */ void Net_WaitAllAckReceived(UINT32 timeout) { -#ifdef NONET - (void)timeout; -#else tic_t tictac = I_GetTime(); timeout = tictac + timeout*NEWTICRATE; @@ -623,7 +600,6 @@ void Net_WaitAllAckReceived(UINT32 timeout) HGetPacket(); Net_AckTicker(); } -#endif } static void InitNode(node_t *node) @@ -639,10 +615,8 @@ static void InitAck(void) { INT32 i; -#ifndef NONET for (i = 0; i < MAXACKPACKETS; i++) ackpak[i].acknum = 0; -#endif for (i = 0; i < MAXNETNODES; i++) InitNode(&nodes[i]); @@ -655,9 +629,6 @@ static void InitAck(void) */ void Net_AbortPacketType(UINT8 packettype) { -#ifdef NONET - (void)packettype; -#else INT32 i; for (i = 0; i < MAXACKPACKETS; i++) if (ackpak[i].acknum && (ackpak[i].pak.data.packettype == packettype @@ -665,7 +636,6 @@ void Net_AbortPacketType(UINT8 packettype) { ackpak[i].acknum = 0; } -#endif } // ----------------------------------------------------------------- @@ -675,9 +645,6 @@ void Net_AbortPacketType(UINT8 packettype) // remove a node, clear all ack from this node and reset askret void Net_CloseConnection(INT32 node) { -#ifdef NONET - (void)node; -#else INT32 i; boolean forceclose = (node & FORCECLOSE) != 0; @@ -722,10 +689,8 @@ void Net_CloseConnection(INT32 node) if (server) SV_AbortLuaFileTransfer(node); I_NetFreeNodenum(node); -#endif } -#ifndef NONET // // Checksum // @@ -741,7 +706,6 @@ static UINT32 NetbufferChecksum(void) return LONG(c); } -#endif #ifdef DEBUGFILE @@ -983,14 +947,12 @@ void Command_Droprate(void) packetdroprate = droprate; } -#ifndef NONET static boolean ShouldDropPacket(void) { return (packetdropquantity[netbuffer->packettype]) || (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100; } #endif -#endif // // HSendPacket @@ -1025,11 +987,6 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen if (!netgame) I_Error("Tried to transmit to another node"); -#ifdef NONET - (void)node; - (void)reliable; - (void)acknum; -#else // do this before GetFreeAcknum because this function backups // the current packet doomcom->remotenode = (INT16)node; @@ -1090,8 +1047,6 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen } #endif -#endif // ndef NONET - return true; } @@ -1125,8 +1080,6 @@ boolean HGetPacket(void) if (!netgame) return false; -#ifndef NONET - while(true) { //nodejustjoined = I_NetGet(); @@ -1186,7 +1139,6 @@ boolean HGetPacket(void) } break; } -#endif // ndef NONET return true; } diff --git a/src/d_net.h b/src/d_net.h index c6c9e2894..803b49d74 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -66,9 +66,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength); boolean HGetPacket(void); void D_SetDoomcom(void); -#ifndef NONET void D_SaveBan(void); -#endif boolean D_CheckNetGame(void); void D_CloseConnection(void); void Net_UnAcknowledgePacket(INT32 node); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 64f478ff7..69eed90de 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -628,11 +628,9 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_maxsend); CV_RegisterVar(&cv_noticedownload); CV_RegisterVar(&cv_downloadspeed); -#ifndef NONET CV_RegisterVar(&cv_allownewplayer); CV_RegisterVar(&cv_showjoinaddress); CV_RegisterVar(&cv_blamecfail); -#endif COM_AddCommand("ping", Command_Ping_f); CV_RegisterVar(&cv_nettimeout); diff --git a/src/d_netfil.c b/src/d_netfil.c index 1fee1df81..bf3952cc9 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -103,14 +103,12 @@ typedef struct } pauseddownload_t; static pauseddownload_t *pauseddownload = NULL; -#ifndef NONET // for cl loading screen INT32 lastfilenum = -1; INT32 downloadcompletednum = 0; UINT32 downloadcompletedsize = 0; INT32 totalfilesrequestednum = 0; UINT32 totalfilesrequestedsize = 0; -#endif luafiletransfer_t *luafiletransfers = NULL; boolean waitingforluafiletransfer = false; @@ -250,9 +248,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 fi void CL_PrepareDownloadSaveGame(const char *tmpsave) { -#ifndef NONET lastfilenum = -1; -#endif FreeFileNeeded(); AllocFileNeeded(1); @@ -1466,9 +1462,7 @@ void PT_FileFragment(SINT8 node, INT32 netconsole) I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s); } -#ifndef NONET lastfilenum = filenum; -#endif } /** \brief Checks if a node is downloading a file diff --git a/src/d_netfil.h b/src/d_netfil.h index 5c7f4ef49..ec53be587 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -70,13 +70,11 @@ extern INT32 fileneedednum; extern fileneeded_t *fileneeded; extern char downloaddir[512]; -#ifndef NONET extern INT32 lastfilenum; extern INT32 downloadcompletednum; extern UINT32 downloadcompletedsize; extern INT32 totalfilesrequestednum; extern UINT32 totalfilesrequestedsize; -#endif void AllocFileNeeded(INT32 size); void FreeFileNeeded(void); diff --git a/src/deh_tables.c b/src/deh_tables.c index a2cc9732d..97b6373cd 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4831,7 +4831,7 @@ const char *const MENUTYPES_LIST[] = { "MP_SERVER", "MP_CONNECT", "MP_ROOM", - "MP_PLAYERSETUP", // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET + "MP_PLAYERSETUP", "MP_SERVER_OPTIONS", // Options diff --git a/src/doomdef.h b/src/doomdef.h index 24b4fa980..b70f0a47e 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -56,7 +56,6 @@ #endif #ifdef _WINDOWS -#define NONET #if !defined (HWRENDER) && !defined (NOHW) #define HWRENDER #endif @@ -657,7 +656,7 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// Maintain compatibility with older 2.2 demos #define OLD22DEMOCOMPAT -#if defined (HAVE_CURL) && ! defined (NONET) +#ifdef HAVE_CURL #define MASTERSERVER #else #undef UPDATE_ALERT diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 805aa694f..37c3f0dc3 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -175,14 +175,12 @@ static huddrawlist_h luahuddrawlist_scores; static tic_t resynch_ticker = 0; -#ifndef NONET // just after static void Command_Say_f(void); static void Command_Sayto_f(void); static void Command_Sayteam_f(void); static void Command_CSay_f(void); static void Got_Saycmd(UINT8 **p, INT32 playernum); -#endif void HU_LoadGraphics(void) { @@ -327,13 +325,11 @@ void HU_LoadGraphics(void) // void HU_Init(void) { -#ifndef NONET COM_AddCommand("say", Command_Say_f); COM_AddCommand("sayto", Command_Sayto_f); COM_AddCommand("sayteam", Command_Sayteam_f); COM_AddCommand("csay", Command_CSay_f); RegisterNetXCmd(XD_SAY, Got_Saycmd); -#endif // set shift translation table shiftxform = english_shiftxform; @@ -363,8 +359,6 @@ void HU_Start(void) // EXECUTION //====================================================================== -#ifndef NONET - // EVERY CHANGE IN THIS SCRIPT IS LOL XD! BY VINCYTM static UINT32 chat_nummsg_log = 0; @@ -412,11 +406,9 @@ static void HU_removeChatText_Log(void) } chat_nummsg_log--; // lost 1 msg. } -#endif void HU_AddChatText(const char *text, boolean playsound) { -#ifndef NONET if (playsound && cv_consolechat.value != 2) // Don't play the sound if we're using hidden chat. S_StartSound(NULL, sfx_radio); // reguardless of our preferences, put all of this in the chat buffer in case we decide to change from oldchat mid-game. @@ -438,14 +430,8 @@ void HU_AddChatText(const char *text, boolean playsound) CONS_Printf("%s\n", text); else // if we aren't, still save the message to log.txt CON_LogMessage(va("%s\n", text)); -#else - (void)playsound; - CONS_Printf("%s\n", text); -#endif } -#ifndef NONET - /** Runs a say command, sending an ::XD_SAY message. * A say command consists of a signed 8-bit integer for the target, an * unsigned 8-bit flag variable, and then the message itself. @@ -865,8 +851,6 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) #endif } -#endif - // // void HU_Ticker(void) @@ -882,7 +866,6 @@ void HU_Ticker(void) else hu_showscores = false; -#ifndef NONET if (chat_on) { // count down the scroll timer. @@ -910,7 +893,6 @@ void HU_Ticker(void) HU_removeChatText_Mini(); } } -#endif if (cechotimer > 0) --cechotimer; @@ -918,8 +900,6 @@ void HU_Ticker(void) resynch_ticker++; } -#ifndef NONET - static boolean teamtalk = false; static boolean justscrolleddown; static boolean justscrolledup; @@ -1027,8 +1007,6 @@ static void HU_sendChatMessage(void) } } -#endif - void HU_clearChatChars(void) { memset(w_chat, '\0', sizeof(w_chat)); @@ -1043,16 +1021,13 @@ void HU_clearChatChars(void) // boolean HU_Responder(event_t *ev) { -#ifndef NONET INT32 c=0; -#endif if (ev->type != ev_keydown) return false; // only KeyDown events now... -#ifndef NONET c = (INT32)ev->key; if (!chat_on) @@ -1202,7 +1177,6 @@ boolean HU_Responder(event_t *ev) return true; } -#endif return false; } @@ -1212,8 +1186,6 @@ boolean HU_Responder(event_t *ev) // HEADS UP DRAWING //====================================================================== -#ifndef NONET - // Precompile a wordwrapped string to any given width. // This is a muuuch better method than V_WORDWRAP. // again stolen and modified a bit from video.c, don't mind me, will need to rearrange this one day. @@ -1793,7 +1765,6 @@ static void HU_DrawChat_Old(void) if (hu_tick < 4) V_DrawCharacter(HU_INPUTX + c, y, '_' | cv_constextsize.value |V_NOSCALESTART|t, true); } -#endif // Draw crosshairs at the exact center of the view. // In splitscreen, crosshairs are stretched vertically to compensate for V_PERPLAYER squishing them. @@ -1933,7 +1904,6 @@ static void HU_DrawDemoInfo(void) // void HU_Drawer(void) { -#ifndef NONET // draw chat string plus cursor if (chat_on) { @@ -1950,7 +1920,6 @@ void HU_Drawer(void) if (!OLDCHAT && cv_consolechat.value < 2 && netgame) // Don't display minimized chat if you set the mode to Window (Hidden) HU_drawMiniChat(); // draw messages in a cool fashion. } -#endif if (cechotimer) HU_DrawCEcho(); diff --git a/src/i_tcp.c b/src/i_tcp.c index 00aebddd3..ec3d1ae93 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -38,96 +38,87 @@ #include "doomdef.h" -#if defined (NOMD5) && !defined (NONET) - //#define NONET +#ifdef USE_WINSOCK1 + #include +#else + #ifndef USE_WINSOCK + #include + #ifdef __APPLE_CC__ + #ifndef _BSD_SOCKLEN_T_ + #define _BSD_SOCKLEN_T_ + #endif //_BSD_SOCKLEN_T_ + #endif //__APPLE_CC__ + #include + #include + #include + #include + #endif //normal BSD API + + #include + #include + + #if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON) + #include + #endif // UNIXCOMMON #endif -#ifdef NONET - #undef HAVE_MINIUPNPC -#else - #ifdef USE_WINSOCK1 - #include - #else - #ifndef USE_WINSOCK - #include - #ifdef __APPLE_CC__ - #ifndef _BSD_SOCKLEN_T_ - #define _BSD_SOCKLEN_T_ - #endif //_BSD_SOCKLEN_T_ - #endif //__APPLE_CC__ - #include - #include - #include - #include - #endif //normal BSD API - - #include - #include - - #if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON) - #include - #endif // UNIXCOMMON +#ifdef USE_WINSOCK + // some undefined under win32 + #undef errno + //#define errno WSAGetLastError() //Alam_GBC: this is the correct way, right? + #define errno h_errno // some very strange things happen when not using h_error?!? + #ifdef EWOULDBLOCK + #undef EWOULDBLOCK #endif - - #ifdef USE_WINSOCK - // some undefined under win32 - #undef errno - //#define errno WSAGetLastError() //Alam_GBC: this is the correct way, right? - #define errno h_errno // some very strange things happen when not using h_error?!? - #ifdef EWOULDBLOCK - #undef EWOULDBLOCK - #endif - #define EWOULDBLOCK WSAEWOULDBLOCK - #ifdef EMSGSIZE - #undef EMSGSIZE - #endif - #define EMSGSIZE WSAEMSGSIZE - #ifdef ECONNREFUSED - #undef ECONNREFUSED - #endif - #define ECONNREFUSED WSAECONNREFUSED - #ifdef ETIMEDOUT - #undef ETIMEDOUT - #endif - #define ETIMEDOUT WSAETIMEDOUT - #ifndef IOC_VENDOR - #define IOC_VENDOR 0x18000000 - #endif - #ifndef _WSAIOW - #define _WSAIOW(x,y) (IOC_IN|(x)|(y)) - #endif - #ifndef SIO_UDP_CONNRESET - #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) - #endif - #ifndef AI_ADDRCONFIG - #define AI_ADDRCONFIG 0x00000400 - #endif - #ifndef STATUS_INVALID_PARAMETER - #define STATUS_INVALID_PARAMETER 0xC000000D - #endif - #endif // USE_WINSOCK - - typedef union - { - struct sockaddr any; - struct sockaddr_in ip4; - #ifdef HAVE_IPV6 - struct sockaddr_in6 ip6; + #define EWOULDBLOCK WSAEWOULDBLOCK + #ifdef EMSGSIZE + #undef EMSGSIZE #endif - } mysockaddr_t; + #define EMSGSIZE WSAEMSGSIZE + #ifdef ECONNREFUSED + #undef ECONNREFUSED + #endif + #define ECONNREFUSED WSAECONNREFUSED + #ifdef ETIMEDOUT + #undef ETIMEDOUT + #endif + #define ETIMEDOUT WSAETIMEDOUT + #ifndef IOC_VENDOR + #define IOC_VENDOR 0x18000000 + #endif + #ifndef _WSAIOW + #define _WSAIOW(x,y) (IOC_IN|(x)|(y)) + #endif + #ifndef SIO_UDP_CONNRESET + #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) + #endif + #ifndef AI_ADDRCONFIG + #define AI_ADDRCONFIG 0x00000400 + #endif + #ifndef STATUS_INVALID_PARAMETER + #define STATUS_INVALID_PARAMETER 0xC000000D + #endif +#endif // USE_WINSOCK - #ifdef HAVE_MINIUPNPC - #ifdef STATIC_MINIUPNPC - #define STATICLIB - #endif - #include "miniupnpc/miniwget.h" - #include "miniupnpc/miniupnpc.h" - #include "miniupnpc/upnpcommands.h" - #undef STATICLIB - static UINT8 UPNP_support = TRUE; - #endif // HAVE_MINIUPNC +typedef union +{ + struct sockaddr any; + struct sockaddr_in ip4; +#ifdef HAVE_IPV6 + struct sockaddr_in6 ip6; +#endif +} mysockaddr_t; -#endif // !NONET +#ifdef HAVE_MINIUPNPC + #ifdef STATIC_MINIUPNPC + #define STATICLIB + #endif + #include "miniupnpc/miniwget.h" + #include "miniupnpc/miniupnpc.h" + #include "miniupnpc/upnpcommands.h" + #undef STATICLIB + static UINT8 UPNP_support = TRUE; +#endif // HAVE_MINIUPNC #define MAXBANS 100 @@ -151,7 +142,7 @@ #define SELECTTEST #define DEFAULTPORT "5029" -#if defined (USE_WINSOCK) && !defined (NONET) +#ifdef USE_WINSOCK typedef SOCKET SOCKET_TYPE; #define ERRSOCKET (SOCKET_ERROR) #else @@ -163,22 +154,20 @@ #define ERRSOCKET (-1) #endif -#ifndef NONET - // define socklen_t in DOS/Windows if it is not already defined - #ifdef USE_WINSOCK1 - typedef int socklen_t; - #endif - static SOCKET_TYPE mysockets[MAXNETNODES+1] = {ERRSOCKET}; - static size_t mysocketses = 0; - static int myfamily[MAXNETNODES+1] = {0}; - static SOCKET_TYPE nodesocket[MAXNETNODES+1] = {ERRSOCKET}; - static mysockaddr_t clientaddress[MAXNETNODES+1]; - static mysockaddr_t broadcastaddress[MAXNETNODES+1]; - static size_t broadcastaddresses = 0; - static boolean nodeconnected[MAXNETNODES+1]; - static mysockaddr_t banned[MAXBANS]; - static UINT8 bannedmask[MAXBANS]; +// define socklen_t in DOS/Windows if it is not already defined +#ifdef USE_WINSOCK1 + typedef int socklen_t; #endif +static SOCKET_TYPE mysockets[MAXNETNODES+1] = {ERRSOCKET}; +static size_t mysocketses = 0; +static int myfamily[MAXNETNODES+1] = {0}; +static SOCKET_TYPE nodesocket[MAXNETNODES+1] = {ERRSOCKET}; +static mysockaddr_t clientaddress[MAXNETNODES+1]; +static mysockaddr_t broadcastaddress[MAXNETNODES+1]; +static size_t broadcastaddresses = 0; +static boolean nodeconnected[MAXNETNODES+1]; +static mysockaddr_t banned[MAXBANS]; +static UINT8 bannedmask[MAXBANS]; static size_t numbans = 0; static boolean SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1? @@ -187,7 +176,6 @@ static boolean init_tcp_driver = false; static const char *serverport_name = DEFAULTPORT; static const char *clientport_name;/* any port */ -#ifndef NONET #ifdef USE_WINSOCK // stupid microsoft makes things complicated static char *get_WSAErrorStr(int e) @@ -374,47 +362,33 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk) #endif return s; } -#endif static const char *SOCK_GetNodeAddress(INT32 node) { if (node == 0) return "self"; -#ifdef NONET - return NULL; -#else if (!nodeconnected[node]) return NULL; return SOCK_AddrToStr(&clientaddress[node]); -#endif } static const char *SOCK_GetBanAddress(size_t ban) { if (ban >= numbans) return NULL; -#ifdef NONET - return NULL; -#else return SOCK_AddrToStr(&banned[ban]); -#endif } static const char *SOCK_GetBanMask(size_t ban) { -#ifdef NONET - (void)ban; -#else static char s[16]; //255.255.255.255 netmask? no, just CDIR for only if (ban >= numbans) return NULL; if (sprintf(s,"%d",bannedmask[ban]) > 0) return s; -#endif return NULL; } -#ifndef NONET static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask) { UINT32 bitmask = INADDR_NONE; @@ -518,9 +492,7 @@ void Command_Numnodes(void) connected, ingame); } #endif -#endif -#ifndef NONET // Returns true if a packet was received from a new node, false in all other cases static boolean SOCK_Get(void) { @@ -583,10 +555,8 @@ static boolean SOCK_Get(void) doomcom->remotenode = -1; // no packet return false; } -#endif // check if we can send (do not go over the buffer) -#ifndef NONET static fd_set masterset; @@ -636,9 +606,7 @@ static boolean SOCK_CanGet(void) return false; } #endif -#endif -#ifndef NONET static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr) { socklen_t d4 = (socklen_t)sizeof(struct sockaddr_in); @@ -701,9 +669,7 @@ static void SOCK_Send(void) SOCK_GetNodeAddress(doomcom->remotenode), e, strerror(e)); } } -#endif -#ifndef NONET static void SOCK_FreeNodenum(INT32 numnode) { // can't disconnect from self :) @@ -718,12 +684,10 @@ static void SOCK_FreeNodenum(INT32 numnode) // put invalid address memset(&clientaddress[numnode], 0, sizeof (clientaddress[numnode])); } -#endif // // UDPsocket // -#ifndef NONET // allocate a socket static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen) @@ -1044,12 +1008,10 @@ static boolean UDP_Socket(void) return true; } -#endif boolean I_InitTcpDriver(void) { boolean tcp_was_up = init_tcp_driver; -#ifndef NONET if (!init_tcp_driver) { #ifdef USE_WINSOCK @@ -1104,7 +1066,7 @@ boolean I_InitTcpDriver(void) #endif init_tcp_driver = true; } -#endif + if (!tcp_was_up && init_tcp_driver) { I_AddExitFunc(I_ShutdownTcpDriver); @@ -1118,7 +1080,6 @@ boolean I_InitTcpDriver(void) return init_tcp_driver; } -#ifndef NONET static void SOCK_CloseSocket(void) { size_t i; @@ -1133,11 +1094,9 @@ static void SOCK_CloseSocket(void) mysockets[i] = ERRSOCKET; } } -#endif void I_ShutdownTcpDriver(void) { -#ifndef NONET SOCK_CloseSocket(); CONS_Printf("I_ShutdownTcpDriver: "); @@ -1147,10 +1106,8 @@ void I_ShutdownTcpDriver(void) #endif CONS_Printf("shut down\n"); init_tcp_driver = false; -#endif } -#ifndef NONET static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port) { SINT8 newnode = -1; @@ -1194,11 +1151,9 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port) I_freeaddrinfo(ai); return newnode; } -#endif static boolean SOCK_OpenSocket(void) { -#ifndef NONET size_t i; memset(clientaddress, 0, sizeof (clientaddress)); @@ -1222,18 +1177,12 @@ static boolean SOCK_OpenSocket(void) // build the socket but close it first SOCK_CloseSocket(); return UDP_Socket(); -#else - return false; -#endif } static boolean SOCK_Ban(INT32 node) { if (node > MAXNETNODES) return false; -#ifdef NONET - return false; -#else if (numbans == MAXBANS) return false; @@ -1252,16 +1201,10 @@ static boolean SOCK_Ban(INT32 node) #endif numbans++; return true; -#endif } static boolean SOCK_SetBanAddress(const char *address, const char *mask) { -#ifdef NONET - (void)address; - (void)mask; - return false; -#else struct my_addrinfo *ai, *runp, hints; int gaie; @@ -1306,7 +1249,6 @@ static boolean SOCK_SetBanAddress(const char *address, const char *mask) I_freeaddrinfo(ai); return true; -#endif } static void SOCK_ClearBans(void) diff --git a/src/m_menu.c b/src/m_menu.c index 7c67cf2da..824ae5c46 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -147,9 +147,7 @@ static struct INT32 index; } gamepadInfo[MAX_CONNECTED_GAMEPADS + 1]; -#ifndef NONET static UINT32 serverlistpage; -#endif static UINT8 numsaves = 0; static saveinfo_t* savegameinfo = NULL; // Extra info about the save games. @@ -189,10 +187,8 @@ static void M_GoBack(INT32 choice); static void M_StopMessage(INT32 choice); static boolean stopstopmessage = false; -#ifndef NONET static void M_HandleServerPage(INT32 choice); static void M_RoomMenu(INT32 choice); -#endif // Prototyping is fun, innit? // ========================================================================== @@ -294,7 +290,6 @@ static void M_SetupMultiPlayer2(INT32 choice); static void M_StartSplitServerMenu(INT32 choice); static void M_StartServer(INT32 choice); static void M_ServerOptions(INT32 choice); -#ifndef NONET static void M_StartServerMenu(INT32 choice); static void M_ConnectMenu(INT32 choice); static void M_ConnectMenuModChecks(INT32 choice); @@ -302,7 +297,6 @@ static void M_Refresh(INT32 choice); static void M_Connect(INT32 choice); static void M_ChooseRoom(INT32 choice); menu_t MP_MainDef; -#endif // Options // Split into multiple parts due to size @@ -381,11 +375,9 @@ static void M_DrawVideoMode(void); static void M_DrawColorMenu(void); static void M_DrawScreenshotMenu(void); static void M_DrawMonitorToggles(void); -#ifndef NONET static void M_DrawConnectMenu(void); static void M_DrawMPMainMenu(void); static void M_DrawRoomMenu(void); -#endif static void M_DrawGamepadList(void); static void M_DrawSetupMultiPlayerMenu(void); @@ -399,10 +391,8 @@ static void M_HandleImageDef(INT32 choice); static void M_HandleLoadSave(INT32 choice); static void M_HandleLevelStats(INT32 choice); static void M_HandlePlaystyleMenu(INT32 choice); -#ifndef NONET static boolean M_CancelConnect(void); static void M_HandleConnectIP(INT32 choice); -#endif static void M_HandleSetupMultiPlayer(INT32 choice); static void M_HandleVideoMode(INT32 choice); @@ -501,11 +491,7 @@ consvar_t cv_dummyloadless = CVAR_INIT ("dummyloadless", "In-game", CV_HIDEN, lo static menuitem_t MainMenu[] = { {IT_STRING|IT_CALL, NULL, "1 Player", M_SinglePlayerMenu, 76}, -#ifndef NONET {IT_STRING|IT_SUBMENU, NULL, "Multiplayer", &MP_MainDef, 84}, -#else - {IT_STRING|IT_CALL, NULL, "Multiplayer", M_StartSplitServerMenu, 84}, -#endif {IT_STRING|IT_CALL, NULL, "Extras", M_SecretsMenu, 92}, {IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 100}, {IT_STRING|IT_CALL, NULL, "Options", M_Options, 108}, @@ -956,16 +942,10 @@ static menuitem_t SP_PlayerMenu[] = static menuitem_t MP_SplitServerMenu[] = { {IT_STRING|IT_CALL, NULL, "Select Gametype/Level...", M_MapChange, 100}, -#ifdef NONET // In order to keep player setup accessible. - {IT_STRING|IT_CALL, NULL, "Player 1 setup...", M_SetupMultiPlayer, 110}, - {IT_STRING|IT_CALL, NULL, "Player 2 setup...", M_SetupMultiPlayer2, 120}, -#endif {IT_STRING|IT_CALL, NULL, "More Options...", M_ServerOptions, 130}, {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 140}, }; -#ifndef NONET - static menuitem_t MP_MainMenu[] = { {IT_HEADER, NULL, "Join a game", NULL, 0}, @@ -1052,8 +1032,6 @@ menuitem_t MP_RoomMenu[] = {IT_DISABLED, NULL, "", M_ChooseRoom, 162}, }; -#endif - static menuitem_t MP_PlayerSetupMenu[] = { {IT_KEYHANDLER, NULL, "", M_HandleSetupMultiPlayer, 0}, // name @@ -1612,14 +1590,12 @@ enum static menuitem_t OP_ServerOptionsMenu[] = { {IT_HEADER, NULL, "General", NULL, 0}, -#ifndef NONET {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Server name", &cv_servername, 7}, {IT_STRING | IT_CVAR, NULL, "Max Players", &cv_maxplayers, 21}, {IT_STRING | IT_CVAR, NULL, "Allow Add-on Downloading", &cv_downloading, 26}, {IT_STRING | IT_CVAR, NULL, "Allow players to join", &cv_allownewplayer, 31}, {IT_STRING | IT_CVAR, NULL, "Minutes for reconnecting", &cv_rejointimeout, 36}, -#endif {IT_STRING | IT_CVAR, NULL, "Map progression", &cv_advancemap, 41}, {IT_STRING | IT_CVAR, NULL, "Intermission Timer", &cv_inttime, 46}, @@ -1658,7 +1634,6 @@ static menuitem_t OP_ServerOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Autobalance sizes", &cv_autobalance, 216}, {IT_STRING | IT_CVAR, NULL, "Scramble on Map Change", &cv_scrambleonchange, 221}, -#ifndef NONET {IT_HEADER, NULL, "Advanced", NULL, 230}, {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server", &cv_masterserver, 236}, @@ -1666,7 +1641,6 @@ static menuitem_t OP_ServerOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 256}, {IT_STRING | IT_CVAR, NULL, "Show IP Address of Joiners", &cv_showjoinaddress, 261}, -#endif }; static menuitem_t OP_MonitorToggleMenu[] = @@ -1976,11 +1950,7 @@ menu_t MP_SplitServerDef = MTREE2(MN_MP_MAIN, MN_MP_SPLITSCREEN), "M_MULTI", sizeof (MP_SplitServerMenu)/sizeof (menuitem_t), -#ifndef NONET &MP_MainDef, -#else - &MainDef, -#endif MP_SplitServerMenu, M_DrawServerMenu, 27, 30 - 50, @@ -1988,8 +1958,6 @@ menu_t MP_SplitServerDef = NULL }; -#ifndef NONET - menu_t MP_MainDef = { MN_MP_MAIN, @@ -2041,15 +2009,10 @@ menu_t MP_RoomDef = 0, NULL }; -#endif menu_t MP_PlayerSetupDef = { -#ifdef NONET - MTREE2(MN_MP_MAIN, MN_MP_PLAYERSETUP), -#else MTREE3(MN_MP_MAIN, MN_MP_SPLITSCREEN, MN_MP_PLAYERSETUP), -#endif "M_SPLAYR", sizeof (MP_PlayerSetupMenu)/sizeof (menuitem_t), &MainDef, // doesn't matter @@ -3991,9 +3954,7 @@ void M_Init(void) OP_GamepadSetMenu[i].itemaction = M_AssignGamepad; } -#ifndef NONET CV_RegisterVar(&cv_serversort); -#endif } void M_InitCharacterTables(void) @@ -11006,7 +10967,6 @@ static void M_EndGame(INT32 choice) #define S_LINEY(n) currentMenu->y + SERVERHEADERHEIGHT + (n * SERVERLINEHEIGHT) -#ifndef NONET static UINT32 localservercount; static void M_HandleServerPage(INT32 choice) @@ -11278,11 +11238,9 @@ static int ServerListEntryComparator_modified(const void *entry1, const void *en // Default to strcmp. return strcmp(sa->info.servername, sb->info.servername); } -#endif void M_SortServerList(void) { -#ifndef NONET switch(cv_serversort.value) { case 0: // Ping. @@ -11304,10 +11262,8 @@ void M_SortServerList(void) qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametypename); break; } -#endif } -#ifndef NONET #ifdef UPDATE_ALERT static boolean M_CheckMODVersion(int id) { @@ -11506,7 +11462,6 @@ static void M_ChooseRoom(INT32 choice) if (currentMenu == &MP_ConnectDef) M_Refresh(0); } -#endif //NONET //=========================================================================== // Start Server Menu @@ -11554,7 +11509,6 @@ static void M_DrawServerMenu(void) { M_DrawGenericMenu(); -#ifndef NONET // Room name if (currentMenu == &MP_ServerDef) { @@ -11566,15 +11520,10 @@ static void M_DrawServerMenu(void) V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey, V_YELLOWMAP, room_list[menuRoomIndex].name); } -#endif if (cv_nextmap.value) { -#ifndef NONET #define imgheight MP_ServerMenu[mp_server_levelgt].alphaKey -#else -#define imgheight 100 -#endif patch_t *PictureOfLevel; lumpnum_t lumpnum; char headerstr[40]; @@ -11626,7 +11575,6 @@ static void M_ServerOptions(INT32 choice) { (void)choice; -#ifndef NONET if ((splitscreen && !netgame) || currentMenu == &MP_SplitServerDef) { OP_ServerOptionsMenu[ 1].status = IT_GRAYEDOUT; // Server name @@ -11647,7 +11595,6 @@ static void M_ServerOptions(INT32 choice) OP_ServerOptionsMenu[37].status = IT_STRING | IT_CVAR; OP_ServerOptionsMenu[38].status = IT_STRING | IT_CVAR; } -#endif /* Disable fading because of different menu head. */ if (currentMenu == &OP_MainDef)/* from Options menu */ @@ -11659,7 +11606,6 @@ static void M_ServerOptions(INT32 choice) M_SetupNextMenu(&OP_ServerOptionsDef); } -#ifndef NONET static void M_StartServerMenu(INT32 choice) { (void)choice; @@ -11870,7 +11816,6 @@ static void M_HandleConnectIP(INT32 choice) M_ClearMenus(true); } } -#endif //!NONET // ======================== // MULTIPLAYER PLAYER SETUP diff --git a/src/m_menu.h b/src/m_menu.h index 8d023811d..8eb183163 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -74,7 +74,7 @@ typedef enum MN_MP_SERVER, MN_MP_CONNECT, MN_MP_ROOM, - MN_MP_PLAYERSETUP, // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET + MN_MP_PLAYERSETUP, MN_MP_SERVER_OPTIONS, // Options diff --git a/src/mserv.c b/src/mserv.c index bff562c95..90091d241 100644 --- a/src/mserv.c +++ b/src/mserv.c @@ -45,9 +45,7 @@ static I_cond MSCond; # define Unlock_state() #endif/*HAVE_THREADS*/ -#ifndef NONET static void Command_Listserv_f(void); -#endif #endif/*MASTERSERVER*/ @@ -89,7 +87,6 @@ msg_rooms_t room_list[NUM_LIST_ROOMS+1]; // +1 for easy test */ void AddMServCommands(void) { -#ifndef NONET CV_RegisterVar(&cv_masterserver); CV_RegisterVar(&cv_masterserver_update_rate); CV_RegisterVar(&cv_masterserver_timeout); @@ -100,7 +97,6 @@ void AddMServCommands(void) COM_AddCommand("listserv", Command_Listserv_f); COM_AddCommand("masterserver_update", Update_parameters); // allows people to updates manually in case you were delisted by accident #endif -#endif } #ifdef MASTERSERVER @@ -189,7 +185,6 @@ void GetMODVersion_Console(void) } #endif -#ifndef NONET /** Gets a list of game servers. Called from console. */ static void Command_Listserv_f(void) @@ -200,7 +195,6 @@ static void Command_Listserv_f(void) HMS_list_servers(); } } -#endif static void Finish_registration (void) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index ee082fd5d..d08f3ff33 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -1592,9 +1592,7 @@ void I_Quit(void) SDLforceUngrabMouse(); quiting = SDL_FALSE; M_SaveConfig(NULL); //save game config, cvars.. -#ifndef NONET D_SaveBan(); // save the ban list -#endif G_SaveGameData(); // Tails 12-08-2002 //added:16-02-98: when recording a demo, should exit using 'q' key, // but sometimes we forget and use 'F10'.. so save here too. @@ -1709,9 +1707,7 @@ void I_Error(const char *error, ...) // --- M_SaveConfig(NULL); // save game config, cvars.. -#ifndef NONET D_SaveBan(); // save the ban list -#endif G_SaveGameData(); // Tails 12-08-2002 // Shutdown. Here might be other errors. From a895a5c37452768bd3dfe8f1393200cab524bb1a Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 31 Dec 2022 04:20:00 -0800 Subject: [PATCH 41/96] hooklib: pass NULL mobj to only run mobj hooks with no type discriminator --- src/lua_hooklib.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 6506d3dc6..50365293c 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -73,7 +73,7 @@ static boolean mobj_hook_available(int hook_type, mobjtype_t mobj_type) return ( mobjHookIds [MT_NULL] [hook_type].numHooks > 0 || - mobjHookIds[mobj_type][hook_type].numHooks > 0 + (mobj_type < NUMMOBJTYPES && mobjHookIds[mobj_type][hook_type].numHooks > 0) ); } @@ -344,8 +344,11 @@ static boolean prepare_mobj_hook Hook_State * hook, int default_status, int hook_type, - mobjtype_t mobj_type + mobj_t * primary_mobj ){ + const mobjtype_t mobj_type = + primary_mobj ? primary_mobj->type : NUMMOBJTYPES; + #ifdef PARANOIA if (mobj_type == MT_NULL) I_Error("MT_NULL has been passed to a mobj hook\n"); @@ -506,7 +509,9 @@ static int call_hooks { /* call generic mobj hooks first */ calls += call_mobj_type_hooks(hook, MT_NULL); - calls += call_mobj_type_hooks(hook, hook->mobj_type); + + if (hook->mobj_type < NUMMOBJTYPES) + calls += call_mobj_type_hooks(hook, hook->mobj_type); ps_lua_mobjhooks.value.i += calls; } @@ -554,7 +559,7 @@ static void res_force(Hook_State *hook) int LUA_HookMobj(mobj_t *mobj, int hook_type) { Hook_State hook; - if (prepare_mobj_hook(&hook, false, hook_type, mobj->type)) + if (prepare_mobj_hook(&hook, false, hook_type, mobj)) { LUA_PushUserdata(gL, mobj, META_MOBJ); call_hooks(&hook, 1, res_true); @@ -565,7 +570,7 @@ int LUA_HookMobj(mobj_t *mobj, int hook_type) int LUA_Hook2Mobj(mobj_t *t1, mobj_t *t2, int hook_type) { Hook_State hook; - if (prepare_mobj_hook(&hook, 0, hook_type, t1->type)) + if (prepare_mobj_hook(&hook, 0, hook_type, t1)) { LUA_PushUserdata(gL, t1, META_MOBJ); LUA_PushUserdata(gL, t2, META_MOBJ); @@ -735,7 +740,7 @@ void LUA_HookThinkFrame(void) int LUA_HookMobjLineCollide(mobj_t *mobj, line_t *line) { Hook_State hook; - if (prepare_mobj_hook(&hook, 0, MOBJ_HOOK(MobjLineCollide), mobj->type)) + if (prepare_mobj_hook(&hook, 0, MOBJ_HOOK(MobjLineCollide), mobj)) { LUA_PushUserdata(gL, mobj, META_MOBJ); LUA_PushUserdata(gL, line, META_LINE); @@ -747,7 +752,7 @@ int LUA_HookMobjLineCollide(mobj_t *mobj, line_t *line) int LUA_HookTouchSpecial(mobj_t *special, mobj_t *toucher) { Hook_State hook; - if (prepare_mobj_hook(&hook, false, MOBJ_HOOK(TouchSpecial), special->type)) + if (prepare_mobj_hook(&hook, false, MOBJ_HOOK(TouchSpecial), special)) { LUA_PushUserdata(gL, special, META_MOBJ); LUA_PushUserdata(gL, toucher, META_MOBJ); @@ -767,7 +772,7 @@ static int damage_hook Hook_Callback results_handler ){ Hook_State hook; - if (prepare_mobj_hook(&hook, 0, hook_type, target->type)) + if (prepare_mobj_hook(&hook, 0, hook_type, target)) { LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); @@ -801,7 +806,7 @@ int LUA_HookMobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 d int LUA_HookMobjMoveBlocked(mobj_t *t1, mobj_t *t2, line_t *line) { Hook_State hook; - if (prepare_mobj_hook(&hook, 0, MOBJ_HOOK(MobjMoveBlocked), t1->type)) + if (prepare_mobj_hook(&hook, 0, MOBJ_HOOK(MobjMoveBlocked), t1)) { LUA_PushUserdata(gL, t1, META_MOBJ); LUA_PushUserdata(gL, t2, META_MOBJ); @@ -972,7 +977,7 @@ void LUA_HookNetArchive(lua_CFunction archFunc) int LUA_HookMapThingSpawn(mobj_t *mobj, mapthing_t *mthing) { Hook_State hook; - if (prepare_mobj_hook(&hook, false, MOBJ_HOOK(MapThingSpawn), mobj->type)) + if (prepare_mobj_hook(&hook, false, MOBJ_HOOK(MapThingSpawn), mobj)) { LUA_PushUserdata(gL, mobj, META_MOBJ); LUA_PushUserdata(gL, mthing, META_MAPTHING); @@ -984,7 +989,7 @@ int LUA_HookMapThingSpawn(mobj_t *mobj, mapthing_t *mthing) int LUA_HookFollowMobj(player_t *player, mobj_t *mobj) { Hook_State hook; - if (prepare_mobj_hook(&hook, false, MOBJ_HOOK(FollowMobj), mobj->type)) + if (prepare_mobj_hook(&hook, false, MOBJ_HOOK(FollowMobj), mobj)) { LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, mobj, META_MOBJ); From fbcdaa6f4dc1ee6ffe0eb077ca86eb3b9531dd78 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 31 Dec 2022 04:25:52 -0800 Subject: [PATCH 42/96] hooklib: move HurtMsg to mobj hooks Fixes regression of mobj type discriminator not working for this hook. blame 8d382e49fb --- src/lua_hook.h | 2 +- src/lua_hooklib.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lua_hook.h b/src/lua_hook.h index 37a38e056..ff6470d76 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -41,6 +41,7 @@ automatically. X (MobjMoveBlocked),/* P_XYMovement (when movement is blocked) */\ X (MapThingSpawn),/* P_SpawnMapThing */\ X (FollowMobj),/* P_PlayerAfterThink Smiles mobj-following */\ + X (HurtMsg),/* imhurttin */\ #define HOOK_LIST(X) \ X (NetVars),/* add to archive table (netsave) */\ @@ -56,7 +57,6 @@ automatically. X (JumpSpinSpecial),/* P_DoJumpStuff (Spin button effect (mid-air)) */\ X (BotTiccmd),/* B_BuildTiccmd */\ X (PlayerMsg),/* chat messages */\ - X (HurtMsg),/* imhurttin */\ X (PlayerSpawn),/* G_SpawnPlayer */\ X (ShieldSpawn),/* P_SpawnShieldOrb */\ X (ShieldSpecial),/* shield abilities */\ diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 50365293c..ef8426d7a 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -933,7 +933,7 @@ int LUA_HookPlayerMsg(int source, int target, int flags, char *msg) int LUA_HookHurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 damagetype) { Hook_State hook; - if (prepare_hook(&hook, false, HOOK(HurtMsg))) + if (prepare_mobj_hook(&hook, false, MOBJ_HOOK(HurtMsg), inflictor)) { LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, inflictor, META_MOBJ); From 717e0d5a17ca22cfa56b6893c8b799dce1d568f3 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sat, 31 Dec 2022 14:10:19 +0100 Subject: [PATCH 43/96] Move netcode files to a new folder --- src/Makefile | 1 + src/Sourcefile | 7 ---- src/android/i_net.c | 2 +- src/blua/liolib.c | 2 +- src/command.c | 4 +- src/d_main.c | 6 +-- src/deh_soc.c | 2 +- src/deh_soc.h | 2 +- src/doomstat.h | 2 +- src/dummy/i_net.c | 2 +- src/f_finale.c | 2 +- src/filesrch.c | 2 +- src/filesrch.h | 2 +- src/g_demo.c | 2 +- src/g_game.c | 2 +- src/g_input.c | 2 +- src/hardware/hw_main.c | 6 +-- src/hu_stuff.c | 2 +- src/i_time.c | 2 +- src/lua_baselib.c | 4 +- src/lua_hooklib.c | 2 +- src/lua_script.c | 2 +- src/m_cheat.c | 2 +- src/m_menu.c | 6 +-- src/m_menu.h | 2 +- src/m_perfstats.c | 2 +- src/netcode/Sourcefile | 7 ++++ src/{ => netcode}/d_clisrv.c | 68 +++++++++++++++++----------------- src/{ => netcode}/d_clisrv.h | 6 +-- src/{ => netcode}/d_net.c | 16 ++++---- src/{ => netcode}/d_net.h | 0 src/{ => netcode}/d_netcmd.c | 66 ++++++++++++++++----------------- src/{ => netcode}/d_netcmd.h | 2 +- src/{ => netcode}/d_netfil.c | 30 +++++++-------- src/{ => netcode}/d_netfil.h | 2 +- src/{ => netcode}/http-mserv.c | 10 ++--- src/{ => netcode}/i_addrinfo.c | 0 src/{ => netcode}/i_addrinfo.h | 0 src/{ => netcode}/i_net.h | 4 +- src/{ => netcode}/i_tcp.c | 8 ++-- src/{ => netcode}/i_tcp.h | 0 src/{ => netcode}/mserv.c | 12 +++--- src/{ => netcode}/mserv.h | 2 +- src/p_ceilng.c | 2 +- src/p_haptic.c | 2 +- src/p_lights.c | 2 +- src/p_user.c | 2 +- src/r_segs.c | 2 +- src/r_things.c | 2 +- src/screen.c | 2 +- src/sdl/i_gamepad.c | 2 +- src/sdl/i_net.c | 6 +-- src/sdl/i_system.c | 4 +- src/sdl/i_ttf.c | 2 +- src/w_wad.c | 4 +- src/y_inter.c | 2 +- 56 files changed, 170 insertions(+), 169 deletions(-) create mode 100644 src/netcode/Sourcefile rename src/{ => netcode}/d_clisrv.c (99%) mode change 100755 => 100644 rename src/{ => netcode}/d_clisrv.h (99%) rename src/{ => netcode}/d_net.c (99%) rename src/{ => netcode}/d_net.h (100%) rename src/{ => netcode}/d_netcmd.c (99%) rename src/{ => netcode}/d_netcmd.h (99%) rename src/{ => netcode}/d_netfil.c (99%) rename src/{ => netcode}/d_netfil.h (99%) rename src/{ => netcode}/http-mserv.c (98%) rename src/{ => netcode}/i_addrinfo.c (100%) rename src/{ => netcode}/i_addrinfo.h (100%) rename src/{ => netcode}/i_net.h (98%) rename src/{ => netcode}/i_tcp.c (99%) rename src/{ => netcode}/i_tcp.h (100%) rename src/{ => netcode}/mserv.c (98%) rename src/{ => netcode}/mserv.h (99%) diff --git a/src/Makefile b/src/Makefile index cec5dc88f..750e8ead5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -207,6 +207,7 @@ objdir:=$(makedir)/objs sources+=\ $(call List,Sourcefile)\ $(call List,blua/Sourcefile)\ + $(call List,netcode/Sourcefile)\ depends:=$(basename $(filter %.c %.s,$(sources))) objects:=$(basename $(filter %.c %.s %.nas,$(sources))) diff --git a/src/Sourcefile b/src/Sourcefile index 83e9ebc3b..7d2146411 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -1,9 +1,5 @@ string.c d_main.c -d_clisrv.c -d_net.c -d_netfil.c -d_netcmd.c dehacked.c deh_soc.c deh_lua.c @@ -77,9 +73,6 @@ s_sound.c sounds.c w_wad.c filesrch.c -mserv.c -http-mserv.c -i_tcp.c lzf.c vid_copy.s b_bot.c diff --git a/src/android/i_net.c b/src/android/i_net.c index f6e642022..4c30dc767 100644 --- a/src/android/i_net.c +++ b/src/android/i_net.c @@ -1,4 +1,4 @@ -#include "../i_net.h" +#include "../netcode/i_net.h" boolean I_InitNetwork(void) { diff --git a/src/blua/liolib.c b/src/blua/liolib.c index e029650c0..8a6354121 100644 --- a/src/blua/liolib.c +++ b/src/blua/liolib.c @@ -19,7 +19,7 @@ #include "lualib.h" #include "../i_system.h" #include "../g_game.h" -#include "../d_netfil.h" +#include "../netcode/d_netfil.h" #include "../lua_libs.h" #include "../byteptr.h" #include "../lua_script.h" diff --git a/src/command.c b/src/command.c index 9be081fb7..4e8989fd3 100644 --- a/src/command.c +++ b/src/command.c @@ -28,11 +28,11 @@ #include "byteptr.h" #include "p_saveg.h" #include "g_game.h" // for player_names -#include "d_netcmd.h" +#include "netcode/d_netcmd.h" #include "hu_stuff.h" #include "p_setup.h" #include "lua_script.h" -#include "d_netfil.h" // findfile +#include "netcode/d_netfil.h" // findfile #include "r_data.h" // Color_cons_t //======== diff --git a/src/d_main.c b/src/d_main.c index 1af8d090c..8b13dba89 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -34,7 +34,7 @@ #include "doomdef.h" #include "am_map.h" #include "console.h" -#include "d_net.h" +#include "netcode/d_net.h" #include "f_finale.h" #include "g_game.h" #include "hu_stuff.h" @@ -57,11 +57,11 @@ #include "w_wad.h" #include "z_zone.h" #include "d_main.h" -#include "d_netfil.h" +#include "netcode/d_netfil.h" #include "m_cheat.h" #include "y_inter.h" #include "p_local.h" // chasecam -#include "mserv.h" // ms_RoomId +#include "netcode/mserv.h" // ms_RoomId #include "m_misc.h" // screenshot functionality #include "deh_tables.h" // Dehacked list test #include "m_cond.h" // condition initialization diff --git a/src/deh_soc.c b/src/deh_soc.c index 583776ee7..f13dd53a2 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -34,7 +34,7 @@ #include "r_sky.h" #include "fastcmp.h" #include "lua_script.h" // Reluctantly included for LUA_EvalMath -#include "d_clisrv.h" +#include "netcode/d_clisrv.h" #ifdef HWRENDER #include "hardware/hw_light.h" diff --git a/src/deh_soc.h b/src/deh_soc.h index f972ec26e..cd55b665b 100644 --- a/src/deh_soc.h +++ b/src/deh_soc.h @@ -35,7 +35,7 @@ #include "r_sky.h" #include "fastcmp.h" #include "lua_script.h" // Reluctantly included for LUA_EvalMath -#include "d_clisrv.h" +#include "netcode/d_clisrv.h" #ifdef HWRENDER #include "hardware/hw_light.h" diff --git a/src/doomstat.h b/src/doomstat.h index bce43416b..344a3daa4 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -683,7 +683,7 @@ extern boolean singletics; // Netgame stuff // ============= -#include "d_clisrv.h" +#include "netcode/d_clisrv.h" extern consvar_t cv_timetic; // display high resolution timer extern consvar_t cv_powerupdisplay; // display powerups diff --git a/src/dummy/i_net.c b/src/dummy/i_net.c index f6e642022..4c30dc767 100644 --- a/src/dummy/i_net.c +++ b/src/dummy/i_net.c @@ -1,4 +1,4 @@ -#include "../i_net.h" +#include "../netcode/i_net.h" boolean I_InitNetwork(void) { diff --git a/src/f_finale.c b/src/f_finale.c index 307e00aaa..2122cf34d 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -14,7 +14,7 @@ #include "doomdef.h" #include "doomstat.h" #include "d_main.h" -#include "d_netcmd.h" +#include "netcode/d_netcmd.h" #include "f_finale.h" #include "g_game.h" #include "hu_stuff.h" diff --git a/src/filesrch.c b/src/filesrch.c index 23b8e7f40..d68a7d5ed 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -26,7 +26,7 @@ #include #include "filesrch.h" -#include "d_netfil.h" +#include "netcode/d_netfil.h" #include "m_misc.h" #include "z_zone.h" #include "m_menu.h" // Addons_option_Onchange diff --git a/src/filesrch.h b/src/filesrch.h index 59ef5269b..a934c48d6 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -5,7 +5,7 @@ #define __FILESRCH_H__ #include "doomdef.h" -#include "d_netfil.h" +#include "netcode/d_netfil.h" #include "m_menu.h" // MAXSTRINGLENGTH #include "w_wad.h" diff --git a/src/g_demo.c b/src/g_demo.c index 9099adc71..6167b3a09 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -15,7 +15,7 @@ #include "console.h" #include "d_main.h" #include "d_player.h" -#include "d_clisrv.h" +#include "netcode/d_clisrv.h" #include "p_setup.h" #include "i_time.h" #include "i_system.h" diff --git a/src/g_game.c b/src/g_game.c index b4a127a73..93b8eb936 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -15,7 +15,7 @@ #include "console.h" #include "d_main.h" #include "d_player.h" -#include "d_clisrv.h" +#include "netcode/d_clisrv.h" #include "f_finale.h" #include "p_setup.h" #include "p_saveg.h" diff --git a/src/g_input.c b/src/g_input.c index 465db0316..5ae5ae0cf 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -18,7 +18,7 @@ #include "i_gamepad.h" #include "keys.h" #include "hu_stuff.h" // need HUFONT start & end -#include "d_net.h" +#include "netcode/d_net.h" #include "console.h" #define MAXMOUSESENSITIVITY 100 // sensitivity steps diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 3cb7275a0..191ee68bb 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -29,7 +29,7 @@ #include "../r_patch.h" #include "../r_picformats.h" #include "../r_bsp.h" -#include "../d_clisrv.h" +#include "../netcode/d_clisrv.h" #include "../w_wad.h" #include "../z_zone.h" #include "../r_splats.h" @@ -5234,7 +5234,7 @@ static void HWR_ProjectSprite(mobj_t *thing) { interpmobjstate_t casterinterp = {}; fixed_t groundz; - fixed_t floordiff; + fixed_t floordiff; if (R_UsingFrameInterpolation() && !paused) { @@ -5244,7 +5244,7 @@ static void HWR_ProjectSprite(mobj_t *thing) { R_InterpolateMobjState(caster, FRACUNIT, &casterinterp); } - + groundz = R_GetShadowZ(thing, NULL); floordiff = abs(((thing->eflags & MFE_VERTICALFLIP) ? caster->height : 0) + casterinterp.z - groundz); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 37c3f0dc3..e5cf5aeb1 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -19,7 +19,7 @@ #include "m_cond.h" // emblems #include "m_misc.h" // word jumping -#include "d_clisrv.h" +#include "netcode/d_clisrv.h" #include "g_game.h" #include "g_input.h" diff --git a/src/i_time.c b/src/i_time.c index c1cc9dfd4..9303d7be7 100644 --- a/src/i_time.c +++ b/src/i_time.c @@ -17,7 +17,7 @@ #include "command.h" #include "doomtype.h" -#include "d_netcmd.h" +#include "netcode/d_netcmd.h" #include "m_fixed.h" #include "i_system.h" diff --git a/src/lua_baselib.c b/src/lua_baselib.c index c94e9e91e..ea519be55 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -27,11 +27,11 @@ #include "y_inter.h" #include "hu_stuff.h" // HU_AddChatText #include "console.h" -#include "d_netcmd.h" // IsPlayerAdmin +#include "netcode/d_netcmd.h" // IsPlayerAdmin #include "m_menu.h" // Player Setup menu color stuff #include "m_misc.h" // M_MapNumber #include "b_bot.h" // B_UpdateBotleader -#include "d_clisrv.h" // CL_RemovePlayer +#include "netcode/d_clisrv.h" // CL_RemovePlayer #include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision #include "lua_script.h" diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 6506d3dc6..e8e6ebea9 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -25,7 +25,7 @@ #include "lua_hud.h" // hud_running errors #include "m_perfstats.h" -#include "d_netcmd.h" // for cv_perfstats +#include "netcode/d_netcmd.h" // for cv_perfstats #include "i_system.h" // I_GetPreciseTime /* ========================================================================= diff --git a/src/lua_script.c b/src/lua_script.c index 8d8fb295c..f1c800df5 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -28,7 +28,7 @@ #include "p_slopes.h" // for P_SlopeById and slopelist #include "p_polyobj.h" // polyobj_t, PolyObjects #ifdef LUA_ALLOW_BYTECODE -#include "d_netfil.h" // for LUA_DumpFile +#include "netcode/d_netfil.h" // for LUA_DumpFile #endif #include "lua_script.h" diff --git a/src/m_cheat.c b/src/m_cheat.c index f94377450..36b2d1907 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -19,7 +19,7 @@ #include "r_local.h" #include "p_local.h" #include "p_setup.h" -#include "d_net.h" +#include "netcode/d_net.h" #include "m_cheat.h" #include "m_menu.h" diff --git a/src/m_menu.c b/src/m_menu.c index 824ae5c46..d3ae4da2a 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -20,7 +20,7 @@ #include "doomdef.h" #include "d_main.h" -#include "d_netcmd.h" +#include "netcode/d_netcmd.h" #include "console.h" #include "r_fps.h" #include "r_local.h" @@ -55,8 +55,8 @@ #include "hardware/hw_main.h" #endif -#include "d_net.h" -#include "mserv.h" +#include "netcode/d_net.h" +#include "netcode/mserv.h" #include "m_misc.h" #include "m_anigif.h" #include "byteptr.h" diff --git a/src/m_menu.h b/src/m_menu.h index 8eb183163..809186a17 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -20,7 +20,7 @@ #include "command.h" #include "f_finale.h" // for ttmode_enum #include "i_threads.h" -#include "mserv.h" +#include "netcode/mserv.h" #include "r_things.h" // for SKINNAMESIZE // Compatibility with old-style named NiGHTS replay files. diff --git a/src/m_perfstats.c b/src/m_perfstats.c index 9f65a7616..cca4c62ca 100644 --- a/src/m_perfstats.c +++ b/src/m_perfstats.c @@ -12,7 +12,7 @@ #include "m_perfstats.h" #include "v_video.h" #include "i_video.h" -#include "d_netcmd.h" +#include "netcode/d_netcmd.h" #include "r_main.h" #include "i_system.h" #include "z_zone.h" diff --git a/src/netcode/Sourcefile b/src/netcode/Sourcefile new file mode 100644 index 000000000..9087917d0 --- /dev/null +++ b/src/netcode/Sourcefile @@ -0,0 +1,7 @@ +d_clisrv.c +d_net.c +d_netcmd.c +d_netfil.c +http-mserv.c +i_tcp.c +mserv.c diff --git a/src/d_clisrv.c b/src/netcode/d_clisrv.c old mode 100755 new mode 100644 similarity index 99% rename from src/d_clisrv.c rename to src/netcode/d_clisrv.c index cb1ccd539..9b11e23ff --- a/src/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -15,48 +15,48 @@ #include //for unlink #endif -#include "i_time.h" +#include "../i_time.h" #include "i_net.h" -#include "i_system.h" -#include "i_video.h" +#include "../i_system.h" +#include "../i_video.h" #include "d_net.h" -#include "d_main.h" -#include "g_game.h" -#include "st_stuff.h" -#include "hu_stuff.h" -#include "keys.h" -#include "g_input.h" -#include "i_gamepad.h" -#include "m_menu.h" -#include "console.h" +#include "../d_main.h" +#include "../g_game.h" +#include "../st_stuff.h" +#include "../hu_stuff.h" +#include "../keys.h" +#include "../g_input.h" +#include "../i_gamepad.h" +#include "../m_menu.h" +#include "../console.h" #include "d_netfil.h" -#include "byteptr.h" -#include "p_saveg.h" -#include "z_zone.h" -#include "p_local.h" -#include "p_haptic.h" -#include "m_misc.h" -#include "am_map.h" -#include "m_random.h" +#include "../byteptr.h" +#include "../p_saveg.h" +#include "../z_zone.h" +#include "../p_local.h" +#include "../p_haptic.h" +#include "../m_misc.h" +#include "../am_map.h" +#include "../m_random.h" #include "mserv.h" -#include "y_inter.h" -#include "r_local.h" -#include "m_argv.h" -#include "p_setup.h" -#include "lzf.h" -#include "lua_script.h" -#include "lua_hook.h" -#include "lua_libs.h" -#include "md5.h" -#include "m_perfstats.h" +#include "../y_inter.h" +#include "../r_local.h" +#include "../m_argv.h" +#include "../p_setup.h" +#include "../lzf.h" +#include "../lua_script.h" +#include "../lua_hook.h" +#include "../lua_libs.h" +#include "../md5.h" +#include "../m_perfstats.h" // aaaaaa -#include "i_gamepad.h" +#include "../i_gamepad.h" // cl loading screen -#include "v_video.h" -#include "f_finale.h" -#include "snake.h" +#include "../v_video.h" +#include "../f_finale.h" +#include "../snake.h" // // NETWORKING diff --git a/src/d_clisrv.h b/src/netcode/d_clisrv.h similarity index 99% rename from src/d_clisrv.h rename to src/netcode/d_clisrv.h index 0d6add13a..50b86e9f0 100644 --- a/src/d_clisrv.h +++ b/src/netcode/d_clisrv.h @@ -13,12 +13,12 @@ #ifndef __D_CLISRV__ #define __D_CLISRV__ -#include "d_ticcmd.h" +#include "../d_ticcmd.h" #include "d_net.h" #include "d_netcmd.h" #include "d_net.h" -#include "tables.h" -#include "d_player.h" +#include "../tables.h" +#include "../d_player.h" #include "mserv.h" /* diff --git a/src/d_net.c b/src/netcode/d_net.c similarity index 99% rename from src/d_net.c rename to src/netcode/d_net.c index 9e3759d32..ae0605001 100644 --- a/src/d_net.c +++ b/src/netcode/d_net.c @@ -16,19 +16,19 @@ /// This protocol uses a mix of "goback n" and "selective repeat" implementation /// The NOTHING packet is sent when connection is idle to acknowledge packets -#include "doomdef.h" -#include "g_game.h" -#include "i_time.h" +#include "../doomdef.h" +#include "../g_game.h" +#include "../i_time.h" #include "i_net.h" -#include "i_system.h" -#include "m_argv.h" +#include "../i_system.h" +#include "../m_argv.h" #include "d_net.h" -#include "w_wad.h" +#include "../w_wad.h" #include "d_netfil.h" #include "d_clisrv.h" -#include "z_zone.h" +#include "../z_zone.h" #include "i_tcp.h" -#include "d_main.h" // srb2home +#include "../d_main.h" // srb2home // // NETWORKING diff --git a/src/d_net.h b/src/netcode/d_net.h similarity index 100% rename from src/d_net.h rename to src/netcode/d_net.h diff --git a/src/d_netcmd.c b/src/netcode/d_netcmd.c similarity index 99% rename from src/d_netcmd.c rename to src/netcode/d_netcmd.c index 69eed90de..ed310805d 100644 --- a/src/d_netcmd.c +++ b/src/netcode/d_netcmd.c @@ -12,44 +12,44 @@ /// commands are executed through the command buffer /// like console commands, other miscellaneous commands (at the end) -#include "doomdef.h" +#include "../doomdef.h" -#include "console.h" -#include "command.h" -#include "i_time.h" -#include "i_system.h" -#include "g_game.h" -#include "hu_stuff.h" -#include "g_input.h" -#include "i_gamepad.h" -#include "m_menu.h" -#include "r_local.h" -#include "r_skins.h" -#include "p_local.h" -#include "p_setup.h" -#include "s_sound.h" -#include "i_sound.h" -#include "m_misc.h" -#include "am_map.h" -#include "byteptr.h" +#include "../console.h" +#include "../command.h" +#include "../i_time.h" +#include "../i_system.h" +#include "../g_game.h" +#include "../hu_stuff.h" +#include "../g_input.h" +#include "../i_gamepad.h" +#include "../m_menu.h" +#include "../r_local.h" +#include "../r_skins.h" +#include "../p_local.h" +#include "../p_setup.h" +#include "../s_sound.h" +#include "../i_sound.h" +#include "../m_misc.h" +#include "../am_map.h" +#include "../byteptr.h" #include "d_netfil.h" -#include "p_spec.h" -#include "m_cheat.h" +#include "../p_spec.h" +#include "../m_cheat.h" #include "d_clisrv.h" #include "d_net.h" -#include "v_video.h" -#include "d_main.h" -#include "m_random.h" -#include "f_finale.h" -#include "filesrch.h" +#include "../v_video.h" +#include "../d_main.h" +#include "../m_random.h" +#include "../f_finale.h" +#include "../filesrch.h" #include "mserv.h" -#include "z_zone.h" -#include "lua_script.h" -#include "lua_hook.h" -#include "m_cond.h" -#include "m_anigif.h" -#include "md5.h" -#include "m_perfstats.h" +#include "../z_zone.h" +#include "../lua_script.h" +#include "../lua_hook.h" +#include "../m_cond.h" +#include "../m_anigif.h" +#include "../md5.h" +#include "../m_perfstats.h" #ifdef NETGAME_DEVMODE #define CV_RESTRICT CV_NETVAR diff --git a/src/d_netcmd.h b/src/netcode/d_netcmd.h similarity index 99% rename from src/d_netcmd.h rename to src/netcode/d_netcmd.h index 47f68a17e..797a686a7 100644 --- a/src/d_netcmd.h +++ b/src/netcode/d_netcmd.h @@ -15,7 +15,7 @@ #ifndef __D_NETCMD__ #define __D_NETCMD__ -#include "command.h" +#include "../command.h" // console vars extern consvar_t cv_playername; diff --git a/src/d_netfil.c b/src/netcode/d_netfil.c similarity index 99% rename from src/d_netfil.c rename to src/netcode/d_netfil.c index bf3952cc9..80fa06852 100644 --- a/src/d_netfil.c +++ b/src/netcode/d_netfil.c @@ -31,24 +31,24 @@ #include #endif -#include "doomdef.h" -#include "doomstat.h" -#include "d_main.h" -#include "g_game.h" -#include "i_time.h" +#include "../doomdef.h" +#include "../doomstat.h" +#include "../d_main.h" +#include "../g_game.h" +#include "../i_time.h" #include "i_net.h" -#include "i_system.h" -#include "m_argv.h" +#include "../i_system.h" +#include "../m_argv.h" #include "d_net.h" -#include "w_wad.h" +#include "../w_wad.h" #include "d_netfil.h" -#include "z_zone.h" -#include "byteptr.h" -#include "p_setup.h" -#include "m_misc.h" -#include "m_menu.h" -#include "md5.h" -#include "filesrch.h" +#include "../z_zone.h" +#include "../byteptr.h" +#include "../p_setup.h" +#include "../m_misc.h" +#include "../m_menu.h" +#include "../md5.h" +#include "../filesrch.h" #include diff --git a/src/d_netfil.h b/src/netcode/d_netfil.h similarity index 99% rename from src/d_netfil.h rename to src/netcode/d_netfil.h index ec53be587..732efcd5e 100644 --- a/src/d_netfil.h +++ b/src/netcode/d_netfil.h @@ -15,7 +15,7 @@ #include "d_net.h" #include "d_clisrv.h" -#include "w_wad.h" +#include "../w_wad.h" typedef enum { diff --git a/src/http-mserv.c b/src/netcode/http-mserv.c similarity index 98% rename from src/http-mserv.c rename to src/netcode/http-mserv.c index b0ef37fa1..72dc1cafb 100644 --- a/src/http-mserv.c +++ b/src/netcode/http-mserv.c @@ -18,14 +18,14 @@ Documentation available here. #include #endif -#include "doomdef.h" +#include "../doomdef.h" #include "d_clisrv.h" -#include "command.h" -#include "m_argv.h" -#include "m_menu.h" +#include "../command.h" +#include "../m_argv.h" +#include "../m_menu.h" #include "mserv.h" #include "i_tcp.h"/* for current_port */ -#include "i_threads.h" +#include "../i_threads.h" /* reasonable default I guess?? */ #define DEFAULT_BUFFER_SIZE (4096) diff --git a/src/i_addrinfo.c b/src/netcode/i_addrinfo.c similarity index 100% rename from src/i_addrinfo.c rename to src/netcode/i_addrinfo.c diff --git a/src/i_addrinfo.h b/src/netcode/i_addrinfo.h similarity index 100% rename from src/i_addrinfo.h rename to src/netcode/i_addrinfo.h diff --git a/src/i_net.h b/src/netcode/i_net.h similarity index 98% rename from src/i_net.h rename to src/netcode/i_net.h index 62b7528d5..66126d050 100644 --- a/src/i_net.h +++ b/src/netcode/i_net.h @@ -18,8 +18,8 @@ #pragma interface #endif -#include "doomdef.h" -#include "command.h" +#include "../doomdef.h" +#include "../command.h" /// \brief program net id #define DOOMCOM_ID (INT32)0x12345678l diff --git a/src/i_tcp.c b/src/netcode/i_tcp.c similarity index 99% rename from src/i_tcp.c rename to src/netcode/i_tcp.c index ec3d1ae93..6baba6275 100644 --- a/src/i_tcp.c +++ b/src/netcode/i_tcp.c @@ -36,7 +36,7 @@ #include #endif -#include "doomdef.h" +#include "../doomdef.h" #ifdef USE_WINSOCK1 #include @@ -122,14 +122,14 @@ typedef union #define MAXBANS 100 -#include "i_system.h" +#include "../i_system.h" #include "i_net.h" #include "d_net.h" #include "d_netfil.h" #include "i_tcp.h" -#include "m_argv.h" +#include "../m_argv.h" -#include "doomstat.h" +#include "../doomstat.h" // win32 #ifdef USE_WINSOCK diff --git a/src/i_tcp.h b/src/netcode/i_tcp.h similarity index 100% rename from src/i_tcp.h rename to src/netcode/i_tcp.h diff --git a/src/mserv.c b/src/netcode/mserv.c similarity index 98% rename from src/mserv.c rename to src/netcode/mserv.c index 90091d241..78301f4d9 100644 --- a/src/mserv.c +++ b/src/netcode/mserv.c @@ -15,13 +15,13 @@ #include #endif -#include "doomstat.h" -#include "doomdef.h" -#include "command.h" -#include "i_threads.h" +#include "../doomstat.h" +#include "../doomdef.h" +#include "../command.h" +#include "../i_threads.h" #include "mserv.h" -#include "m_menu.h" -#include "z_zone.h" +#include "../m_menu.h" +#include "../z_zone.h" #ifdef MASTERSERVER diff --git a/src/mserv.h b/src/netcode/mserv.h similarity index 99% rename from src/mserv.h rename to src/netcode/mserv.h index 23b26fbc5..7fdf3ed1b 100644 --- a/src/mserv.h +++ b/src/netcode/mserv.h @@ -14,7 +14,7 @@ #ifndef _MSERV_H_ #define _MSERV_H_ -#include "i_threads.h" +#include "../i_threads.h" // lowered from 32 due to menu changes #define NUM_LIST_ROOMS 16 diff --git a/src/p_ceilng.c b/src/p_ceilng.c index 66f2dd58e..949eeddf2 100644 --- a/src/p_ceilng.c +++ b/src/p_ceilng.c @@ -17,7 +17,7 @@ #include "r_main.h" #include "s_sound.h" #include "z_zone.h" -#include "d_netcmd.h" +#include "netcode/d_netcmd.h" // ========================================================================== // CEILINGS diff --git a/src/p_haptic.c b/src/p_haptic.c index dbfa58737..4d22fbd77 100644 --- a/src/p_haptic.c +++ b/src/p_haptic.c @@ -11,7 +11,7 @@ #include "p_haptic.h" #include "g_game.h" -#include "d_netcmd.h" +#include "netcode/d_netcmd.h" #include "i_gamepad.h" #include "doomstat.h" diff --git a/src/p_lights.c b/src/p_lights.c index 4c783f884..a1f4de853 100644 --- a/src/p_lights.c +++ b/src/p_lights.c @@ -17,7 +17,7 @@ #include "r_state.h" #include "z_zone.h" #include "m_random.h" -#include "d_netcmd.h" +#include "netcode/d_netcmd.h" /** Removes any active lighting effects in a sector. * diff --git a/src/p_user.c b/src/p_user.c index 6fd24eb13..1e8dee885 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -18,7 +18,7 @@ #include "doomdef.h" #include "i_system.h" #include "d_event.h" -#include "d_net.h" +#include "netcode/d_net.h" #include "g_game.h" #include "p_local.h" #include "r_fps.h" diff --git a/src/r_segs.c b/src/r_segs.c index 43a7f945f..704f33334 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -20,7 +20,7 @@ #include "w_wad.h" #include "z_zone.h" -#include "d_netcmd.h" +#include "netcode/d_netcmd.h" #include "m_misc.h" #include "p_local.h" // Camera... #include "p_slopes.h" diff --git a/src/r_things.c b/src/r_things.c index fed873fd6..a466def70 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -34,7 +34,7 @@ #include "p_tick.h" #include "p_local.h" #include "p_slopes.h" -#include "d_netfil.h" // blargh. for nameonly(). +#include "netcode/d_netfil.h" // blargh. for nameonly(). #include "m_cheat.h" // objectplace #ifdef HWRENDER #include "hardware/hw_md2.h" diff --git a/src/screen.c b/src/screen.c index e984f9ee5..00895f013 100644 --- a/src/screen.c +++ b/src/screen.c @@ -27,7 +27,7 @@ #include "hu_stuff.h" #include "z_zone.h" #include "d_main.h" -#include "d_clisrv.h" +#include "netcode/d_clisrv.h" #include "f_finale.h" #include "y_inter.h" // usebuffer #include "i_sound.h" // closed captions diff --git a/src/sdl/i_gamepad.c b/src/sdl/i_gamepad.c index ecde251fb..f27504f76 100644 --- a/src/sdl/i_gamepad.c +++ b/src/sdl/i_gamepad.c @@ -15,7 +15,7 @@ #include "../i_system.h" #include "../doomdef.h" #include "../d_main.h" -#include "../d_netcmd.h" +#include "../netcode/d_netcmd.h" #include "../g_game.h" #include "../m_argv.h" #include "../m_menu.h" diff --git a/src/sdl/i_net.c b/src/sdl/i_net.c index ee4a34c13..515a85568 100644 --- a/src/sdl/i_net.c +++ b/src/sdl/i_net.c @@ -21,16 +21,16 @@ #include "../i_system.h" #include "../d_event.h" -#include "../d_net.h" +#include "../netcode/d_net.h" #include "../m_argv.h" #include "../doomstat.h" -#include "../i_net.h" +#include "../netcode/i_net.h" #include "../z_zone.h" -#include "../i_tcp.h" +#include "../netcode/i_tcp.h" #ifdef HAVE_SDL diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index d08f3ff33..7684045fc 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -188,7 +188,7 @@ static char returnWadPath[256]; #include "../i_gamepad.h" #include "../i_threads.h" #include "../screen.h" //vid.WndParent -#include "../d_net.h" +#include "../netcode/d_net.h" #include "../g_game.h" #include "../filesrch.h" #include "endtxt.h" @@ -207,7 +207,7 @@ static char returnWadPath[256]; #if !defined(NOMUMBLE) && defined(HAVE_MUMBLE) // Mumble context string -#include "../d_clisrv.h" +#include "../netcode/d_clisrv.h" #include "../byteptr.h" #endif diff --git a/src/sdl/i_ttf.c b/src/sdl/i_ttf.c index f2cd497ee..1f838e9b4 100644 --- a/src/sdl/i_ttf.c +++ b/src/sdl/i_ttf.c @@ -21,7 +21,7 @@ #include "SDL_ttf.h" #include "../doomdef.h" #include "../doomstat.h" -#include "../d_netfil.h" +#include "../netcode/d_netfil.h" #include "../filesrch.h" #include "i_ttf.h" diff --git a/src/w_wad.c b/src/w_wad.c index 42c6bf83b..1e64cf093 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -51,8 +51,8 @@ #include "filesrch.h" #include "d_main.h" -#include "d_netfil.h" -#include "d_clisrv.h" +#include "netcode/d_netfil.h" +#include "netcode/d_clisrv.h" #include "dehacked.h" #include "r_defs.h" #include "r_data.h" diff --git a/src/y_inter.c b/src/y_inter.c index 7faceff50..de757ec70 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -15,7 +15,7 @@ #include "f_finale.h" #include "g_game.h" #include "hu_stuff.h" -#include "i_net.h" +#include "netcode/i_net.h" #include "i_video.h" #include "p_tick.h" #include "r_defs.h" From 4660d3cab62567f20763b3be90a64c2a2dde178a Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sat, 31 Dec 2022 21:37:35 +0100 Subject: [PATCH 44/96] Move client connection handling to a new file --- src/m_menu.c | 1 + src/netcode/Sourcefile | 1 + src/netcode/client_connection.c | 1181 ++++++++++++++++++++++++++++++ src/netcode/client_connection.h | 61 ++ src/netcode/d_clisrv.c | 1184 +------------------------------ src/netcode/d_clisrv.h | 16 +- src/netcode/http-mserv.c | 1 + src/netcode/mserv.c | 1 + 8 files changed, 1256 insertions(+), 1190 deletions(-) create mode 100644 src/netcode/client_connection.c create mode 100644 src/netcode/client_connection.h diff --git a/src/m_menu.c b/src/m_menu.c index d3ae4da2a..06d1b1b96 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -57,6 +57,7 @@ #include "netcode/d_net.h" #include "netcode/mserv.h" +#include "netcode/client_connection.h" #include "m_misc.h" #include "m_anigif.h" #include "byteptr.h" diff --git a/src/netcode/Sourcefile b/src/netcode/Sourcefile index 9087917d0..c11b3d6c1 100644 --- a/src/netcode/Sourcefile +++ b/src/netcode/Sourcefile @@ -1,4 +1,5 @@ d_clisrv.c +client_connection.c d_net.c d_netcmd.c d_netfil.c diff --git a/src/netcode/client_connection.c b/src/netcode/client_connection.c new file mode 100644 index 000000000..bfaea2e81 --- /dev/null +++ b/src/netcode/client_connection.c @@ -0,0 +1,1181 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file client_connection.h +/// \brief Client connection handling + +#include "client_connection.h" +#include "d_clisrv.h" +#include "d_netfil.h" +#include "../d_main.h" +#include "../f_finale.h" +#include "../g_game.h" +#include "../i_gamepad.h" +#include "i_net.h" +#include "../i_system.h" +#include "../i_time.h" +#include "../i_video.h" +#include "../m_menu.h" +#include "../m_misc.h" +#include "../snake.h" +#include "../s_sound.h" +#include "../v_video.h" +#include "../y_inter.h" +#include "../z_zone.h" +#include "../doomtype.h" +#include "../doomstat.h" + +cl_mode_t cl_mode = CL_SEARCHING; +static UINT16 cl_lastcheckedfilecount = 0; // used for full file list +boolean serverisfull = false; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not +tic_t firstconnectattempttime = 0; +UINT8 mynode; // my address pointofview server +static void *snake = NULL; + +static void CL_DrawConnectionStatusBox(void) +{ + M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1); + if (cl_mode != CL_CONFIRMCONNECT) + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); +} + +// +// CL_DrawConnectionStatus +// +// Keep the local client informed of our status. +// +static inline void CL_DrawConnectionStatus(void) +{ + INT32 ccstime = I_GetTime(); + + // Draw background fade + V_DrawFadeScreen(0xFF00, 16); // force default + + if (cl_mode != CL_DOWNLOADFILES && cl_mode != CL_LOADFILES) + { + INT32 i, animtime = ((ccstime / 4) & 15) + 16; + UINT8 palstart; + const char *cltext; + + // Draw the bottom box. + CL_DrawConnectionStatusBox(); + + if (cl_mode == CL_SEARCHING) + palstart = 32; // Red + else if (cl_mode == CL_CONFIRMCONNECT) + palstart = 48; // Orange + else + palstart = 96; // Green + + if (!(cl_mode == CL_DOWNLOADSAVEGAME && lastfilenum != -1)) + for (i = 0; i < 16; ++i) // 15 pal entries total. + V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-16, 16, 8, palstart + ((animtime - i) & 15)); + + switch (cl_mode) + { + case CL_DOWNLOADSAVEGAME: + if (fileneeded && lastfilenum != -1) + { + UINT32 currentsize = fileneeded[lastfilenum].currentsize; + UINT32 totalsize = fileneeded[lastfilenum].totalsize; + INT32 dldlength; + + cltext = M_GetText("Downloading game state..."); + Net_GetNetStat(); + + dldlength = (INT32)((currentsize/(double)totalsize) * 256); + if (dldlength > 256) + dldlength = 256; + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, dldlength, 8, 96); + + V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, + va(" %4uK/%4uK",currentsize>>10,totalsize>>10)); + + V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, + va("%3.1fK/s ", ((double)getbps)/1024)); + } + else + cltext = M_GetText("Waiting to download game state..."); + break; + case CL_ASKFULLFILELIST: + case CL_CHECKFILES: + cltext = M_GetText("Checking server addon list..."); + break; + case CL_CONFIRMCONNECT: + cltext = ""; + break; + case CL_LOADFILES: + cltext = M_GetText("Loading server addons..."); + break; + case CL_ASKJOIN: + case CL_WAITJOINRESPONSE: + if (serverisfull) + cltext = M_GetText("Server full, waiting for a slot..."); + else + cltext = M_GetText("Requesting to join..."); + break; + default: + cltext = M_GetText("Connecting to server..."); + break; + } + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, cltext); + } + else + { + if (cl_mode == CL_LOADFILES) + { + INT32 totalfileslength; + INT32 loadcompletednum = 0; + INT32 i; + + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); + + //ima just count files here + if (fileneeded) + { + for (i = 0; i < fileneedednum; i++) + if (fileneeded[i].status == FS_OPEN) + loadcompletednum++; + } + + // Loading progress + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, "Loading server addons..."); + totalfileslength = (INT32)((loadcompletednum/(double)(fileneedednum)) * 256); + M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, totalfileslength, 8, 96); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, + va(" %2u/%2u Files",loadcompletednum,fileneedednum)); + } + else if (lastfilenum != -1) + { + INT32 dldlength; + static char tempname[28]; + fileneeded_t *file; + char *filename; + + if (snake) + Snake_Draw(snake); + + // Draw the bottom box. + CL_DrawConnectionStatusBox(); + + if (fileneeded) + { + file = &fileneeded[lastfilenum]; + filename = file->filename; + } + else + return; + + Net_GetNetStat(); + dldlength = (INT32)((file->currentsize/(double)file->totalsize) * 256); + if (dldlength > 256) + dldlength = 256; + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, dldlength, 8, 96); + + memset(tempname, 0, sizeof(tempname)); + // offset filename to just the name only part + filename += strlen(filename) - nameonlylength(filename); + + if (strlen(filename) > sizeof(tempname)-1) // too long to display fully + { + size_t endhalfpos = strlen(filename)-10; + // display as first 14 chars + ... + last 10 chars + // which should add up to 27 if our math(s) is correct + snprintf(tempname, sizeof(tempname), "%.14s...%.10s", filename, filename+endhalfpos); + } + else // we can copy the whole thing in safely + { + strncpy(tempname, filename, sizeof(tempname)-1); + } + + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, + va(M_GetText("Downloading \"%s\""), tempname)); + V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, + va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,file->totalsize>>10)); + V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, + va("%3.1fK/s ", ((double)getbps)/1024)); + } + else + { + if (snake) + Snake_Draw(snake); + + CL_DrawConnectionStatusBox(); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, + M_GetText("Waiting to download files...")); + } + } +} + +static boolean CL_AskFileList(INT32 firstfile) +{ + netbuffer->packettype = PT_TELLFILESNEEDED; + netbuffer->u.filesneedednum = firstfile; + + return HSendPacket(servernode, false, 0, sizeof (INT32)); +} + +/** Sends a special packet to declare how many players in local + * Used only in arbitratrenetstart() + * Sends a PT_CLIENTJOIN packet to the server + * + * \return True if the packet was successfully sent + * \todo Improve the description... + * + */ +boolean CL_SendJoin(void) +{ + UINT8 localplayers = 1; + if (netgame) + CONS_Printf(M_GetText("Sending join request...\n")); + netbuffer->packettype = PT_CLIENTJOIN; + + netbuffer->u.clientcfg.modversion = MODVERSION; + strncpy(netbuffer->u.clientcfg.application, + SRB2APPLICATION, + sizeof netbuffer->u.clientcfg.application); + + if (splitscreen || botingame) + localplayers++; + netbuffer->u.clientcfg.localplayers = localplayers; + + CleanupPlayerName(consoleplayer, cv_playername.zstring); + if (splitscreen) + CleanupPlayerName(1, cv_playername2.zstring);/* 1 is a HACK? oh no */ + + strncpy(netbuffer->u.clientcfg.names[0], cv_playername.zstring, MAXPLAYERNAME); + strncpy(netbuffer->u.clientcfg.names[1], cv_playername2.zstring, MAXPLAYERNAME); + + return HSendPacket(servernode, true, 0, sizeof (clientconfig_pak)); +} + +static void SendAskInfo(INT32 node) +{ + const tic_t asktime = I_GetTime(); + netbuffer->packettype = PT_ASKINFO; + netbuffer->u.askinfo.version = VERSION; + netbuffer->u.askinfo.time = (tic_t)LONG(asktime); + + // Even if this never arrives due to the host being firewalled, we've + // now allowed traffic from the host to us in, so once the MS relays + // our address to the host, it'll be able to speak to us. + HSendPacket(node, false, 0, sizeof (askinfo_pak)); +} + +serverelem_t serverlist[MAXSERVERLIST]; +UINT32 serverlistcount = 0; + +#define FORCECLOSE 0x8000 + +static void SL_ClearServerList(INT32 connectedserver) +{ + UINT32 i; + + for (i = 0; i < serverlistcount; i++) + if (connectedserver != serverlist[i].node) + { + Net_CloseConnection(serverlist[i].node|FORCECLOSE); + serverlist[i].node = 0; + } + serverlistcount = 0; +} + +static UINT32 SL_SearchServer(INT32 node) +{ + UINT32 i; + for (i = 0; i < serverlistcount; i++) + if (serverlist[i].node == node) + return i; + + return UINT32_MAX; +} + +static void SL_InsertServer(serverinfo_pak* info, SINT8 node) +{ + UINT32 i; + + // search if not already on it + i = SL_SearchServer(node); + if (i == UINT32_MAX) + { + // not found add it + if (serverlistcount >= MAXSERVERLIST) + return; // list full + + /* check it later if connecting to this one */ + if (node != servernode) + { + if (info->_255 != 255) + return;/* old packet format */ + + if (info->packetversion != PACKETVERSION) + return;/* old new packet format */ + + if (info->version != VERSION) + return; // Not same version. + + if (info->subversion != SUBVERSION) + return; // Close, but no cigar. + + if (strcmp(info->application, SRB2APPLICATION)) + return;/* that's a different mod */ + } + + i = serverlistcount++; + } + + serverlist[i].info = *info; + serverlist[i].node = node; + + // resort server list + M_SortServerList(); +} + +#if defined (MASTERSERVER) && defined (HAVE_THREADS) +struct Fetch_servers_ctx +{ + int room; + int id; +}; + +static void +Fetch_servers_thread (struct Fetch_servers_ctx *ctx) +{ + msg_server_t *server_list; + + server_list = GetShortServersList(ctx->room, ctx->id); + + if (server_list) + { + I_lock_mutex(&ms_QueryId_mutex); + { + if (ctx->id != ms_QueryId) + { + free(server_list); + server_list = NULL; + } + } + I_unlock_mutex(ms_QueryId_mutex); + + if (server_list) + { + I_lock_mutex(&m_menu_mutex); + { + if (m_waiting_mode == M_WAITING_SERVERS) + m_waiting_mode = M_NOT_WAITING; + } + I_unlock_mutex(m_menu_mutex); + + I_lock_mutex(&ms_ServerList_mutex); + { + ms_ServerList = server_list; + } + I_unlock_mutex(ms_ServerList_mutex); + } + } + + free(ctx); +} +#endif/*defined (MASTERSERVER) && defined (HAVE_THREADS)*/ + +void CL_QueryServerList (msg_server_t *server_list) +{ + INT32 i; + + for (i = 0; server_list[i].header.buffer[0]; i++) + { + // Make sure MS version matches our own, to + // thwart nefarious servers who lie to the MS. + + /* lol bruh, that version COMES from the servers */ + //if (strcmp(version, server_list[i].version) == 0) + { + INT32 node = I_NetMakeNodewPort(server_list[i].ip, server_list[i].port); + if (node == -1) + break; // no more node free + SendAskInfo(node); + // Force close the connection so that servers can't eat + // up nodes forever if we never get a reply back from them + // (usually when they've not forwarded their ports). + // + // Don't worry, we'll get in contact with the working + // servers again when they send SERVERINFO to us later! + // + // (Note: as a side effect this probably means every + // server in the list will probably be using the same node (e.g. node 1), + // not that it matters which nodes they use when + // the connections are closed afterwards anyway) + // -- Monster Iestyn 12/11/18 + Net_CloseConnection(node|FORCECLOSE); + } + } +} + +void CL_UpdateServerList(boolean internetsearch, INT32 room) +{ + (void)internetsearch; + (void)room; + + SL_ClearServerList(0); + + if (!netgame && I_NetOpenSocket) + { + if (I_NetOpenSocket()) + { + netgame = true; + multiplayer = true; + } + } + + // search for local servers + if (netgame) + SendAskInfo(BROADCASTADDR); + +#ifdef MASTERSERVER + if (internetsearch) + { +#ifdef HAVE_THREADS + struct Fetch_servers_ctx *ctx; + + ctx = malloc(sizeof *ctx); + + /* This called from M_Refresh so I don't use a mutex */ + m_waiting_mode = M_WAITING_SERVERS; + + I_lock_mutex(&ms_QueryId_mutex); + { + ctx->id = ms_QueryId; + } + I_unlock_mutex(ms_QueryId_mutex); + + ctx->room = room; + + I_spawn_thread("fetch-servers", (I_thread_fn)Fetch_servers_thread, ctx); +#else + msg_server_t *server_list; + + server_list = GetShortServersList(room, 0); + + if (server_list) + { + CL_QueryServerList(server_list); + free(server_list); + } +#endif + } +#endif/*MASTERSERVER*/ +} + +static void M_ConfirmConnect(event_t *ev) +{ + if (ev->type == ev_keydown || ev->type == ev_gamepad_down) + { + if ((ev->type == ev_keydown && (ev->key == ' ' || ev->key == 'y' || ev->key == KEY_ENTER)) || (ev->type == ev_gamepad_down && ev->which == 0 && ev->key == GAMEPAD_BUTTON_A)) + { + if (totalfilesrequestednum > 0) + { + if (CL_SendFileRequest()) + { + cl_mode = CL_DOWNLOADFILES; + Snake_Allocate(&snake); + } + } + else + cl_mode = CL_LOADFILES; + + M_ClearMenus(true); + } + else if ((ev->type == ev_keydown && (ev->key == 'n' || ev->key == KEY_ESCAPE)) || (ev->type == ev_gamepad_down && ev->which == 0 && ev->key == GAMEPAD_BUTTON_B)) + { + cl_mode = CL_ABORTED; + M_ClearMenus(true); + } + } +} + +static boolean CL_FinishedFileList(void) +{ + INT32 i; + char *downloadsize = NULL; + + //CONS_Printf(M_GetText("Checking files...\n")); + i = CL_CheckFiles(); + if (i == 4) // still checking ... + { + return true; + } + else if (i == 3) // too many files + { + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "You have too many WAD files loaded\n" + "to add ones the server is using.\n" + "Please restart SRB2 before connecting.\n\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } + else if (i == 2) // cannot join for some reason + { + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "You have the wrong addons loaded.\n\n" + "To play on this server, restart\n" + "the game and don't load any addons.\n" + "SRB2 will automatically add\n" + "everything you need when you join.\n\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } + else if (i == 1) + { + if (serverisfull) + { + M_StartMessage(M_GetText( + "This server is full!\n" + "\n" + "You may load server addons (if any), and wait for a slot.\n" + "\n" + "Press ENTER to continue\nor ESC to cancel.\n\n" + ), M_ConfirmConnect, MM_EVENTHANDLER); + cl_mode = CL_CONFIRMCONNECT; + curfadevalue = 0; + } + else + cl_mode = CL_LOADFILES; + } + else + { + // must download something + // can we, though? + if (!CL_CheckDownloadable()) // nope! + { + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "An error occured when trying to\n" + "download missing addons.\n" + "(This is almost always a problem\n" + "with the server, not your game.)\n\n" + "See the console or log file\n" + "for additional details.\n\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } + + downloadcompletednum = 0; + downloadcompletedsize = 0; + totalfilesrequestednum = 0; + totalfilesrequestedsize = 0; + + if (fileneeded == NULL) + I_Error("CL_FinishedFileList: fileneeded == NULL"); + + for (i = 0; i < fileneedednum; i++) + if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD) + { + totalfilesrequestednum++; + totalfilesrequestedsize += fileneeded[i].totalsize; + } + + if (totalfilesrequestedsize>>20 >= 100) + downloadsize = Z_StrDup(va("%uM",totalfilesrequestedsize>>20)); + else + downloadsize = Z_StrDup(va("%uK",totalfilesrequestedsize>>10)); + + if (serverisfull) + M_StartMessage(va(M_GetText( + "This server is full!\n" + "Download of %s additional content\nis required to join.\n" + "\n" + "You may download, load server addons,\nand wait for a slot.\n" + "\n" + "Press ENTER to continue\nor ESC to cancel.\n" + ), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER); + else + M_StartMessage(va(M_GetText( + "Download of %s additional content\nis required to join.\n" + "\n" + "Press ENTER to continue\nor ESC to cancel.\n" + ), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER); + + Z_Free(downloadsize); + cl_mode = CL_CONFIRMCONNECT; + curfadevalue = 0; + } + return true; +} + +static const char * InvalidServerReason (serverinfo_pak *info) +{ +#define EOT "\nPress ESC\n" + + /* magic number for new packet format */ + if (info->_255 != 255) + { + return + "Outdated server (version unknown).\n" EOT; + } + + if (strncmp(info->application, SRB2APPLICATION, sizeof + info->application)) + { + return va( + "%s cannot connect\n" + "to %s servers.\n" EOT, + SRB2APPLICATION, + info->application); + } + + if ( + info->packetversion != PACKETVERSION || + info->version != VERSION || + info->subversion != SUBVERSION + ){ + return va( + "Incompatible %s versions.\n" + "(server version %d.%d.%d)\n" EOT, + SRB2APPLICATION, + info->version / 100, + info->version % 100, + info->subversion); + } + + switch (info->refusereason) + { + case REFUSE_BANNED: + return + "You have been banned\n" + "from the server.\n" EOT; + case REFUSE_JOINS_DISABLED: + return + "The server is not accepting\n" + "joins for the moment.\n" EOT; + case REFUSE_SLOTS_FULL: + return va( + "Maximum players reached: %d\n" EOT, + info->maxplayer); + default: + if (info->refusereason) + { + return + "You can't join.\n" + "I don't know why,\n" + "but you can't join.\n" EOT; + } + } + + return NULL; + +#undef EOT +} + +/** Called by CL_ServerConnectionTicker + * + * \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit. + * \return False if the connection was aborted + * \sa CL_ServerConnectionTicker + * \sa CL_ConnectToServer + * + */ +static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) +{ + INT32 i; + + // serverlist is updated by GetPacket function + if (serverlistcount > 0) + { + // this can be a responce to our broadcast request + if (servernode == -1 || servernode >= MAXNETNODES) + { + i = 0; + servernode = serverlist[i].node; + CONS_Printf(M_GetText("Found, ")); + } + else + { + i = SL_SearchServer(servernode); + if (i < 0) + return true; + } + + if (client) + { + serverinfo_pak *info = &serverlist[i].info; + + if (info->refusereason == REFUSE_SLOTS_FULL) + serverisfull = true; + else + { + const char *reason = InvalidServerReason(info); + + // Quit here rather than downloading files + // and being refused later. + if (reason) + { + char *message = Z_StrDup(reason); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(message, NULL, MM_NOTHING); + Z_Free(message); + return false; + } + } + + D_ParseFileneeded(info->fileneedednum, info->fileneeded, 0); + + if (info->flags & SV_LOTSOFADDONS) + { + cl_mode = CL_ASKFULLFILELIST; + cl_lastcheckedfilecount = 0; + return true; + } + + cl_mode = CL_CHECKFILES; + } + else + { + cl_mode = CL_ASKJOIN; // files need not be checked for the server. + *asksent = 0; + } + + return true; + } + + // Ask the info to the server (askinfo packet) + if (*asksent + NEWTICRATE < I_GetTime()) + { + SendAskInfo(servernode); + *asksent = I_GetTime(); + } + + return true; +} + +/** Called by CL_ConnectToServer + * + * \param tmpsave The name of the gamestate file??? + * \param oldtic Used for knowing when to poll events and redraw + * \param asksent ??? + * \return False if the connection was aborted + * \sa CL_ServerConnectionSearchTicker + * \sa CL_ConnectToServer + * + */ +static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic_t *asksent) +{ + boolean waitmore; + INT32 i; + + switch (cl_mode) + { + case CL_SEARCHING: + if (!CL_ServerConnectionSearchTicker(asksent)) + return false; + break; + + case CL_ASKFULLFILELIST: + if (cl_lastcheckedfilecount == UINT16_MAX) // All files retrieved + cl_mode = CL_CHECKFILES; + else if (fileneedednum != cl_lastcheckedfilecount || I_GetTime() >= *asksent) + { + if (CL_AskFileList(fileneedednum)) + { + cl_lastcheckedfilecount = fileneedednum; + *asksent = I_GetTime() + NEWTICRATE; + } + } + break; + case CL_CHECKFILES: + if (!CL_FinishedFileList()) + return false; + break; + case CL_DOWNLOADFILES: + waitmore = false; + for (i = 0; i < fileneedednum; i++) + if (fileneeded[i].status == FS_DOWNLOADING + || fileneeded[i].status == FS_REQUESTED) + { + waitmore = true; + break; + } + if (waitmore) + break; // exit the case + + Snake_Free(&snake); + + cl_mode = CL_LOADFILES; + break; + case CL_LOADFILES: + if (CL_LoadServerFiles()) + { + FreeFileNeeded(); + *asksent = 0; //This ensure the first join ask is right away + firstconnectattempttime = I_GetTime(); + cl_mode = CL_ASKJOIN; + } + break; + case CL_ASKJOIN: + if (firstconnectattempttime + NEWTICRATE*300 < I_GetTime() && !server) + { + CONS_Printf(M_GetText("5 minute wait time exceeded.\n")); + CONS_Printf(M_GetText("Network game synchronization aborted.\n")); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "5 minute wait time exceeded.\n" + "You may retry connection.\n" + "\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } + + // prepare structures to save the file + // WARNING: this can be useless in case of server not in GS_LEVEL + // but since the network layer doesn't provide ordered packets... + CL_PrepareDownloadSaveGame(tmpsave); + + if (I_GetTime() >= *asksent && CL_SendJoin()) + { + *asksent = I_GetTime() + NEWTICRATE*3; + cl_mode = CL_WAITJOINRESPONSE; + } + break; + case CL_WAITJOINRESPONSE: + if (I_GetTime() >= *asksent) + { + cl_mode = CL_ASKJOIN; + } + break; + case CL_DOWNLOADSAVEGAME: + // At this state, the first (and only) needed file is the gamestate + if (fileneeded[0].status == FS_FOUND) + { + // Gamestate is now handled within CL_LoadReceivedSavegame() + CL_LoadReceivedSavegame(false); + cl_mode = CL_CONNECTED; + } // don't break case continue to CL_CONNECTED + else + break; + + case CL_CONNECTED: + case CL_CONFIRMCONNECT: //logic is handled by M_ConfirmConnect + default: + break; + + // Connection closed by cancel, timeout or refusal. + case CL_ABORTED: + cl_mode = CL_SEARCHING; + return false; + } + + GetPackets(); + Net_AckTicker(); + + // Call it only once by tic + if (*oldtic != I_GetTime()) + { + I_OsPolling(); + + if (cl_mode == CL_CONFIRMCONNECT) + D_ProcessEvents(); //needed for menu system to receive inputs + else + { + // my hand has been forced and I am dearly sorry for this awful hack :vomit: + for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) + { + G_MapEventsToControls(&events[eventtail]); + } + } + + if (gamekeydown[KEY_ESCAPE] || gamepads[0].buttons[GAMEPAD_BUTTON_B] || cl_mode == CL_ABORTED) + { + CONS_Printf(M_GetText("Network game synchronization aborted.\n")); + M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); + + Snake_Free(&snake); + + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + memset(gamekeydown, 0, NUMKEYS); + return false; + } + else if (cl_mode == CL_DOWNLOADFILES && snake) + Snake_Update(snake); + + if (client && (cl_mode == CL_DOWNLOADFILES || cl_mode == CL_DOWNLOADSAVEGAME)) + FileReceiveTicker(); + + // why are these here? this is for servers, we're a client + //if (key == 's' && server) + // doomcom->numnodes = (INT16)pnumnodes; + //FileSendTicker(); + *oldtic = I_GetTime(); + + if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED) + { + if (!snake) + { + F_MenuPresTicker(true); // title sky + F_TitleScreenTicker(true); + F_TitleScreenDrawer(); + } + CL_DrawConnectionStatus(); +#ifdef HAVE_THREADS + I_lock_mutex(&m_menu_mutex); +#endif + M_Drawer(); //Needed for drawing messageboxes on the connection screen +#ifdef HAVE_THREADS + I_unlock_mutex(m_menu_mutex); +#endif + I_UpdateNoVsync(); // page flip or blit buffer + if (moviemode) + M_SaveFrame(); + S_UpdateSounds(); + S_UpdateClosedCaptions(); + } + } + else + { + I_Sleep(cv_sleep.value); + I_UpdateTime(cv_timescale.value); + } + + return true; +} + +#define TMPSAVENAME "$$$.sav" + +/** Use adaptive send using net_bandwidth and stat.sendbytes + * + * \todo Better description... + * + */ +void CL_ConnectToServer(void) +{ + INT32 pnumnodes, nodewaited = doomcom->numnodes, i; + tic_t oldtic; + tic_t asksent; + char tmpsave[256]; + + sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); + + lastfilenum = -1; + + cl_mode = CL_SEARCHING; + + // Don't get a corrupt savegame error because tmpsave already exists + if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1) + I_Error("Can't delete %s\n", tmpsave); + + if (netgame) + { + if (servernode < 0 || servernode >= MAXNETNODES) + CONS_Printf(M_GetText("Searching for a server...\n")); + else + CONS_Printf(M_GetText("Contacting the server...\n")); + } + + if (gamestate == GS_INTERMISSION) + Y_EndIntermission(); // clean up intermission graphics etc + + DEBFILE(va("waiting %d nodes\n", doomcom->numnodes)); + G_SetGamestate(GS_WAITINGPLAYERS); + wipegamestate = GS_WAITINGPLAYERS; + + ClearAdminPlayers(); + pnumnodes = 1; + oldtic = I_GetTime() - 1; + + asksent = (tic_t) - TICRATE; + firstconnectattempttime = I_GetTime(); + + i = SL_SearchServer(servernode); + + if (i != -1) + { + char *gametypestr = serverlist[i].info.gametypename; + CONS_Printf(M_GetText("Connecting to: %s\n"), serverlist[i].info.servername); + gametypestr[sizeof serverlist[i].info.gametypename - 1] = '\0'; + CONS_Printf(M_GetText("Gametype: %s\n"), gametypestr); + CONS_Printf(M_GetText("Version: %d.%d.%u\n"), serverlist[i].info.version/100, + serverlist[i].info.version%100, serverlist[i].info.subversion); + } + SL_ClearServerList(servernode); + + do + { + // If the connection was aborted for some reason, leave + if (!CL_ServerConnectionTicker(tmpsave, &oldtic, &asksent)) + return; + + if (server) + { + pnumnodes = 0; + for (i = 0; i < MAXNETNODES; i++) + if (netnodes[i].ingame) + pnumnodes++; + } + } + while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes)))); + + DEBFILE(va("Synchronisation Finished\n")); + + displayplayer = consoleplayer; +} + +/** Called when a PT_SERVERINFO packet is received + * + * \param node The packet sender + * \note What happens if the packet comes from a client or something like that? + * + */ +void HandleServerInfo(SINT8 node) +{ + // compute ping in ms + const tic_t ticnow = I_GetTime(); + const tic_t ticthen = (tic_t)LONG(netbuffer->u.serverinfo.time); + const tic_t ticdiff = (ticnow - ticthen)*1000/NEWTICRATE; + netbuffer->u.serverinfo.time = (tic_t)LONG(ticdiff); + netbuffer->u.serverinfo.servername[MAXSERVERNAME-1] = 0; + netbuffer->u.serverinfo.application + [sizeof netbuffer->u.serverinfo.application - 1] = '\0'; + netbuffer->u.serverinfo.gametypename + [sizeof netbuffer->u.serverinfo.gametypename - 1] = '\0'; + + SL_InsertServer(&netbuffer->u.serverinfo, node); +} + +// Helper function for packets that should only be sent by the server +// If it is NOT from the server, bail out and close the connection! +static boolean ServerOnly(SINT8 node) +{ + if (node == servernode) + return false; + + Net_CloseConnection(node); + return true; +} + +void PT_MoreFilesNeeded(SINT8 node) +{ + if (server && serverrunning) + { // But wait I thought I'm the server? + Net_CloseConnection(node); + return; + } + if (ServerOnly(node)) + return; + if (cl_mode == CL_ASKFULLFILELIST && netbuffer->u.filesneededcfg.first == fileneedednum) + { + D_ParseFileneeded(netbuffer->u.filesneededcfg.num, netbuffer->u.filesneededcfg.files, netbuffer->u.filesneededcfg.first); + if (!netbuffer->u.filesneededcfg.more) + cl_lastcheckedfilecount = UINT16_MAX; // Got the whole file list + } +} + +// Negative response of client join request +void PT_ServerRefuse(SINT8 node) +{ + if (server && serverrunning) + { // But wait I thought I'm the server? + Net_CloseConnection(node); + return; + } + if (ServerOnly(node)) + return; + if (cl_mode == CL_WAITJOINRESPONSE) + { + // Save the reason so it can be displayed after quitting the netgame + char *reason = strdup(netbuffer->u.serverrefuse.reason); + if (!reason) + I_Error("Out of memory!\n"); + + if (strstr(reason, "Maximum players reached")) + { + serverisfull = true; + //Special timeout for when refusing due to player cap. The client will wait 3 seconds between join requests when waiting for a slot, so we need this to be much longer + //We set it back to the value of cv_nettimeout.value in CL_Reset + connectiontimeout = NEWTICRATE*7; + cl_mode = CL_ASKJOIN; + free(reason); + return; + } + + M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"), + reason), NULL, MM_NOTHING); + + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + + free(reason); + + // Will be reset by caller. Signals refusal. + cl_mode = CL_ABORTED; + } +} + +// Positive response of client join request +void PT_ServerCFG(SINT8 node) +{ + if (server && serverrunning && node != servernode) + { // but wait I thought I'm the server? + Net_CloseConnection(node); + return; + } + if (ServerOnly(node)) + return; + /// \note how would this happen? and is it doing the right thing if it does? + if (cl_mode != CL_WAITJOINRESPONSE) + return; + + if (client) + { + maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); + G_SetGametype(netbuffer->u.servercfg.gametype); + modifiedgame = netbuffer->u.servercfg.modifiedgame; + memcpy(server_context, netbuffer->u.servercfg.server_context, 8); + } + + netnodes[(UINT8)servernode].ingame = true; + serverplayer = netbuffer->u.servercfg.serverplayer; + doomcom->numslots = SHORT(netbuffer->u.servercfg.totalslotnum); + mynode = netbuffer->u.servercfg.clientnode; + if (serverplayer >= 0) + playernode[(UINT8)serverplayer] = servernode; + + if (netgame) + CONS_Printf(M_GetText("Join accepted, waiting for complete game state...\n")); + DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode)); + + /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? + /// Shouldn't them be downloaded even at intermission time? + /// Also, according to HandleConnect, the server will send the savegame even during intermission... + if (netbuffer->u.servercfg.gamestate == GS_LEVEL/* || + netbuffer->u.servercfg.gamestate == GS_INTERMISSION*/) + cl_mode = CL_DOWNLOADSAVEGAME; + else + cl_mode = CL_CONNECTED; +} diff --git a/src/netcode/client_connection.h b/src/netcode/client_connection.h new file mode 100644 index 000000000..a76411ba6 --- /dev/null +++ b/src/netcode/client_connection.h @@ -0,0 +1,61 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file client_connection.h +/// \brief Client connection handling + +#ifndef __D_CLIENT_CONNECTION__ +#define __D_CLIENT_CONNECTION__ + +#include "../doomtype.h" +#include "d_clisrv.h" + +#define MAXSERVERLIST (MAXNETNODES-1) + +typedef struct +{ + SINT8 node; + serverinfo_pak info; +} serverelem_t; + +typedef enum +{ + CL_SEARCHING, + CL_CHECKFILES, + CL_DOWNLOADFILES, + CL_ASKJOIN, + CL_LOADFILES, + CL_WAITJOINRESPONSE, + CL_DOWNLOADSAVEGAME, + CL_CONNECTED, + CL_ABORTED, + CL_ASKFULLFILELIST, + CL_CONFIRMCONNECT +} cl_mode_t; + +extern serverelem_t serverlist[MAXSERVERLIST]; +extern UINT32 serverlistcount; + +extern cl_mode_t cl_mode; +extern boolean serverisfull; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not +extern tic_t firstconnectattempttime; +extern UINT8 mynode; // my address pointofview server + +void CL_QueryServerList(msg_server_t *list); +void CL_UpdateServerList(boolean internetsearch, INT32 room); + +void CL_ConnectToServer(void); +boolean CL_SendJoin(void); + +void HandleServerInfo(SINT8 node); +void PT_MoreFilesNeeded(SINT8 node); +void PT_ServerRefuse(SINT8 node); +void PT_ServerCFG(SINT8 node); + +#endif diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index 9b11e23ff..f7a9260e1 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -49,14 +49,7 @@ #include "../lua_libs.h" #include "../md5.h" #include "../m_perfstats.h" - -// aaaaaa -#include "../i_gamepad.h" - -// cl loading screen -#include "../v_video.h" -#include "../f_finale.h" -#include "../snake.h" +#include "client_connection.h" // // NETWORKING @@ -103,7 +96,7 @@ tic_t servermaxping = 800; // server's max ping. Defaults to 800 static tic_t firstticstosend; // min of the nettics static tic_t tictoclear = 0; // optimize d_clearticcmd -static tic_t maketic; +tic_t maketic; static INT16 consistancy[BACKUPTICS]; @@ -121,21 +114,17 @@ static ticcmd_t localcmds; static ticcmd_t localcmds2; static boolean cl_packetmissed; // here it is for the secondary local player (splitscreen) -static UINT8 mynode; // my address pointofview server static boolean cl_redownloadinggamestate = false; static UINT8 localtextcmd[MAXTEXTCMD]; static UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen -static tic_t neededtic; +tic_t neededtic; SINT8 servernode = 0; // the number of the server node /// \brief do we accept new players? /// \todo WORK! boolean acceptnewnode = true; -static boolean serverisfull = false; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not -static tic_t firstconnectattempttime = 0; - // engine // Must be a power of two @@ -512,250 +501,6 @@ void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum) static INT16 Consistancy(void); -typedef enum -{ - CL_SEARCHING, - CL_CHECKFILES, - CL_DOWNLOADFILES, - CL_ASKJOIN, - CL_LOADFILES, - CL_WAITJOINRESPONSE, - CL_DOWNLOADSAVEGAME, - CL_CONNECTED, - CL_ABORTED, - CL_ASKFULLFILELIST, - CL_CONFIRMCONNECT -} cl_mode_t; - -static void GetPackets(void); - -static cl_mode_t cl_mode = CL_SEARCHING; - -static UINT16 cl_lastcheckedfilecount = 0; // used for full file list - -static void *snake = NULL; - -static void CL_DrawConnectionStatusBox(void) -{ - M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1); - if (cl_mode != CL_CONFIRMCONNECT) - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); -} - -// -// CL_DrawConnectionStatus -// -// Keep the local client informed of our status. -// -static inline void CL_DrawConnectionStatus(void) -{ - INT32 ccstime = I_GetTime(); - - // Draw background fade - V_DrawFadeScreen(0xFF00, 16); // force default - - if (cl_mode != CL_DOWNLOADFILES && cl_mode != CL_LOADFILES) - { - INT32 i, animtime = ((ccstime / 4) & 15) + 16; - UINT8 palstart; - const char *cltext; - - // Draw the bottom box. - CL_DrawConnectionStatusBox(); - - if (cl_mode == CL_SEARCHING) - palstart = 32; // Red - else if (cl_mode == CL_CONFIRMCONNECT) - palstart = 48; // Orange - else - palstart = 96; // Green - - if (!(cl_mode == CL_DOWNLOADSAVEGAME && lastfilenum != -1)) - for (i = 0; i < 16; ++i) // 15 pal entries total. - V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-16, 16, 8, palstart + ((animtime - i) & 15)); - - switch (cl_mode) - { - case CL_DOWNLOADSAVEGAME: - if (fileneeded && lastfilenum != -1) - { - UINT32 currentsize = fileneeded[lastfilenum].currentsize; - UINT32 totalsize = fileneeded[lastfilenum].totalsize; - INT32 dldlength; - - cltext = M_GetText("Downloading game state..."); - Net_GetNetStat(); - - dldlength = (INT32)((currentsize/(double)totalsize) * 256); - if (dldlength > 256) - dldlength = 256; - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, dldlength, 8, 96); - - V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, - va(" %4uK/%4uK",currentsize>>10,totalsize>>10)); - - V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, - va("%3.1fK/s ", ((double)getbps)/1024)); - } - else - cltext = M_GetText("Waiting to download game state..."); - break; - case CL_ASKFULLFILELIST: - case CL_CHECKFILES: - cltext = M_GetText("Checking server addon list..."); - break; - case CL_CONFIRMCONNECT: - cltext = ""; - break; - case CL_LOADFILES: - cltext = M_GetText("Loading server addons..."); - break; - case CL_ASKJOIN: - case CL_WAITJOINRESPONSE: - if (serverisfull) - cltext = M_GetText("Server full, waiting for a slot..."); - else - cltext = M_GetText("Requesting to join..."); - break; - default: - cltext = M_GetText("Connecting to server..."); - break; - } - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, cltext); - } - else - { - if (cl_mode == CL_LOADFILES) - { - INT32 totalfileslength; - INT32 loadcompletednum = 0; - INT32 i; - - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); - - //ima just count files here - if (fileneeded) - { - for (i = 0; i < fileneedednum; i++) - if (fileneeded[i].status == FS_OPEN) - loadcompletednum++; - } - - // Loading progress - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, "Loading server addons..."); - totalfileslength = (INT32)((loadcompletednum/(double)(fileneedednum)) * 256); - M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, totalfileslength, 8, 96); - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, - va(" %2u/%2u Files",loadcompletednum,fileneedednum)); - } - else if (lastfilenum != -1) - { - INT32 dldlength; - static char tempname[28]; - fileneeded_t *file; - char *filename; - - if (snake) - Snake_Draw(snake); - - // Draw the bottom box. - CL_DrawConnectionStatusBox(); - - if (fileneeded) - { - file = &fileneeded[lastfilenum]; - filename = file->filename; - } - else - return; - - Net_GetNetStat(); - dldlength = (INT32)((file->currentsize/(double)file->totalsize) * 256); - if (dldlength > 256) - dldlength = 256; - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, dldlength, 8, 96); - - memset(tempname, 0, sizeof(tempname)); - // offset filename to just the name only part - filename += strlen(filename) - nameonlylength(filename); - - if (strlen(filename) > sizeof(tempname)-1) // too long to display fully - { - size_t endhalfpos = strlen(filename)-10; - // display as first 14 chars + ... + last 10 chars - // which should add up to 27 if our math(s) is correct - snprintf(tempname, sizeof(tempname), "%.14s...%.10s", filename, filename+endhalfpos); - } - else // we can copy the whole thing in safely - { - strncpy(tempname, filename, sizeof(tempname)-1); - } - - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, - va(M_GetText("Downloading \"%s\""), tempname)); - V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, - va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,file->totalsize>>10)); - V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, - va("%3.1fK/s ", ((double)getbps)/1024)); - } - else - { - if (snake) - Snake_Draw(snake); - - CL_DrawConnectionStatusBox(); - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, - M_GetText("Waiting to download files...")); - } - } -} - -static boolean CL_AskFileList(INT32 firstfile) -{ - netbuffer->packettype = PT_TELLFILESNEEDED; - netbuffer->u.filesneedednum = firstfile; - - return HSendPacket(servernode, false, 0, sizeof (INT32)); -} - -/** Sends a special packet to declare how many players in local - * Used only in arbitratrenetstart() - * Sends a PT_CLIENTJOIN packet to the server - * - * \return True if the packet was successfully sent - * \todo Improve the description... - * - */ -static boolean CL_SendJoin(void) -{ - UINT8 localplayers = 1; - if (netgame) - CONS_Printf(M_GetText("Sending join request...\n")); - netbuffer->packettype = PT_CLIENTJOIN; - - netbuffer->u.clientcfg.modversion = MODVERSION; - strncpy(netbuffer->u.clientcfg.application, - SRB2APPLICATION, - sizeof netbuffer->u.clientcfg.application); - - if (splitscreen || botingame) - localplayers++; - netbuffer->u.clientcfg.localplayers = localplayers; - - CleanupPlayerName(consoleplayer, cv_playername.zstring); - if (splitscreen) - CleanupPlayerName(1, cv_playername2.zstring);/* 1 is a HACK? oh no */ - - strncpy(netbuffer->u.clientcfg.names[0], cv_playername.zstring, MAXPLAYERNAME); - strncpy(netbuffer->u.clientcfg.names[1], cv_playername2.zstring, MAXPLAYERNAME); - - return HSendPacket(servernode, true, 0, sizeof (clientconfig_pak)); -} - static INT32 FindRejoinerNum(SINT8 node) { char strippednodeaddress[64]; @@ -1105,7 +850,7 @@ static void SV_SavedGame(void) #define TMPSAVENAME "$$$.sav" -static void CL_LoadReceivedSavegame(boolean reloading) +void CL_LoadReceivedSavegame(boolean reloading) { UINT8 *savebuffer = NULL; size_t length, decompressedlen; @@ -1206,790 +951,6 @@ static void CL_ReloadReceivedSavegame(void) CONS_Printf(M_GetText("Game state reloaded\n")); } -static void SendAskInfo(INT32 node) -{ - const tic_t asktime = I_GetTime(); - netbuffer->packettype = PT_ASKINFO; - netbuffer->u.askinfo.version = VERSION; - netbuffer->u.askinfo.time = (tic_t)LONG(asktime); - - // Even if this never arrives due to the host being firewalled, we've - // now allowed traffic from the host to us in, so once the MS relays - // our address to the host, it'll be able to speak to us. - HSendPacket(node, false, 0, sizeof (askinfo_pak)); -} - -serverelem_t serverlist[MAXSERVERLIST]; -UINT32 serverlistcount = 0; - -#define FORCECLOSE 0x8000 - -static void SL_ClearServerList(INT32 connectedserver) -{ - UINT32 i; - - for (i = 0; i < serverlistcount; i++) - if (connectedserver != serverlist[i].node) - { - Net_CloseConnection(serverlist[i].node|FORCECLOSE); - serverlist[i].node = 0; - } - serverlistcount = 0; -} - -static UINT32 SL_SearchServer(INT32 node) -{ - UINT32 i; - for (i = 0; i < serverlistcount; i++) - if (serverlist[i].node == node) - return i; - - return UINT32_MAX; -} - -static void SL_InsertServer(serverinfo_pak* info, SINT8 node) -{ - UINT32 i; - - // search if not already on it - i = SL_SearchServer(node); - if (i == UINT32_MAX) - { - // not found add it - if (serverlistcount >= MAXSERVERLIST) - return; // list full - - /* check it later if connecting to this one */ - if (node != servernode) - { - if (info->_255 != 255) - return;/* old packet format */ - - if (info->packetversion != PACKETVERSION) - return;/* old new packet format */ - - if (info->version != VERSION) - return; // Not same version. - - if (info->subversion != SUBVERSION) - return; // Close, but no cigar. - - if (strcmp(info->application, SRB2APPLICATION)) - return;/* that's a different mod */ - } - - i = serverlistcount++; - } - - serverlist[i].info = *info; - serverlist[i].node = node; - - // resort server list - M_SortServerList(); -} - -#if defined (MASTERSERVER) && defined (HAVE_THREADS) -struct Fetch_servers_ctx -{ - int room; - int id; -}; - -static void -Fetch_servers_thread (struct Fetch_servers_ctx *ctx) -{ - msg_server_t *server_list; - - server_list = GetShortServersList(ctx->room, ctx->id); - - if (server_list) - { - I_lock_mutex(&ms_QueryId_mutex); - { - if (ctx->id != ms_QueryId) - { - free(server_list); - server_list = NULL; - } - } - I_unlock_mutex(ms_QueryId_mutex); - - if (server_list) - { - I_lock_mutex(&m_menu_mutex); - { - if (m_waiting_mode == M_WAITING_SERVERS) - m_waiting_mode = M_NOT_WAITING; - } - I_unlock_mutex(m_menu_mutex); - - I_lock_mutex(&ms_ServerList_mutex); - { - ms_ServerList = server_list; - } - I_unlock_mutex(ms_ServerList_mutex); - } - } - - free(ctx); -} -#endif/*defined (MASTERSERVER) && defined (HAVE_THREADS)*/ - -void CL_QueryServerList (msg_server_t *server_list) -{ - INT32 i; - - for (i = 0; server_list[i].header.buffer[0]; i++) - { - // Make sure MS version matches our own, to - // thwart nefarious servers who lie to the MS. - - /* lol bruh, that version COMES from the servers */ - //if (strcmp(version, server_list[i].version) == 0) - { - INT32 node = I_NetMakeNodewPort(server_list[i].ip, server_list[i].port); - if (node == -1) - break; // no more node free - SendAskInfo(node); - // Force close the connection so that servers can't eat - // up nodes forever if we never get a reply back from them - // (usually when they've not forwarded their ports). - // - // Don't worry, we'll get in contact with the working - // servers again when they send SERVERINFO to us later! - // - // (Note: as a side effect this probably means every - // server in the list will probably be using the same node (e.g. node 1), - // not that it matters which nodes they use when - // the connections are closed afterwards anyway) - // -- Monster Iestyn 12/11/18 - Net_CloseConnection(node|FORCECLOSE); - } - } -} - -void CL_UpdateServerList(boolean internetsearch, INT32 room) -{ - (void)internetsearch; - (void)room; - - SL_ClearServerList(0); - - if (!netgame && I_NetOpenSocket) - { - if (I_NetOpenSocket()) - { - netgame = true; - multiplayer = true; - } - } - - // search for local servers - if (netgame) - SendAskInfo(BROADCASTADDR); - -#ifdef MASTERSERVER - if (internetsearch) - { -#ifdef HAVE_THREADS - struct Fetch_servers_ctx *ctx; - - ctx = malloc(sizeof *ctx); - - /* This called from M_Refresh so I don't use a mutex */ - m_waiting_mode = M_WAITING_SERVERS; - - I_lock_mutex(&ms_QueryId_mutex); - { - ctx->id = ms_QueryId; - } - I_unlock_mutex(ms_QueryId_mutex); - - ctx->room = room; - - I_spawn_thread("fetch-servers", (I_thread_fn)Fetch_servers_thread, ctx); -#else - msg_server_t *server_list; - - server_list = GetShortServersList(room, 0); - - if (server_list) - { - CL_QueryServerList(server_list); - free(server_list); - } -#endif - } -#endif/*MASTERSERVER*/ -} - -static void M_ConfirmConnect(event_t *ev) -{ - if (ev->type == ev_keydown || ev->type == ev_gamepad_down) - { - if ((ev->type == ev_keydown && (ev->key == ' ' || ev->key == 'y' || ev->key == KEY_ENTER)) || (ev->type == ev_gamepad_down && ev->which == 0 && ev->key == GAMEPAD_BUTTON_A)) - { - if (totalfilesrequestednum > 0) - { - if (CL_SendFileRequest()) - { - cl_mode = CL_DOWNLOADFILES; - Snake_Allocate(&snake); - } - } - else - cl_mode = CL_LOADFILES; - - M_ClearMenus(true); - } - else if ((ev->type == ev_keydown && (ev->key == 'n' || ev->key == KEY_ESCAPE)) || (ev->type == ev_gamepad_down && ev->which == 0 && ev->key == GAMEPAD_BUTTON_B)) - { - cl_mode = CL_ABORTED; - M_ClearMenus(true); - } - } -} - -static boolean CL_FinishedFileList(void) -{ - INT32 i; - char *downloadsize = NULL; - - //CONS_Printf(M_GetText("Checking files...\n")); - i = CL_CheckFiles(); - if (i == 4) // still checking ... - { - return true; - } - else if (i == 3) // too many files - { - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText( - "You have too many WAD files loaded\n" - "to add ones the server is using.\n" - "Please restart SRB2 before connecting.\n\n" - "Press ESC\n" - ), NULL, MM_NOTHING); - return false; - } - else if (i == 2) // cannot join for some reason - { - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText( - "You have the wrong addons loaded.\n\n" - "To play on this server, restart\n" - "the game and don't load any addons.\n" - "SRB2 will automatically add\n" - "everything you need when you join.\n\n" - "Press ESC\n" - ), NULL, MM_NOTHING); - return false; - } - else if (i == 1) - { - if (serverisfull) - { - M_StartMessage(M_GetText( - "This server is full!\n" - "\n" - "You may load server addons (if any), and wait for a slot.\n" - "\n" - "Press ENTER to continue\nor ESC to cancel.\n\n" - ), M_ConfirmConnect, MM_EVENTHANDLER); - cl_mode = CL_CONFIRMCONNECT; - curfadevalue = 0; - } - else - cl_mode = CL_LOADFILES; - } - else - { - // must download something - // can we, though? - if (!CL_CheckDownloadable()) // nope! - { - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText( - "An error occured when trying to\n" - "download missing addons.\n" - "(This is almost always a problem\n" - "with the server, not your game.)\n\n" - "See the console or log file\n" - "for additional details.\n\n" - "Press ESC\n" - ), NULL, MM_NOTHING); - return false; - } - - downloadcompletednum = 0; - downloadcompletedsize = 0; - totalfilesrequestednum = 0; - totalfilesrequestedsize = 0; - - if (fileneeded == NULL) - I_Error("CL_FinishedFileList: fileneeded == NULL"); - - for (i = 0; i < fileneedednum; i++) - if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD) - { - totalfilesrequestednum++; - totalfilesrequestedsize += fileneeded[i].totalsize; - } - - if (totalfilesrequestedsize>>20 >= 100) - downloadsize = Z_StrDup(va("%uM",totalfilesrequestedsize>>20)); - else - downloadsize = Z_StrDup(va("%uK",totalfilesrequestedsize>>10)); - - if (serverisfull) - M_StartMessage(va(M_GetText( - "This server is full!\n" - "Download of %s additional content\nis required to join.\n" - "\n" - "You may download, load server addons,\nand wait for a slot.\n" - "\n" - "Press ENTER to continue\nor ESC to cancel.\n" - ), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER); - else - M_StartMessage(va(M_GetText( - "Download of %s additional content\nis required to join.\n" - "\n" - "Press ENTER to continue\nor ESC to cancel.\n" - ), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER); - - Z_Free(downloadsize); - cl_mode = CL_CONFIRMCONNECT; - curfadevalue = 0; - } - return true; -} - -static const char * InvalidServerReason (serverinfo_pak *info) -{ -#define EOT "\nPress ESC\n" - - /* magic number for new packet format */ - if (info->_255 != 255) - { - return - "Outdated server (version unknown).\n" EOT; - } - - if (strncmp(info->application, SRB2APPLICATION, sizeof - info->application)) - { - return va( - "%s cannot connect\n" - "to %s servers.\n" EOT, - SRB2APPLICATION, - info->application); - } - - if ( - info->packetversion != PACKETVERSION || - info->version != VERSION || - info->subversion != SUBVERSION - ){ - return va( - "Incompatible %s versions.\n" - "(server version %d.%d.%d)\n" EOT, - SRB2APPLICATION, - info->version / 100, - info->version % 100, - info->subversion); - } - - switch (info->refusereason) - { - case REFUSE_BANNED: - return - "You have been banned\n" - "from the server.\n" EOT; - case REFUSE_JOINS_DISABLED: - return - "The server is not accepting\n" - "joins for the moment.\n" EOT; - case REFUSE_SLOTS_FULL: - return va( - "Maximum players reached: %d\n" EOT, - info->maxplayer); - default: - if (info->refusereason) - { - return - "You can't join.\n" - "I don't know why,\n" - "but you can't join.\n" EOT; - } - } - - return NULL; - -#undef EOT -} - -/** Called by CL_ServerConnectionTicker - * - * \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit. - * \return False if the connection was aborted - * \sa CL_ServerConnectionTicker - * \sa CL_ConnectToServer - * - */ -static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) -{ - INT32 i; - - // serverlist is updated by GetPacket function - if (serverlistcount > 0) - { - // this can be a responce to our broadcast request - if (servernode == -1 || servernode >= MAXNETNODES) - { - i = 0; - servernode = serverlist[i].node; - CONS_Printf(M_GetText("Found, ")); - } - else - { - i = SL_SearchServer(servernode); - if (i < 0) - return true; - } - - if (client) - { - serverinfo_pak *info = &serverlist[i].info; - - if (info->refusereason == REFUSE_SLOTS_FULL) - serverisfull = true; - else - { - const char *reason = InvalidServerReason(info); - - // Quit here rather than downloading files - // and being refused later. - if (reason) - { - char *message = Z_StrDup(reason); - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(message, NULL, MM_NOTHING); - Z_Free(message); - return false; - } - } - - D_ParseFileneeded(info->fileneedednum, info->fileneeded, 0); - - if (info->flags & SV_LOTSOFADDONS) - { - cl_mode = CL_ASKFULLFILELIST; - cl_lastcheckedfilecount = 0; - return true; - } - - cl_mode = CL_CHECKFILES; - } - else - { - cl_mode = CL_ASKJOIN; // files need not be checked for the server. - *asksent = 0; - } - - return true; - } - - // Ask the info to the server (askinfo packet) - if (*asksent + NEWTICRATE < I_GetTime()) - { - SendAskInfo(servernode); - *asksent = I_GetTime(); - } - - return true; -} - -/** Called by CL_ConnectToServer - * - * \param tmpsave The name of the gamestate file??? - * \param oldtic Used for knowing when to poll events and redraw - * \param asksent ??? - * \return False if the connection was aborted - * \sa CL_ServerConnectionSearchTicker - * \sa CL_ConnectToServer - * - */ -static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic_t *asksent) -{ - boolean waitmore; - INT32 i; - - switch (cl_mode) - { - case CL_SEARCHING: - if (!CL_ServerConnectionSearchTicker(asksent)) - return false; - break; - - case CL_ASKFULLFILELIST: - if (cl_lastcheckedfilecount == UINT16_MAX) // All files retrieved - cl_mode = CL_CHECKFILES; - else if (fileneedednum != cl_lastcheckedfilecount || I_GetTime() >= *asksent) - { - if (CL_AskFileList(fileneedednum)) - { - cl_lastcheckedfilecount = fileneedednum; - *asksent = I_GetTime() + NEWTICRATE; - } - } - break; - case CL_CHECKFILES: - if (!CL_FinishedFileList()) - return false; - break; - case CL_DOWNLOADFILES: - waitmore = false; - for (i = 0; i < fileneedednum; i++) - if (fileneeded[i].status == FS_DOWNLOADING - || fileneeded[i].status == FS_REQUESTED) - { - waitmore = true; - break; - } - if (waitmore) - break; // exit the case - - Snake_Free(&snake); - - cl_mode = CL_LOADFILES; - break; - case CL_LOADFILES: - if (CL_LoadServerFiles()) - { - FreeFileNeeded(); - *asksent = 0; //This ensure the first join ask is right away - firstconnectattempttime = I_GetTime(); - cl_mode = CL_ASKJOIN; - } - break; - case CL_ASKJOIN: - if (firstconnectattempttime + NEWTICRATE*300 < I_GetTime() && !server) - { - CONS_Printf(M_GetText("5 minute wait time exceeded.\n")); - CONS_Printf(M_GetText("Network game synchronization aborted.\n")); - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText( - "5 minute wait time exceeded.\n" - "You may retry connection.\n" - "\n" - "Press ESC\n" - ), NULL, MM_NOTHING); - return false; - } - - // prepare structures to save the file - // WARNING: this can be useless in case of server not in GS_LEVEL - // but since the network layer doesn't provide ordered packets... - CL_PrepareDownloadSaveGame(tmpsave); - - if (I_GetTime() >= *asksent && CL_SendJoin()) - { - *asksent = I_GetTime() + NEWTICRATE*3; - cl_mode = CL_WAITJOINRESPONSE; - } - break; - case CL_WAITJOINRESPONSE: - if (I_GetTime() >= *asksent) - { - cl_mode = CL_ASKJOIN; - } - break; - case CL_DOWNLOADSAVEGAME: - // At this state, the first (and only) needed file is the gamestate - if (fileneeded[0].status == FS_FOUND) - { - // Gamestate is now handled within CL_LoadReceivedSavegame() - CL_LoadReceivedSavegame(false); - cl_mode = CL_CONNECTED; - } // don't break case continue to CL_CONNECTED - else - break; - - case CL_CONNECTED: - case CL_CONFIRMCONNECT: //logic is handled by M_ConfirmConnect - default: - break; - - // Connection closed by cancel, timeout or refusal. - case CL_ABORTED: - cl_mode = CL_SEARCHING; - return false; - } - - GetPackets(); - Net_AckTicker(); - - // Call it only once by tic - if (*oldtic != I_GetTime()) - { - I_OsPolling(); - - if (cl_mode == CL_CONFIRMCONNECT) - D_ProcessEvents(); //needed for menu system to receive inputs - else - { - // my hand has been forced and I am dearly sorry for this awful hack :vomit: - for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) - { - G_MapEventsToControls(&events[eventtail]); - } - } - - if (gamekeydown[KEY_ESCAPE] || gamepads[0].buttons[GAMEPAD_BUTTON_B] || cl_mode == CL_ABORTED) - { - CONS_Printf(M_GetText("Network game synchronization aborted.\n")); - M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); - - Snake_Free(&snake); - - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - memset(gamekeydown, 0, NUMKEYS); - return false; - } - else if (cl_mode == CL_DOWNLOADFILES && snake) - Snake_Update(snake); - - if (client && (cl_mode == CL_DOWNLOADFILES || cl_mode == CL_DOWNLOADSAVEGAME)) - FileReceiveTicker(); - - // why are these here? this is for servers, we're a client - //if (key == 's' && server) - // doomcom->numnodes = (INT16)pnumnodes; - //FileSendTicker(); - *oldtic = I_GetTime(); - - if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED) - { - if (!snake) - { - F_MenuPresTicker(true); // title sky - F_TitleScreenTicker(true); - F_TitleScreenDrawer(); - } - CL_DrawConnectionStatus(); -#ifdef HAVE_THREADS - I_lock_mutex(&m_menu_mutex); -#endif - M_Drawer(); //Needed for drawing messageboxes on the connection screen -#ifdef HAVE_THREADS - I_unlock_mutex(m_menu_mutex); -#endif - I_UpdateNoVsync(); // page flip or blit buffer - if (moviemode) - M_SaveFrame(); - S_UpdateSounds(); - S_UpdateClosedCaptions(); - } - } - else - { - I_Sleep(cv_sleep.value); - I_UpdateTime(cv_timescale.value); - } - - return true; -} - -/** Use adaptive send using net_bandwidth and stat.sendbytes - * - * \todo Better description... - * - */ -static void CL_ConnectToServer(void) -{ - INT32 pnumnodes, nodewaited = doomcom->numnodes, i; - tic_t oldtic; - tic_t asksent; - char tmpsave[256]; - - sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); - - lastfilenum = -1; - - cl_mode = CL_SEARCHING; - - // Don't get a corrupt savegame error because tmpsave already exists - if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1) - I_Error("Can't delete %s\n", tmpsave); - - if (netgame) - { - if (servernode < 0 || servernode >= MAXNETNODES) - CONS_Printf(M_GetText("Searching for a server...\n")); - else - CONS_Printf(M_GetText("Contacting the server...\n")); - } - - if (gamestate == GS_INTERMISSION) - Y_EndIntermission(); // clean up intermission graphics etc - - DEBFILE(va("waiting %d nodes\n", doomcom->numnodes)); - G_SetGamestate(GS_WAITINGPLAYERS); - wipegamestate = GS_WAITINGPLAYERS; - - ClearAdminPlayers(); - pnumnodes = 1; - oldtic = I_GetTime() - 1; - - asksent = (tic_t) - TICRATE; - firstconnectattempttime = I_GetTime(); - - i = SL_SearchServer(servernode); - - if (i != -1) - { - char *gametypestr = serverlist[i].info.gametypename; - CONS_Printf(M_GetText("Connecting to: %s\n"), serverlist[i].info.servername); - gametypestr[sizeof serverlist[i].info.gametypename - 1] = '\0'; - CONS_Printf(M_GetText("Gametype: %s\n"), gametypestr); - CONS_Printf(M_GetText("Version: %d.%d.%u\n"), serverlist[i].info.version/100, - serverlist[i].info.version%100, serverlist[i].info.subversion); - } - SL_ClearServerList(servernode); - - do - { - // If the connection was aborted for some reason, leave - if (!CL_ServerConnectionTicker(tmpsave, &oldtic, &asksent)) - return; - - if (server) - { - pnumnodes = 0; - for (i = 0; i < MAXNETNODES; i++) - if (netnodes[i].ingame) - pnumnodes++; - } - } - while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes)))); - - DEBFILE(va("Synchronisation Finished\n")); - - displayplayer = consoleplayer; -} - typedef struct banreason_s { char *reason; @@ -3525,39 +2486,6 @@ static void HandleTimeout(SINT8 node) M_StartMessage(M_GetText("Server Timeout\n\nPress Esc\n"), NULL, MM_NOTHING); } -/** Called when a PT_SERVERINFO packet is received - * - * \param node The packet sender - * \note What happens if the packet comes from a client or something like that? - * - */ -static void HandleServerInfo(SINT8 node) -{ - // compute ping in ms - const tic_t ticnow = I_GetTime(); - const tic_t ticthen = (tic_t)LONG(netbuffer->u.serverinfo.time); - const tic_t ticdiff = (ticnow - ticthen)*1000/NEWTICRATE; - netbuffer->u.serverinfo.time = (tic_t)LONG(ticdiff); - netbuffer->u.serverinfo.servername[MAXSERVERNAME-1] = 0; - netbuffer->u.serverinfo.application - [sizeof netbuffer->u.serverinfo.application - 1] = '\0'; - netbuffer->u.serverinfo.gametypename - [sizeof netbuffer->u.serverinfo.gametypename - 1] = '\0'; - - SL_InsertServer(&netbuffer->u.serverinfo, node); -} - -// Helper function for packets that should only be sent by the server -// If it is NOT from the server, bail out and close the connection! -static boolean ServerOnly(SINT8 node) -{ - if (node == servernode) - return false; - - Net_CloseConnection(node); - return true; -} - static void PT_AskInfoViaMS(SINT8 node) { Net_CloseConnection(node); @@ -3582,23 +2510,6 @@ static void PT_TellFilesNeeded(SINT8 node) Net_CloseConnection(node); } -static void PT_MoreFilesNeeded(SINT8 node) -{ - if (server && serverrunning) - { // But wait I thought I'm the server? - Net_CloseConnection(node); - return; - } - if (ServerOnly(node)) - return; - if (cl_mode == CL_ASKFULLFILELIST && netbuffer->u.filesneededcfg.first == fileneedednum) - { - D_ParseFileneeded(netbuffer->u.filesneededcfg.num, netbuffer->u.filesneededcfg.files, netbuffer->u.filesneededcfg.first); - if (!netbuffer->u.filesneededcfg.more) - cl_lastcheckedfilecount = UINT16_MAX; // Got the whole file list - } -} - static void PT_AskInfo(SINT8 node) { if (server && serverrunning) @@ -3609,91 +2520,6 @@ static void PT_AskInfo(SINT8 node) Net_CloseConnection(node); } -// Negative response of client join request -static void PT_ServerRefuse(SINT8 node) -{ - if (server && serverrunning) - { // But wait I thought I'm the server? - Net_CloseConnection(node); - return; - } - if (ServerOnly(node)) - return; - if (cl_mode == CL_WAITJOINRESPONSE) - { - // Save the reason so it can be displayed after quitting the netgame - char *reason = strdup(netbuffer->u.serverrefuse.reason); - if (!reason) - I_Error("Out of memory!\n"); - - if (strstr(reason, "Maximum players reached")) - { - serverisfull = true; - //Special timeout for when refusing due to player cap. The client will wait 3 seconds between join requests when waiting for a slot, so we need this to be much longer - //We set it back to the value of cv_nettimeout.value in CL_Reset - connectiontimeout = NEWTICRATE*7; - cl_mode = CL_ASKJOIN; - free(reason); - return; - } - - M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"), - reason), NULL, MM_NOTHING); - - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - - free(reason); - - // Will be reset by caller. Signals refusal. - cl_mode = CL_ABORTED; - } -} - -// Positive response of client join request -static void PT_ServerCFG(SINT8 node) -{ - if (server && serverrunning && node != servernode) - { // but wait I thought I'm the server? - Net_CloseConnection(node); - return; - } - if (ServerOnly(node)) - return; - /// \note how would this happen? and is it doing the right thing if it does? - if (cl_mode != CL_WAITJOINRESPONSE) - return; - - if (client) - { - maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); - G_SetGametype(netbuffer->u.servercfg.gametype); - modifiedgame = netbuffer->u.servercfg.modifiedgame; - memcpy(server_context, netbuffer->u.servercfg.server_context, 8); - } - - netnodes[(UINT8)servernode].ingame = true; - serverplayer = netbuffer->u.servercfg.serverplayer; - doomcom->numslots = SHORT(netbuffer->u.servercfg.totalslotnum); - mynode = netbuffer->u.servercfg.clientnode; - if (serverplayer >= 0) - playernode[(UINT8)serverplayer] = servernode; - - if (netgame) - CONS_Printf(M_GetText("Join accepted, waiting for complete game state...\n")); - DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode)); - - /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? - /// Shouldn't them be downloaded even at intermission time? - /// Also, according to HandleConnect, the server will send the savegame even during intermission... - if (netbuffer->u.servercfg.gamestate == GS_LEVEL/* || - netbuffer->u.servercfg.gamestate == GS_INTERMISSION*/) - cl_mode = CL_DOWNLOADSAVEGAME; - else - cl_mode = CL_CONNECTED; -} - static void PT_ClientCmd(SINT8 node, INT32 netconsole) { tic_t realend, realstart; @@ -4190,7 +3016,7 @@ static void HandlePacketFromPlayer(SINT8 node) * \todo Add details to this description (lol) * */ -static void GetPackets(void) +void GetPackets(void) { SINT8 node; // The packet sender diff --git a/src/netcode/d_clisrv.h b/src/netcode/d_clisrv.h index 50b86e9f0..3b0690a79 100644 --- a/src/netcode/d_clisrv.h +++ b/src/netcode/d_clisrv.h @@ -332,15 +332,6 @@ typedef struct #pragma pack() #endif -#define MAXSERVERLIST (MAXNETNODES-1) -typedef struct -{ - SINT8 node; - serverinfo_pak info; -} serverelem_t; - -extern serverelem_t serverlist[MAXSERVERLIST]; -extern UINT32 serverlistcount; extern INT32 mapchangepending; // Points inside doomcom @@ -385,6 +376,8 @@ extern boolean dedicated; // For dedicated server extern UINT16 software_MAXPACKETLENGTH; extern boolean acceptnewnode; extern SINT8 servernode; +extern tic_t maketic; +extern tic_t neededtic; void Command_Ping_f(void); extern tic_t connectiontimeout; @@ -411,6 +404,8 @@ void SendKick(UINT8 playernum, UINT8 msg); // Create any new ticcmds and broadcast to other players. void NetUpdate(void); +void GetPackets(void); + void SV_StartSinglePlayerServer(void); void SV_SpawnServer(void); void SV_StopServer(void); @@ -419,9 +414,8 @@ void CL_AddSplitscreenPlayer(void); void CL_RemoveSplitscreenPlayer(void); void CL_Reset(void); void CL_ClearPlayer(INT32 playernum); -void CL_QueryServerList(msg_server_t *list); -void CL_UpdateServerList(boolean internetsearch, INT32 room); void CL_RemovePlayer(INT32 playernum, kickreason_t reason); +void CL_LoadReceivedSavegame(boolean reloading); // Is there a game running boolean Playing(void); diff --git a/src/netcode/http-mserv.c b/src/netcode/http-mserv.c index 72dc1cafb..68e46b52a 100644 --- a/src/netcode/http-mserv.c +++ b/src/netcode/http-mserv.c @@ -20,6 +20,7 @@ Documentation available here. #include "../doomdef.h" #include "d_clisrv.h" +#include "client_connection.h" #include "../command.h" #include "../m_argv.h" #include "../m_menu.h" diff --git a/src/netcode/mserv.c b/src/netcode/mserv.c index 78301f4d9..f603d78e5 100644 --- a/src/netcode/mserv.c +++ b/src/netcode/mserv.c @@ -20,6 +20,7 @@ #include "../command.h" #include "../i_threads.h" #include "mserv.h" +#include "client_connection.h" #include "../m_menu.h" #include "../z_zone.h" From 636e6d8c14877e283ef17c55800384b8e17c8143 Mon Sep 17 00:00:00 2001 From: Arthur Date: Sat, 31 Dec 2022 19:35:07 -0500 Subject: [PATCH 45/96] MSVC project file works again! Supports Visual Studio 2022. Also fixed issues with the d_netcmd.c file/folder adding logic. --- .../projects/visualc10/libpng.vcxproj | 22 +- libs/zlib/projects/visualc10/zlib.vcxproj | 22 +- srb2-vc9.sln | 89 - src/blua/lua.h | 4 + src/blua/luaconf.h | 12 +- src/byteptr.h | 36 +- src/command.c | 4 + src/d_netcmd.c | 120 +- src/deh_soc.c | 8 +- src/doomtype.h | 10 - src/hardware/hw_main.c | 4 +- src/hardware/r_opengl/r_opengl-vc10.vcxproj | 18 +- src/hardware/r_opengl/r_opengl.c | 10 +- src/hardware/s_openal/s_openal-vc10.vcxproj | 18 +- src/p_mobj.c | 2 +- src/r_main.c | 2 +- src/r_picformats.c | 2 +- src/r_things.c | 8 +- src/sdl/Srb2SDL-vc10.vcxproj | 56 +- src/sdl/Srb2SDL-vc10.vcxproj.filters | 43 +- src/sdl/Srb2SDL-vc9.vcproj | 6021 ----------------- src/sdl/Srb2SDL.dsp | 1049 --- src/sdl/Srb2SDL.dsw | 74 - src/strcasestr.c | 10 + 24 files changed, 265 insertions(+), 7379 deletions(-) delete mode 100644 srb2-vc9.sln delete mode 100644 src/sdl/Srb2SDL-vc9.vcproj delete mode 100644 src/sdl/Srb2SDL.dsp delete mode 100644 src/sdl/Srb2SDL.dsw diff --git a/libs/libpng-src/projects/visualc10/libpng.vcxproj b/libs/libpng-src/projects/visualc10/libpng.vcxproj index eaa3d4ffb..351b4317d 100644 --- a/libs/libpng-src/projects/visualc10/libpng.vcxproj +++ b/libs/libpng-src/projects/visualc10/libpng.vcxproj @@ -37,51 +37,51 @@ {72B01ACA-7A1A-4F7B-ACEF-2607299CF052} libpng - 10.0.16299.0 + 10.0 StaticLibrary false - v140 + v143 StaticLibrary false - v141 + v143 true StaticLibrary false - v140 + v143 StaticLibrary false - v141 + v143 true StaticLibrary false - v140 + v143 StaticLibrary false - v141 + v143 true StaticLibrary false - v140 + v143 StaticLibrary false - v141 + v143 true @@ -278,7 +278,7 @@ Disabled ..\..;..\..\..\zlib;%(AdditionalIncludeDirectories) WIN32;_DEBUG;DEBUG;PNG_DEBUG=1;PNG_USE_PNGVCRD;PNG_LIBPNG_SPECIALBUILD;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - true + false EnableFastChecks MultiThreadedDebugDLL $(ProjectDir)$(Platform)\$(Configuration)\ @@ -288,7 +288,7 @@ true EditAndContinue CompileAsC - false + true _DEBUG;%(PreprocessorDefinitions) diff --git a/libs/zlib/projects/visualc10/zlib.vcxproj b/libs/zlib/projects/visualc10/zlib.vcxproj index de7b2aaab..5c00ea4a9 100644 --- a/libs/zlib/projects/visualc10/zlib.vcxproj +++ b/libs/zlib/projects/visualc10/zlib.vcxproj @@ -37,51 +37,51 @@ {73A5729C-7323-41D4-AB48-8A03C9F81603} zlib - 10.0.16299.0 + 10.0 StaticLibrary false - v140 + v143 StaticLibrary false - v141 + v143 true StaticLibrary false - v140 + v143 StaticLibrary false - v141 + v143 true StaticLibrary false - v140 + v143 true StaticLibrary false - v141 + v143 StaticLibrary false - v140 + v143 StaticLibrary false - v141 + v143 true @@ -144,7 +144,7 @@ Disabled WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) - true + false Default MultiThreadedDebugDLL $(ProjectDir)$(Platform)\$(Configuration)\ @@ -154,7 +154,7 @@ true EditAndContinue CompileAsC - false + true _DEBUG;%(PreprocessorDefinitions) diff --git a/srb2-vc9.sln b/srb2-vc9.sln deleted file mode 100644 index bbfcf0e77..000000000 --- a/srb2-vc9.sln +++ /dev/null @@ -1,89 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual C++ Express 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Srb2win", "src\win32\Srb2win-vc9.vcproj", "{0F554F1D-ED49-4D65-A9A7-F63C57F277BE}" - ProjectSection(ProjectDependencies) = postProject - {73A5729C-7323-41D4-AB48-8A03C9F81603} = {73A5729C-7323-41D4-AB48-8A03C9F81603} - {72B01ACA-7A1A-4F7B-ACEF-2607299CF052} = {72B01ACA-7A1A-4F7B-ACEF-2607299CF052} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "libs\libpng-src\projects\visualc9\libpng.vcproj", "{72B01ACA-7A1A-4F7B-ACEF-2607299CF052}" - ProjectSection(ProjectDependencies) = postProject - {73A5729C-7323-41D4-AB48-8A03C9F81603} = {73A5729C-7323-41D4-AB48-8A03C9F81603} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "r_opengl", "src\hardware\r_opengl\r_opengl-vc9.vcproj", "{51137D5C-4E81-4955-AACF-EA3092006051}" - ProjectSection(ProjectDependencies) = postProject - {0F554F1D-ED49-4D65-A9A7-F63C57F277BE} = {0F554F1D-ED49-4D65-A9A7-F63C57F277BE} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "libs\zlib\projects\visualc9\zlib.vcproj", "{73A5729C-7323-41D4-AB48-8A03C9F81603}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "s_openal", "src\hardware\s_openal\s_openal-vc9.vcproj", "{E662D0B3-412D-4D55-A5EC-8CBD680DDCBE}" - ProjectSection(ProjectDependencies) = postProject - {0F554F1D-ED49-4D65-A9A7-F63C57F277BE} = {0F554F1D-ED49-4D65-A9A7-F63C57F277BE} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Srb2SDL", "src\sdl\Srb2SDL-vc9.vcproj", "{61BA7D3C-F77D-4D31-B718-1177FE482CF2}" - ProjectSection(ProjectDependencies) = postProject - {73A5729C-7323-41D4-AB48-8A03C9F81603} = {73A5729C-7323-41D4-AB48-8A03C9F81603} - {72B01ACA-7A1A-4F7B-ACEF-2607299CF052} = {72B01ACA-7A1A-4F7B-ACEF-2607299CF052} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0F554F1D-ED49-4D65-A9A7-F63C57F277BE}.Debug|Win32.ActiveCfg = Debug|Win32 - {0F554F1D-ED49-4D65-A9A7-F63C57F277BE}.Debug|Win32.Build.0 = Debug|Win32 - {0F554F1D-ED49-4D65-A9A7-F63C57F277BE}.Debug|x64.ActiveCfg = Debug|x64 - {0F554F1D-ED49-4D65-A9A7-F63C57F277BE}.Debug|x64.Build.0 = Debug|x64 - {0F554F1D-ED49-4D65-A9A7-F63C57F277BE}.Release|Win32.ActiveCfg = Release|Win32 - {0F554F1D-ED49-4D65-A9A7-F63C57F277BE}.Release|Win32.Build.0 = Release|Win32 - {0F554F1D-ED49-4D65-A9A7-F63C57F277BE}.Release|x64.ActiveCfg = Release|x64 - {0F554F1D-ED49-4D65-A9A7-F63C57F277BE}.Release|x64.Build.0 = Release|x64 - {72B01ACA-7A1A-4F7B-ACEF-2607299CF052}.Debug|Win32.ActiveCfg = Debug|Win32 - {72B01ACA-7A1A-4F7B-ACEF-2607299CF052}.Debug|Win32.Build.0 = Debug|Win32 - {72B01ACA-7A1A-4F7B-ACEF-2607299CF052}.Debug|x64.ActiveCfg = Debug|x64 - {72B01ACA-7A1A-4F7B-ACEF-2607299CF052}.Debug|x64.Build.0 = Debug|x64 - {72B01ACA-7A1A-4F7B-ACEF-2607299CF052}.Release|Win32.ActiveCfg = Release|Win32 - {72B01ACA-7A1A-4F7B-ACEF-2607299CF052}.Release|Win32.Build.0 = Release|Win32 - {72B01ACA-7A1A-4F7B-ACEF-2607299CF052}.Release|x64.ActiveCfg = Release|x64 - {72B01ACA-7A1A-4F7B-ACEF-2607299CF052}.Release|x64.Build.0 = Release|x64 - {51137D5C-4E81-4955-AACF-EA3092006051}.Debug|Win32.ActiveCfg = Debug|Win32 - {51137D5C-4E81-4955-AACF-EA3092006051}.Debug|Win32.Build.0 = Debug|Win32 - {51137D5C-4E81-4955-AACF-EA3092006051}.Debug|x64.ActiveCfg = Debug|x64 - {51137D5C-4E81-4955-AACF-EA3092006051}.Debug|x64.Build.0 = Debug|x64 - {51137D5C-4E81-4955-AACF-EA3092006051}.Release|Win32.ActiveCfg = Release|Win32 - {51137D5C-4E81-4955-AACF-EA3092006051}.Release|Win32.Build.0 = Release|Win32 - {51137D5C-4E81-4955-AACF-EA3092006051}.Release|x64.ActiveCfg = Release|x64 - {51137D5C-4E81-4955-AACF-EA3092006051}.Release|x64.Build.0 = Release|x64 - {73A5729C-7323-41D4-AB48-8A03C9F81603}.Debug|Win32.ActiveCfg = Debug|Win32 - {73A5729C-7323-41D4-AB48-8A03C9F81603}.Debug|Win32.Build.0 = Debug|Win32 - {73A5729C-7323-41D4-AB48-8A03C9F81603}.Debug|x64.ActiveCfg = Debug|x64 - {73A5729C-7323-41D4-AB48-8A03C9F81603}.Debug|x64.Build.0 = Debug|x64 - {73A5729C-7323-41D4-AB48-8A03C9F81603}.Release|Win32.ActiveCfg = Release|Win32 - {73A5729C-7323-41D4-AB48-8A03C9F81603}.Release|Win32.Build.0 = Release|Win32 - {73A5729C-7323-41D4-AB48-8A03C9F81603}.Release|x64.ActiveCfg = Release|x64 - {73A5729C-7323-41D4-AB48-8A03C9F81603}.Release|x64.Build.0 = Release|x64 - {E662D0B3-412D-4D55-A5EC-8CBD680DDCBE}.Debug|Win32.ActiveCfg = Debug|Win32 - {E662D0B3-412D-4D55-A5EC-8CBD680DDCBE}.Debug|x64.ActiveCfg = Debug|x64 - {E662D0B3-412D-4D55-A5EC-8CBD680DDCBE}.Release|Win32.ActiveCfg = Release|Win32 - {E662D0B3-412D-4D55-A5EC-8CBD680DDCBE}.Release|x64.ActiveCfg = Release|x64 - {61BA7D3C-F77D-4D31-B718-1177FE482CF2}.Debug|Win32.ActiveCfg = Debug|Win32 - {61BA7D3C-F77D-4D31-B718-1177FE482CF2}.Debug|Win32.Build.0 = Debug|Win32 - {61BA7D3C-F77D-4D31-B718-1177FE482CF2}.Debug|x64.ActiveCfg = Debug|x64 - {61BA7D3C-F77D-4D31-B718-1177FE482CF2}.Debug|x64.Build.0 = Debug|x64 - {61BA7D3C-F77D-4D31-B718-1177FE482CF2}.Release|Win32.ActiveCfg = Release|Win32 - {61BA7D3C-F77D-4D31-B718-1177FE482CF2}.Release|Win32.Build.0 = Release|Win32 - {61BA7D3C-F77D-4D31-B718-1177FE482CF2}.Release|x64.ActiveCfg = Release|x64 - {61BA7D3C-F77D-4D31-B718-1177FE482CF2}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/src/blua/lua.h b/src/blua/lua.h index 4e26c2a79..50e520690 100644 --- a/src/blua/lua.h +++ b/src/blua/lua.h @@ -12,6 +12,10 @@ #include #include +#ifdef _MSC_VER +#include +#endif + #include "luaconf.h" diff --git a/src/blua/luaconf.h b/src/blua/luaconf.h index 9e2948f41..223a85703 100644 --- a/src/blua/luaconf.h +++ b/src/blua/luaconf.h @@ -11,9 +11,7 @@ #include #include -#ifdef _MSC_VER -#define INT32 __int32 -#else +#ifndef _MSC_VER #include #define INT32 int32_t #endif @@ -147,7 +145,7 @@ ** CHANGE that if ptrdiff_t is not adequate on your machine. (On most ** machines, ptrdiff_t gives a good choice between int or long.) */ -#define LUA_INTEGER INT32 +#define LUA_INTEGER int32_t /* @@ -509,13 +507,13 @@ */ //#define LUA_NUMBER_DOUBLE -#define LUA_NUMBER INT32 +#define LUA_NUMBER int32_t /* @@ LUAI_UACNUMBER is the result of an 'usual argument conversion' @* over a number. */ -#define LUAI_UACNUMBER INT32 +#define LUAI_UACNUMBER int32_t /* @@ -778,6 +776,4 @@ union luai_Cast { double l_d; long l_l; }; ** without modifying the main part of the file. */ - - #endif diff --git a/src/byteptr.h b/src/byteptr.h index 33c2c8a4b..3aa2aa508 100644 --- a/src/byteptr.h +++ b/src/byteptr.h @@ -150,7 +150,7 @@ FUNCINLINE static ATTRINLINE UINT32 readulong(void *ptr) #undef DEALIGNED -#define WRITESTRINGN(p, s, n) ({ \ +#define WRITESTRINGN(p, s, n) { \ size_t tmp_i; \ \ for (tmp_i = 0; tmp_i < n && s[tmp_i] != '\0'; tmp_i++) \ @@ -158,70 +158,70 @@ FUNCINLINE static ATTRINLINE UINT32 readulong(void *ptr) \ if (tmp_i < n) \ WRITECHAR(p, '\0'); \ -}) +} -#define WRITESTRINGL(p, s, n) ({ \ +#define WRITESTRINGL(p, s, n) { \ size_t tmp_i; \ \ for (tmp_i = 0; tmp_i < n - 1 && s[tmp_i] != '\0'; tmp_i++) \ WRITECHAR(p, s[tmp_i]); \ \ WRITECHAR(p, '\0'); \ -}) +} -#define WRITESTRING(p, s) ({ \ +#define WRITESTRING(p, s) { \ size_t tmp_i; \ \ for (tmp_i = 0; s[tmp_i] != '\0'; tmp_i++) \ WRITECHAR(p, s[tmp_i]); \ \ WRITECHAR(p, '\0'); \ -}) +} -#define WRITEMEM(p, s, n) ({ \ +#define WRITEMEM(p, s, n) { \ memcpy(p, s, n); \ p += n; \ -}) +} #define SKIPSTRING(p) while (READCHAR(p) != '\0') -#define SKIPSTRINGN(p, n) ({ \ +#define SKIPSTRINGN(p, n) { \ size_t tmp_i = 0; \ \ while (tmp_i < n && READCHAR(p) != '\0') \ tmp_i++; \ -}) +} #define SKIPSTRINGL(p, n) SKIPSTRINGN(p, n) -#define READSTRINGN(p, s, n) ({ \ +#define READSTRINGN(p, s, n) { \ size_t tmp_i = 0; \ \ while (tmp_i < n && (s[tmp_i] = READCHAR(p)) != '\0') \ tmp_i++; \ \ s[tmp_i] = '\0'; \ -}) +} -#define READSTRINGL(p, s, n) ({ \ +#define READSTRINGL(p, s, n) { \ size_t tmp_i = 0; \ \ while (tmp_i < n - 1 && (s[tmp_i] = READCHAR(p)) != '\0') \ tmp_i++; \ \ s[tmp_i] = '\0'; \ -}) +} -#define READSTRING(p, s) ({ \ +#define READSTRING(p, s) { \ size_t tmp_i = 0; \ \ while ((s[tmp_i] = READCHAR(p)) != '\0') \ tmp_i++; \ \ s[tmp_i] = '\0'; \ -}) +} -#define READMEM(p, s, n) ({ \ +#define READMEM(p, s, n) { \ memcpy(s, p, n); \ p += n; \ -}) +} diff --git a/src/command.c b/src/command.c index 9be081fb7..201cceeee 100644 --- a/src/command.c +++ b/src/command.c @@ -1724,9 +1724,13 @@ void CV_SaveVars(UINT8 **p, boolean in_demo) if ((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar)) { if (in_demo) + { WRITESTRING(*p, cvar->name); + } else + { WRITEUINT16(*p, cvar->netid); + } WRITESTRING(*p, cvar->string); WRITEUINT8(*p, false); ++count; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 5f02bc2de..07dba1777 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -50,6 +50,7 @@ #include "m_anigif.h" #include "md5.h" #include "m_perfstats.h" +#include "hardware/u_list.h" // TODO: this should be a standard utility class #ifdef NETGAME_DEVMODE #define CV_RESTRICT CV_NETVAR @@ -3312,6 +3313,69 @@ static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum) G_SetGameModified(true); } +// C++ would make this SO much simpler! +typedef struct addedfile_s +{ + struct addedfile_s *next; + struct addedfile_s *prev; + char *value; +} addedfile_t; + +static boolean AddedFileContains(addedfile_t *list, const char *value) +{ + addedfile_t *node; + for (node = list; node; node = node->next) + { + if (!strcmp(value, node->value)) + return true; + } + + return false; +} + +static void AddedFilesAdd(addedfile_t **list, const char *value) +{ + addedfile_t *item = Z_Calloc(sizeof(addedfile_t), PU_STATIC, NULL); + item->value = Z_StrDup(value); + ListAdd(item, (listitem_t**)list); +} + +static void AddedFilesRemove(void *pItem, addedfile_t **itemHead) +{ + addedfile_t *item = (addedfile_t *)pItem; + + if (item == *itemHead) // Start of list + { + *itemHead = item->next; + + if (*itemHead) + (*itemHead)->prev = NULL; + } + else if (item->next == NULL) // end of list + { + item->prev->next = NULL; + } + else // Somewhere in between + { + item->prev->next = item->next; + item->next->prev = item->prev; + } + + Z_Free(item->value); + Z_Free(item); +} + +static void AddedFilesClearList(addedfile_t **itemHead) +{ + addedfile_t *item; + addedfile_t *next; + for (item = *itemHead; item; item = next) + { + next = item->next; + AddedFilesRemove(item, itemHead); + } +} + /** Adds a pwad at runtime. * Searches for sounds, maps, music, new images. */ @@ -3320,8 +3384,7 @@ static void Command_Addfile(void) size_t argc = COM_Argc(); // amount of arguments total size_t curarg; // current argument index - const char *addedfiles[argc]; // list of filenames already processed - size_t numfilesadded = 0; // the amount of filenames processed + addedfile_t *addedfiles = NULL; // list of filenames already processed if (argc < 2) { @@ -3336,25 +3399,14 @@ static void Command_Addfile(void) char buf[256]; char *buf_p = buf; INT32 i; - size_t ii; int musiconly; // W_VerifyNMUSlumps isn't boolean boolean fileadded = false; fn = COM_Argv(curarg); // For the amount of filenames previously processed... - for (ii = 0; ii < numfilesadded; ii++) - { - // If this is one of them, don't try to add it. - if (!strcmp(fn, addedfiles[ii])) - { - fileadded = true; - break; - } - } - - // If we've added this one, skip to the next one. - if (fileadded) + fileadded = AddedFileContains(addedfiles, fn); + if (fileadded) // If this is one of them, don't try to add it. { CONS_Alert(CONS_WARNING, M_GetText("Already processed %s, skipping\n"), fn); continue; @@ -3363,13 +3415,16 @@ static void Command_Addfile(void) // Disallow non-printing characters and semicolons. for (i = 0; fn[i] != '\0'; i++) if (!isprint(fn[i]) || fn[i] == ';') + { + AddedFilesClearList(&addedfiles); return; + } musiconly = W_VerifyNMUSlumps(fn, false); if (musiconly == -1) { - addedfiles[numfilesadded++] = fn; + AddedFilesAdd(&addedfiles, fn); continue; } @@ -3388,7 +3443,7 @@ static void Command_Addfile(void) if (!(netgame || multiplayer) || musiconly) { P_AddWadFile(fn); - addedfiles[numfilesadded++] = fn; + AddedFilesAdd(&addedfiles, fn); continue; } @@ -3403,6 +3458,7 @@ static void Command_Addfile(void) if (numwadfiles >= MAX_WADFILES) { CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); + AddedFilesClearList(&addedfiles); return; } @@ -3442,13 +3498,15 @@ static void Command_Addfile(void) WRITEMEM(buf_p, md5sum, 16); } - addedfiles[numfilesadded++] = fn; + AddedFilesAdd(&addedfiles, fn); if (IsPlayerAdmin(consoleplayer) && (!server)) // Request to add file SendNetXCmd(XD_REQADDFILE, buf, buf_p - buf); else SendNetXCmd(XD_ADDFILE, buf, buf_p - buf); } + + AddedFilesClearList(&addedfiles); } static void Command_Addfolder(void) @@ -3456,8 +3514,7 @@ static void Command_Addfolder(void) size_t argc = COM_Argc(); // amount of arguments total size_t curarg; // current argument index - const char *addedfolders[argc]; // list of filenames already processed - size_t numfoldersadded = 0; // the amount of filenames processed + addedfile_t *addedfolders = NULL; // list of filenames already processed if (argc < 2) { @@ -3473,24 +3530,13 @@ static void Command_Addfolder(void) char buf[256]; char *buf_p = buf; INT32 i, stat; - size_t ii; boolean folderadded = false; fn = COM_Argv(curarg); // For the amount of filenames previously processed... - for (ii = 0; ii < numfoldersadded; ii++) - { - // If this is one of them, don't try to add it. - if (!strcmp(fn, addedfolders[ii])) - { - folderadded = true; - break; - } - } - - // If we've added this one, skip to the next one. - if (folderadded) + folderadded = AddedFileContains(addedfolders, fn); + if (folderadded) // If we've added this one, skip to the next one. { CONS_Alert(CONS_WARNING, M_GetText("Already processed %s, skipping\n"), fn); continue; @@ -3499,13 +3545,16 @@ static void Command_Addfolder(void) // Disallow non-printing characters and semicolons. for (i = 0; fn[i] != '\0'; i++) if (!isprint(fn[i]) || fn[i] == ';') + { + AddedFilesClearList(&addedfolders); return; + } // Add file on your client directly if you aren't in a netgame. if (!(netgame || multiplayer)) { P_AddFolder(fn); - addedfolders[numfoldersadded++] = fn; + AddedFilesAdd(&addedfolders, fn); continue; } @@ -3527,6 +3576,7 @@ static void Command_Addfolder(void) if (numwadfiles >= MAX_WADFILES) { CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); + AddedFilesClearList(&addedfolders); return; } @@ -3572,7 +3622,7 @@ static void Command_Addfolder(void) Z_Free(fullpath); - addedfolders[numfoldersadded++] = fn; + AddedFilesAdd(&addedfolders, fn); WRITESTRINGN(buf_p,p,240); diff --git a/src/deh_soc.c b/src/deh_soc.c index b3c3c4e0c..cbc7940f7 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -693,7 +693,8 @@ void readskincolor(MYFILE *f, INT32 num) if (fastcmp(word, "NAME")) { size_t namesize = sizeof(skincolors[num].name); - char truncword[namesize]; + char *truncword = malloc(namesize); // Follow C standard - SSNTails + UINT16 dupecheck; deh_strlcpy(truncword, word2, namesize, va("Skincolor %d: name", num)); // truncate here to check for dupes @@ -701,7 +702,7 @@ void readskincolor(MYFILE *f, INT32 num) if (truncword[0] != '\0' && (!stricmp(truncword, skincolors[SKINCOLOR_NONE].name) || (dupecheck && dupecheck != num))) { size_t lastchar = strlen(truncword); - char oldword[lastchar+1]; + char *oldword = malloc(lastchar + 1); // Follow C standard - SSNTails char dupenum = '1'; strlcpy(oldword, truncword, lastchar+1); @@ -726,9 +727,12 @@ void readskincolor(MYFILE *f, INT32 num) } deh_warning("Skincolor %d: name %s is a duplicate of another skincolor's name - renamed to %s", num, oldword, truncword); + free(oldword); } strlcpy(skincolors[num].name, truncword, namesize); // already truncated + + free(truncword); } else if (fastcmp(word, "RAMP")) { diff --git a/src/doomtype.h b/src/doomtype.h index b8f602c64..456f56380 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -31,18 +31,8 @@ #include #endif -#define UINT8 unsigned __int8 #define SINT8 signed __int8 -#define UINT16 unsigned __int16 -#define INT16 __int16 - -#define INT32 __int32 -#define UINT32 unsigned __int32 - -#define INT64 __int64 -#define UINT64 unsigned __int64 - typedef long ssize_t; /* Older Visual C++ headers don't have the Win64-compatible typedefs... */ diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 3cb7275a0..3a6baab71 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5232,7 +5232,7 @@ static void HWR_ProjectSprite(mobj_t *thing) if (caster && !P_MobjWasRemoved(caster)) { - interpmobjstate_t casterinterp = {}; + interpmobjstate_t casterinterp = { 0 }; fixed_t groundz; fixed_t floordiff; @@ -5340,7 +5340,7 @@ static void HWR_ProjectSprite(mobj_t *thing) if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) { - interpmobjstate_t tracer_interp = {}; + interpmobjstate_t tracer_interp = { 0 }; if (! R_ThingVisible(thing->tracer)) return; diff --git a/src/hardware/r_opengl/r_opengl-vc10.vcxproj b/src/hardware/r_opengl/r_opengl-vc10.vcxproj index d1f856e96..c93e47d50 100644 --- a/src/hardware/r_opengl/r_opengl-vc10.vcxproj +++ b/src/hardware/r_opengl/r_opengl-vc10.vcxproj @@ -38,51 +38,51 @@ r_opengl {51137D5C-4E81-4955-AACF-EA3092006051} r_opengl - 10.0.16299.0 + 10.0 DynamicLibrary false - v140 + v143 DynamicLibrary false - v141 + v143 true DynamicLibrary false - v140 + v143 DynamicLibrary false - v141 + v143 true DynamicLibrary false - v140 + v143 DynamicLibrary false - v141 + v143 true DynamicLibrary false - v140 + v143 DynamicLibrary false - v141 + v143 true diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 9d1630abb..0b51fa05c 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -1130,7 +1130,7 @@ static void GLPerspective(GLfloat fovy, GLfloat aspect) const GLfloat zNear = NEAR_CLIPPING_PLANE; const GLfloat zFar = FAR_CLIPPING_PLANE; const GLfloat radians = (GLfloat)(fovy / 2.0f * M_PIl / 180.0f); - const GLfloat sine = sin(radians); + const GLfloat sine = (GLfloat)sin(radians); const GLfloat deltaZ = zFar - zNear; GLfloat cotangent; @@ -2042,9 +2042,9 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF if (Surface != NULL) { - UNIFORM_1(shader->uniforms[gluniform_lighting], Surface->LightInfo.light_level, pglUniform1f); - UNIFORM_1(shader->uniforms[gluniform_fade_start], Surface->LightInfo.fade_start, pglUniform1f); - UNIFORM_1(shader->uniforms[gluniform_fade_end], Surface->LightInfo.fade_end, pglUniform1f); + UNIFORM_1(shader->uniforms[gluniform_lighting], (GLfloat)Surface->LightInfo.light_level, pglUniform1f); + UNIFORM_1(shader->uniforms[gluniform_fade_start], (GLfloat)Surface->LightInfo.fade_start, pglUniform1f); + UNIFORM_1(shader->uniforms[gluniform_fade_end], (GLfloat)Surface->LightInfo.fade_end, pglUniform1f); } UNIFORM_1(shader->uniforms[gluniform_leveltime], shader_leveltime, pglUniform1f); @@ -3038,7 +3038,7 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) if (special_splitscreen) { - used_fov = atan(tan(used_fov*M_PI/360)*0.8)*360/M_PI; + used_fov = (float)(atan(tan(used_fov*M_PI/360)*0.8)*360/M_PI); GLPerspective(used_fov, 2*ASPECT_RATIO); } else diff --git a/src/hardware/s_openal/s_openal-vc10.vcxproj b/src/hardware/s_openal/s_openal-vc10.vcxproj index 5039cd006..1480cd3d0 100644 --- a/src/hardware/s_openal/s_openal-vc10.vcxproj +++ b/src/hardware/s_openal/s_openal-vc10.vcxproj @@ -38,52 +38,52 @@ s_openal {E662D0B3-412D-4D55-A5EC-8CBD680DDCBE} s_openal - 10.0.16299.0 + 10.0 DynamicLibrary false MultiByte - v140 + v143 DynamicLibrary false MultiByte - v141 + v143 DynamicLibrary false - v140 + v143 DynamicLibrary false - v141 + v143 DynamicLibrary false MultiByte - v140 + v143 DynamicLibrary false MultiByte - v141 + v143 DynamicLibrary false - v140 + v143 DynamicLibrary false - v141 + v143 diff --git a/src/p_mobj.c b/src/p_mobj.c index e1657c12f..38d6e7a7e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13508,7 +13508,7 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 numi static void P_SpawnSingularItemRow(mapthing_t *mthing, mobjtype_t itemtype, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle, boolean bonustime) { mobjtype_t itemtypes[1] = { itemtype }; - return P_SpawnItemRow(mthing, itemtypes, 1, numitems, horizontalspacing, verticalspacing, fixedangle, bonustime); + P_SpawnItemRow(mthing, itemtypes, 1, numitems, horizontalspacing, verticalspacing, fixedangle, bonustime); } static void P_SpawnItemCircle(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 numitemtypes, INT32 numitems, fixed_t size, boolean bonustime) diff --git a/src/r_main.c b/src/r_main.c index 3763092fc..187925408 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -620,7 +620,7 @@ static struct { 0, 0, - {}, {}, + {0}, {0}, false }; diff --git a/src/r_picformats.c b/src/r_picformats.c index 6aa4659b9..5a7aebcf7 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -447,7 +447,7 @@ void *Picture_FlatConvert( for (y = 0; y < inheight; y++) for (x = 0; x < inwidth; x++) { - void *input; + void *input = NULL; size_t offs = ((y * inwidth) + x); // Read pixel diff --git a/src/r_things.c b/src/r_things.c index fed873fd6..461761977 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1785,7 +1785,11 @@ static void R_ProjectSprite(mobj_t *thing) range++; // fencepost problem - scalestep = ((yscale2 - yscale)/range) ?: 1; + // Compatibility with MSVC - SSNTails + scalestep = ((yscale2 - yscale) / range); + if (!scalestep) + scalestep = 1; + xscale = FixedDiv(range<target; - interpmobjstate_t casterinterp = {}; + interpmobjstate_t casterinterp = { 0 }; // MSVC compatibility - SSNTails if (R_UsingFrameInterpolation() && !paused) { diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index d79dde766..c20265ed1 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -39,46 +39,46 @@ {61BA7D3C-F77D-4D31-B718-1177FE482CF2} Win32Proj Srb2SDL - 10.0.16299.0 + 10.0 Srb2Win - v140 + v143 true - v141 + v143 true true - v140 + v143 false true - v141 + v143 false true true - v140 + v143 true - v141 + v143 true true - v140 + v143 false true - v141 + v143 false true true @@ -134,6 +134,9 @@ <_ProjectFileVersion>10.0.30319.1 false + + $(ProjectName)_Debug + ProgramDatabase @@ -154,6 +157,26 @@ setupapi.lib;winmm.lib;imm32.lib;version.lib;ole32.lib;advapi32.lib;shell32.lib;gdi32.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies) + + + Default + false + 4244;4267;4146 + true + false + stdcpp17 + + + + + stdcpp17 + + + + + 4244;4267;4146;4003 + + {72b01aca-7a1a-4f7b-acef-2607299cf052} @@ -246,11 +269,13 @@ + + @@ -264,6 +289,7 @@ + @@ -272,6 +298,7 @@ + @@ -286,6 +313,7 @@ + @@ -403,11 +431,13 @@ true + + @@ -429,6 +459,7 @@ + @@ -438,6 +469,7 @@ + @@ -464,6 +496,7 @@ true + @@ -478,7 +511,6 @@ - @@ -507,7 +539,7 @@ true - + @@ -524,4 +556,4 @@ - + \ No newline at end of file diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index 4d2532ca4..eb37ce9da 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -144,7 +144,6 @@ D_Doom - D_Doom @@ -511,6 +510,21 @@ R_Rend + + LUA + + + I_Interface + + + R_Rend + + + P_Play + + + M_Misc + @@ -625,7 +639,6 @@ D_Doom - D_Doom @@ -821,9 +834,6 @@ M_Misc - - M_Misc - O_Other @@ -965,9 +975,6 @@ SDLApp - - SDLApp - SDLApp @@ -1023,10 +1030,28 @@ R_Rend + + LUA + + + SDLApp + + + I_Interface + + + R_Rend + + + P_Play + + + M_Misc + SDLApp - + \ No newline at end of file diff --git a/src/sdl/Srb2SDL-vc9.vcproj b/src/sdl/Srb2SDL-vc9.vcproj deleted file mode 100644 index 95f035267..000000000 --- a/src/sdl/Srb2SDL-vc9.vcproj +++ /dev/null @@ -1,6021 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/sdl/Srb2SDL.dsp b/src/sdl/Srb2SDL.dsp deleted file mode 100644 index 9f6dd7b33..000000000 --- a/src/sdl/Srb2SDL.dsp +++ /dev/null @@ -1,1049 +0,0 @@ -# Microsoft Developer Studio Project File - Name="Srb2SDL" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=Srb2SDL - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "Srb2SDL.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "Srb2SDL.mak" CFG="Srb2SDL - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "Srb2SDL - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "Srb2SDL - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "Srb2SDL - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\..\bin\VC\Release\SDL" -# PROP Intermediate_Dir "..\..\objs\VC\Release\SDL" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -MTL=midl.exe -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /G5 /W3 /GX /Zi /Ot /Og /Oi /Op /Oy /Ob1 /I "..\..\libs\libpng-src" /I "..\..\libs\zlib" /D "NDEBUG" /D "SDLMAIN" /D "NO_STDIO_REDIRECT" /D "USE_WGL_SWAP" /D "DIRECTFULLSCREEN" /D "HAVE_SDL" /D "HWRENDER" /D "HW3SOUND" /D "HAVE_FILTER" /D "HAVE_MIXER" /D "USEASM" /D "HAVE_PNG" /FR /FD /GF /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -# SUBTRACT RSC /x -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo /o"..\..\objs\SDL\Release\SRB2.bsc" -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 SDL.lib SDL_mixer.lib user32.lib advapi32.lib ws2_32.lib /nologo /subsystem:windows /pdb:"C:\srb2demo2\srb2sdl.pdb" /debug /machine:I386 /out:"C:\srb2demo2\srb2sdl.exe" -# SUBTRACT LINK32 /profile /pdb:none /incremental:yes - -!ELSEIF "$(CFG)" == "Srb2SDL - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "..\..\bin\VC\Debug\SDL" -# PROP Intermediate_Dir "..\..\objs\VC\Debug\SDL" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -MTL=midl.exe -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /G6 /W4 /WX /Gm /GX /ZI /Od /Op /I "..\..\libs\libpng-src" /I "..\..\libs\zlib" /D "_DEBUG" /D "USE_WGL_SWAP" /D "DIRECTFULLSCREEN" /D "HAVE_SDL" /D "HWRENDER" /D "HW3SOUND" /D "HAVE_FILTER" /D "HAVE_MIXER" /D "USEASM" /D "HAVE_PNG" /FR /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -# SUBTRACT RSC /x -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo /o"..\..\objs\SDL\Debug\SRB2.bsc" -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 SDL.lib SDL_mixer.lib user32.lib advapi32.lib ws2_32.lib /nologo /subsystem:console /pdb:"C:\srb2demo2\srb2sdldebug.pdb" /debug /machine:I386 /out:"C:\srb2demo2\srb2sdldebug.exe" /pdbtype:sept -# SUBTRACT LINK32 /pdb:none - -!ENDIF - -# Begin Target - -# Name "Srb2SDL - Win32 Release" -# Name "Srb2SDL - Win32 Debug" -# Begin Group "SDLapp" - -# PROP Default_Filter "" -# Begin Group "filter" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\filter\filters.c -# End Source File -# Begin Source File - -SOURCE=.\filter\filters.h -# End Source File -# Begin Source File - -SOURCE=.\filter\hq2x.c -# End Source File -# Begin Source File - -SOURCE=.\filter\hq2x.h -# End Source File -# Begin Source File - -SOURCE=.\filter\interp.h -# End Source File -# Begin Source File - -SOURCE=.\filter\lq2x.c -# End Source File -# Begin Source File - -SOURCE=.\filter\lq2x.h -# End Source File -# End Group -# Begin Source File - -SOURCE=.\dosstr.c -# End Source File -# Begin Source File - -SOURCE=.\endtxt.c -# End Source File -# Begin Source File - -SOURCE=.\endtxt.h -# End Source File -# Begin Source File - -SOURCE=..\filesrch.c -# End Source File -# Begin Source File - -SOURCE=..\filesrch.h -# End Source File -# Begin Source File - -SOURCE=.\hwsym_sdl.c -# End Source File -# Begin Source File - -SOURCE=.\hwsym_sdl.h -# End Source File -# Begin Source File - -SOURCE=.\i_cdmus.c -# End Source File -# Begin Source File - -SOURCE=.\i_main.c -# End Source File -# Begin Source File - -SOURCE=.\i_net.c -# End Source File -# Begin Source File - -SOURCE=.\i_sound.c -# End Source File -# Begin Source File - -SOURCE=.\i_system.c -# End Source File -# Begin Source File - -SOURCE=.\i_video.c -# End Source File -# Begin Source File - -SOURCE=.\IMG_xpm.c -# PROP Exclude_From_Build 1 -# End Source File -# Begin Source File - -SOURCE=.\ogl_sdl.c -# End Source File -# Begin Source File - -SOURCE=.\ogl_sdl.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\r_opengl\r_opengl.c -# End Source File -# Begin Source File - -SOURCE=..\hardware\r_opengl\r_opengl.h -# End Source File -# Begin Source File - -SOURCE=.\SDL_icon.xpm -# End Source File -# Begin Source File - -SOURCE=.\SDL_main\SDL_win32_main.c - -!IF "$(CFG)" == "Srb2SDL - Win32 Release" - -!ELSEIF "$(CFG)" == "Srb2SDL - Win32 Debug" - -# PROP Exclude_From_Build 1 - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\sdlmain.h -# End Source File -# Begin Source File - -SOURCE=..\win32\Srb2win.rc -# End Source File -# Begin Source File - -SOURCE=..\win32\win_dbg.c -# End Source File -# Begin Source File - -SOURCE=..\win32\win_dbg.h -# End Source File -# Begin Source File - -SOURCE=..\win32\win_main.h -# End Source File -# End Group -# Begin Group "A_Asm" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\p5prof.h -# End Source File -# Begin Source File - -SOURCE=..\tmap.nas - -!IF "$(CFG)" == "Srb2SDL - Win32 Release" - -# PROP Ignore_Default_Tool 1 -# Begin Custom Build - Compiling $(InputName).nas with NASM... -IntDir=.\..\..\objs\VC\Release\SDL -InputPath=..\tmap.nas -InputName=tmap - -"$(IntDir)/$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - nasm -g -o $(IntDir)/$(InputName).obj -f win32 $(InputPath) - -# End Custom Build - -!ELSEIF "$(CFG)" == "Srb2SDL - Win32 Debug" - -# PROP Ignore_Default_Tool 1 -# Begin Custom Build - Compiling $(InputName).nas with NASM... -IntDir=.\..\..\objs\VC\Debug\SDL -InputPath=..\tmap.nas -InputName=tmap - -"$(IntDir)/$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - nasm -g -o $(IntDir)/$(InputName).obj -f win32 $(InputPath) - -# End Custom Build - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\tmap_mmx.nas - -!IF "$(CFG)" == "Srb2SDL - Win32 Release" - -# PROP Ignore_Default_Tool 1 -# Begin Custom Build - Compiling $(InputName).nas with NASM... -IntDir=.\..\..\objs\VC\Release\SDL -InputPath=..\tmap_mmx.nas -InputName=tmap_mmx - -"$(IntDir)/$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - nasm -g -o $(IntDir)/$(InputName).obj -f win32 $(InputPath) - -# End Custom Build - -!ELSEIF "$(CFG)" == "Srb2SDL - Win32 Debug" - -# PROP Ignore_Default_Tool 1 -# Begin Custom Build - Compiling $(InputName).nas with NASM... - -IntDir=.\..\..\objs\VC\Debug\SDL -InputPath=..\tmap_mmx.nas -InputName=tmap_mmx - -"$(IntDir)/$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - nasm -g -o $(IntDir)/$(InputName).obj -f win32 $(InputPath) - -# End Custom Build - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\tmap_vc.nas - -!IF "$(CFG)" == "Srb2SDL - Win32 Release" - -# Begin Custom Build - Compiling $(InputName).nas with NASM... -IntDir=.\..\..\objs\VC\Release\SDL -InputPath=..\tmap_vc.nas -InputName=tmap_vc - -"$(IntDir)/$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - nasm -g -o $(IntDir)/$(InputName).obj -f win32 $(InputPath) - -# End Custom Build - -!ELSEIF "$(CFG)" == "Srb2SDL - Win32 Debug" - -# Begin Custom Build - Compiling $(InputName).nas with NASM... -IntDir=.\..\..\objs\VC\Debug\SDL -InputPath=..\tmap_vc.nas -InputName=tmap_vc - -"$(IntDir)/$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - nasm -g -o $(IntDir)/$(InputName).obj -f win32 $(InputPath) - -# End Custom Build - -!ENDIF - -# End Source File -# End Group -# Begin Group "D_Doom" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\comptime.c -# End Source File -# Begin Source File - -SOURCE=..\d_clisrv.c -# End Source File -# Begin Source File - -SOURCE=..\d_clisrv.h -# End Source File -# Begin Source File - -SOURCE=..\d_event.h -# End Source File -# Begin Source File - -SOURCE=..\d_main.c -# End Source File -# Begin Source File - -SOURCE=..\d_main.h -# End Source File -# Begin Source File - -SOURCE=..\d_net.c -# End Source File -# Begin Source File - -SOURCE=..\d_net.h -# End Source File -# Begin Source File - -SOURCE=..\d_netcmd.c -# End Source File -# Begin Source File - -SOURCE=..\d_netcmd.h -# End Source File -# Begin Source File - -SOURCE=..\d_netfil.c -# End Source File -# Begin Source File - -SOURCE=..\d_netfil.h -# End Source File -# Begin Source File - -SOURCE=..\d_player.h -# End Source File -# Begin Source File - -SOURCE=..\d_think.h -# End Source File -# Begin Source File - -SOURCE=..\d_ticcmd.h -# End Source File -# Begin Source File - -SOURCE=..\dehacked.c -# End Source File -# Begin Source File - -SOURCE=..\dehacked.h -# End Source File -# Begin Source File - -SOURCE=..\doomdata.h -# End Source File -# Begin Source File - -SOURCE=..\doomdef.h -# End Source File -# Begin Source File - -SOURCE=..\doomstat.h -# End Source File -# Begin Source File - -SOURCE=..\doomtype.h -# End Source File -# Begin Source File - -SOURCE=..\z_zone.c -# End Source File -# Begin Source File - -SOURCE=..\z_zone.h -# End Source File -# End Group -# Begin Group "F_Frame" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\f_finale.c -# End Source File -# Begin Source File - -SOURCE=..\f_finale.h -# End Source File -# Begin Source File - -SOURCE=..\f_wipe.c -# End Source File -# End Group -# Begin Group "G_Game" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\g_game.c -# End Source File -# Begin Source File - -SOURCE=..\g_game.h -# End Source File -# Begin Source File - -SOURCE=..\g_input.c -# End Source File -# Begin Source File - -SOURCE=..\g_input.h -# End Source File -# Begin Source File - -SOURCE=..\g_state.h -# End Source File -# End Group -# Begin Group "H_Hud" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\am_map.c -# End Source File -# Begin Source File - -SOURCE=..\am_map.h -# End Source File -# Begin Source File - -SOURCE=..\command.c -# End Source File -# Begin Source File - -SOURCE=..\command.h -# End Source File -# Begin Source File - -SOURCE=..\console.c -# End Source File -# Begin Source File - -SOURCE=..\console.h -# End Source File -# Begin Source File - -SOURCE=..\hu_stuff.c -# End Source File -# Begin Source File - -SOURCE=..\hu_stuff.h -# End Source File -# Begin Source File - -SOURCE=..\st_stuff.c -# End Source File -# Begin Source File - -SOURCE=..\st_stuff.h -# End Source File -# Begin Source File - -SOURCE=..\y_inter.c -# End Source File -# Begin Source File - -SOURCE=..\y_inter.h -# End Source File -# End Group -# Begin Group "Hw_Hardware" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\hardware\hw3dsdrv.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw3sound.c -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw3sound.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_bsp.c -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_cache.c -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_data.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_defs.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_dll.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_draw.c -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_drv.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_glob.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_light.c -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_light.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_main.c -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_main.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_md2.c -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_md2.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hws_data.h -# End Source File -# End Group -# Begin Group "I_Interface" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\byteptr.h -# End Source File -# Begin Source File - -SOURCE=..\i_joy.h -# End Source File -# Begin Source File - -SOURCE=..\i_net.h -# End Source File -# Begin Source File - -SOURCE=..\i_sound.h -# End Source File -# Begin Source File - -SOURCE=..\i_system.h -# End Source File -# Begin Source File - -SOURCE=..\i_tcp.c -# End Source File -# Begin Source File - -SOURCE=..\i_tcp.h -# End Source File -# Begin Source File - -SOURCE=..\i_video.h -# End Source File -# Begin Source File - -SOURCE=..\keys.h -# End Source File -# Begin Source File - -SOURCE=..\mserv.c -# End Source File -# Begin Source File - -SOURCE=..\mserv.h -# End Source File -# End Group -# Begin Group "M_Misc" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\m_argv.c -# End Source File -# Begin Source File - -SOURCE=..\m_argv.h -# End Source File -# Begin Source File - -SOURCE=..\m_bbox.c -# End Source File -# Begin Source File - -SOURCE=..\m_bbox.h -# End Source File -# Begin Source File - -SOURCE=..\m_cheat.c -# End Source File -# Begin Source File - -SOURCE=..\m_cheat.h -# End Source File -# Begin Source File - -SOURCE=..\m_dllist.h -# End Source File -# Begin Source File - -SOURCE=..\m_fixed.c -# End Source File -# Begin Source File - -SOURCE=..\m_fixed.h -# End Source File -# Begin Source File - -SOURCE=..\m_menu.c -# End Source File -# Begin Source File - -SOURCE=..\m_menu.h -# End Source File -# Begin Source File - -SOURCE=..\m_misc.c -# End Source File -# Begin Source File - -SOURCE=..\m_misc.h -# End Source File -# Begin Source File - -SOURCE=..\m_queue.c -# End Source File -# Begin Source File - -SOURCE=..\m_queue.h -# End Source File -# Begin Source File - -SOURCE=..\m_random.c -# End Source File -# Begin Source File - -SOURCE=..\m_random.h -# End Source File -# Begin Source File - -SOURCE=..\m_swap.h -# End Source File -# Begin Source File - -SOURCE=..\string.c -# End Source File -# End Group -# Begin Group "P_Play" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\info.c -# End Source File -# Begin Source File - -SOURCE=..\info.h -# End Source File -# Begin Source File - -SOURCE=..\p_ceilng.c -# End Source File -# Begin Source File - -SOURCE=..\p_enemy.c -# End Source File -# Begin Source File - -SOURCE=..\p_fab.c -# End Source File -# Begin Source File - -SOURCE=..\p_floor.c -# End Source File -# Begin Source File - -SOURCE=..\p_inter.c -# End Source File -# Begin Source File - -SOURCE=..\p_lights.c -# End Source File -# Begin Source File - -SOURCE=..\p_local.h -# End Source File -# Begin Source File - -SOURCE=..\p_map.c -# End Source File -# Begin Source File - -SOURCE=..\p_maputl.c -# End Source File -# Begin Source File - -SOURCE=..\p_maputl.h -# End Source File -# Begin Source File - -SOURCE=..\p_mobj.c -# End Source File -# Begin Source File - -SOURCE=..\p_mobj.h -# End Source File -# Begin Source File - -SOURCE=..\p_polyobj.c -# End Source File -# Begin Source File - -SOURCE=..\p_polyobj.h -# End Source File -# Begin Source File - -SOURCE=..\p_pspr.h -# End Source File -# Begin Source File - -SOURCE=..\p_saveg.c -# End Source File -# Begin Source File - -SOURCE=..\p_saveg.h -# End Source File -# Begin Source File - -SOURCE=..\p_setup.c -# End Source File -# Begin Source File - -SOURCE=..\p_setup.h -# End Source File -# Begin Source File - -SOURCE=..\p_sight.c -# End Source File -# Begin Source File - -SOURCE=..\p_spec.c -# End Source File -# Begin Source File - -SOURCE=..\p_spec.h -# End Source File -# Begin Source File - -SOURCE=..\p_telept.c -# End Source File -# Begin Source File - -SOURCE=..\p_tick.c -# End Source File -# Begin Source File - -SOURCE=..\p_tick.h -# End Source File -# Begin Source File - -SOURCE=..\p_user.c -# End Source File -# Begin Source File - -SOURCE=..\tables.c -# End Source File -# Begin Source File - -SOURCE=..\tables.h -# End Source File -# End Group -# Begin Group "R_Rend" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\r_bsp.c -# End Source File -# Begin Source File - -SOURCE=..\r_bsp.h -# End Source File -# Begin Source File - -SOURCE=..\r_data.c -# End Source File -# Begin Source File - -SOURCE=..\r_data.h -# End Source File -# Begin Source File - -SOURCE=..\r_defs.h -# End Source File -# Begin Source File - -SOURCE=..\r_draw.c -# End Source File -# Begin Source File - -SOURCE=..\r_draw.h -# End Source File -# Begin Source File - -SOURCE=..\r_draw16.c -# PROP Exclude_From_Build 1 -# End Source File -# Begin Source File - -SOURCE=..\r_draw8.c -# PROP Exclude_From_Build 1 -# End Source File -# Begin Source File - -SOURCE=..\r_local.h -# End Source File -# Begin Source File - -SOURCE=..\r_main.c -# End Source File -# Begin Source File - -SOURCE=..\r_main.h -# End Source File -# Begin Source File - -SOURCE=..\r_plane.c -# End Source File -# Begin Source File - -SOURCE=..\r_plane.h -# End Source File -# Begin Source File - -SOURCE=..\r_segs.c -# End Source File -# Begin Source File - -SOURCE=..\r_segs.h -# End Source File -# Begin Source File - -SOURCE=..\r_sky.c -# End Source File -# Begin Source File - -SOURCE=..\r_sky.h -# End Source File -# Begin Source File - -SOURCE=..\r_splats.c -# End Source File -# Begin Source File - -SOURCE=..\r_splats.h -# End Source File -# Begin Source File - -SOURCE=..\r_state.h -# End Source File -# Begin Source File - -SOURCE=..\r_things.c -# End Source File -# Begin Source File - -SOURCE=..\r_things.h -# End Source File -# Begin Source File - -SOURCE=..\screen.c -# End Source File -# Begin Source File - -SOURCE=..\screen.h -# End Source File -# Begin Source File - -SOURCE=..\v_video.c -# End Source File -# Begin Source File - -SOURCE=..\v_video.h -# End Source File -# End Group -# Begin Group "S_Sounds" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\s_sound.c -# End Source File -# Begin Source File - -SOURCE=..\s_sound.h -# End Source File -# Begin Source File - -SOURCE=..\sounds.c -# End Source File -# Begin Source File - -SOURCE=..\sounds.h -# End Source File -# End Group -# Begin Group "W_Wad" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\lzf.c -# End Source File -# Begin Source File - -SOURCE=..\lzf.h -# End Source File -# Begin Source File - -SOURCE=..\md5.c -# End Source File -# Begin Source File - -SOURCE=..\md5.h -# End Source File -# Begin Source File - -SOURCE=..\w_wad.c -# End Source File -# Begin Source File - -SOURCE=..\w_wad.h -# End Source File -# End Group -# Begin Group "Docs" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\doc\copying -# End Source File -# Begin Source File - -SOURCE=..\..\doc\faq.txt -# End Source File -# Begin Source File - -SOURCE=..\..\readme.txt -# End Source File -# Begin Source File - -SOURCE=..\..\doc\source.txt -# End Source File -# End Group -# Begin Source File - -SOURCE=..\win32\Srb2win.ico -# End Source File -# End Target -# End Project diff --git a/src/sdl/Srb2SDL.dsw b/src/sdl/Srb2SDL.dsw deleted file mode 100644 index 4f8f7bdce..000000000 --- a/src/sdl/Srb2SDL.dsw +++ /dev/null @@ -1,74 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "Srb2SDL"=.\Srb2SDL.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name libpng - End Project Dependency - Begin Project Dependency - Project_Dep_Name zlib - End Project Dependency -}}} - -############################################################################### - -Project: "libpng"="..\..\libs\libpng-src\projects\visualc6\libpng.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name zlib - End Project Dependency -}}} - -############################################################################### - -Project: "s_openal"=..\hardware\s_openal\s_openal.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "zlib"=..\..\libs\zlib\projects\visualc6\zlib.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/src/strcasestr.c b/src/strcasestr.c index 6a686d6dc..6affde364 100644 --- a/src/strcasestr.c +++ b/src/strcasestr.c @@ -22,6 +22,16 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef _MSC_VER +#include +#include +#include + +#ifndef strncasecmp +#define strncasecmp _strnicmp +#endif + +#endif static inline int trycmp (char **pp, char *cp, From b461cb919bf37ae5a33b57c62d264538576b01a8 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 1 Jan 2023 11:45:09 +0100 Subject: [PATCH 46/96] Move server-side connection handling to a new file --- src/netcode/Sourcefile | 1 + src/netcode/d_clisrv.c | 475 +----------------------------- src/netcode/d_clisrv.h | 3 +- src/netcode/d_netcmd.c | 1 + src/netcode/server_connection.c | 497 ++++++++++++++++++++++++++++++++ src/netcode/server_connection.h | 29 ++ 6 files changed, 533 insertions(+), 473 deletions(-) create mode 100644 src/netcode/server_connection.c create mode 100644 src/netcode/server_connection.h diff --git a/src/netcode/Sourcefile b/src/netcode/Sourcefile index c11b3d6c1..4177166a4 100644 --- a/src/netcode/Sourcefile +++ b/src/netcode/Sourcefile @@ -1,4 +1,5 @@ d_clisrv.c +server_connection.c client_connection.c d_net.c d_netcmd.c diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index f7a9260e1..c1264768e 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -49,6 +49,7 @@ #include "../lua_libs.h" #include "../md5.h" #include "../m_perfstats.h" +#include "server_connection.h" #include "client_connection.h" // @@ -79,15 +80,6 @@ netnode_t netnodes[MAXNETNODES]; // Server specific vars UINT8 playernode[MAXPLAYERS]; -char playeraddress[MAXPLAYERS][64]; - -// Minimum timeout for sending the savegame -// The actual timeout will be longer depending on the savegame length -tic_t jointimeout = (10*TICRATE); - -// Incremented by cv_joindelay when a client joins, decremented each tic. -// If higher than cv_joindelay * 2 (3 joins in a short timespan), joins are temporarily disabled. -static tic_t joindelay = 0; UINT16 pingmeasurecount = 1; UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone. @@ -100,7 +92,6 @@ tic_t maketic; static INT16 consistancy[BACKUPTICS]; -static UINT8 player_joining = false; UINT8 hu_redownloadinggamestate = 0; // true when a player is connecting or disconnecting so that the gameplay has stopped in its tracks @@ -501,229 +492,6 @@ void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum) static INT16 Consistancy(void); -static INT32 FindRejoinerNum(SINT8 node) -{ - char strippednodeaddress[64]; - const char *nodeaddress; - char *port; - INT32 i; - - // Make sure there is no dead dress before proceeding to the stripping - if (!I_GetNodeAddress) - return -1; - nodeaddress = I_GetNodeAddress(node); - if (!nodeaddress) - return -1; - - // Strip the address of its port - strcpy(strippednodeaddress, nodeaddress); - port = strchr(strippednodeaddress, ':'); - if (port) - *port = '\0'; - - // Check if any player matches the stripped address - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && playeraddress[i][0] && playernode[i] == UINT8_MAX - && !strcmp(playeraddress[i], strippednodeaddress)) - return i; - } - - return -1; -} - -static UINT8 -GetRefuseReason (INT32 node) -{ - if (!node || FindRejoinerNum(node) != -1) - return 0; - else if (bannednode && bannednode[node]) - return REFUSE_BANNED; - else if (!cv_allownewplayer.value) - return REFUSE_JOINS_DISABLED; - else if (D_NumPlayers() >= cv_maxplayers.value) - return REFUSE_SLOTS_FULL; - else - return 0; -} - -static void SV_SendServerInfo(INT32 node, tic_t servertime) -{ - UINT8 *p; - - netbuffer->packettype = PT_SERVERINFO; - netbuffer->u.serverinfo._255 = 255; - netbuffer->u.serverinfo.packetversion = PACKETVERSION; - netbuffer->u.serverinfo.version = VERSION; - netbuffer->u.serverinfo.subversion = SUBVERSION; - strncpy(netbuffer->u.serverinfo.application, SRB2APPLICATION, - sizeof netbuffer->u.serverinfo.application); - // return back the time value so client can compute their ping - netbuffer->u.serverinfo.time = (tic_t)LONG(servertime); - netbuffer->u.serverinfo.leveltime = (tic_t)LONG(leveltime); - - netbuffer->u.serverinfo.numberofplayer = (UINT8)D_NumPlayers(); - netbuffer->u.serverinfo.maxplayer = (UINT8)cv_maxplayers.value; - - netbuffer->u.serverinfo.refusereason = GetRefuseReason(node); - - strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype], - sizeof netbuffer->u.serverinfo.gametypename); - netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame; - netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled(); - netbuffer->u.serverinfo.flags = (dedicated ? SV_DEDICATED : 0); - strncpy(netbuffer->u.serverinfo.servername, cv_servername.string, - MAXSERVERNAME); - strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7); - - M_Memcpy(netbuffer->u.serverinfo.mapmd5, mapmd5, 16); - - memset(netbuffer->u.serverinfo.maptitle, 0, sizeof netbuffer->u.serverinfo.maptitle); - - if (mapheaderinfo[gamemap-1] && *mapheaderinfo[gamemap-1]->lvlttl) - { - char *read = mapheaderinfo[gamemap-1]->lvlttl, *writ = netbuffer->u.serverinfo.maptitle; - while (writ < (netbuffer->u.serverinfo.maptitle+32) && *read != '\0') - { - if (!(*read & 0x80)) - { - *writ = toupper(*read); - writ++; - } - read++; - } - *writ = '\0'; - //strncpy(netbuffer->u.serverinfo.maptitle, (char *)mapheaderinfo[gamemap-1]->lvlttl, 33); - } - else - strncpy(netbuffer->u.serverinfo.maptitle, "UNKNOWN", 32); - - if (mapheaderinfo[gamemap-1] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) - netbuffer->u.serverinfo.iszone = 1; - else - netbuffer->u.serverinfo.iszone = 0; - - if (mapheaderinfo[gamemap-1]) - netbuffer->u.serverinfo.actnum = mapheaderinfo[gamemap-1]->actnum; - - p = PutFileNeeded(0); - - HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); -} - -static void SV_SendPlayerInfo(INT32 node) -{ - UINT8 i; - netbuffer->packettype = PT_PLAYERINFO; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - { - netbuffer->u.playerinfo[i].num = 255; // This slot is empty. - continue; - } - - netbuffer->u.playerinfo[i].num = i; - strncpy(netbuffer->u.playerinfo[i].name, (const char *)&player_names[i], MAXPLAYERNAME+1); - netbuffer->u.playerinfo[i].name[MAXPLAYERNAME] = '\0'; - - //fetch IP address - //No, don't do that, you fuckface. - memset(netbuffer->u.playerinfo[i].address, 0, 4); - - if (G_GametypeHasTeams()) - { - if (!players[i].ctfteam) - netbuffer->u.playerinfo[i].team = 255; - else - netbuffer->u.playerinfo[i].team = (UINT8)players[i].ctfteam; - } - else - { - if (players[i].spectator) - netbuffer->u.playerinfo[i].team = 255; - else - netbuffer->u.playerinfo[i].team = 0; - } - - netbuffer->u.playerinfo[i].score = LONG(players[i].score); - netbuffer->u.playerinfo[i].timeinserver = SHORT((UINT16)(players[i].jointime / TICRATE)); - netbuffer->u.playerinfo[i].skin = (UINT8)(players[i].skin -#ifdef DEVELOP // it's safe to do this only because PLAYERINFO isn't read by the game itself - % 3 -#endif - ); - - // Extra data - netbuffer->u.playerinfo[i].data = 0; //players[i].skincolor; - - if (players[i].pflags & PF_TAGIT) - netbuffer->u.playerinfo[i].data |= 0x20; - - if (players[i].gotflag) - netbuffer->u.playerinfo[i].data |= 0x40; - - if (players[i].powers[pw_super]) - netbuffer->u.playerinfo[i].data |= 0x80; - } - - HSendPacket(node, false, 0, sizeof(plrinfo) * MAXPLAYERS); -} - -/** Sends a PT_SERVERCFG packet - * - * \param node The destination - * \return True if the packet was successfully sent - * - */ -static boolean SV_SendServerConfig(INT32 node) -{ - boolean waspacketsent; - - netbuffer->packettype = PT_SERVERCFG; - - netbuffer->u.servercfg.serverplayer = (UINT8)serverplayer; - netbuffer->u.servercfg.totalslotnum = (UINT8)(doomcom->numslots); - netbuffer->u.servercfg.gametic = (tic_t)LONG(gametic); - netbuffer->u.servercfg.clientnode = (UINT8)node; - netbuffer->u.servercfg.gamestate = (UINT8)gamestate; - netbuffer->u.servercfg.gametype = (UINT8)gametype; - netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame; - - memcpy(netbuffer->u.servercfg.server_context, server_context, 8); - - { - const size_t len = sizeof (serverconfig_pak); - -#ifdef DEBUGFILE - if (debugfile) - { - fprintf(debugfile, "ServerConfig Packet about to be sent, size of packet:%s to node:%d\n", - sizeu1(len), node); - } -#endif - - waspacketsent = HSendPacket(node, true, 0, len); - } - -#ifdef DEBUGFILE - if (debugfile) - { - if (waspacketsent) - { - fprintf(debugfile, "ServerConfig Packet was sent\n"); - } - else - { - fprintf(debugfile, "ServerConfig Packet could not be sent right now\n"); - } - } -#endif - - return waspacketsent; -} - #define SAVEGAMESIZE (768*1024) static boolean SV_ResendingSavegameToAnyone(void) @@ -736,7 +504,7 @@ static boolean SV_ResendingSavegameToAnyone(void) return false; } -static void SV_SendSaveGame(INT32 node, boolean resending) +void SV_SendSaveGame(INT32 node, boolean resending) { size_t length, compressedlen; UINT8 *savebuffer; @@ -1190,7 +958,7 @@ static void Command_connect(void) CL_ConnectToServer(); } -static void ResetNode(INT32 node) +void ResetNode(INT32 node) { memset(&netnodes[node], 0, sizeof(*netnodes)); netnodes[node].player = -1; @@ -2020,17 +1788,6 @@ void D_QuitNetGame(void) #endif } -// Adds a node to the game (player will follow at map change or at savegame....) -static inline void SV_AddNode(INT32 node) -{ - netnodes[node].tic = gametic; - netnodes[node].supposedtic = gametic; - // little hack because the server connects to itself and puts - // nodeingame when connected not here - if (node) - netnodes[node].ingame = true; -} - // Xcmd XD_ADDPLAYER static void Got_AddPlayer(UINT8 **p, INT32 playernum) { @@ -2163,56 +1920,6 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) LUA_HookInt(newplayernum, HOOK(PlayerJoin)); } -static void SV_AddPlayer(SINT8 node, const char *name) -{ - INT32 n; - UINT8 buf[2 + MAXPLAYERNAME]; - UINT8 *p; - INT32 newplayernum; - - newplayernum = FindRejoinerNum(node); - if (newplayernum == -1) - { - // search for a free playernum - // we can't use playeringame since it is not updated here - for (newplayernum = dedicated ? 1 : 0; newplayernum < MAXPLAYERS; newplayernum++) - { - if (playeringame[newplayernum]) - continue; - for (n = 0; n < MAXNETNODES; n++) - if (netnodes[n].player == newplayernum || netnodes[n].player2 == newplayernum) - break; - if (n == MAXNETNODES) - break; - } - } - - // should never happen since we check the playernum - // before accepting the join - I_Assert(newplayernum < MAXPLAYERS); - - playernode[newplayernum] = (UINT8)node; - - p = buf + 2; - buf[0] = (UINT8)node; - buf[1] = newplayernum; - if (netnodes[node].numplayers < 1) - { - netnodes[node].player = newplayernum; - } - else - { - netnodes[node].player2 = newplayernum; - buf[1] |= 0x80; - } - WRITESTRINGN(p, name, MAXPLAYERNAME); - netnodes[node].numplayers++; - - SendNetXCmd(XD_ADDPLAYER, &buf, p - buf); - - DEBFILE(va("Server added player %d node %d\n", newplayernum, node)); -} - void CL_AddSplitscreenPlayer(void) { if (cl_mode == CL_CONNECTED) @@ -2298,15 +2005,6 @@ void SV_StartSinglePlayerServer(void) multiplayer = true; } -static void SV_SendRefuse(INT32 node, const char *reason) -{ - strcpy(netbuffer->u.serverrefuse.reason, reason); - - netbuffer->packettype = PT_SERVERREFUSE; - HSendPacket(node, true, 0, strlen(netbuffer->u.serverrefuse.reason) + 1); - Net_CloseConnection(node); -} - // used at txtcmds received to check packetsize bound static size_t TotalTextCmdPerTic(tic_t tic) { @@ -2323,139 +2021,6 @@ static size_t TotalTextCmdPerTic(tic_t tic) return total; } -static const char * -GetRefuseMessage (SINT8 node, INT32 rejoinernum) -{ - clientconfig_pak *cc = &netbuffer->u.clientcfg; - - boolean rejoining = (rejoinernum != -1); - - if (!node)/* server connecting to itself */ - return NULL; - - if ( - cc->modversion != MODVERSION || - strncmp(cc->application, SRB2APPLICATION, - sizeof cc->application) - ){ - return/* this is probably client's fault */ - "Incompatible."; - } - else if (bannednode && bannednode[node]) - { - return - "You have been banned\n" - "from the server."; - } - else if (cc->localplayers != 1) - { - return - "Wrong player count."; - } - - if (!rejoining) - { - if (!cv_allownewplayer.value) - { - return - "The server is not accepting\n" - "joins for the moment."; - } - else if (D_NumPlayers() >= cv_maxplayers.value) - { - return va( - "Maximum players reached: %d", - cv_maxplayers.value); - } - } - - if (luafiletransfers) - { - return - "The serveris broadcasting a file\n" - "requested by a Lua script.\n" - "Please wait a bit and then\n" - "try rejoining."; - } - - if (netgame) - { - const tic_t th = 2 * cv_joindelay.value * TICRATE; - - if (joindelay > th) - { - return va( - "Too many people are connecting.\n" - "Please wait %d seconds and then\n" - "try rejoining.", - (joindelay - th) / TICRATE); - } - } - - return NULL; -} - -/** Called when a PT_CLIENTJOIN packet is received - * - * \param node The packet sender - * - */ -static void HandleConnect(SINT8 node) -{ - char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1]; - INT32 numplayers = netbuffer->u.clientcfg.localplayers; - INT32 rejoinernum; - INT32 i; - - // Ignore duplicate packets - if (netnodes[node].ingame) - return; - - rejoinernum = FindRejoinerNum(node); - - const char *refuse = GetRefuseMessage(node, rejoinernum); - if (refuse) - { - SV_SendRefuse(node, refuse); - return; - } - - for (i = 0; i < numplayers; i++) - { - strlcpy(names[i], netbuffer->u.clientcfg.names[i], MAXPLAYERNAME + 1); - if (!EnsurePlayerNameIsGood(names[i], rejoinernum)) - { - SV_SendRefuse(node, "Bad player name"); - return; - } - } - - SV_AddNode(node); - - if (!SV_SendServerConfig(node)) - { - /// \note Shouldn't SV_SendRefuse be called before ResetNode? - ResetNode(node); - SV_SendRefuse(node, M_GetText("Server couldn't send info, please try again")); - /// \todo fix this !!! - return; // restart the while - } - DEBFILE("new node joined\n"); - - if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) - { - SV_SendSaveGame(node, false); // send a complete game state - DEBFILE("send savegame\n"); - } - - // Splitscreen can allow 2 players in one node - for (i = 0; i < numplayers; i++) - SV_AddPlayer(node, names[i]); - - joindelay += cv_joindelay.value * TICRATE; - player_joining = true; -} - /** Called when a PT_SERVERSHUTDOWN packet is received * * \param node The packet sender (should be the server) @@ -2486,40 +2051,6 @@ static void HandleTimeout(SINT8 node) M_StartMessage(M_GetText("Server Timeout\n\nPress Esc\n"), NULL, MM_NOTHING); } -static void PT_AskInfoViaMS(SINT8 node) -{ - Net_CloseConnection(node); -} - -static void PT_TellFilesNeeded(SINT8 node) -{ - if (server && serverrunning) - { - UINT8 *p; - INT32 firstfile = netbuffer->u.filesneedednum; - - netbuffer->packettype = PT_MOREFILESNEEDED; - netbuffer->u.filesneededcfg.first = firstfile; - netbuffer->u.filesneededcfg.more = 0; - - p = PutFileNeeded(firstfile); - - HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); - } - else // Shouldn't get this if you aren't the server...? - Net_CloseConnection(node); -} - -static void PT_AskInfo(SINT8 node) -{ - if (server && serverrunning) - { - SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time)); - SV_SendPlayerInfo(node); // Send extra info - } - Net_CloseConnection(node); -} - static void PT_ClientCmd(SINT8 node, INT32 netconsole) { tic_t realend, realstart; diff --git a/src/netcode/d_clisrv.h b/src/netcode/d_clisrv.h index 3b0690a79..b8da645ba 100644 --- a/src/netcode/d_clisrv.h +++ b/src/netcode/d_clisrv.h @@ -381,7 +381,6 @@ extern tic_t neededtic; void Command_Ping_f(void); extern tic_t connectiontimeout; -extern tic_t jointimeout; extern UINT16 pingmeasurecount; extern UINT32 realpingtable[MAXPLAYERS]; extern UINT32 playerpingtable[MAXPLAYERS]; @@ -405,11 +404,13 @@ void SendKick(UINT8 playernum, UINT8 msg); void NetUpdate(void); void GetPackets(void); +void ResetNode(INT32 node); void SV_StartSinglePlayerServer(void); void SV_SpawnServer(void); void SV_StopServer(void); void SV_ResetServer(void); +void SV_SendSaveGame(INT32 node, boolean resending); void CL_AddSplitscreenPlayer(void); void CL_RemoveSplitscreenPlayer(void); void CL_Reset(void); diff --git a/src/netcode/d_netcmd.c b/src/netcode/d_netcmd.c index ed310805d..fe4cf22bd 100644 --- a/src/netcode/d_netcmd.c +++ b/src/netcode/d_netcmd.c @@ -36,6 +36,7 @@ #include "../p_spec.h" #include "../m_cheat.h" #include "d_clisrv.h" +#include "server_connection.h" #include "d_net.h" #include "../v_video.h" #include "../d_main.h" diff --git a/src/netcode/server_connection.c b/src/netcode/server_connection.c new file mode 100644 index 000000000..9e397b0f3 --- /dev/null +++ b/src/netcode/server_connection.c @@ -0,0 +1,497 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file server_connection.c +/// \brief Server-side part of connection handling + +#include "server_connection.h" +#include "i_net.h" +#include "d_clisrv.h" +#include "d_netfil.h" +#include "mserv.h" +#include "../byteptr.h" +#include "../g_game.h" +#include "../g_state.h" +#include "../p_setup.h" +#include "../p_tick.h" +#include "../doomstat.h" + +// Minimum timeout for sending the savegame +// The actual timeout will be longer depending on the savegame length +tic_t jointimeout = (10*TICRATE); + +// Incremented by cv_joindelay when a client joins, decremented each tic. +// If higher than cv_joindelay * 2 (3 joins in a short timespan), joins are temporarily disabled. +tic_t joindelay = 0; + +// Minimum timeout for sending the savegame +// The actual timeout will be longer depending on the savegame length +char playeraddress[MAXPLAYERS][64]; + +UINT8 player_joining = false; + +static INT32 FindRejoinerNum(SINT8 node) +{ + char strippednodeaddress[64]; + const char *nodeaddress; + char *port; + INT32 i; + + // Make sure there is no dead dress before proceeding to the stripping + if (!I_GetNodeAddress) + return -1; + nodeaddress = I_GetNodeAddress(node); + if (!nodeaddress) + return -1; + + // Strip the address of its port + strcpy(strippednodeaddress, nodeaddress); + port = strchr(strippednodeaddress, ':'); + if (port) + *port = '\0'; + + // Check if any player matches the stripped address + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && playeraddress[i][0] && playernode[i] == UINT8_MAX + && !strcmp(playeraddress[i], strippednodeaddress)) + return i; + } + + return -1; +} + +static UINT8 +GetRefuseReason (INT32 node) +{ + if (!node || FindRejoinerNum(node) != -1) + return 0; + else if (bannednode && bannednode[node]) + return REFUSE_BANNED; + else if (!cv_allownewplayer.value) + return REFUSE_JOINS_DISABLED; + else if (D_NumPlayers() >= cv_maxplayers.value) + return REFUSE_SLOTS_FULL; + else + return 0; +} + +static void SV_SendServerInfo(INT32 node, tic_t servertime) +{ + UINT8 *p; + + netbuffer->packettype = PT_SERVERINFO; + netbuffer->u.serverinfo._255 = 255; + netbuffer->u.serverinfo.packetversion = PACKETVERSION; + netbuffer->u.serverinfo.version = VERSION; + netbuffer->u.serverinfo.subversion = SUBVERSION; + strncpy(netbuffer->u.serverinfo.application, SRB2APPLICATION, + sizeof netbuffer->u.serverinfo.application); + // return back the time value so client can compute their ping + netbuffer->u.serverinfo.time = (tic_t)LONG(servertime); + netbuffer->u.serverinfo.leveltime = (tic_t)LONG(leveltime); + + netbuffer->u.serverinfo.numberofplayer = (UINT8)D_NumPlayers(); + netbuffer->u.serverinfo.maxplayer = (UINT8)cv_maxplayers.value; + + netbuffer->u.serverinfo.refusereason = GetRefuseReason(node); + + strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype], + sizeof netbuffer->u.serverinfo.gametypename); + netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame; + netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled(); + netbuffer->u.serverinfo.flags = (dedicated ? SV_DEDICATED : 0); + strncpy(netbuffer->u.serverinfo.servername, cv_servername.string, + MAXSERVERNAME); + strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7); + + M_Memcpy(netbuffer->u.serverinfo.mapmd5, mapmd5, 16); + + memset(netbuffer->u.serverinfo.maptitle, 0, sizeof netbuffer->u.serverinfo.maptitle); + + if (mapheaderinfo[gamemap-1] && *mapheaderinfo[gamemap-1]->lvlttl) + { + char *read = mapheaderinfo[gamemap-1]->lvlttl, *writ = netbuffer->u.serverinfo.maptitle; + while (writ < (netbuffer->u.serverinfo.maptitle+32) && *read != '\0') + { + if (!(*read & 0x80)) + { + *writ = toupper(*read); + writ++; + } + read++; + } + *writ = '\0'; + //strncpy(netbuffer->u.serverinfo.maptitle, (char *)mapheaderinfo[gamemap-1]->lvlttl, 33); + } + else + strncpy(netbuffer->u.serverinfo.maptitle, "UNKNOWN", 32); + + if (mapheaderinfo[gamemap-1] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) + netbuffer->u.serverinfo.iszone = 1; + else + netbuffer->u.serverinfo.iszone = 0; + + if (mapheaderinfo[gamemap-1]) + netbuffer->u.serverinfo.actnum = mapheaderinfo[gamemap-1]->actnum; + + p = PutFileNeeded(0); + + HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); +} + +static void SV_SendPlayerInfo(INT32 node) +{ + UINT8 i; + netbuffer->packettype = PT_PLAYERINFO; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + { + netbuffer->u.playerinfo[i].num = 255; // This slot is empty. + continue; + } + + netbuffer->u.playerinfo[i].num = i; + strncpy(netbuffer->u.playerinfo[i].name, (const char *)&player_names[i], MAXPLAYERNAME+1); + netbuffer->u.playerinfo[i].name[MAXPLAYERNAME] = '\0'; + + //fetch IP address + //No, don't do that, you fuckface. + memset(netbuffer->u.playerinfo[i].address, 0, 4); + + if (G_GametypeHasTeams()) + { + if (!players[i].ctfteam) + netbuffer->u.playerinfo[i].team = 255; + else + netbuffer->u.playerinfo[i].team = (UINT8)players[i].ctfteam; + } + else + { + if (players[i].spectator) + netbuffer->u.playerinfo[i].team = 255; + else + netbuffer->u.playerinfo[i].team = 0; + } + + netbuffer->u.playerinfo[i].score = LONG(players[i].score); + netbuffer->u.playerinfo[i].timeinserver = SHORT((UINT16)(players[i].jointime / TICRATE)); + netbuffer->u.playerinfo[i].skin = (UINT8)(players[i].skin +#ifdef DEVELOP // it's safe to do this only because PLAYERINFO isn't read by the game itself + % 3 +#endif + ); + + // Extra data + netbuffer->u.playerinfo[i].data = 0; //players[i].skincolor; + + if (players[i].pflags & PF_TAGIT) + netbuffer->u.playerinfo[i].data |= 0x20; + + if (players[i].gotflag) + netbuffer->u.playerinfo[i].data |= 0x40; + + if (players[i].powers[pw_super]) + netbuffer->u.playerinfo[i].data |= 0x80; + } + + HSendPacket(node, false, 0, sizeof(plrinfo) * MAXPLAYERS); +} + +/** Sends a PT_SERVERCFG packet + * + * \param node The destination + * \return True if the packet was successfully sent + * + */ +static boolean SV_SendServerConfig(INT32 node) +{ + boolean waspacketsent; + + netbuffer->packettype = PT_SERVERCFG; + + netbuffer->u.servercfg.serverplayer = (UINT8)serverplayer; + netbuffer->u.servercfg.totalslotnum = (UINT8)(doomcom->numslots); + netbuffer->u.servercfg.gametic = (tic_t)LONG(gametic); + netbuffer->u.servercfg.clientnode = (UINT8)node; + netbuffer->u.servercfg.gamestate = (UINT8)gamestate; + netbuffer->u.servercfg.gametype = (UINT8)gametype; + netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame; + + memcpy(netbuffer->u.servercfg.server_context, server_context, 8); + + { + const size_t len = sizeof (serverconfig_pak); + +#ifdef DEBUGFILE + if (debugfile) + { + fprintf(debugfile, "ServerConfig Packet about to be sent, size of packet:%s to node:%d\n", + sizeu1(len), node); + } +#endif + + waspacketsent = HSendPacket(node, true, 0, len); + } + +#ifdef DEBUGFILE + if (debugfile) + { + if (waspacketsent) + { + fprintf(debugfile, "ServerConfig Packet was sent\n"); + } + else + { + fprintf(debugfile, "ServerConfig Packet could not be sent right now\n"); + } + } +#endif + + return waspacketsent; +} + +// Adds a node to the game (player will follow at map change or at savegame....) +static inline void SV_AddNode(INT32 node) +{ + netnodes[node].tic = gametic; + netnodes[node].supposedtic = gametic; + // little hack because the server connects to itself and puts + // nodeingame when connected not here + if (node) + netnodes[node].ingame = true; +} + +static void SV_AddPlayer(SINT8 node, const char *name) +{ + INT32 n; + UINT8 buf[2 + MAXPLAYERNAME]; + UINT8 *p; + INT32 newplayernum; + + newplayernum = FindRejoinerNum(node); + if (newplayernum == -1) + { + // search for a free playernum + // we can't use playeringame since it is not updated here + for (newplayernum = dedicated ? 1 : 0; newplayernum < MAXPLAYERS; newplayernum++) + { + if (playeringame[newplayernum]) + continue; + for (n = 0; n < MAXNETNODES; n++) + if (netnodes[n].player == newplayernum || netnodes[n].player2 == newplayernum) + break; + if (n == MAXNETNODES) + break; + } + } + + // should never happen since we check the playernum + // before accepting the join + I_Assert(newplayernum < MAXPLAYERS); + + playernode[newplayernum] = (UINT8)node; + + p = buf + 2; + buf[0] = (UINT8)node; + buf[1] = newplayernum; + if (netnodes[node].numplayers < 1) + { + netnodes[node].player = newplayernum; + } + else + { + netnodes[node].player2 = newplayernum; + buf[1] |= 0x80; + } + WRITESTRINGN(p, name, MAXPLAYERNAME); + netnodes[node].numplayers++; + + SendNetXCmd(XD_ADDPLAYER, &buf, p - buf); + + DEBFILE(va("Server added player %d node %d\n", newplayernum, node)); +} + +static void SV_SendRefuse(INT32 node, const char *reason) +{ + strcpy(netbuffer->u.serverrefuse.reason, reason); + + netbuffer->packettype = PT_SERVERREFUSE; + HSendPacket(node, true, 0, strlen(netbuffer->u.serverrefuse.reason) + 1); + Net_CloseConnection(node); +} + +static const char * +GetRefuseMessage (SINT8 node, INT32 rejoinernum) +{ + clientconfig_pak *cc = &netbuffer->u.clientcfg; + + boolean rejoining = (rejoinernum != -1); + + if (!node)/* server connecting to itself */ + return NULL; + + if ( + cc->modversion != MODVERSION || + strncmp(cc->application, SRB2APPLICATION, + sizeof cc->application) + ){ + return/* this is probably client's fault */ + "Incompatible."; + } + else if (bannednode && bannednode[node]) + { + return + "You have been banned\n" + "from the server."; + } + else if (cc->localplayers != 1) + { + return + "Wrong player count."; + } + + if (!rejoining) + { + if (!cv_allownewplayer.value) + { + return + "The server is not accepting\n" + "joins for the moment."; + } + else if (D_NumPlayers() >= cv_maxplayers.value) + { + return va( + "Maximum players reached: %d", + cv_maxplayers.value); + } + } + + if (luafiletransfers) + { + return + "The serveris broadcasting a file\n" + "requested by a Lua script.\n" + "Please wait a bit and then\n" + "try rejoining."; + } + + if (netgame) + { + const tic_t th = 2 * cv_joindelay.value * TICRATE; + + if (joindelay > th) + { + return va( + "Too many people are connecting.\n" + "Please wait %d seconds and then\n" + "try rejoining.", + (joindelay - th) / TICRATE); + } + } + + return NULL; +} + +/** Called when a PT_CLIENTJOIN packet is received + * + * \param node The packet sender + * + */ +void HandleConnect(SINT8 node) +{ + char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1]; + INT32 numplayers = netbuffer->u.clientcfg.localplayers; + INT32 rejoinernum; + INT32 i; + + // Ignore duplicate packets + if (netnodes[node].ingame) + return; + + rejoinernum = FindRejoinerNum(node); + + const char *refuse = GetRefuseMessage(node, rejoinernum); + if (refuse) + { + SV_SendRefuse(node, refuse); + return; + } + + for (i = 0; i < numplayers; i++) + { + strlcpy(names[i], netbuffer->u.clientcfg.names[i], MAXPLAYERNAME + 1); + if (!EnsurePlayerNameIsGood(names[i], rejoinernum)) + { + SV_SendRefuse(node, "Bad player name"); + return; + } + } + + SV_AddNode(node); + + if (!SV_SendServerConfig(node)) + { + /// \note Shouldn't SV_SendRefuse be called before ResetNode? + ResetNode(node); + SV_SendRefuse(node, M_GetText("Server couldn't send info, please try again")); + /// \todo fix this !!! + return; // restart the while + } + DEBFILE("new node joined\n"); + + if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) + { + SV_SendSaveGame(node, false); // send a complete game state + DEBFILE("send savegame\n"); + } + + // Splitscreen can allow 2 players in one node + for (i = 0; i < numplayers; i++) + SV_AddPlayer(node, names[i]); + + joindelay += cv_joindelay.value * TICRATE; + player_joining = true; +} + +void PT_AskInfoViaMS(SINT8 node) +{ + Net_CloseConnection(node); +} + +void PT_TellFilesNeeded(SINT8 node) +{ + if (server && serverrunning) + { + UINT8 *p; + INT32 firstfile = netbuffer->u.filesneedednum; + + netbuffer->packettype = PT_MOREFILESNEEDED; + netbuffer->u.filesneededcfg.first = firstfile; + netbuffer->u.filesneededcfg.more = 0; + + p = PutFileNeeded(firstfile); + + HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); + } + else // Shouldn't get this if you aren't the server...? + Net_CloseConnection(node); +} + +void PT_AskInfo(SINT8 node) +{ + if (server && serverrunning) + { + SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time)); + SV_SendPlayerInfo(node); // Send extra info + } + Net_CloseConnection(node); +} diff --git a/src/netcode/server_connection.h b/src/netcode/server_connection.h new file mode 100644 index 000000000..4204db2e6 --- /dev/null +++ b/src/netcode/server_connection.h @@ -0,0 +1,29 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file server_connection.h +/// \brief Server-side part of connection handling + +#ifndef __D_SERVER_CONNECTION__ +#define __D_SERVER_CONNECTION__ + +#include "../doomdef.h" +#include "../doomtype.h" + +void HandleConnect(SINT8 node); +void PT_AskInfoViaMS(SINT8 node); +void PT_TellFilesNeeded(SINT8 node); +void PT_AskInfo(SINT8 node); + +extern tic_t jointimeout; +extern tic_t joindelay; +extern char playeraddress[MAXPLAYERS][64]; +extern UINT8 player_joining; + +#endif From 7800c9e5c9cc0427905936049a26b8c1b45396c8 Mon Sep 17 00:00:00 2001 From: Ashnal Date: Sat, 12 Nov 2022 17:20:03 -0600 Subject: [PATCH 47/96] Fix use after free bug --- src/p_mobj.c | 36 ++++++++++++++++++++++++++++-------- src/p_saveg.c | 22 +++++++++++++++++++++- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index e658d192c..651b26857 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11195,21 +11195,41 @@ void P_RemovePrecipMobj(precipmobj_t *mobj) void P_RemoveSavegameMobj(mobj_t *mobj) { // unlink from sector and block lists - P_UnsetThingPosition(mobj); - - // Remove touching_sectorlist from mobj. - if (sector_list) + if (((thinker_t *)mobj)->function.acp1 == (actionf_p1)P_NullPrecipThinker) { - P_DelSeclist(sector_list); - sector_list = NULL; + P_UnsetPrecipThingPosition((precipmobj_t *)mobj); + + if (precipsector_list) + { + P_DelPrecipSeclist(precipsector_list); + precipsector_list = NULL; + } + } + else + { + // unlink from sector and block lists + P_UnsetThingPosition(mobj); + + // Remove touching_sectorlist from mobj. + if (sector_list) + { + P_DelSeclist(sector_list); + sector_list = NULL; + } } // stop any playing sound S_StopSound(mobj); + R_RemoveMobjInterpolator(mobj); // free block - P_RemoveThinker((thinker_t *)mobj); - R_RemoveMobjInterpolator(mobj); + // Here we use the same code as R_RemoveThinkerDelayed, but without reference counting (we're removing everything so it shouldn't matter) and without touching currentthinker since we aren't in P_RunThinkers + { + thinker_t *thinker = (thinker_t *)mobj; + thinker_t *next = thinker->next; + (next->prev = thinker->prev)->next = next; + Z_Free(thinker); + } } static CV_PossibleValue_t respawnitemtime_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}}; diff --git a/src/p_saveg.c b/src/p_saveg.c index ce7353b95..42125dae7 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -3059,6 +3059,18 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->player->viewz = mobj->player->mo->z + mobj->player->viewheight; } + if (mobj->type == MT_SKYBOX && mobj->spawnpoint) + { + mtag_t tag = Tag_FGet(&mobj->spawnpoint->tags); + if (tag >= 0 && tag <= 15) + { + if (mobj->spawnpoint->args[0]) + skyboxcenterpnts[tag] = mobj; + else + skyboxviewpnts[tag] = mobj; + } + } + mobj->info = (mobjinfo_t *)next; // temporarily, set when leave this function R_AddMobjInterpolator(mobj); @@ -3680,10 +3692,14 @@ static void P_NetUnArchiveThinkers(void) { next = currentthinker->next; - if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker) + if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker || currentthinker->function.acp1 == (actionf_p1)P_NullPrecipThinker) P_RemoveSavegameMobj((mobj_t *)currentthinker); // item isn't saved, don't remove it else + { + (next->prev = currentthinker->prev)->next = next; + R_DestroyLevelInterpolators(currentthinker); Z_Free(currentthinker); + } } } @@ -3885,6 +3901,10 @@ static void P_NetUnArchiveThinkers(void) CONS_Debug(DBG_NETPLAY, "%u thinkers loaded in list %d\n", numloaded, i); } + // Set each skyboxmo to the first skybox (or NULL) + skyboxmo[0] = skyboxviewpnts[0]; + skyboxmo[1] = skyboxcenterpnts[0]; + if (restoreNum) { executor_t *delay = NULL; From eeff182abbea12e8abdc7dda5354a66c72e3bdda Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 3 Jan 2023 14:09:12 -0600 Subject: [PATCH 48/96] Reverse axis event mapping in G_RemapGamepadEvent Was erroneously mapping events inside the deadzone as key down and vice versa. --- src/g_input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_input.c b/src/g_input.c index 465db0316..6b0da7e41 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -543,9 +543,9 @@ INT32 G_RemapGamepadEvent(event_t *event, INT32 *type) const INT16 value = G_GetGamepadAxisValue(event->which, event->key); if (value < -jdeadzone || value > jdeadzone) - *type = ev_keyup; - else *type = ev_keydown; + else + *type = ev_keyup; if (value < -jdeadzone) return KEY_INV_AXES + event->key; From c270cca55f6e13731c91d872a75c58ff01eda769 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 3 Jan 2023 14:39:15 -0600 Subject: [PATCH 49/96] Always swallow pad axis events when menu is active This prevents axis events from trickling out of the menu and taking effect in G_Responder when they aren't hitting the digital deadzone needed to be mapped into internal menu key events. --- src/m_menu.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 51d13df98..1d5bd65f3 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -3224,6 +3224,7 @@ boolean M_Responder(event_t *ev) static INT32 pjoyx = 0, pjoyy = 0; static INT32 pmousex = 0, pmousey = 0; static INT32 lastx = 0, lasty = 0; + boolean shouldswallowevent = false; void (*routine)(INT32 choice); // for some casting problem if (dedicated || (demoplayback && titledemo) @@ -3239,11 +3240,18 @@ boolean M_Responder(event_t *ev) boolean useEventHandler = false; + if (menuactive && ev->type == ev_gamepad_axis && ev->which == 0) + { + // ALWAYS swallow gamepad axis events, to prevent trickling down to game input + // this applies even if the axis event does not get remapped + shouldswallowevent = true; + } + if (noFurtherInput) { // Ignore input after enter/escape/other buttons // (but still allow shift keyup so caps doesn't get stuck) - return false; + return shouldswallowevent; } else if (menuactive) { @@ -3368,7 +3376,7 @@ boolean M_Responder(event_t *ev) } if (!useEventHandler && ch == -1) - return false; + return shouldswallowevent; else if (ch == gamecontrol[GC_SYSTEMMENU][0] || ch == gamecontrol[GC_SYSTEMMENU][1]) // allow remappable ESC key ch = KEY_ESCAPE; @@ -3601,7 +3609,7 @@ boolean M_Responder(event_t *ev) //currentMenu->lastOn = itemOn; //if (currentMenu->prevMenu) // M_SetupNextMenu(currentMenu->prevMenu); - return false; + return shouldswallowevent; default: CON_Responder(ev); From 5bbfb1840ab21eb5902093e0846ecd08979eea64 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Wed, 4 Jan 2023 08:58:40 +0100 Subject: [PATCH 50/96] Fix scaling mistake in A_FishJump --- src/p_enemy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index ece4f3814..373f09123 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -4859,12 +4859,12 @@ void A_FishJump(mobj_t *actor) else { if (actor->spawnpoint && actor->spawnpoint->args[0]) - jumpval = actor->spawnpoint->args[0]; + jumpval = actor->spawnpoint->args[0] << (FRACBITS - 2); else - jumpval = 44; + jumpval = 44 << (FRACBITS - 2); } - actor->momz = FixedMul(jumpval << (FRACBITS - 2), actor->scale); + actor->momz = FixedMul(jumpval, actor->scale); P_SetMobjStateNF(actor, actor->info->seestate); } From 7c2fe20cd5aa9badc4d7d7fed9561e8bf966997b Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Thu, 5 Jan 2023 22:51:17 +0100 Subject: [PATCH 51/96] Move tic and net command handling to new files --- src/blua/liolib.c | 1 + src/command.c | 1 + src/g_game.c | 1 + src/hu_stuff.c | 1 + src/lua_consolelib.c | 1 + src/netcode/Sourcefile | 2 + src/netcode/d_clisrv.c | 878 +------------------------------- src/netcode/d_clisrv.h | 12 +- src/netcode/d_net.c | 1 + src/netcode/d_netcmd.c | 1 + src/netcode/d_netfil.c | 1 + src/netcode/net_command.c | 315 ++++++++++++ src/netcode/net_command.h | 62 +++ src/netcode/server_connection.c | 1 + src/netcode/tic_command.c | 504 ++++++++++++++++++ src/netcode/tic_command.h | 44 ++ src/p_inter.c | 1 + src/p_mobj.c | 1 + src/p_setup.c | 2 + src/p_tick.c | 1 + src/p_user.c | 1 + 21 files changed, 955 insertions(+), 877 deletions(-) create mode 100644 src/netcode/net_command.c create mode 100644 src/netcode/net_command.h create mode 100644 src/netcode/tic_command.c create mode 100644 src/netcode/tic_command.h diff --git a/src/blua/liolib.c b/src/blua/liolib.c index 8a6354121..bce8e87cc 100644 --- a/src/blua/liolib.c +++ b/src/blua/liolib.c @@ -20,6 +20,7 @@ #include "../i_system.h" #include "../g_game.h" #include "../netcode/d_netfil.h" +#include "../netcode/net_command.h" #include "../lua_libs.h" #include "../byteptr.h" #include "../lua_script.h" diff --git a/src/command.c b/src/command.c index 4e8989fd3..a87a04dcc 100644 --- a/src/command.c +++ b/src/command.c @@ -29,6 +29,7 @@ #include "p_saveg.h" #include "g_game.h" // for player_names #include "netcode/d_netcmd.h" +#include "netcode/net_command.h" #include "hu_stuff.h" #include "p_setup.h" #include "lua_script.h" diff --git a/src/g_game.c b/src/g_game.c index 93b8eb936..17dbff7d3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -16,6 +16,7 @@ #include "d_main.h" #include "d_player.h" #include "netcode/d_clisrv.h" +#include "netcode/net_command.h" #include "f_finale.h" #include "p_setup.h" #include "p_saveg.h" diff --git a/src/hu_stuff.c b/src/hu_stuff.c index e5cf5aeb1..e08351a8a 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -20,6 +20,7 @@ #include "m_misc.h" // word jumping #include "netcode/d_clisrv.h" +#include "netcode/net_command.h" #include "g_game.h" #include "g_input.h" diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 816051199..a1bdf380d 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -16,6 +16,7 @@ #include "g_game.h" #include "byteptr.h" #include "z_zone.h" +#include "netcode/net_command.h" #include "lua_script.h" #include "lua_libs.h" diff --git a/src/netcode/Sourcefile b/src/netcode/Sourcefile index 4177166a4..1039b218a 100644 --- a/src/netcode/Sourcefile +++ b/src/netcode/Sourcefile @@ -1,6 +1,8 @@ d_clisrv.c server_connection.c client_connection.c +tic_command.c +net_command.c d_net.c d_netcmd.c d_netfil.c diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index c1264768e..06e6da751 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -51,6 +51,8 @@ #include "../m_perfstats.h" #include "server_connection.h" #include "client_connection.h" +#include "tic_command.h" +#include "net_command.h" // // NETWORKING @@ -86,11 +88,9 @@ UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values. tic_t servermaxping = 800; // server's max ping. Defaults to 800 -static tic_t firstticstosend; // min of the nettics -static tic_t tictoclear = 0; // optimize d_clearticcmd tic_t maketic; -static INT16 consistancy[BACKUPTICS]; +INT16 consistancy[BACKUPTICS]; UINT8 hu_redownloadinggamestate = 0; @@ -101,14 +101,9 @@ UINT8 adminpassmd5[16]; boolean adminpasswordset = false; // Client specific -static ticcmd_t localcmds; -static ticcmd_t localcmds2; -static boolean cl_packetmissed; // here it is for the secondary local player (splitscreen) static boolean cl_redownloadinggamestate = false; -static UINT8 localtextcmd[MAXTEXTCMD]; -static UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen tic_t neededtic; SINT8 servernode = 0; // the number of the server node @@ -116,385 +111,19 @@ SINT8 servernode = 0; // the number of the server node /// \todo WORK! boolean acceptnewnode = true; -// engine - -// Must be a power of two -#define TEXTCMD_HASH_SIZE 4 - -typedef struct textcmdplayer_s -{ - INT32 playernum; - UINT8 cmd[MAXTEXTCMD]; - struct textcmdplayer_s *next; -} textcmdplayer_t; - -typedef struct textcmdtic_s -{ - tic_t tic; - textcmdplayer_t *playercmds[TEXTCMD_HASH_SIZE]; - struct textcmdtic_s *next; -} textcmdtic_t; - -ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; -static textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL}; - - consvar_t cv_showjoinaddress = CVAR_INIT ("showjoinaddress", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}}; consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_cons_t, NULL); -static inline void *G_DcpyTiccmd(void* dest, const ticcmd_t* src, const size_t n) -{ - const size_t d = n / sizeof(ticcmd_t); - const size_t r = n % sizeof(ticcmd_t); - UINT8 *ret = dest; - - if (r) - M_Memcpy(dest, src, n); - else if (d) - G_MoveTiccmd(dest, src, d); - return ret+n; -} - -static inline void *G_ScpyTiccmd(ticcmd_t* dest, void* src, const size_t n) -{ - const size_t d = n / sizeof(ticcmd_t); - const size_t r = n % sizeof(ticcmd_t); - UINT8 *ret = src; - - if (r) - M_Memcpy(dest, src, n); - else if (d) - G_MoveTiccmd(dest, src, d); - return ret+n; -} - - - // Some software don't support largest packet // (original sersetup, not exactely, but the probability of sending a packet // of 512 bytes is like 0.1) UINT16 software_MAXPACKETLENGTH; -/** Guesses the full value of a tic from its lowest byte, for a specific node - * - * \param low The lowest byte of the tic value - * \param node The node to deduce the tic for - * \return The full tic value - * - */ -tic_t ExpandTics(INT32 low, INT32 node) -{ - INT32 delta; - - delta = low - (netnodes[node].tic & UINT8_MAX); - - if (delta >= -64 && delta <= 64) - return (netnodes[node].tic & ~UINT8_MAX) + low; - else if (delta > 64) - return (netnodes[node].tic & ~UINT8_MAX) - 256 + low; - else //if (delta < -64) - return (netnodes[node].tic & ~UINT8_MAX) + 256 + low; -} - -// ----------------------------------------------------------------- -// Some extra data function for handle textcmd buffer -// ----------------------------------------------------------------- - -static void (*listnetxcmd[MAXNETXCMD])(UINT8 **p, INT32 playernum); - -void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)) -{ -#ifdef PARANOIA - if (id >= MAXNETXCMD) - I_Error("Command id %d too big", id); - if (listnetxcmd[id] != 0) - I_Error("Command id %d already used", id); -#endif - listnetxcmd[id] = cmd_f; -} - -void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam) -{ - if (localtextcmd[0]+2+nparam > MAXTEXTCMD) - { - // for future reference: if (cv_debug) != debug disabled. - CONS_Alert(CONS_ERROR, M_GetText("NetXCmd buffer full, cannot add netcmd %d! (size: %d, needed: %s)\n"), id, localtextcmd[0], sizeu1(nparam)); - return; - } - localtextcmd[0]++; - localtextcmd[localtextcmd[0]] = (UINT8)id; - if (param && nparam) - { - M_Memcpy(&localtextcmd[localtextcmd[0]+1], param, nparam); - localtextcmd[0] = (UINT8)(localtextcmd[0] + (UINT8)nparam); - } -} - -// splitscreen player -void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam) -{ - if (localtextcmd2[0]+2+nparam > MAXTEXTCMD) - { - I_Error("No more place in the buffer for netcmd %d\n",id); - return; - } - localtextcmd2[0]++; - localtextcmd2[localtextcmd2[0]] = (UINT8)id; - if (param && nparam) - { - M_Memcpy(&localtextcmd2[localtextcmd2[0]+1], param, nparam); - localtextcmd2[0] = (UINT8)(localtextcmd2[0] + (UINT8)nparam); - } -} - -UINT8 GetFreeXCmdSize(void) -{ - // -1 for the size and another -1 for the ID. - return (UINT8)(localtextcmd[0] - 2); -} - -// Frees all textcmd memory for the specified tic -static void D_FreeTextcmd(tic_t tic) -{ - textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; - textcmdtic_t *textcmdtic = *tctprev; - - while (textcmdtic && textcmdtic->tic != tic) - { - tctprev = &textcmdtic->next; - textcmdtic = textcmdtic->next; - } - - if (textcmdtic) - { - INT32 i; - - // Remove this tic from the list. - *tctprev = textcmdtic->next; - - // Free all players. - for (i = 0; i < TEXTCMD_HASH_SIZE; i++) - { - textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[i]; - - while (textcmdplayer) - { - textcmdplayer_t *tcpnext = textcmdplayer->next; - Z_Free(textcmdplayer); - textcmdplayer = tcpnext; - } - } - - // Free this tic's own memory. - Z_Free(textcmdtic); - } -} - -// Gets the buffer for the specified ticcmd, or NULL if there isn't one -static UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum) -{ - textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; - while (textcmdtic && textcmdtic->tic != tic) textcmdtic = textcmdtic->next; - - // Do we have an entry for the tic? If so, look for player. - if (textcmdtic) - { - textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)]; - while (textcmdplayer && textcmdplayer->playernum != playernum) textcmdplayer = textcmdplayer->next; - - if (textcmdplayer) return textcmdplayer->cmd; - } - - return NULL; -} - -// Gets the buffer for the specified ticcmd, creating one if necessary -static UINT8* D_GetTextcmd(tic_t tic, INT32 playernum) -{ - textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; - textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; - textcmdplayer_t *textcmdplayer, **tcpprev; - - // Look for the tic. - while (textcmdtic && textcmdtic->tic != tic) - { - tctprev = &textcmdtic->next; - textcmdtic = textcmdtic->next; - } - - // If we don't have an entry for the tic, make it. - if (!textcmdtic) - { - textcmdtic = *tctprev = Z_Calloc(sizeof (textcmdtic_t), PU_STATIC, NULL); - textcmdtic->tic = tic; - } - - tcpprev = &textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)]; - textcmdplayer = *tcpprev; - - // Look for the player. - while (textcmdplayer && textcmdplayer->playernum != playernum) - { - tcpprev = &textcmdplayer->next; - textcmdplayer = textcmdplayer->next; - } - - // If we don't have an entry for the player, make it. - if (!textcmdplayer) - { - textcmdplayer = *tcpprev = Z_Calloc(sizeof (textcmdplayer_t), PU_STATIC, NULL); - textcmdplayer->playernum = playernum; - } - - return textcmdplayer->cmd; -} - -static void ExtraDataTicker(void) -{ - INT32 i; - - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] || i == 0) - { - UINT8 *bufferstart = D_GetExistingTextcmd(gametic, i); - - if (bufferstart) - { - UINT8 *curpos = bufferstart; - UINT8 *bufferend = &curpos[curpos[0]+1]; - - curpos++; - while (curpos < bufferend) - { - if (*curpos < MAXNETXCMD && listnetxcmd[*curpos]) - { - const UINT8 id = *curpos; - curpos++; - DEBFILE(va("executing x_cmd %s ply %u ", netxcmdnames[id - 1], i)); - (listnetxcmd[id])(&curpos, i); - DEBFILE("done\n"); - } - else - { - if (server) - { - SendKick(i, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - DEBFILE(va("player %d kicked [gametic=%u] reason as follows:\n", i, gametic)); - } - CONS_Alert(CONS_WARNING, M_GetText("Got unknown net command [%s]=%d (max %d)\n"), sizeu1(curpos - bufferstart), *curpos, bufferstart[0]); - break; - } - } - } - } - - // If you are a client, you can safely forget the net commands for this tic - // If you are the server, you need to remember them until every client has been acknowledged, - // because if you need to resend a PT_SERVERTICS packet, you will need to put the commands in it - if (client) - D_FreeTextcmd(gametic); -} - -static void D_Clearticcmd(tic_t tic) -{ - INT32 i; - - D_FreeTextcmd(tic); - - for (i = 0; i < MAXPLAYERS; i++) - netcmds[tic%BACKUPTICS][i].angleturn = 0; - - DEBFILE(va("clear tic %5u (%2u)\n", tic, tic%BACKUPTICS)); -} - -void D_ResetTiccmds(void) -{ - INT32 i; - - memset(&localcmds, 0, sizeof(ticcmd_t)); - memset(&localcmds2, 0, sizeof(ticcmd_t)); - - // Reset the net command list - for (i = 0; i < TEXTCMD_HASH_SIZE; i++) - while (textcmds[i]) - D_Clearticcmd(textcmds[i]->tic); -} - -void SendKick(UINT8 playernum, UINT8 msg) -{ - UINT8 buf[2]; - - if (!(server && cv_rejointimeout.value)) - msg &= ~KICK_MSG_KEEP_BODY; - - buf[0] = playernum; - buf[1] = msg; - SendNetXCmd(XD_KICK, &buf, 2); -} - -// ----------------------------------------------------------------- -// end of extra data function -// ----------------------------------------------------------------- - -// ----------------------------------------------------------------- -// extra data function for lmps -// ----------------------------------------------------------------- - -// if extradatabit is set, after the ziped tic you find this: -// -// type | description -// ---------+-------------- -// byte | size of the extradata -// byte | the extradata (xd) bits: see XD_... -// with this byte you know what parameter folow -// if (xd & XDNAMEANDCOLOR) -// byte | color -// char[MAXPLAYERNAME] | name of the player -// endif -// if (xd & XD_WEAPON_PREF) -// byte | original weapon switch: boolean, true if use the old -// | weapon switch methode -// char[NUMWEAPONS] | the weapon switch priority -// byte | autoaim: true if use the old autoaim system -// endif -/*boolean AddLmpExtradata(UINT8 **demo_point, INT32 playernum) -{ - UINT8 *textcmd = D_GetExistingTextcmd(gametic, playernum); - - if (!textcmd) - return false; - - M_Memcpy(*demo_point, textcmd, textcmd[0]+1); - *demo_point += textcmd[0]+1; - return true; -} - -void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum) -{ - UINT8 nextra; - UINT8 *textcmd; - - if (!demo_pointer) - return; - - textcmd = D_GetTextcmd(gametic, playernum); - nextra = **demo_pointer; - M_Memcpy(textcmd, *demo_pointer, nextra + 1); - // increment demo pointer - *demo_pointer += nextra + 1; -}*/ - -// ----------------------------------------------------------------- -// end extra data function for lmps -// ----------------------------------------------------------------- - -static INT16 Consistancy(void); - #define SAVEGAMESIZE (768*1024) -static boolean SV_ResendingSavegameToAnyone(void) +boolean SV_ResendingSavegameToAnyone(void) { INT32 i; @@ -2005,22 +1634,6 @@ void SV_StartSinglePlayerServer(void) multiplayer = true; } -// used at txtcmds received to check packetsize bound -static size_t TotalTextCmdPerTic(tic_t tic) -{ - INT32 i; - size_t total = 1; // num of textcmds in the tic (ntextcmd byte) - - for (i = 0; i < MAXPLAYERS; i++) - { - UINT8 *textcmd = D_GetExistingTextcmd(tic, i); - if ((!i || playeringame[i]) && textcmd) - total += 2 + textcmd[0]; // "+2" for size and playernum - } - - return total; -} - /** Called when a PT_SERVERSHUTDOWN packet is received * * \param node The packet sender (should be the server) @@ -2051,168 +1664,6 @@ static void HandleTimeout(SINT8 node) M_StartMessage(M_GetText("Server Timeout\n\nPress Esc\n"), NULL, MM_NOTHING); } -static void PT_ClientCmd(SINT8 node, INT32 netconsole) -{ - tic_t realend, realstart; - - if (client) - return; - - // To save bytes, only the low byte of tic numbers are sent - // Use ExpandTics to figure out what the rest of the bytes are - realstart = ExpandTics(netbuffer->u.clientpak.client_tic, node); - realend = ExpandTics(netbuffer->u.clientpak.resendfrom, node); - - if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS - || netbuffer->packettype == PT_NODEKEEPALIVEMIS - || netnodes[node].supposedtic < realend) - { - netnodes[node].supposedtic = realend; - } - // Discard out of order packet - if (netnodes[node].tic > realend) - { - DEBFILE(va("out of order ticcmd discarded nettics = %u\n", netnodes[node].tic)); - return; - } - - // Update the nettics - netnodes[node].tic = realend; - - // Don't do anything for packets of type NODEKEEPALIVE? - if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE - || netbuffer->packettype == PT_NODEKEEPALIVEMIS) - return; - - // As long as clients send valid ticcmds, the server can keep running, so reset the timeout - /// \todo Use a separate cvar for that kind of timeout? - netnodes[node].freezetimeout = I_GetTime() + connectiontimeout; - - // Copy ticcmd - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); - - // Check ticcmd for "speed hacks" - if (netcmds[maketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE - || netcmds[maketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].sidemove < -MAXPLMOVE) - { - CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), netconsole); - //D_Clearticcmd(k); - - SendKick(netconsole, KICK_MSG_CON_FAIL); - return; - } - - // Splitscreen cmd - if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) - && netnodes[node].player2 >= 0) - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)netnodes[node].player2], - &netbuffer->u.client2pak.cmd2, 1); - - // Check player consistancy during the level - if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL - && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) - && !SV_ResendingSavegameToAnyone() - && !netnodes[node].resendingsavegame && netnodes[node].savegameresendcooldown <= I_GetTime()) - { - if (cv_resynchattempts.value) - { - // Tell the client we are about to resend them the gamestate - netbuffer->packettype = PT_WILLRESENDGAMESTATE; - HSendPacket(node, true, 0, 0); - - netnodes[node].resendingsavegame = true; - - if (cv_blamecfail.value) - CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), - netconsole+1, player_names[netconsole], - consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy)); - DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", - netconsole, realstart, consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy))); - return; - } - else - { - SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", - netconsole, realstart, consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy))); - return; - } - } -} - -static void PT_TextCmd(SINT8 node, INT32 netconsole) -{ - if (client) - return; - - // splitscreen special - if (netbuffer->packettype == PT_TEXTCMD2) - netconsole = netnodes[node].player2; - - if (netconsole < 0 || netconsole >= MAXPLAYERS) - Net_UnAcknowledgePacket(node); - else - { - size_t j; - tic_t tic = maketic; - UINT8 *textcmd; - - // ignore if the textcmd has a reported size of zero - // this shouldn't be sent at all - if (!netbuffer->u.textcmd[0]) - { - DEBFILE(va("GetPacket: Textcmd with size 0 detected! (node %u, player %d)\n", - node, netconsole)); - Net_UnAcknowledgePacket(node); - return; - } - - // ignore if the textcmd size var is actually larger than it should be - // BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength - if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1) - { - DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n", - netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1), - node, netconsole)); - Net_UnAcknowledgePacket(node); - return; - } - - // check if tic that we are making isn't too large else we cannot send it :( - // doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time - j = software_MAXPACKETLENGTH - - (netbuffer->u.textcmd[0]+2+BASESERVERTICSSIZE - + (doomcom->numslots+1)*sizeof(ticcmd_t)); - - // search a tic that have enougth space in the ticcmd - while ((textcmd = D_GetExistingTextcmd(tic, netconsole)), - (TotalTextCmdPerTic(tic) > j || netbuffer->u.textcmd[0] + (textcmd ? textcmd[0] : 0) > MAXTEXTCMD) - && tic < firstticstosend + BACKUPTICS) - tic++; - - if (tic >= firstticstosend + BACKUPTICS) - { - DEBFILE(va("GetPacket: Textcmd too long (max %s, used %s, mak %d, " - "tosend %u, node %u, player %d)\n", sizeu1(j), sizeu2(TotalTextCmdPerTic(maketic)), - maketic, firstticstosend, node, netconsole)); - Net_UnAcknowledgePacket(node); - return; - } - - // Make sure we have a buffer - if (!textcmd) textcmd = D_GetTextcmd(tic, netconsole); - - DEBFILE(va("textcmd put in tic %u at position %d (player %d) ftts %u mk %u\n", - tic, textcmd[0]+1, netconsole, firstticstosend, maketic)); - - M_Memcpy(&textcmd[textcmd[0]+1], netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]); - textcmd[0] += (UINT8)netbuffer->u.textcmd[0]; - } -} - static void PT_Login(SINT8 node, INT32 netconsole) { (void)node; @@ -2314,81 +1765,6 @@ static void PT_ReceivedGamestate(SINT8 node) netnodes[node].savegameresendcooldown = I_GetTime() + 5 * TICRATE; } -static void PT_ServerTics(SINT8 node, INT32 netconsole) -{ - UINT8 *pak, *txtpak, numtxtpak; - tic_t realend, realstart; - - if (!netnodes[node].ingame) - { - // Do not remove my own server (we have just get a out of order packet) - if (node != servernode) - { - DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype)); - Net_CloseConnection(node); - } - return; - } - - // Only accept PT_SERVERTICS from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_SERVERTICS", node); - if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - return; - } - - realstart = netbuffer->u.serverpak.starttic; - realend = realstart + netbuffer->u.serverpak.numtics; - - txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots - * netbuffer->u.serverpak.numtics]; - - if (realend > gametic + CLIENTBACKUPTICS) - realend = gametic + CLIENTBACKUPTICS; - cl_packetmissed = realstart > neededtic; - - if (realstart <= neededtic && realend > neededtic) - { - tic_t i, j; - pak = (UINT8 *)&netbuffer->u.serverpak.cmds; - - for (i = realstart; i < realend; i++) - { - // clear first - D_Clearticcmd(i); - - // copy the tics - pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak, - netbuffer->u.serverpak.numslots*sizeof (ticcmd_t)); - - // copy the textcmds - numtxtpak = *txtpak++; - for (j = 0; j < numtxtpak; j++) - { - INT32 k = *txtpak++; // playernum - const size_t txtsize = txtpak[0]+1; - - if (i >= gametic) // Don't copy old net commands - M_Memcpy(D_GetTextcmd(i, k), txtpak, txtsize); - txtpak += txtsize; - } - } - - neededtic = realend; - } - else - { - DEBFILE(va("frame not in bound: %u\n", neededtic)); - /*if (realend < neededtic - 2 * TICRATE || neededtic + 2 * TICRATE < realstart) - I_Error("Received an out of order PT_SERVERTICS packet!\n" - "Got tics %d-%d, needed tic %d\n\n" - "Please report this crash on the Master Board,\n" - "IRC or Discord so it can be fixed.\n", (INT32)realstart, (INT32)realend, (INT32)neededtic);*/ - } -} - static void PT_Ping(SINT8 node, INT32 netconsole) { // Only accept PT_PING from the server. @@ -2602,7 +1978,7 @@ void GetPackets(void) // no more use random generator, because at very first tic isn't yet synchronized // Note: It is called consistAncy on purpose. // -static INT16 Consistancy(void) +INT16 Consistancy(void) { INT32 i; UINT32 ret = 0; @@ -2708,239 +2084,11 @@ static INT16 Consistancy(void) return (INT16)(ret & 0xFFFF); } -// send the client packet to the server -static void CL_SendClientCmd(void) -{ - size_t packetsize = 0; - - netbuffer->packettype = PT_CLIENTCMD; - - if (cl_packetmissed) - netbuffer->packettype++; - netbuffer->u.clientpak.resendfrom = (UINT8)(neededtic & UINT8_MAX); - netbuffer->u.clientpak.client_tic = (UINT8)(gametic & UINT8_MAX); - - if (gamestate == GS_WAITINGPLAYERS) - { - // Send PT_NODEKEEPALIVE packet - netbuffer->packettype += 4; - packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16); - HSendPacket(servernode, false, 0, packetsize); - } - else if (gamestate != GS_NULL && (addedtogame || dedicated)) - { - G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1); - netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]); - - // Send a special packet with 2 cmd for splitscreen - if (splitscreen || botingame) - { - netbuffer->packettype += 2; - G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1); - packetsize = sizeof (client2cmd_pak); - } - else - packetsize = sizeof (clientcmd_pak); - - HSendPacket(servernode, false, 0, packetsize); - } - - if (cl_mode == CL_CONNECTED || dedicated) - { - // Send extra data if needed - if (localtextcmd[0]) - { - netbuffer->packettype = PT_TEXTCMD; - M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1); - // All extra data have been sent - if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail... - localtextcmd[0] = 0; - } - - // Send extra data if needed for player 2 (splitscreen) - if (localtextcmd2[0]) - { - netbuffer->packettype = PT_TEXTCMD2; - M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1); - // All extra data have been sent - if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail... - localtextcmd2[0] = 0; - } - } -} - -// send the server packet -// send tic from firstticstosend to maketic-1 -static void SV_SendTics(void) -{ - tic_t realfirsttic, lasttictosend, i; - UINT32 n; - INT32 j; - size_t packsize; - UINT8 *bufpos; - UINT8 *ntextcmd; - - // send to all client but not to me - // for each node create a packet with x tics and send it - // x is computed using netnodes[n].supposedtic, max packet size and maketic - for (n = 1; n < MAXNETNODES; n++) - if (netnodes[n].ingame) - { - // assert netnodes[n].supposedtic>=netnodes[n].tic - realfirsttic = netnodes[n].supposedtic; - lasttictosend = min(maketic, netnodes[n].tic + CLIENTBACKUPTICS); - - if (realfirsttic >= lasttictosend) - { - // well we have sent all tics we will so use extrabandwidth - // to resent packet that are supposed lost (this is necessary since lost - // packet detection work when we have received packet with firsttic > neededtic - // (getpacket servertics case) - DEBFILE(va("Nothing to send node %u mak=%u sup=%u net=%u \n", - n, maketic, netnodes[n].supposedtic, netnodes[n].tic)); - realfirsttic = netnodes[n].tic; - if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3) - // all tic are ok - continue; - DEBFILE(va("Sent %d anyway\n", realfirsttic)); - } - if (realfirsttic < firstticstosend) - realfirsttic = firstticstosend; - - // compute the length of the packet and cut it if too large - packsize = BASESERVERTICSSIZE; - for (i = realfirsttic; i < lasttictosend; i++) - { - packsize += sizeof (ticcmd_t) * doomcom->numslots; - packsize += TotalTextCmdPerTic(i); - - if (packsize > software_MAXPACKETLENGTH) - { - DEBFILE(va("packet too large (%s) at tic %d (should be from %d to %d)\n", - sizeu1(packsize), i, realfirsttic, lasttictosend)); - lasttictosend = i; - - // too bad: too much player have send extradata and there is too - // much data in one tic. - // To avoid it put the data on the next tic. (see getpacket - // textcmd case) but when numplayer changes the computation can be different - if (lasttictosend == realfirsttic) - { - if (packsize > MAXPACKETLENGTH) - I_Error("Too many players: can't send %s data for %d players to node %d\n" - "Well sorry nobody is perfect....\n", - sizeu1(packsize), doomcom->numslots, n); - else - { - lasttictosend++; // send it anyway! - DEBFILE("sending it anyway\n"); - } - } - break; - } - } - - // Send the tics - netbuffer->packettype = PT_SERVERTICS; - netbuffer->u.serverpak.starttic = realfirsttic; - netbuffer->u.serverpak.numtics = (UINT8)(lasttictosend - realfirsttic); - netbuffer->u.serverpak.numslots = (UINT8)SHORT(doomcom->numslots); - bufpos = (UINT8 *)&netbuffer->u.serverpak.cmds; - - for (i = realfirsttic; i < lasttictosend; i++) - { - bufpos = G_DcpyTiccmd(bufpos, netcmds[i%BACKUPTICS], doomcom->numslots * sizeof (ticcmd_t)); - } - - // add textcmds - for (i = realfirsttic; i < lasttictosend; i++) - { - ntextcmd = bufpos++; - *ntextcmd = 0; - for (j = 0; j < MAXPLAYERS; j++) - { - UINT8 *textcmd = D_GetExistingTextcmd(i, j); - INT32 size = textcmd ? textcmd[0] : 0; - - if ((!j || playeringame[j]) && size) - { - (*ntextcmd)++; - WRITEUINT8(bufpos, j); - M_Memcpy(bufpos, textcmd, size + 1); - bufpos += size + 1; - } - } - } - packsize = bufpos - (UINT8 *)&(netbuffer->u); - - HSendPacket(n, false, 0, packsize); - // when tic are too large, only one tic is sent so don't go backward! - if (lasttictosend-doomcom->extratics > realfirsttic) - netnodes[n].supposedtic = lasttictosend-doomcom->extratics; - else - netnodes[n].supposedtic = lasttictosend; - if (netnodes[n].supposedtic < netnodes[n].tic) netnodes[n].supposedtic = netnodes[n].tic; - } - // node 0 is me! - netnodes[0].supposedtic = maketic; -} - -// -// TryRunTics -// -static void Local_Maketic(INT32 realtics) -{ - I_OsPolling(); // I_Getevent - D_ProcessEvents(); // menu responder, cons responder, - // game responder calls HU_Responder, AM_Responder, - // and G_MapEventsToControls - if (!dedicated) rendergametic = gametic; - // translate inputs (keyboard/mouse/gamepad) into game controls - G_BuildTiccmd(&localcmds, realtics, 1); - if (splitscreen || botingame) - G_BuildTiccmd(&localcmds2, realtics, 2); - - localcmds.angleturn |= TICCMD_RECEIVED; - localcmds2.angleturn |= TICCMD_RECEIVED; -} - -// create missed tic -static void SV_Maketic(void) -{ - INT32 i; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - - // We didn't receive this tic - if ((netcmds[maketic % BACKUPTICS][i].angleturn & TICCMD_RECEIVED) == 0) - { - ticcmd_t * ticcmd = &netcmds[(maketic ) % BACKUPTICS][i]; - ticcmd_t *prevticcmd = &netcmds[(maketic - 1) % BACKUPTICS][i]; - - if (players[i].quittime) - { - // Copy the angle/aiming from the previous tic - // and empty the other inputs - memset(ticcmd, 0, sizeof(netcmds[0][0])); - ticcmd->angleturn = prevticcmd->angleturn | TICCMD_RECEIVED; - ticcmd->aiming = prevticcmd->aiming; - } - else - { - DEBFILE(va("MISS tic%4d for player %d\n", maketic, i)); - // Copy the input from the previous tic - *ticcmd = *prevticcmd; - ticcmd->angleturn &= ~TICCMD_RECEIVED; - } - } - } - - // all tic are now proceed make the next - maketic++; -} +/* +Ping Update except better: +We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out. +If they're not lagging, decrement the timer by 1. Of course, reset all of this if they leave. +*/ boolean TryRunTics(tic_t realtics) { @@ -3049,12 +2197,6 @@ boolean TryRunTics(tic_t realtics) return ticking; } -/* -Ping Update except better: -We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out. -If they're not lagging, decrement the timer by 1. Of course, reset all of this if they leave. -*/ - static INT32 pingtimeout[MAXPLAYERS]; static inline void PingUpdate(void) diff --git a/src/netcode/d_clisrv.h b/src/netcode/d_clisrv.h index b8da645ba..8b73170da 100644 --- a/src/netcode/d_clisrv.h +++ b/src/netcode/d_clisrv.h @@ -378,6 +378,7 @@ extern boolean acceptnewnode; extern SINT8 servernode; extern tic_t maketic; extern tic_t neededtic; +extern INT16 consistancy[BACKUPTICS]; void Command_Ping_f(void); extern tic_t connectiontimeout; @@ -391,20 +392,15 @@ extern consvar_t cv_resynchattempts, cv_blamecfail; extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed; // Used in d_net, the only dependence -tic_t ExpandTics(INT32 low, INT32 node); void D_ClientServerInit(void); -// Initialise the other field -void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)); -void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam); -void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player -void SendKick(UINT8 playernum, UINT8 msg); - // Create any new ticcmds and broadcast to other players. void NetUpdate(void); void GetPackets(void); void ResetNode(INT32 node); +INT16 Consistancy(void); +boolean SV_ResendingSavegameToAnyone(void); void SV_StartSinglePlayerServer(void); void SV_SpawnServer(void); @@ -440,10 +436,8 @@ extern char motd[254], server_context[8]; extern UINT8 playernode[MAXPLAYERS]; INT32 D_NumPlayers(void); -void D_ResetTiccmds(void); tic_t GetLag(INT32 node); -UINT8 GetFreeXCmdSize(void); void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest); diff --git a/src/netcode/d_net.c b/src/netcode/d_net.c index ae0605001..972342282 100644 --- a/src/netcode/d_net.c +++ b/src/netcode/d_net.c @@ -26,6 +26,7 @@ #include "../w_wad.h" #include "d_netfil.h" #include "d_clisrv.h" +#include "tic_command.h" #include "../z_zone.h" #include "i_tcp.h" #include "../d_main.h" // srb2home diff --git a/src/netcode/d_netcmd.c b/src/netcode/d_netcmd.c index fe4cf22bd..0d1785510 100644 --- a/src/netcode/d_netcmd.c +++ b/src/netcode/d_netcmd.c @@ -37,6 +37,7 @@ #include "../m_cheat.h" #include "d_clisrv.h" #include "server_connection.h" +#include "net_command.h" #include "d_net.h" #include "../v_video.h" #include "../d_main.h" diff --git a/src/netcode/d_netfil.c b/src/netcode/d_netfil.c index 80fa06852..e581be2ac 100644 --- a/src/netcode/d_netfil.c +++ b/src/netcode/d_netfil.c @@ -42,6 +42,7 @@ #include "d_net.h" #include "../w_wad.h" #include "d_netfil.h" +#include "net_command.h" #include "../z_zone.h" #include "../byteptr.h" #include "../p_setup.h" diff --git a/src/netcode/net_command.c b/src/netcode/net_command.c new file mode 100644 index 000000000..eeb479d21 --- /dev/null +++ b/src/netcode/net_command.c @@ -0,0 +1,315 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file net_command.c +/// \brief Net command handling + +#include "net_command.h" +#include "tic_command.h" +#include "d_clisrv.h" +#include "i_net.h" +#include "../g_game.h" +#include "../z_zone.h" +#include "../doomtype.h" + +textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL}; +UINT8 localtextcmd[MAXTEXTCMD]; +UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen +static void (*listnetxcmd[MAXNETXCMD])(UINT8 **p, INT32 playernum); + +void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)) +{ +#ifdef PARANOIA + if (id >= MAXNETXCMD) + I_Error("Command id %d too big", id); + if (listnetxcmd[id] != 0) + I_Error("Command id %d already used", id); +#endif + listnetxcmd[id] = cmd_f; +} + +void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam) +{ + if (localtextcmd[0]+2+nparam > MAXTEXTCMD) + { + // for future reference: if (cv_debug) != debug disabled. + CONS_Alert(CONS_ERROR, M_GetText("NetXCmd buffer full, cannot add netcmd %d! (size: %d, needed: %s)\n"), id, localtextcmd[0], sizeu1(nparam)); + return; + } + localtextcmd[0]++; + localtextcmd[localtextcmd[0]] = (UINT8)id; + if (param && nparam) + { + M_Memcpy(&localtextcmd[localtextcmd[0]+1], param, nparam); + localtextcmd[0] = (UINT8)(localtextcmd[0] + (UINT8)nparam); + } +} + +// splitscreen player +void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam) +{ + if (localtextcmd2[0]+2+nparam > MAXTEXTCMD) + { + I_Error("No more place in the buffer for netcmd %d\n",id); + return; + } + localtextcmd2[0]++; + localtextcmd2[localtextcmd2[0]] = (UINT8)id; + if (param && nparam) + { + M_Memcpy(&localtextcmd2[localtextcmd2[0]+1], param, nparam); + localtextcmd2[0] = (UINT8)(localtextcmd2[0] + (UINT8)nparam); + } +} + +UINT8 GetFreeXCmdSize(void) +{ + // -1 for the size and another -1 for the ID. + return (UINT8)(localtextcmd[0] - 2); +} + +// Frees all textcmd memory for the specified tic +void D_FreeTextcmd(tic_t tic) +{ + textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; + textcmdtic_t *textcmdtic = *tctprev; + + while (textcmdtic && textcmdtic->tic != tic) + { + tctprev = &textcmdtic->next; + textcmdtic = textcmdtic->next; + } + + if (textcmdtic) + { + INT32 i; + + // Remove this tic from the list. + *tctprev = textcmdtic->next; + + // Free all players. + for (i = 0; i < TEXTCMD_HASH_SIZE; i++) + { + textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[i]; + + while (textcmdplayer) + { + textcmdplayer_t *tcpnext = textcmdplayer->next; + Z_Free(textcmdplayer); + textcmdplayer = tcpnext; + } + } + + // Free this tic's own memory. + Z_Free(textcmdtic); + } +} + +// Gets the buffer for the specified ticcmd, or NULL if there isn't one +UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum) +{ + textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; + while (textcmdtic && textcmdtic->tic != tic) textcmdtic = textcmdtic->next; + + // Do we have an entry for the tic? If so, look for player. + if (textcmdtic) + { + textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)]; + while (textcmdplayer && textcmdplayer->playernum != playernum) textcmdplayer = textcmdplayer->next; + + if (textcmdplayer) return textcmdplayer->cmd; + } + + return NULL; +} + +// Gets the buffer for the specified ticcmd, creating one if necessary +UINT8* D_GetTextcmd(tic_t tic, INT32 playernum) +{ + textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; + textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; + textcmdplayer_t *textcmdplayer, **tcpprev; + + // Look for the tic. + while (textcmdtic && textcmdtic->tic != tic) + { + tctprev = &textcmdtic->next; + textcmdtic = textcmdtic->next; + } + + // If we don't have an entry for the tic, make it. + if (!textcmdtic) + { + textcmdtic = *tctprev = Z_Calloc(sizeof (textcmdtic_t), PU_STATIC, NULL); + textcmdtic->tic = tic; + } + + tcpprev = &textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)]; + textcmdplayer = *tcpprev; + + // Look for the player. + while (textcmdplayer && textcmdplayer->playernum != playernum) + { + tcpprev = &textcmdplayer->next; + textcmdplayer = textcmdplayer->next; + } + + // If we don't have an entry for the player, make it. + if (!textcmdplayer) + { + textcmdplayer = *tcpprev = Z_Calloc(sizeof (textcmdplayer_t), PU_STATIC, NULL); + textcmdplayer->playernum = playernum; + } + + return textcmdplayer->cmd; +} + +void ExtraDataTicker(void) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] || i == 0) + { + UINT8 *bufferstart = D_GetExistingTextcmd(gametic, i); + + if (bufferstart) + { + UINT8 *curpos = bufferstart; + UINT8 *bufferend = &curpos[curpos[0]+1]; + + curpos++; + while (curpos < bufferend) + { + if (*curpos < MAXNETXCMD && listnetxcmd[*curpos]) + { + const UINT8 id = *curpos; + curpos++; + DEBFILE(va("executing x_cmd %s ply %u ", netxcmdnames[id - 1], i)); + (listnetxcmd[id])(&curpos, i); + DEBFILE("done\n"); + } + else + { + if (server) + { + SendKick(i, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + DEBFILE(va("player %d kicked [gametic=%u] reason as follows:\n", i, gametic)); + } + CONS_Alert(CONS_WARNING, M_GetText("Got unknown net command [%s]=%d (max %d)\n"), sizeu1(curpos - bufferstart), *curpos, bufferstart[0]); + break; + } + } + } + } + + // If you are a client, you can safely forget the net commands for this tic + // If you are the server, you need to remember them until every client has been acknowledged, + // because if you need to resend a PT_SERVERTICS packet, you will need to put the commands in it + if (client) + D_FreeTextcmd(gametic); +} + +// used at txtcmds received to check packetsize bound +size_t TotalTextCmdPerTic(tic_t tic) +{ + INT32 i; + size_t total = 1; // num of textcmds in the tic (ntextcmd byte) + + for (i = 0; i < MAXPLAYERS; i++) + { + UINT8 *textcmd = D_GetExistingTextcmd(tic, i); + if ((!i || playeringame[i]) && textcmd) + total += 2 + textcmd[0]; // "+2" for size and playernum + } + + return total; +} + +void PT_TextCmd(SINT8 node, INT32 netconsole) +{ + if (client) + return; + + // splitscreen special + if (netbuffer->packettype == PT_TEXTCMD2) + netconsole = netnodes[node].player2; + + if (netconsole < 0 || netconsole >= MAXPLAYERS) + Net_UnAcknowledgePacket(node); + else + { + size_t j; + tic_t tic = maketic; + UINT8 *textcmd; + + // ignore if the textcmd has a reported size of zero + // this shouldn't be sent at all + if (!netbuffer->u.textcmd[0]) + { + DEBFILE(va("GetPacket: Textcmd with size 0 detected! (node %u, player %d)\n", + node, netconsole)); + Net_UnAcknowledgePacket(node); + return; + } + + // ignore if the textcmd size var is actually larger than it should be + // BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength + if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1) + { + DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n", + netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1), + node, netconsole)); + Net_UnAcknowledgePacket(node); + return; + } + + // check if tic that we are making isn't too large else we cannot send it :( + // doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time + j = software_MAXPACKETLENGTH + - (netbuffer->u.textcmd[0]+2+BASESERVERTICSSIZE + + (doomcom->numslots+1)*sizeof(ticcmd_t)); + + // search a tic that have enougth space in the ticcmd + while ((textcmd = D_GetExistingTextcmd(tic, netconsole)), + (TotalTextCmdPerTic(tic) > j || netbuffer->u.textcmd[0] + (textcmd ? textcmd[0] : 0) > MAXTEXTCMD) + && tic < firstticstosend + BACKUPTICS) + tic++; + + if (tic >= firstticstosend + BACKUPTICS) + { + DEBFILE(va("GetPacket: Textcmd too long (max %s, used %s, mak %d, " + "tosend %u, node %u, player %d)\n", sizeu1(j), sizeu2(TotalTextCmdPerTic(maketic)), + maketic, firstticstosend, node, netconsole)); + Net_UnAcknowledgePacket(node); + return; + } + + // Make sure we have a buffer + if (!textcmd) textcmd = D_GetTextcmd(tic, netconsole); + + DEBFILE(va("textcmd put in tic %u at position %d (player %d) ftts %u mk %u\n", + tic, textcmd[0]+1, netconsole, firstticstosend, maketic)); + + M_Memcpy(&textcmd[textcmd[0]+1], netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]); + textcmd[0] += (UINT8)netbuffer->u.textcmd[0]; + } +} + +void SendKick(UINT8 playernum, UINT8 msg) +{ + UINT8 buf[2]; + + if (!(server && cv_rejointimeout.value)) + msg &= ~KICK_MSG_KEEP_BODY; + + buf[0] = playernum; + buf[1] = msg; + SendNetXCmd(XD_KICK, &buf, 2); +} diff --git a/src/netcode/net_command.h b/src/netcode/net_command.h new file mode 100644 index 000000000..1fc5035c8 --- /dev/null +++ b/src/netcode/net_command.h @@ -0,0 +1,62 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file net_command.h +/// \brief Net command handling + +#ifndef __D_NET_COMMAND__ +#define __D_NET_COMMAND__ + +#include "d_clisrv.h" +#include "../doomtype.h" + +// Must be a power of two +#define TEXTCMD_HASH_SIZE 4 + +typedef struct textcmdplayer_s +{ + INT32 playernum; + UINT8 cmd[MAXTEXTCMD]; + struct textcmdplayer_s *next; +} textcmdplayer_t; + +typedef struct textcmdtic_s +{ + tic_t tic; + textcmdplayer_t *playercmds[TEXTCMD_HASH_SIZE]; + struct textcmdtic_s *next; +} textcmdtic_t; + +extern textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE]; + +extern UINT8 localtextcmd[MAXTEXTCMD]; +extern UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen + +void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)); +void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam); +void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player + +UINT8 GetFreeXCmdSize(void); +void D_FreeTextcmd(tic_t tic); + +// Gets the buffer for the specified ticcmd, or NULL if there isn't one +UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum); + +// Gets the buffer for the specified ticcmd, creating one if necessary +UINT8* D_GetTextcmd(tic_t tic, INT32 playernum); + +void ExtraDataTicker(void); + +// used at txtcmds received to check packetsize bound +size_t TotalTextCmdPerTic(tic_t tic); + +void PT_TextCmd(SINT8 node, INT32 netconsole); +void SendKick(UINT8 playernum, UINT8 msg); + +#endif diff --git a/src/netcode/server_connection.c b/src/netcode/server_connection.c index 9e397b0f3..b776db422 100644 --- a/src/netcode/server_connection.c +++ b/src/netcode/server_connection.c @@ -15,6 +15,7 @@ #include "d_clisrv.h" #include "d_netfil.h" #include "mserv.h" +#include "net_command.h" #include "../byteptr.h" #include "../g_game.h" #include "../g_state.h" diff --git a/src/netcode/tic_command.c b/src/netcode/tic_command.c new file mode 100644 index 000000000..e7df895ff --- /dev/null +++ b/src/netcode/tic_command.c @@ -0,0 +1,504 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file tic_command.c +/// \brief Tic command handling + +#include "tic_command.h" +#include "d_clisrv.h" +#include "net_command.h" +#include "client_connection.h" +#include "i_net.h" +#include "../d_main.h" +#include "../g_game.h" +#include "../i_system.h" +#include "../i_time.h" +#include "../byteptr.h" +#include "../doomstat.h" +#include "../doomtype.h" + +tic_t firstticstosend; // min of the nettics +tic_t tictoclear = 0; // optimize d_clearticcmd +ticcmd_t localcmds; +ticcmd_t localcmds2; +boolean cl_packetmissed; +ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; + +static inline void *G_DcpyTiccmd(void* dest, const ticcmd_t* src, const size_t n) +{ + const size_t d = n / sizeof(ticcmd_t); + const size_t r = n % sizeof(ticcmd_t); + UINT8 *ret = dest; + + if (r) + M_Memcpy(dest, src, n); + else if (d) + G_MoveTiccmd(dest, src, d); + return ret+n; +} + +static inline void *G_ScpyTiccmd(ticcmd_t* dest, void* src, const size_t n) +{ + const size_t d = n / sizeof(ticcmd_t); + const size_t r = n % sizeof(ticcmd_t); + UINT8 *ret = src; + + if (r) + M_Memcpy(dest, src, n); + else if (d) + G_MoveTiccmd(dest, src, d); + return ret+n; +} + +/** Guesses the full value of a tic from its lowest byte, for a specific node + * + * \param low The lowest byte of the tic value + * \param node The node to deduce the tic for + * \return The full tic value + * + */ +tic_t ExpandTics(INT32 low, INT32 node) +{ + INT32 delta; + + delta = low - (netnodes[node].tic & UINT8_MAX); + + if (delta >= -64 && delta <= 64) + return (netnodes[node].tic & ~UINT8_MAX) + low; + else if (delta > 64) + return (netnodes[node].tic & ~UINT8_MAX) - 256 + low; + else //if (delta < -64) + return (netnodes[node].tic & ~UINT8_MAX) + 256 + low; +} + +void D_Clearticcmd(tic_t tic) +{ + INT32 i; + + D_FreeTextcmd(tic); + + for (i = 0; i < MAXPLAYERS; i++) + netcmds[tic%BACKUPTICS][i].angleturn = 0; + + DEBFILE(va("clear tic %5u (%2u)\n", tic, tic%BACKUPTICS)); +} + +void D_ResetTiccmds(void) +{ + INT32 i; + + memset(&localcmds, 0, sizeof(ticcmd_t)); + memset(&localcmds2, 0, sizeof(ticcmd_t)); + + // Reset the net command list + for (i = 0; i < TEXTCMD_HASH_SIZE; i++) + while (textcmds[i]) + D_Clearticcmd(textcmds[i]->tic); +} + +void PT_ClientCmd(SINT8 node, INT32 netconsole) +{ + tic_t realend, realstart; + + if (client) + return; + + // To save bytes, only the low byte of tic numbers are sent + // Use ExpandTics to figure out what the rest of the bytes are + realstart = ExpandTics(netbuffer->u.clientpak.client_tic, node); + realend = ExpandTics(netbuffer->u.clientpak.resendfrom, node); + + if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS + || netbuffer->packettype == PT_NODEKEEPALIVEMIS + || netnodes[node].supposedtic < realend) + { + netnodes[node].supposedtic = realend; + } + // Discard out of order packet + if (netnodes[node].tic > realend) + { + DEBFILE(va("out of order ticcmd discarded nettics = %u\n", netnodes[node].tic)); + return; + } + + // Update the nettics + netnodes[node].tic = realend; + + // Don't do anything for packets of type NODEKEEPALIVE? + if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE + || netbuffer->packettype == PT_NODEKEEPALIVEMIS) + return; + + // As long as clients send valid ticcmds, the server can keep running, so reset the timeout + /// \todo Use a separate cvar for that kind of timeout? + netnodes[node].freezetimeout = I_GetTime() + connectiontimeout; + + // Copy ticcmd + G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); + + // Check ticcmd for "speed hacks" + if (netcmds[maketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE + || netcmds[maketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].sidemove < -MAXPLMOVE) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), netconsole); + //D_Clearticcmd(k); + + SendKick(netconsole, KICK_MSG_CON_FAIL); + return; + } + + // Splitscreen cmd + if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) + && netnodes[node].player2 >= 0) + G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)netnodes[node].player2], + &netbuffer->u.client2pak.cmd2, 1); + + // Check player consistancy during the level + if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL + && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) + && !SV_ResendingSavegameToAnyone() + && !netnodes[node].resendingsavegame && netnodes[node].savegameresendcooldown <= I_GetTime()) + { + if (cv_resynchattempts.value) + { + // Tell the client we are about to resend them the gamestate + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + HSendPacket(node, true, 0, 0); + + netnodes[node].resendingsavegame = true; + + if (cv_blamecfail.value) + CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), + netconsole+1, player_names[netconsole], + consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy)); + DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", + netconsole, realstart, consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy))); + return; + } + else + { + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", + netconsole, realstart, consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy))); + return; + } + } +} + +void PT_ServerTics(SINT8 node, INT32 netconsole) +{ + UINT8 *pak, *txtpak, numtxtpak; + tic_t realend, realstart; + + if (!netnodes[node].ingame) + { + // Do not remove my own server (we have just get a out of order packet) + if (node != servernode) + { + DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype)); + Net_CloseConnection(node); + } + return; + } + + // Only accept PT_SERVERTICS from the server. + if (node != servernode) + { + CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_SERVERTICS", node); + if (server) + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + return; + } + + realstart = netbuffer->u.serverpak.starttic; + realend = realstart + netbuffer->u.serverpak.numtics; + + txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots + * netbuffer->u.serverpak.numtics]; + + if (realend > gametic + CLIENTBACKUPTICS) + realend = gametic + CLIENTBACKUPTICS; + cl_packetmissed = realstart > neededtic; + + if (realstart <= neededtic && realend > neededtic) + { + tic_t i, j; + pak = (UINT8 *)&netbuffer->u.serverpak.cmds; + + for (i = realstart; i < realend; i++) + { + // clear first + D_Clearticcmd(i); + + // copy the tics + pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak, + netbuffer->u.serverpak.numslots*sizeof (ticcmd_t)); + + // copy the textcmds + numtxtpak = *txtpak++; + for (j = 0; j < numtxtpak; j++) + { + INT32 k = *txtpak++; // playernum + const size_t txtsize = txtpak[0]+1; + + if (i >= gametic) // Don't copy old net commands + M_Memcpy(D_GetTextcmd(i, k), txtpak, txtsize); + txtpak += txtsize; + } + } + + neededtic = realend; + } + else + { + DEBFILE(va("frame not in bound: %u\n", neededtic)); + /*if (realend < neededtic - 2 * TICRATE || neededtic + 2 * TICRATE < realstart) + I_Error("Received an out of order PT_SERVERTICS packet!\n" + "Got tics %d-%d, needed tic %d\n\n" + "Please report this crash on the Master Board,\n" + "IRC or Discord so it can be fixed.\n", (INT32)realstart, (INT32)realend, (INT32)neededtic);*/ + } +} + +// send the client packet to the server +void CL_SendClientCmd(void) +{ + size_t packetsize = 0; + + netbuffer->packettype = PT_CLIENTCMD; + + if (cl_packetmissed) + netbuffer->packettype++; + netbuffer->u.clientpak.resendfrom = (UINT8)(neededtic & UINT8_MAX); + netbuffer->u.clientpak.client_tic = (UINT8)(gametic & UINT8_MAX); + + if (gamestate == GS_WAITINGPLAYERS) + { + // Send PT_NODEKEEPALIVE packet + netbuffer->packettype += 4; + packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16); + HSendPacket(servernode, false, 0, packetsize); + } + else if (gamestate != GS_NULL && (addedtogame || dedicated)) + { + G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1); + netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]); + + // Send a special packet with 2 cmd for splitscreen + if (splitscreen || botingame) + { + netbuffer->packettype += 2; + G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1); + packetsize = sizeof (client2cmd_pak); + } + else + packetsize = sizeof (clientcmd_pak); + + HSendPacket(servernode, false, 0, packetsize); + } + + if (cl_mode == CL_CONNECTED || dedicated) + { + // Send extra data if needed + if (localtextcmd[0]) + { + netbuffer->packettype = PT_TEXTCMD; + M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1); + // All extra data have been sent + if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail... + localtextcmd[0] = 0; + } + + // Send extra data if needed for player 2 (splitscreen) + if (localtextcmd2[0]) + { + netbuffer->packettype = PT_TEXTCMD2; + M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1); + // All extra data have been sent + if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail... + localtextcmd2[0] = 0; + } + } +} + +// send the server packet +// send tic from firstticstosend to maketic-1 +void SV_SendTics(void) +{ + tic_t realfirsttic, lasttictosend, i; + UINT32 n; + INT32 j; + size_t packsize; + UINT8 *bufpos; + UINT8 *ntextcmd; + + // send to all client but not to me + // for each node create a packet with x tics and send it + // x is computed using netnodes[n].supposedtic, max packet size and maketic + for (n = 1; n < MAXNETNODES; n++) + if (netnodes[n].ingame) + { + // assert netnodes[n].supposedtic>=netnodes[n].tic + realfirsttic = netnodes[n].supposedtic; + lasttictosend = min(maketic, netnodes[n].tic + CLIENTBACKUPTICS); + + if (realfirsttic >= lasttictosend) + { + // well we have sent all tics we will so use extrabandwidth + // to resent packet that are supposed lost (this is necessary since lost + // packet detection work when we have received packet with firsttic > neededtic + // (getpacket servertics case) + DEBFILE(va("Nothing to send node %u mak=%u sup=%u net=%u \n", + n, maketic, netnodes[n].supposedtic, netnodes[n].tic)); + realfirsttic = netnodes[n].tic; + if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3) + // all tic are ok + continue; + DEBFILE(va("Sent %d anyway\n", realfirsttic)); + } + if (realfirsttic < firstticstosend) + realfirsttic = firstticstosend; + + // compute the length of the packet and cut it if too large + packsize = BASESERVERTICSSIZE; + for (i = realfirsttic; i < lasttictosend; i++) + { + packsize += sizeof (ticcmd_t) * doomcom->numslots; + packsize += TotalTextCmdPerTic(i); + + if (packsize > software_MAXPACKETLENGTH) + { + DEBFILE(va("packet too large (%s) at tic %d (should be from %d to %d)\n", + sizeu1(packsize), i, realfirsttic, lasttictosend)); + lasttictosend = i; + + // too bad: too much player have send extradata and there is too + // much data in one tic. + // To avoid it put the data on the next tic. (see getpacket + // textcmd case) but when numplayer changes the computation can be different + if (lasttictosend == realfirsttic) + { + if (packsize > MAXPACKETLENGTH) + I_Error("Too many players: can't send %s data for %d players to node %d\n" + "Well sorry nobody is perfect....\n", + sizeu1(packsize), doomcom->numslots, n); + else + { + lasttictosend++; // send it anyway! + DEBFILE("sending it anyway\n"); + } + } + break; + } + } + + // Send the tics + netbuffer->packettype = PT_SERVERTICS; + netbuffer->u.serverpak.starttic = realfirsttic; + netbuffer->u.serverpak.numtics = (UINT8)(lasttictosend - realfirsttic); + netbuffer->u.serverpak.numslots = (UINT8)SHORT(doomcom->numslots); + bufpos = (UINT8 *)&netbuffer->u.serverpak.cmds; + + for (i = realfirsttic; i < lasttictosend; i++) + { + bufpos = G_DcpyTiccmd(bufpos, netcmds[i%BACKUPTICS], doomcom->numslots * sizeof (ticcmd_t)); + } + + // add textcmds + for (i = realfirsttic; i < lasttictosend; i++) + { + ntextcmd = bufpos++; + *ntextcmd = 0; + for (j = 0; j < MAXPLAYERS; j++) + { + UINT8 *textcmd = D_GetExistingTextcmd(i, j); + INT32 size = textcmd ? textcmd[0] : 0; + + if ((!j || playeringame[j]) && size) + { + (*ntextcmd)++; + WRITEUINT8(bufpos, j); + M_Memcpy(bufpos, textcmd, size + 1); + bufpos += size + 1; + } + } + } + packsize = bufpos - (UINT8 *)&(netbuffer->u); + + HSendPacket(n, false, 0, packsize); + // when tic are too large, only one tic is sent so don't go backward! + if (lasttictosend-doomcom->extratics > realfirsttic) + netnodes[n].supposedtic = lasttictosend-doomcom->extratics; + else + netnodes[n].supposedtic = lasttictosend; + if (netnodes[n].supposedtic < netnodes[n].tic) netnodes[n].supposedtic = netnodes[n].tic; + } + // node 0 is me! + netnodes[0].supposedtic = maketic; +} + +// +// TryRunTics +// +void Local_Maketic(INT32 realtics) +{ + I_OsPolling(); // I_Getevent + D_ProcessEvents(); // menu responder, cons responder, + // game responder calls HU_Responder, AM_Responder, + // and G_MapEventsToControls + if (!dedicated) rendergametic = gametic; + // translate inputs (keyboard/mouse/gamepad) into game controls + G_BuildTiccmd(&localcmds, realtics, 1); + if (splitscreen || botingame) + G_BuildTiccmd(&localcmds2, realtics, 2); + + localcmds.angleturn |= TICCMD_RECEIVED; + localcmds2.angleturn |= TICCMD_RECEIVED; +} + +// create missed tic +void SV_Maketic(void) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + // We didn't receive this tic + if ((netcmds[maketic % BACKUPTICS][i].angleturn & TICCMD_RECEIVED) == 0) + { + ticcmd_t * ticcmd = &netcmds[(maketic ) % BACKUPTICS][i]; + ticcmd_t *prevticcmd = &netcmds[(maketic - 1) % BACKUPTICS][i]; + + if (players[i].quittime) + { + // Copy the angle/aiming from the previous tic + // and empty the other inputs + memset(ticcmd, 0, sizeof(netcmds[0][0])); + ticcmd->angleturn = prevticcmd->angleturn | TICCMD_RECEIVED; + ticcmd->aiming = prevticcmd->aiming; + } + else + { + DEBFILE(va("MISS tic%4d for player %d\n", maketic, i)); + // Copy the input from the previous tic + *ticcmd = *prevticcmd; + ticcmd->angleturn &= ~TICCMD_RECEIVED; + } + } + } + + // all tic are now proceed make the next + maketic++; +} diff --git a/src/netcode/tic_command.h b/src/netcode/tic_command.h new file mode 100644 index 000000000..d19f4c1aa --- /dev/null +++ b/src/netcode/tic_command.h @@ -0,0 +1,44 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file tic_command.h +/// \brief Tic command handling + +#ifndef __D_TIC_COMMAND__ +#define __D_TIC_COMMAND__ + +#include "d_clisrv.h" +#include "../d_ticcmd.h" +#include "../doomdef.h" +#include "../doomtype.h" + +extern tic_t firstticstosend; // min of the nettics +extern tic_t tictoclear; // optimize d_clearticcmd + +extern ticcmd_t localcmds; +extern ticcmd_t localcmds2; +extern boolean cl_packetmissed; + +extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; + +tic_t ExpandTics(INT32 low, INT32 node); +void D_Clearticcmd(tic_t tic); +void D_ResetTiccmds(void); + +void PT_ClientCmd(SINT8 node, INT32 netconsole); +void PT_ServerTics(SINT8 node, INT32 netconsole); + +// send the client packet to the server +void CL_SendClientCmd(void); + +void SV_SendTics(void); +void Local_Maketic(INT32 realtics); +void SV_Maketic(void); + +#endif diff --git a/src/p_inter.c b/src/p_inter.c index f3c13e315..f33494d1f 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -30,6 +30,7 @@ #include "m_misc.h" #include "v_video.h" // video flags for CEchos #include "f_finale.h" +#include "netcode/net_command.h" // CTF player names #define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : "" diff --git a/src/p_mobj.c b/src/p_mobj.c index 49c438b3f..e60e81ace 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -36,6 +36,7 @@ #include "p_slopes.h" #include "f_finale.h" #include "m_cond.h" +#include "netcode/net_command.h" static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}}; consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL); diff --git a/src/p_setup.c b/src/p_setup.c index cd9185484..22d48dd0b 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -87,6 +87,8 @@ #include "taglist.h" +#include "netcode/net_command.h" + // // Map MD5, calculated on level load. // Sent to clients in PT_SERVERINFO. diff --git a/src/p_tick.c b/src/p_tick.c index fe6a4d33f..8fb99d737 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -26,6 +26,7 @@ #include "r_main.h" #include "r_fps.h" #include "i_video.h" // rendermode +#include "netcode/net_command.h" // Object place #include "m_cheat.h" diff --git a/src/p_user.c b/src/p_user.c index 1e8dee885..a06bf894f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -19,6 +19,7 @@ #include "i_system.h" #include "d_event.h" #include "netcode/d_net.h" +#include "netcode/net_command.h" #include "g_game.h" #include "p_local.h" #include "r_fps.h" From f1ad1bf13e211ead21da068f3414d62605296f6a Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Thu, 5 Jan 2023 23:48:44 +0100 Subject: [PATCH 52/96] Declare data exchanged through the network to a new file --- src/netcode/d_clisrv.c | 1 + src/netcode/d_clisrv.h | 313 +------------------------------------- src/netcode/d_net.h | 2 + src/netcode/protocol.h | 335 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 339 insertions(+), 312 deletions(-) create mode 100644 src/netcode/protocol.h diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index 06e6da751..b834c92f5 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -53,6 +53,7 @@ #include "client_connection.h" #include "tic_command.h" #include "net_command.h" +#include "protocol.h" // // NETWORKING diff --git a/src/netcode/d_clisrv.h b/src/netcode/d_clisrv.h index 8b73170da..691a2787f 100644 --- a/src/netcode/d_clisrv.h +++ b/src/netcode/d_clisrv.h @@ -13,6 +13,7 @@ #ifndef __D_CLISRV__ #define __D_CLISRV__ +#include "protocol.h" #include "../d_ticcmd.h" #include "d_net.h" #include "d_netcmd.h" @@ -21,85 +22,7 @@ #include "../d_player.h" #include "mserv.h" -/* -The 'packet version' is used to distinguish packet -formats. This version is independent of VERSION and -SUBVERSION. Different applications may follow different -packet versions. - -If you change the struct or the meaning of a field -therein, increment this number. -*/ -#define PACKETVERSION 4 - -// Network play related stuff. -// There is a data struct that stores network -// communication related stuff, and another -// one that defines the actual packets to -// be transmitted. - -// Networking and tick handling related. -#define BACKUPTICS 1024 #define CLIENTBACKUPTICS 32 -#define MAXTEXTCMD 256 -// -// Packet structure -// -typedef enum -{ - PT_NOTHING, // To send a nop through the network. ^_~ - PT_SERVERCFG, // Server config used in start game - // (must stay 1 for backwards compatibility). - // This is a positive response to a CLIENTJOIN request. - PT_CLIENTCMD, // Ticcmd of the client. - PT_CLIENTMIS, // Same as above with but saying resend from. - PT_CLIENT2CMD, // 2 cmds in the packet for splitscreen. - PT_CLIENT2MIS, // Same as above with but saying resend from - PT_NODEKEEPALIVE, // Same but without ticcmd and consistancy - PT_NODEKEEPALIVEMIS, - PT_SERVERTICS, // All cmds for the tic. - PT_SERVERREFUSE, // Server refuses joiner (reason inside). - PT_SERVERSHUTDOWN, - PT_CLIENTQUIT, // Client closes the connection. - - PT_ASKINFO, // Anyone can ask info of the server. - PT_SERVERINFO, // Send game & server info (gamespy). - PT_PLAYERINFO, // Send information for players in game (gamespy). - PT_REQUESTFILE, // Client requests a file transfer - PT_ASKINFOVIAMS, // Packet from the MS requesting info be sent to new client. - // If this ID changes, update masterserver definition. - - PT_WILLRESENDGAMESTATE, // Hey Client, I am about to resend you the gamestate! - PT_CANRECEIVEGAMESTATE, // Okay Server, I'm ready to receive it, you can go ahead. - PT_RECEIVEDGAMESTATE, // Thank you Server, I am ready to play again! - - PT_SENDINGLUAFILE, // Server telling a client Lua needs to open a file - PT_ASKLUAFILE, // Client telling the server they don't have the file - PT_HASLUAFILE, // Client telling the server they have the file - - // Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility. - - PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL - // allows HSendPacket(*, true, *, *) to return false. - // In addition, this packet can't occupy all the available slots. - - PT_FILEFRAGMENT = PT_CANFAIL, // A part of a file. - PT_FILEACK, - PT_FILERECEIVED, - - PT_TEXTCMD, // Extra text commands from the client. - PT_TEXTCMD2, // Splitscreen text commands. - PT_CLIENTJOIN, // Client wants to join; used in start game. - PT_NODETIMEOUT, // Packet sent to self if the connection times out. - - PT_LOGIN, // Login attempt from the client. - - PT_TELLFILESNEEDED, // Client, to server: "what other files do I need starting from this number?" - PT_MOREFILESNEEDED, // Server, to client: "you need these (+ more on top of those)" - - PT_PING, // Packet sent to tell clients the other client's latency to server. - NUMPACKETTYPE -} packettype_t; #ifdef PACKETDROP void Command_Drop(void); @@ -109,229 +32,6 @@ void Command_Droprate(void); void Command_Numnodes(void); #endif -#if defined(_MSC_VER) -#pragma pack(1) -#endif - -// Client to server packet -typedef struct -{ - UINT8 client_tic; - UINT8 resendfrom; - INT16 consistancy; - ticcmd_t cmd; -} ATTRPACK clientcmd_pak; - -// Splitscreen packet -// WARNING: must have the same format of clientcmd_pak, for more easy use -typedef struct -{ - UINT8 client_tic; - UINT8 resendfrom; - INT16 consistancy; - ticcmd_t cmd, cmd2; -} ATTRPACK client2cmd_pak; - -#ifdef _MSC_VER -#pragma warning(disable : 4200) -#endif - -// Server to client packet -// this packet is too large -typedef struct -{ - tic_t starttic; - UINT8 numtics; - UINT8 numslots; // "Slots filled": Highest player number in use plus one. - ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large -} ATTRPACK servertics_pak; - -typedef struct -{ - // Server launch stuffs - UINT8 serverplayer; - UINT8 totalslotnum; // "Slots": highest player number in use plus one. - - tic_t gametic; - UINT8 clientnode; - UINT8 gamestate; - - UINT8 gametype; - UINT8 modifiedgame; - - char server_context[8]; // Unique context id, generated at server startup. -} ATTRPACK serverconfig_pak; - -typedef struct -{ - UINT8 fileid; - UINT32 filesize; - UINT8 iteration; - UINT32 position; - UINT16 size; - UINT8 data[0]; // Size is variable using hardware_MAXPACKETLENGTH -} ATTRPACK filetx_pak; - -typedef struct -{ - UINT32 start; - UINT32 acks; -} ATTRPACK fileacksegment_t; - -typedef struct -{ - UINT8 fileid; - UINT8 iteration; - UINT8 numsegments; - fileacksegment_t segments[0]; -} ATTRPACK fileack_pak; - -#ifdef _MSC_VER -#pragma warning(default : 4200) -#endif - -#define MAXAPPLICATION 16 - -typedef struct -{ - UINT8 modversion; - char application[MAXAPPLICATION]; - UINT8 localplayers; - UINT8 mode; - char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME]; -} ATTRPACK clientconfig_pak; - -#define SV_DEDICATED 0x40 // server is dedicated -#define SV_LOTSOFADDONS 0x20 // flag used to ask for full file list in d_netfil - -enum { - REFUSE_JOINS_DISABLED = 1, - REFUSE_SLOTS_FULL, - REFUSE_BANNED, -}; - -#define MAXSERVERNAME 32 -#define MAXFILENEEDED 915 -// This packet is too large -typedef struct -{ - /* - In the old packet, 'version' is the first field. Now that field is set - to 255 always, so older versions won't be confused with the new - versions or vice-versa. - */ - UINT8 _255; - UINT8 packetversion; - char application[MAXAPPLICATION]; - UINT8 version; - UINT8 subversion; - UINT8 numberofplayer; - UINT8 maxplayer; - UINT8 refusereason; // 0: joinable, REFUSE enum - char gametypename[24]; - UINT8 modifiedgame; - UINT8 cheatsenabled; - UINT8 flags; - UINT8 fileneedednum; - tic_t time; - tic_t leveltime; - char servername[MAXSERVERNAME]; - char mapname[8]; - char maptitle[33]; - unsigned char mapmd5[16]; - UINT8 actnum; - UINT8 iszone; - UINT8 fileneeded[MAXFILENEEDED]; // is filled with writexxx (byteptr.h) -} ATTRPACK serverinfo_pak; - -typedef struct -{ - char reason[255]; -} ATTRPACK serverrefuse_pak; - -typedef struct -{ - UINT8 version; - tic_t time; // used for ping evaluation -} ATTRPACK askinfo_pak; - -typedef struct -{ - char clientaddr[22]; - tic_t time; // used for ping evaluation -} ATTRPACK msaskinfo_pak; - -// Shorter player information for external use. -typedef struct -{ - UINT8 num; - char name[MAXPLAYERNAME+1]; - UINT8 address[4]; // sending another string would run us up against MAXPACKETLENGTH - UINT8 team; - UINT8 skin; - UINT8 data; // Color is first four bits, hasflag, isit and issuper have one bit each, the last is unused. - UINT32 score; - UINT16 timeinserver; // In seconds. -} ATTRPACK plrinfo; - -// Shortest player information for join during intermission. -typedef struct -{ - char name[MAXPLAYERNAME+1]; - UINT8 skin; - UINT16 color; - UINT32 pflags; - UINT32 score; - UINT8 ctfteam; -} ATTRPACK plrconfig; - -typedef struct -{ - INT32 first; - UINT8 num; - UINT8 more; - UINT8 files[MAXFILENEEDED]; // is filled with writexxx (byteptr.h) -} ATTRPACK filesneededconfig_pak; - -// -// Network packet data -// -typedef struct -{ - UINT32 checksum; - UINT8 ack; // If not zero the node asks for acknowledgement, the receiver must resend the ack - UINT8 ackreturn; // The return of the ack number - - UINT8 packettype; - UINT8 reserved; // Padding - union - { - clientcmd_pak clientpak; // 144 bytes - client2cmd_pak client2pak; // 200 bytes - servertics_pak serverpak; // 132495 bytes (more around 360, no?) - serverconfig_pak servercfg; // 773 bytes - UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...) - filetx_pak filetxpak; // 139 bytes - fileack_pak fileack; - UINT8 filereceived; - clientconfig_pak clientcfg; // 136 bytes - UINT8 md5sum[16]; - serverinfo_pak serverinfo; // 1024 bytes - serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...) - askinfo_pak askinfo; // 61 bytes - msaskinfo_pak msaskinfo; // 22 bytes - plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?) - plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?) - INT32 filesneedednum; // 4 bytes - filesneededconfig_pak filesneededcfg; // ??? bytes - UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes - } u; // This is needed to pack diff packet types data together -} ATTRPACK doomdata_t; - -#if defined(_MSC_VER) -#pragma pack() -#endif - extern INT32 mapchangepending; // Points inside doomcom @@ -341,19 +41,8 @@ extern consvar_t cv_showjoinaddress; extern consvar_t cv_playbackspeed; #define BASEPACKETSIZE offsetof(doomdata_t, u) -#define FILETXHEADER offsetof(filetx_pak, data) #define BASESERVERTICSSIZE offsetof(doomdata_t, u.serverpak.cmds[0]) -#define KICK_MSG_GO_AWAY 1 -#define KICK_MSG_CON_FAIL 2 -#define KICK_MSG_PLAYER_QUIT 3 -#define KICK_MSG_TIMEOUT 4 -#define KICK_MSG_BANNED 5 -#define KICK_MSG_PING_HIGH 6 -#define KICK_MSG_CUSTOM_KICK 7 -#define KICK_MSG_CUSTOM_BAN 8 -#define KICK_MSG_KEEP_BODY 0x80 - typedef enum { KR_KICK = 1, //Kicked by server diff --git a/src/netcode/d_net.h b/src/netcode/d_net.h index 803b49d74..857c3463c 100644 --- a/src/netcode/d_net.h +++ b/src/netcode/d_net.h @@ -18,6 +18,8 @@ #ifndef __D_NET__ #define __D_NET__ +#include "../doomtype.h" + // Max computers in a game // 127 is probably as high as this can go, because // SINT8 is used for nodes sometimes >:( diff --git a/src/netcode/protocol.h b/src/netcode/protocol.h new file mode 100644 index 000000000..566d10d8c --- /dev/null +++ b/src/netcode/protocol.h @@ -0,0 +1,335 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file protocol.h +/// \brief Data exchanged through the network + +#ifndef __PROTOCOL__ +#define __PROTOCOL__ + +#include "d_net.h" +#include "../d_ticcmd.h" +#include "../doomdef.h" + +/* +The 'packet version' is used to distinguish packet +formats. This version is independent of VERSION and +SUBVERSION. Different applications may follow different +packet versions. + +If you change the struct or the meaning of a field +therein, increment this number. +*/ +#define PACKETVERSION 4 + +// Network play related stuff. +// There is a data struct that stores network +// communication related stuff, and another +// one that defines the actual packets to +// be transmitted. + +#define BACKUPTICS 1024 +#define MAXTEXTCMD 256 + +// +// Packet structure +// +typedef enum +{ + PT_NOTHING, // To send a nop through the network. ^_~ + PT_SERVERCFG, // Server config used in start game + // (must stay 1 for backwards compatibility). + // This is a positive response to a CLIENTJOIN request. + PT_CLIENTCMD, // Ticcmd of the client. + PT_CLIENTMIS, // Same as above with but saying resend from. + PT_CLIENT2CMD, // 2 cmds in the packet for splitscreen. + PT_CLIENT2MIS, // Same as above with but saying resend from + PT_NODEKEEPALIVE, // Same but without ticcmd and consistancy + PT_NODEKEEPALIVEMIS, + PT_SERVERTICS, // All cmds for the tic. + PT_SERVERREFUSE, // Server refuses joiner (reason inside). + PT_SERVERSHUTDOWN, + PT_CLIENTQUIT, // Client closes the connection. + + PT_ASKINFO, // Anyone can ask info of the server. + PT_SERVERINFO, // Send game & server info (gamespy). + PT_PLAYERINFO, // Send information for players in game (gamespy). + PT_REQUESTFILE, // Client requests a file transfer + PT_ASKINFOVIAMS, // Packet from the MS requesting info be sent to new client. + // If this ID changes, update masterserver definition. + + PT_WILLRESENDGAMESTATE, // Hey Client, I am about to resend you the gamestate! + PT_CANRECEIVEGAMESTATE, // Okay Server, I'm ready to receive it, you can go ahead. + PT_RECEIVEDGAMESTATE, // Thank you Server, I am ready to play again! + + PT_SENDINGLUAFILE, // Server telling a client Lua needs to open a file + PT_ASKLUAFILE, // Client telling the server they don't have the file + PT_HASLUAFILE, // Client telling the server they have the file + + // Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility. + + PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL + // allows HSendPacket(*, true, *, *) to return false. + // In addition, this packet can't occupy all the available slots. + + PT_FILEFRAGMENT = PT_CANFAIL, // A part of a file. + PT_FILEACK, + PT_FILERECEIVED, + + PT_TEXTCMD, // Extra text commands from the client. + PT_TEXTCMD2, // Splitscreen text commands. + PT_CLIENTJOIN, // Client wants to join; used in start game. + PT_NODETIMEOUT, // Packet sent to self if the connection times out. + + PT_LOGIN, // Login attempt from the client. + + PT_TELLFILESNEEDED, // Client, to server: "what other files do I need starting from this number?" + PT_MOREFILESNEEDED, // Server, to client: "you need these (+ more on top of those)" + + PT_PING, // Packet sent to tell clients the other client's latency to server. + NUMPACKETTYPE +} packettype_t; + +#if defined(_MSC_VER) +#pragma pack(1) +#endif + +// Client to server packet +typedef struct +{ + UINT8 client_tic; + UINT8 resendfrom; + INT16 consistancy; + ticcmd_t cmd; +} ATTRPACK clientcmd_pak; + +// Splitscreen packet +// WARNING: must have the same format of clientcmd_pak, for more easy use +typedef struct +{ + UINT8 client_tic; + UINT8 resendfrom; + INT16 consistancy; + ticcmd_t cmd, cmd2; +} ATTRPACK client2cmd_pak; + +#ifdef _MSC_VER +#pragma warning(disable : 4200) +#endif + +// Server to client packet +// this packet is too large +typedef struct +{ + tic_t starttic; + UINT8 numtics; + UINT8 numslots; // "Slots filled": Highest player number in use plus one. + ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large +} ATTRPACK servertics_pak; + +typedef struct +{ + // Server launch stuffs + UINT8 serverplayer; + UINT8 totalslotnum; // "Slots": highest player number in use plus one. + + tic_t gametic; + UINT8 clientnode; + UINT8 gamestate; + + UINT8 gametype; + UINT8 modifiedgame; + + char server_context[8]; // Unique context id, generated at server startup. +} ATTRPACK serverconfig_pak; + +typedef struct +{ + UINT8 fileid; + UINT32 filesize; + UINT8 iteration; + UINT32 position; + UINT16 size; + UINT8 data[0]; // Size is variable using hardware_MAXPACKETLENGTH +} ATTRPACK filetx_pak; + +typedef struct +{ + UINT32 start; + UINT32 acks; +} ATTRPACK fileacksegment_t; + +typedef struct +{ + UINT8 fileid; + UINT8 iteration; + UINT8 numsegments; + fileacksegment_t segments[0]; +} ATTRPACK fileack_pak; + +#ifdef _MSC_VER +#pragma warning(default : 4200) +#endif + +#define MAXAPPLICATION 16 + +typedef struct +{ + UINT8 modversion; + char application[MAXAPPLICATION]; + UINT8 localplayers; + UINT8 mode; + char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME]; +} ATTRPACK clientconfig_pak; + +#define SV_DEDICATED 0x40 // server is dedicated +#define SV_LOTSOFADDONS 0x20 // flag used to ask for full file list in d_netfil + +enum { + REFUSE_JOINS_DISABLED = 1, + REFUSE_SLOTS_FULL, + REFUSE_BANNED, +}; + +#define MAXSERVERNAME 32 +#define MAXFILENEEDED 915 + +// This packet is too large +typedef struct +{ + /* + In the old packet, 'version' is the first field. Now that field is set + to 255 always, so older versions won't be confused with the new + versions or vice-versa. + */ + UINT8 _255; + UINT8 packetversion; + char application[MAXAPPLICATION]; + UINT8 version; + UINT8 subversion; + UINT8 numberofplayer; + UINT8 maxplayer; + UINT8 refusereason; // 0: joinable, REFUSE enum + char gametypename[24]; + UINT8 modifiedgame; + UINT8 cheatsenabled; + UINT8 flags; + UINT8 fileneedednum; + tic_t time; + tic_t leveltime; + char servername[MAXSERVERNAME]; + char mapname[8]; + char maptitle[33]; + unsigned char mapmd5[16]; + UINT8 actnum; + UINT8 iszone; + UINT8 fileneeded[MAXFILENEEDED]; // is filled with writexxx (byteptr.h) +} ATTRPACK serverinfo_pak; + +typedef struct +{ + char reason[255]; +} ATTRPACK serverrefuse_pak; + +typedef struct +{ + UINT8 version; + tic_t time; // used for ping evaluation +} ATTRPACK askinfo_pak; + +typedef struct +{ + char clientaddr[22]; + tic_t time; // used for ping evaluation +} ATTRPACK msaskinfo_pak; + +// Shorter player information for external use. +typedef struct +{ + UINT8 num; + char name[MAXPLAYERNAME+1]; + UINT8 address[4]; // sending another string would run us up against MAXPACKETLENGTH + UINT8 team; + UINT8 skin; + UINT8 data; // Color is first four bits, hasflag, isit and issuper have one bit each, the last is unused. + UINT32 score; + UINT16 timeinserver; // In seconds. +} ATTRPACK plrinfo; + +// Shortest player information for join during intermission. +typedef struct +{ + char name[MAXPLAYERNAME+1]; + UINT8 skin; + UINT16 color; + UINT32 pflags; + UINT32 score; + UINT8 ctfteam; +} ATTRPACK plrconfig; + +typedef struct +{ + INT32 first; + UINT8 num; + UINT8 more; + UINT8 files[MAXFILENEEDED]; // is filled with writexxx (byteptr.h) +} ATTRPACK filesneededconfig_pak; + +// +// Network packet data +// +typedef struct +{ + UINT32 checksum; + UINT8 ack; // If not zero the node asks for acknowledgement, the receiver must resend the ack + UINT8 ackreturn; // The return of the ack number + + UINT8 packettype; + UINT8 reserved; // Padding + union + { + clientcmd_pak clientpak; // 144 bytes + client2cmd_pak client2pak; // 200 bytes + servertics_pak serverpak; // 132495 bytes (more around 360, no?) + serverconfig_pak servercfg; // 773 bytes + UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...) + filetx_pak filetxpak; // 139 bytes + fileack_pak fileack; + UINT8 filereceived; + clientconfig_pak clientcfg; // 136 bytes + UINT8 md5sum[16]; + serverinfo_pak serverinfo; // 1024 bytes + serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...) + askinfo_pak askinfo; // 61 bytes + msaskinfo_pak msaskinfo; // 22 bytes + plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?) + plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?) + INT32 filesneedednum; // 4 bytes + filesneededconfig_pak filesneededcfg; // ??? bytes + UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes + } u; // This is needed to pack diff packet types data together +} ATTRPACK doomdata_t; + +#if defined(_MSC_VER) +#pragma pack() +#endif + +#define FILETXHEADER offsetof(filetx_pak, data) + +#define KICK_MSG_GO_AWAY 1 +#define KICK_MSG_CON_FAIL 2 +#define KICK_MSG_PLAYER_QUIT 3 +#define KICK_MSG_TIMEOUT 4 +#define KICK_MSG_BANNED 5 +#define KICK_MSG_PING_HIGH 6 +#define KICK_MSG_CUSTOM_KICK 7 +#define KICK_MSG_CUSTOM_BAN 8 +#define KICK_MSG_KEEP_BODY 0x80 + +#endif From 20cd8cefd11cc52de1c302674b14ab7ed5f2b591 Mon Sep 17 00:00:00 2001 From: katsy Date: Fri, 6 Jan 2023 18:41:35 -0600 Subject: [PATCH 53/96] fix flickering flight indicator --- src/b_bot.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/b_bot.c b/src/b_bot.c index 6c1495c72..2774337cc 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -188,6 +188,7 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) && !(pcmd->forwardmove || pcmd->sidemove || player->dashspeed) && P_IsObjectOnGround(sonic) && P_IsObjectOnGround(tails) && !(player->pflags & PF_STASIS) + && !(player->exiting) && bot->charability == CA_FLY) mem->thinkstate = AI_THINKFLY; else if (mem->thinkstate == AI_THINKFLY) From d1c5f7adcc02d2c0d5a49a9b2f4c0997821212ae Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sat, 7 Jan 2023 13:01:48 +0100 Subject: [PATCH 54/96] Move gamestate handling to a new file --- src/hu_stuff.c | 1 + src/netcode/Sourcefile | 1 + src/netcode/d_clisrv.c | 308 +---------------------------- src/netcode/d_clisrv.h | 5 - src/netcode/gamestate.c | 341 ++++++++++++++++++++++++++++++++ src/netcode/gamestate.h | 31 +++ src/netcode/net_command.c | 1 + src/netcode/server_connection.c | 1 + src/netcode/tic_command.c | 1 + 9 files changed, 378 insertions(+), 312 deletions(-) create mode 100644 src/netcode/gamestate.c create mode 100644 src/netcode/gamestate.h diff --git a/src/hu_stuff.c b/src/hu_stuff.c index e08351a8a..7ec33bd79 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -21,6 +21,7 @@ #include "netcode/d_clisrv.h" #include "netcode/net_command.h" +#include "netcode/gamestate.h" #include "g_game.h" #include "g_input.h" diff --git a/src/netcode/Sourcefile b/src/netcode/Sourcefile index 1039b218a..c59050367 100644 --- a/src/netcode/Sourcefile +++ b/src/netcode/Sourcefile @@ -3,6 +3,7 @@ server_connection.c client_connection.c tic_command.c net_command.c +gamestate.c d_net.c d_netcmd.c d_netfil.c diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index b834c92f5..8ba10f6ea 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -53,6 +53,7 @@ #include "client_connection.h" #include "tic_command.h" #include "net_command.h" +#include "gamestate.h" #include "protocol.h" // @@ -93,18 +94,12 @@ tic_t maketic; INT16 consistancy[BACKUPTICS]; -UINT8 hu_redownloadinggamestate = 0; - // true when a player is connecting or disconnecting so that the gameplay has stopped in its tracks boolean hu_stopped = false; UINT8 adminpassmd5[16]; boolean adminpasswordset = false; -// Client specific -// here it is for the secondary local player (splitscreen) -static boolean cl_redownloadinggamestate = false; - tic_t neededtic; SINT8 servernode = 0; // the number of the server node @@ -122,233 +117,6 @@ consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_c // of 512 bytes is like 0.1) UINT16 software_MAXPACKETLENGTH; -#define SAVEGAMESIZE (768*1024) - -boolean SV_ResendingSavegameToAnyone(void) -{ - INT32 i; - - for (i = 0; i < MAXNETNODES; i++) - if (netnodes[i].resendingsavegame) - return true; - return false; -} - -void SV_SendSaveGame(INT32 node, boolean resending) -{ - size_t length, compressedlen; - UINT8 *savebuffer; - UINT8 *compressedsave; - UINT8 *buffertosend; - - // first save it in a malloced buffer - savebuffer = (UINT8 *)malloc(SAVEGAMESIZE); - if (!savebuffer) - { - CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); - return; - } - - // Leave room for the uncompressed length. - save_p = savebuffer + sizeof(UINT32); - - P_SaveNetGame(resending); - - length = save_p - savebuffer; - if (length > SAVEGAMESIZE) - { - free(savebuffer); - save_p = NULL; - I_Error("Savegame buffer overrun"); - } - - // Allocate space for compressed save: one byte fewer than for the - // uncompressed data to ensure that the compression is worthwhile. - compressedsave = malloc(length - 1); - if (!compressedsave) - { - CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); - return; - } - - // Attempt to compress it. - if((compressedlen = lzf_compress(savebuffer + sizeof(UINT32), length - sizeof(UINT32), compressedsave + sizeof(UINT32), length - sizeof(UINT32) - 1))) - { - // Compressing succeeded; send compressed data - - free(savebuffer); - - // State that we're compressed. - buffertosend = compressedsave; - WRITEUINT32(compressedsave, length - sizeof(UINT32)); - length = compressedlen + sizeof(UINT32); - } - else - { - // Compression failed to make it smaller; send original - - free(compressedsave); - - // State that we're not compressed - buffertosend = savebuffer; - WRITEUINT32(savebuffer, 0); - } - - AddRamToSendQueue(node, buffertosend, length, SF_RAM, 0); - save_p = NULL; - - // Remember when we started sending the savegame so we can handle timeouts - netnodes[node].sendingsavegame = true; - netnodes[node].freezetimeout = I_GetTime() + jointimeout + length / 1024; // 1 extra tic for each kilobyte -} - -#ifdef DUMPCONSISTENCY -#define TMPSAVENAME "badmath.sav" -static consvar_t cv_dumpconsistency = CVAR_INIT ("dumpconsistency", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); - -static void SV_SavedGame(void) -{ - size_t length; - UINT8 *savebuffer; - char tmpsave[256]; - - if (!cv_dumpconsistency.value) - return; - - sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); - - // first save it in a malloced buffer - save_p = savebuffer = (UINT8 *)malloc(SAVEGAMESIZE); - if (!save_p) - { - CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); - return; - } - - P_SaveNetGame(false); - - length = save_p - savebuffer; - if (length > SAVEGAMESIZE) - { - free(savebuffer); - save_p = NULL; - I_Error("Savegame buffer overrun"); - } - - // then save it! - if (!FIL_WriteFile(tmpsave, savebuffer, length)) - CONS_Printf(M_GetText("Didn't save %s for netgame"), tmpsave); - - free(savebuffer); - save_p = NULL; -} - -#undef TMPSAVENAME -#endif -#define TMPSAVENAME "$$$.sav" - - -void CL_LoadReceivedSavegame(boolean reloading) -{ - UINT8 *savebuffer = NULL; - size_t length, decompressedlen; - char tmpsave[256]; - - FreeFileNeeded(); - - sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); - - length = FIL_ReadFile(tmpsave, &savebuffer); - - CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(length)); - if (!length) - { - I_Error("Can't read savegame sent"); - return; - } - - save_p = savebuffer; - - // Decompress saved game if necessary. - decompressedlen = READUINT32(save_p); - if(decompressedlen > 0) - { - UINT8 *decompressedbuffer = Z_Malloc(decompressedlen, PU_STATIC, NULL); - lzf_decompress(save_p, length - sizeof(UINT32), decompressedbuffer, decompressedlen); - Z_Free(savebuffer); - save_p = savebuffer = decompressedbuffer; - } - - paused = false; - demoplayback = false; - titlemapinaction = TITLEMAP_OFF; - titledemo = false; - automapactive = false; - - P_StopRumble(NULL); - - // load a base level - if (P_LoadNetGame(reloading)) - { - const UINT8 actnum = mapheaderinfo[gamemap-1]->actnum; - CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap)); - if (strcmp(mapheaderinfo[gamemap-1]->lvlttl, "")) - { - CONS_Printf(": %s", mapheaderinfo[gamemap-1]->lvlttl); - if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) - CONS_Printf(M_GetText(" Zone")); - if (actnum > 0) - CONS_Printf(" %2d", actnum); - } - CONS_Printf("\"\n"); - } - - // done - Z_Free(savebuffer); - save_p = NULL; - if (unlink(tmpsave) == -1) - CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave); - consistancy[gametic%BACKUPTICS] = Consistancy(); - CON_ToggleOff(); - - // Tell the server we have received and reloaded the gamestate - // so they know they can resume the game - netbuffer->packettype = PT_RECEIVEDGAMESTATE; - HSendPacket(servernode, true, 0, 0); -} - -static void CL_ReloadReceivedSavegame(void) -{ - INT32 i; - - for (i = 0; i < MAXPLAYERS; i++) - { - LUA_InvalidatePlayer(&players[i]); - sprintf(player_names[i], "Player %d", i + 1); - } - - CL_LoadReceivedSavegame(true); - - if (neededtic < gametic) - neededtic = gametic; - maketic = neededtic; - - ticcmd_oldangleturn[0] = players[consoleplayer].oldrelangleturn; - P_ForceLocalAngle(&players[consoleplayer], (angle_t)(players[consoleplayer].angleturn << 16)); - if (splitscreen) - { - ticcmd_oldangleturn[1] = players[secondarydisplayplayer].oldrelangleturn; - P_ForceLocalAngle(&players[secondarydisplayplayer], (angle_t)(players[secondarydisplayplayer].angleturn << 16)); - } - - camera.subsector = R_PointInSubsector(camera.x, camera.y); - camera2.subsector = R_PointInSubsector(camera2.x, camera2.y); - - cl_redownloadinggamestate = false; - - CONS_Printf(M_GetText("Game state reloaded\n")); -} - typedef struct banreason_s { char *reason; @@ -1006,34 +774,6 @@ static void Command_Kick(void) CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); } -static void Command_ResendGamestate(void) -{ - SINT8 playernum; - - if (COM_Argc() == 1) - { - CONS_Printf(M_GetText("resendgamestate : resend the game state to a player\n")); - return; - } - else if (client) - { - CONS_Printf(M_GetText("Only the server can use this.\n")); - return; - } - - playernum = nametonum(COM_Argv(1)); - if (playernum == -1 || playernum == 0) - return; - - // Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on - netbuffer->packettype = PT_WILLRESENDGAMESTATE; - if (!HSendPacket(playernode[playernum], true, 0, 0)) - { - CONS_Alert(CONS_ERROR, M_GetText("A problem occured, please try again.\n")); - return; - } -} - static void Got_KickCmd(UINT8 **p, INT32 playernum) { INT32 pnum, msg; @@ -1736,17 +1476,6 @@ static void PT_ClientQuit(SINT8 node, INT32 netconsole) netnodes[node].ingame = false; } -static void PT_CanReceiveGamestate(SINT8 node) -{ - if (client || netnodes[node].sendingsavegame) - return; - - CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[netnodes[node].player]); - - SV_SendSaveGame(node, true); // Resend a complete game state - netnodes[node].resendingsavegame = true; -} - static void PT_AskLuaFile(SINT8 node) { if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_ASKED) @@ -1759,13 +1488,6 @@ static void PT_HasLuaFile(SINT8 node) SV_HandleLuaFileSent(node); } -static void PT_ReceivedGamestate(SINT8 node) -{ - netnodes[node].sendingsavegame = false; - netnodes[node].resendingsavegame = false; - netnodes[node].savegameresendcooldown = I_GetTime() + 5 * TICRATE; -} - static void PT_Ping(SINT8 node, INT32 netconsole) { // Only accept PT_PING from the server. @@ -1789,34 +1511,6 @@ static void PT_Ping(SINT8 node, INT32 netconsole) } } -static void PT_WillResendGamestate(SINT8 node) -{ - (void)node; - - char tmpsave[256]; - - if (server || cl_redownloadinggamestate) - return; - - // Send back a PT_CANRECEIVEGAMESTATE packet to the server - // so they know they can start sending the game state - netbuffer->packettype = PT_CANRECEIVEGAMESTATE; - if (!HSendPacket(servernode, true, 0, 0)) - return; - - CONS_Printf(M_GetText("Reloading game state...\n")); - - sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); - - // Don't get a corrupt savegame error because tmpsave already exists - if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1) - I_Error("Can't delete %s\n", tmpsave); - - CL_PrepareDownloadSaveGame(tmpsave); - - cl_redownloadinggamestate = true; -} - static void PT_SendingLuaFile(SINT8 node) { (void)node; diff --git a/src/netcode/d_clisrv.h b/src/netcode/d_clisrv.h index 691a2787f..d5bafe750 100644 --- a/src/netcode/d_clisrv.h +++ b/src/netcode/d_clisrv.h @@ -89,19 +89,16 @@ void NetUpdate(void); void GetPackets(void); void ResetNode(INT32 node); INT16 Consistancy(void); -boolean SV_ResendingSavegameToAnyone(void); void SV_StartSinglePlayerServer(void); void SV_SpawnServer(void); void SV_StopServer(void); void SV_ResetServer(void); -void SV_SendSaveGame(INT32 node, boolean resending); void CL_AddSplitscreenPlayer(void); void CL_RemoveSplitscreenPlayer(void); void CL_Reset(void); void CL_ClearPlayer(INT32 playernum); void CL_RemovePlayer(INT32 playernum, kickreason_t reason); -void CL_LoadReceivedSavegame(boolean reloading); // Is there a game running boolean Playing(void); @@ -130,8 +127,6 @@ tic_t GetLag(INT32 node); void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest); -extern UINT8 hu_redownloadinggamestate; - extern UINT8 adminpassmd5[16]; extern boolean adminpasswordset; diff --git a/src/netcode/gamestate.c b/src/netcode/gamestate.c new file mode 100644 index 000000000..4a3e9f3af --- /dev/null +++ b/src/netcode/gamestate.c @@ -0,0 +1,341 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file gamestate.c +/// \brief Gamestate (re)sending + +#include "d_clisrv.h" +#include "d_netfil.h" +#include "gamestate.h" +#include "i_net.h" +#include "protocol.h" +#include "server_connection.h" +#include "../am_map.h" +#include "../byteptr.h" +#include "../console.h" +#include "../d_main.h" +#include "../doomstat.h" +#include "../doomtype.h" +#include "../f_finale.h" +#include "../g_demo.h" +#include "../g_game.h" +#include "../i_time.h" +#include "../lua_script.h" +#include "../lzf.h" +#include "../m_misc.h" +#include "../p_haptic.h" +#include "../p_local.h" +#include "../p_saveg.h" +#include "../r_main.h" +#include "../tables.h" +#include "../z_zone.h" + +#define SAVEGAMESIZE (768*1024) + +UINT8 hu_redownloadinggamestate = 0; +boolean cl_redownloadinggamestate = false; + +boolean SV_ResendingSavegameToAnyone(void) +{ + INT32 i; + + for (i = 0; i < MAXNETNODES; i++) + if (netnodes[i].resendingsavegame) + return true; + return false; +} + +void SV_SendSaveGame(INT32 node, boolean resending) +{ + size_t length, compressedlen; + UINT8 *savebuffer; + UINT8 *compressedsave; + UINT8 *buffertosend; + + // first save it in a malloced buffer + savebuffer = (UINT8 *)malloc(SAVEGAMESIZE); + if (!savebuffer) + { + CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); + return; + } + + // Leave room for the uncompressed length. + save_p = savebuffer + sizeof(UINT32); + + P_SaveNetGame(resending); + + length = save_p - savebuffer; + if (length > SAVEGAMESIZE) + { + free(savebuffer); + save_p = NULL; + I_Error("Savegame buffer overrun"); + } + + // Allocate space for compressed save: one byte fewer than for the + // uncompressed data to ensure that the compression is worthwhile. + compressedsave = malloc(length - 1); + if (!compressedsave) + { + CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); + return; + } + + // Attempt to compress it. + if((compressedlen = lzf_compress(savebuffer + sizeof(UINT32), length - sizeof(UINT32), compressedsave + sizeof(UINT32), length - sizeof(UINT32) - 1))) + { + // Compressing succeeded; send compressed data + + free(savebuffer); + + // State that we're compressed. + buffertosend = compressedsave; + WRITEUINT32(compressedsave, length - sizeof(UINT32)); + length = compressedlen + sizeof(UINT32); + } + else + { + // Compression failed to make it smaller; send original + + free(compressedsave); + + // State that we're not compressed + buffertosend = savebuffer; + WRITEUINT32(savebuffer, 0); + } + + AddRamToSendQueue(node, buffertosend, length, SF_RAM, 0); + save_p = NULL; + + // Remember when we started sending the savegame so we can handle timeouts + netnodes[node].sendingsavegame = true; + netnodes[node].freezetimeout = I_GetTime() + jointimeout + length / 1024; // 1 extra tic for each kilobyte +} + +#ifdef DUMPCONSISTENCY +#define TMPSAVENAME "badmath.sav" +static consvar_t cv_dumpconsistency = CVAR_INIT ("dumpconsistency", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); + +void SV_SavedGame(void) +{ + size_t length; + UINT8 *savebuffer; + char tmpsave[256]; + + if (!cv_dumpconsistency.value) + return; + + sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); + + // first save it in a malloced buffer + save_p = savebuffer = (UINT8 *)malloc(SAVEGAMESIZE); + if (!save_p) + { + CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); + return; + } + + P_SaveNetGame(false); + + length = save_p - savebuffer; + if (length > SAVEGAMESIZE) + { + free(savebuffer); + save_p = NULL; + I_Error("Savegame buffer overrun"); + } + + // then save it! + if (!FIL_WriteFile(tmpsave, savebuffer, length)) + CONS_Printf(M_GetText("Didn't save %s for netgame"), tmpsave); + + free(savebuffer); + save_p = NULL; +} + +#undef TMPSAVENAME +#endif +#define TMPSAVENAME "$$$.sav" + + +void CL_LoadReceivedSavegame(boolean reloading) +{ + UINT8 *savebuffer = NULL; + size_t length, decompressedlen; + char tmpsave[256]; + + FreeFileNeeded(); + + sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); + + length = FIL_ReadFile(tmpsave, &savebuffer); + + CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(length)); + if (!length) + { + I_Error("Can't read savegame sent"); + return; + } + + save_p = savebuffer; + + // Decompress saved game if necessary. + decompressedlen = READUINT32(save_p); + if(decompressedlen > 0) + { + UINT8 *decompressedbuffer = Z_Malloc(decompressedlen, PU_STATIC, NULL); + lzf_decompress(save_p, length - sizeof(UINT32), decompressedbuffer, decompressedlen); + Z_Free(savebuffer); + save_p = savebuffer = decompressedbuffer; + } + + paused = false; + demoplayback = false; + titlemapinaction = TITLEMAP_OFF; + titledemo = false; + automapactive = false; + + P_StopRumble(NULL); + + // load a base level + if (P_LoadNetGame(reloading)) + { + const UINT8 actnum = mapheaderinfo[gamemap-1]->actnum; + CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap)); + if (strcmp(mapheaderinfo[gamemap-1]->lvlttl, "")) + { + CONS_Printf(": %s", mapheaderinfo[gamemap-1]->lvlttl); + if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) + CONS_Printf(M_GetText(" Zone")); + if (actnum > 0) + CONS_Printf(" %2d", actnum); + } + CONS_Printf("\"\n"); + } + + // done + Z_Free(savebuffer); + save_p = NULL; + if (unlink(tmpsave) == -1) + CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave); + consistancy[gametic%BACKUPTICS] = Consistancy(); + CON_ToggleOff(); + + // Tell the server we have received and reloaded the gamestate + // so they know they can resume the game + netbuffer->packettype = PT_RECEIVEDGAMESTATE; + HSendPacket(servernode, true, 0, 0); +} + +void CL_ReloadReceivedSavegame(void) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + LUA_InvalidatePlayer(&players[i]); + sprintf(player_names[i], "Player %d", i + 1); + } + + CL_LoadReceivedSavegame(true); + + if (neededtic < gametic) + neededtic = gametic; + maketic = neededtic; + + ticcmd_oldangleturn[0] = players[consoleplayer].oldrelangleturn; + P_ForceLocalAngle(&players[consoleplayer], (angle_t)(players[consoleplayer].angleturn << 16)); + if (splitscreen) + { + ticcmd_oldangleturn[1] = players[secondarydisplayplayer].oldrelangleturn; + P_ForceLocalAngle(&players[secondarydisplayplayer], (angle_t)(players[secondarydisplayplayer].angleturn << 16)); + } + + camera.subsector = R_PointInSubsector(camera.x, camera.y); + camera2.subsector = R_PointInSubsector(camera2.x, camera2.y); + + cl_redownloadinggamestate = false; + + CONS_Printf(M_GetText("Game state reloaded\n")); +} + +void Command_ResendGamestate(void) +{ + SINT8 playernum; + + if (COM_Argc() == 1) + { + CONS_Printf(M_GetText("resendgamestate : resend the game state to a player\n")); + return; + } + else if (client) + { + CONS_Printf(M_GetText("Only the server can use this.\n")); + return; + } + + playernum = nametonum(COM_Argv(1)); + if (playernum == -1 || playernum == 0) + return; + + // Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + if (!HSendPacket(playernode[playernum], true, 0, 0)) + { + CONS_Alert(CONS_ERROR, M_GetText("A problem occured, please try again.\n")); + return; + } +} + +void PT_CanReceiveGamestate(SINT8 node) +{ + if (client || netnodes[node].sendingsavegame) + return; + + CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[netnodes[node].player]); + + SV_SendSaveGame(node, true); // Resend a complete game state + netnodes[node].resendingsavegame = true; +} + +void PT_ReceivedGamestate(SINT8 node) +{ + netnodes[node].sendingsavegame = false; + netnodes[node].resendingsavegame = false; + netnodes[node].savegameresendcooldown = I_GetTime() + 5 * TICRATE; +} + +void PT_WillResendGamestate(SINT8 node) +{ + (void)node; + + char tmpsave[256]; + + if (server || cl_redownloadinggamestate) + return; + + // Send back a PT_CANRECEIVEGAMESTATE packet to the server + // so they know they can start sending the game state + netbuffer->packettype = PT_CANRECEIVEGAMESTATE; + if (!HSendPacket(servernode, true, 0, 0)) + return; + + CONS_Printf(M_GetText("Reloading game state...\n")); + + sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); + + // Don't get a corrupt savegame error because tmpsave already exists + if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1) + I_Error("Can't delete %s\n", tmpsave); + + CL_PrepareDownloadSaveGame(tmpsave); + + cl_redownloadinggamestate = true; +} diff --git a/src/netcode/gamestate.h b/src/netcode/gamestate.h new file mode 100644 index 000000000..9d2779772 --- /dev/null +++ b/src/netcode/gamestate.h @@ -0,0 +1,31 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file gamestate.h +/// \brief Gamestate (re)sending + +#ifndef __GAMESTATE__ +#define __GAMESTATE__ + +#include "../doomtype.h" + +extern UINT8 hu_redownloadinggamestate; +extern boolean cl_redownloadinggamestate; + +boolean SV_ResendingSavegameToAnyone(void); +void SV_SendSaveGame(INT32 node, boolean resending); +void SV_SavedGame(void); +void CL_LoadReceivedSavegame(boolean reloading); +void CL_ReloadReceivedSavegame(void); +void Command_ResendGamestate(void); +void PT_CanReceiveGamestate(SINT8 node); +void PT_ReceivedGamestate(SINT8 node); +void PT_WillResendGamestate(SINT8 node); + +#endif diff --git a/src/netcode/net_command.c b/src/netcode/net_command.c index eeb479d21..6f9f3f79a 100644 --- a/src/netcode/net_command.c +++ b/src/netcode/net_command.c @@ -12,6 +12,7 @@ #include "net_command.h" #include "tic_command.h" +#include "gamestate.h" #include "d_clisrv.h" #include "i_net.h" #include "../g_game.h" diff --git a/src/netcode/server_connection.c b/src/netcode/server_connection.c index b776db422..28d97c052 100644 --- a/src/netcode/server_connection.c +++ b/src/netcode/server_connection.c @@ -16,6 +16,7 @@ #include "d_netfil.h" #include "mserv.h" #include "net_command.h" +#include "gamestate.h" #include "../byteptr.h" #include "../g_game.h" #include "../g_state.h" diff --git a/src/netcode/tic_command.c b/src/netcode/tic_command.c index e7df895ff..180d54e69 100644 --- a/src/netcode/tic_command.c +++ b/src/netcode/tic_command.c @@ -14,6 +14,7 @@ #include "d_clisrv.h" #include "net_command.h" #include "client_connection.h" +#include "gamestate.h" #include "i_net.h" #include "../d_main.h" #include "../g_game.h" From 94ba47a950ca0e01c664c5d03fa3af707b944253 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sat, 7 Jan 2023 13:37:33 +0100 Subject: [PATCH 55/96] Remove unused stuff --- src/netcode/d_clisrv.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index 8ba10f6ea..36116b931 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -69,13 +69,9 @@ // firstticstosend is used to optimize a condition // Normally maketic >= gametic > 0 -#define PREDICTIONQUEUE BACKUPTICS -#define PREDICTIONMASK (PREDICTIONQUEUE-1) #define MAX_REASONLENGTH 30 boolean server = true; // true or false but !server == client -#define client (!server) -boolean nodownload = false; boolean serverrunning = false; INT32 serverplayer = 0; char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support) From dfdbdee0a823ee6f02946d8faf74d99465cf8160 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sat, 7 Jan 2023 15:57:04 +0100 Subject: [PATCH 56/96] Move netcode console variables to appropriate files --- src/m_menu.c | 1 + src/netcode/client_connection.c | 1 + src/netcode/d_clisrv.c | 40 +++++++++------------------------ src/netcode/d_clisrv.h | 7 +----- src/netcode/d_netfil.c | 9 ++++++++ src/netcode/d_netfil.h | 2 ++ src/netcode/net_command.c | 1 + src/netcode/server_connection.c | 14 ++++++++++++ src/netcode/server_connection.h | 2 ++ src/p_tick.c | 1 + 10 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 06d1b1b96..34322200d 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -57,6 +57,7 @@ #include "netcode/d_net.h" #include "netcode/mserv.h" +#include "netcode/server_connection.h" #include "netcode/client_connection.h" #include "m_misc.h" #include "m_anigif.h" diff --git a/src/netcode/client_connection.c b/src/netcode/client_connection.c index bfaea2e81..a00157a50 100644 --- a/src/netcode/client_connection.c +++ b/src/netcode/client_connection.c @@ -11,6 +11,7 @@ /// \brief Client connection handling #include "client_connection.h" +#include "gamestate.h" #include "d_clisrv.h" #include "d_netfil.h" #include "../d_main.h" diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index 36116b931..0b1c487d8 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -103,11 +103,6 @@ SINT8 servernode = 0; // the number of the server node /// \todo WORK! boolean acceptnewnode = true; -consvar_t cv_showjoinaddress = CVAR_INIT ("showjoinaddress", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); - -static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}}; -consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_cons_t, NULL); - // Some software don't support largest packet // (original sersetup, not exactely, but the probability of sending a packet // of 512 bytes is like 0.1) @@ -123,6 +118,17 @@ typedef struct banreason_s static banreason_t *reasontail = NULL; //last entry, use prev static banreason_t *reasonhead = NULL; //1st entry, use next +static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; +consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL); + +static CV_PossibleValue_t resynchattempts_cons_t[] = {{1, "MIN"}, {20, "MAX"}, {0, "No"}, {0, NULL}}; +consvar_t cv_resynchattempts = CVAR_INIT ("resynchattempts", "10", CV_SAVE|CV_NETVAR, resynchattempts_cons_t, NULL); + +consvar_t cv_blamecfail = CVAR_INIT ("blamecfail", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); + +static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}}; +consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_cons_t, NULL); + static void Command_ShowBan(void) //Print out ban list { size_t i; @@ -961,30 +967,6 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) CL_RemovePlayer(pnum, kickreason); } -static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; -consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL); - -consvar_t cv_allownewplayer = CVAR_INIT ("allowjoin", "On", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); -static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}}; -consvar_t cv_maxplayers = CVAR_INIT ("maxplayers", "8", CV_SAVE|CV_NETVAR, maxplayers_cons_t, NULL); -static CV_PossibleValue_t joindelay_cons_t[] = {{1, "MIN"}, {3600, "MAX"}, {0, "Off"}, {0, NULL}}; -consvar_t cv_joindelay = CVAR_INIT ("joindelay", "10", CV_SAVE|CV_NETVAR, joindelay_cons_t, NULL); -static CV_PossibleValue_t rejointimeout_cons_t[] = {{1, "MIN"}, {60 * FRACUNIT, "MAX"}, {0, "Off"}, {0, NULL}}; -consvar_t cv_rejointimeout = CVAR_INIT ("rejointimeout", "2", CV_SAVE|CV_NETVAR|CV_FLOAT, rejointimeout_cons_t, NULL); - -static CV_PossibleValue_t resynchattempts_cons_t[] = {{1, "MIN"}, {20, "MAX"}, {0, "No"}, {0, NULL}}; -consvar_t cv_resynchattempts = CVAR_INIT ("resynchattempts", "10", CV_SAVE|CV_NETVAR, resynchattempts_cons_t, NULL); -consvar_t cv_blamecfail = CVAR_INIT ("blamecfail", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); - -// max file size to send to a player (in kilobytes) -static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {204800, "MAX"}, {0, NULL}}; -consvar_t cv_maxsend = CVAR_INIT ("maxsend", "4096", CV_SAVE|CV_NETVAR, maxsend_cons_t, NULL); -consvar_t cv_noticedownload = CVAR_INIT ("noticedownload", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); - -// Speed of file downloading (in packets per tic) -static CV_PossibleValue_t downloadspeed_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}}; -consvar_t cv_downloadspeed = CVAR_INIT ("downloadspeed", "16", CV_SAVE|CV_NETVAR, downloadspeed_cons_t, NULL); - static void Got_AddPlayer(UINT8 **p, INT32 playernum); // called one time at init diff --git a/src/netcode/d_clisrv.h b/src/netcode/d_clisrv.h index d5bafe750..9cb3ef3e8 100644 --- a/src/netcode/d_clisrv.h +++ b/src/netcode/d_clisrv.h @@ -37,9 +37,6 @@ extern INT32 mapchangepending; // Points inside doomcom extern doomdata_t *netbuffer; -extern consvar_t cv_showjoinaddress; -extern consvar_t cv_playbackspeed; - #define BASEPACKETSIZE offsetof(doomdata_t, u) #define BASESERVERTICSSIZE offsetof(doomdata_t, u.serverpak.cmds[0]) @@ -76,9 +73,7 @@ extern UINT32 realpingtable[MAXPLAYERS]; extern UINT32 playerpingtable[MAXPLAYERS]; extern tic_t servermaxping; -extern consvar_t cv_netticbuffer, cv_allownewplayer, cv_maxplayers, cv_joindelay, cv_rejointimeout; -extern consvar_t cv_resynchattempts, cv_blamecfail; -extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed; +extern consvar_t cv_netticbuffer, cv_resynchattempts, cv_blamecfail, cv_playbackspeed; // Used in d_net, the only dependence void D_ClientServerInit(void); diff --git a/src/netcode/d_netfil.c b/src/netcode/d_netfil.c index e581be2ac..205abf713 100644 --- a/src/netcode/d_netfil.c +++ b/src/netcode/d_netfil.c @@ -116,6 +116,15 @@ boolean waitingforluafiletransfer = false; boolean waitingforluafilecommand = false; char luafiledir[256 + 16] = "luafiles"; +// max file size to send to a player (in kilobytes) +static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {204800, "MAX"}, {0, NULL}}; +consvar_t cv_maxsend = CVAR_INIT ("maxsend", "4096", CV_SAVE|CV_NETVAR, maxsend_cons_t, NULL); + +consvar_t cv_noticedownload = CVAR_INIT ("noticedownload", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); + +// Speed of file downloading (in packets per tic) +static CV_PossibleValue_t downloadspeed_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}}; +consvar_t cv_downloadspeed = CVAR_INIT ("downloadspeed", "16", CV_SAVE|CV_NETVAR, downloadspeed_cons_t, NULL); static UINT16 GetWadNumFromFileNeededId(UINT8 id) { diff --git a/src/netcode/d_netfil.h b/src/netcode/d_netfil.h index 732efcd5e..850e24d49 100644 --- a/src/netcode/d_netfil.h +++ b/src/netcode/d_netfil.h @@ -76,6 +76,8 @@ extern UINT32 downloadcompletedsize; extern INT32 totalfilesrequestednum; extern UINT32 totalfilesrequestedsize; +extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed; + void AllocFileNeeded(INT32 size); void FreeFileNeeded(void); UINT8 *PutFileNeeded(UINT16 firstfile); diff --git a/src/netcode/net_command.c b/src/netcode/net_command.c index 6f9f3f79a..95a49a959 100644 --- a/src/netcode/net_command.c +++ b/src/netcode/net_command.c @@ -13,6 +13,7 @@ #include "net_command.h" #include "tic_command.h" #include "gamestate.h" +#include "server_connection.h" #include "d_clisrv.h" #include "i_net.h" #include "../g_game.h" diff --git a/src/netcode/server_connection.c b/src/netcode/server_connection.c index 28d97c052..ce1192475 100644 --- a/src/netcode/server_connection.c +++ b/src/netcode/server_connection.c @@ -22,6 +22,7 @@ #include "../g_state.h" #include "../p_setup.h" #include "../p_tick.h" +#include "../command.h" #include "../doomstat.h" // Minimum timeout for sending the savegame @@ -38,6 +39,19 @@ char playeraddress[MAXPLAYERS][64]; UINT8 player_joining = false; +consvar_t cv_showjoinaddress = CVAR_INIT ("showjoinaddress", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); + +consvar_t cv_allownewplayer = CVAR_INIT ("allowjoin", "On", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); + +static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}}; +consvar_t cv_maxplayers = CVAR_INIT ("maxplayers", "8", CV_SAVE|CV_NETVAR, maxplayers_cons_t, NULL); + +static CV_PossibleValue_t joindelay_cons_t[] = {{1, "MIN"}, {3600, "MAX"}, {0, "Off"}, {0, NULL}}; +consvar_t cv_joindelay = CVAR_INIT ("joindelay", "10", CV_SAVE|CV_NETVAR, joindelay_cons_t, NULL); + +static CV_PossibleValue_t rejointimeout_cons_t[] = {{1, "MIN"}, {60 * FRACUNIT, "MAX"}, {0, "Off"}, {0, NULL}}; +consvar_t cv_rejointimeout = CVAR_INIT ("rejointimeout", "2", CV_SAVE|CV_NETVAR|CV_FLOAT, rejointimeout_cons_t, NULL); + static INT32 FindRejoinerNum(SINT8 node) { char strippednodeaddress[64]; diff --git a/src/netcode/server_connection.h b/src/netcode/server_connection.h index 4204db2e6..a40bd4603 100644 --- a/src/netcode/server_connection.h +++ b/src/netcode/server_connection.h @@ -13,6 +13,7 @@ #ifndef __D_SERVER_CONNECTION__ #define __D_SERVER_CONNECTION__ +#include "../command.h" #include "../doomdef.h" #include "../doomtype.h" @@ -25,5 +26,6 @@ extern tic_t jointimeout; extern tic_t joindelay; extern char playeraddress[MAXPLAYERS][64]; extern UINT8 player_joining; +extern consvar_t cv_showjoinaddress, cv_allownewplayer, cv_maxplayers, cv_joindelay, cv_rejointimeout; #endif diff --git a/src/p_tick.c b/src/p_tick.c index 8fb99d737..e92dfe8e4 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -27,6 +27,7 @@ #include "r_fps.h" #include "i_video.h" // rendermode #include "netcode/net_command.h" +#include "netcode/server_connection.h" // Object place #include "m_cheat.h" From 7240ed22de0260e7f1a9ea0fcc1118b166d63c11 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sat, 7 Jan 2023 15:57:17 +0100 Subject: [PATCH 57/96] Add missing PT_ prefix to a few packet handlers --- src/netcode/client_connection.c | 4 ++-- src/netcode/client_connection.h | 2 +- src/netcode/d_clisrv.c | 12 ++++++------ src/netcode/server_connection.c | 2 +- src/netcode/server_connection.h | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/netcode/client_connection.c b/src/netcode/client_connection.c index a00157a50..bed445a64 100644 --- a/src/netcode/client_connection.c +++ b/src/netcode/client_connection.c @@ -1052,7 +1052,7 @@ void CL_ConnectToServer(void) * \note What happens if the packet comes from a client or something like that? * */ -void HandleServerInfo(SINT8 node) +void PT_ServerInfo(SINT8 node) { // compute ping in ms const tic_t ticnow = I_GetTime(); @@ -1173,7 +1173,7 @@ void PT_ServerCFG(SINT8 node) /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? /// Shouldn't them be downloaded even at intermission time? - /// Also, according to HandleConnect, the server will send the savegame even during intermission... + /// Also, according to PT_Connect, the server will send the savegame even during intermission... if (netbuffer->u.servercfg.gamestate == GS_LEVEL/* || netbuffer->u.servercfg.gamestate == GS_INTERMISSION*/) cl_mode = CL_DOWNLOADSAVEGAME; diff --git a/src/netcode/client_connection.h b/src/netcode/client_connection.h index a76411ba6..74cff61ff 100644 --- a/src/netcode/client_connection.h +++ b/src/netcode/client_connection.h @@ -53,7 +53,7 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room); void CL_ConnectToServer(void); boolean CL_SendJoin(void); -void HandleServerInfo(SINT8 node); +void PT_ServerInfo(SINT8 node); void PT_MoreFilesNeeded(SINT8 node); void PT_ServerRefuse(SINT8 node); void PT_ServerCFG(SINT8 node); diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index 0b1c487d8..4589c83d3 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -1358,7 +1358,7 @@ void SV_StartSinglePlayerServer(void) * \param node The packet sender (should be the server) * */ -static void HandleShutdown(SINT8 node) +static void PT_Shutdown(SINT8 node) { (void)node; LUA_HookBool(false, HOOK(GameQuit)); @@ -1373,7 +1373,7 @@ static void HandleShutdown(SINT8 node) * \param node The packet sender (should be the server) * */ -static void HandleTimeout(SINT8 node) +static void PT_Timeout(SINT8 node) { (void)node; LUA_HookBool(false, HOOK(GameQuit)); @@ -1608,26 +1608,26 @@ void GetPackets(void) if (netbuffer->packettype == PT_CLIENTJOIN && server) { - HandleConnect(node); + PT_Connect(node); continue; } if (node == servernode && client && cl_mode != CL_SEARCHING) { if (netbuffer->packettype == PT_SERVERSHUTDOWN) { - HandleShutdown(node); + PT_Shutdown(node); continue; } if (netbuffer->packettype == PT_NODETIMEOUT) { - HandleTimeout(node); + PT_Timeout(node); continue; } } if (netbuffer->packettype == PT_SERVERINFO) { - HandleServerInfo(node); + PT_ServerInfo(node); continue; } diff --git a/src/netcode/server_connection.c b/src/netcode/server_connection.c index ce1192475..e37c45951 100644 --- a/src/netcode/server_connection.c +++ b/src/netcode/server_connection.c @@ -422,7 +422,7 @@ GetRefuseMessage (SINT8 node, INT32 rejoinernum) * \param node The packet sender * */ -void HandleConnect(SINT8 node) +void PT_Connect(SINT8 node) { char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1]; INT32 numplayers = netbuffer->u.clientcfg.localplayers; diff --git a/src/netcode/server_connection.h b/src/netcode/server_connection.h index a40bd4603..585c9e428 100644 --- a/src/netcode/server_connection.h +++ b/src/netcode/server_connection.h @@ -17,7 +17,7 @@ #include "../doomdef.h" #include "../doomtype.h" -void HandleConnect(SINT8 node); +void PT_Connect(SINT8 node); void PT_AskInfoViaMS(SINT8 node); void PT_TellFilesNeeded(SINT8 node); void PT_AskInfo(SINT8 node); From 4a2fd43aff5e5604a70ce8c01946977f5f5af816 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sat, 7 Jan 2023 16:14:41 +0100 Subject: [PATCH 58/96] Add missing _pak suffix to a few packet structures --- src/netcode/protocol.h | 8 ++++---- src/netcode/server_connection.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/netcode/protocol.h b/src/netcode/protocol.h index 566d10d8c..1eba9286b 100644 --- a/src/netcode/protocol.h +++ b/src/netcode/protocol.h @@ -260,7 +260,7 @@ typedef struct UINT8 data; // Color is first four bits, hasflag, isit and issuper have one bit each, the last is unused. UINT32 score; UINT16 timeinserver; // In seconds. -} ATTRPACK plrinfo; +} ATTRPACK plrinfo_pak; // Shortest player information for join during intermission. typedef struct @@ -271,7 +271,7 @@ typedef struct UINT32 pflags; UINT32 score; UINT8 ctfteam; -} ATTRPACK plrconfig; +} ATTRPACK plrconfig_pak; typedef struct { @@ -308,8 +308,8 @@ typedef struct serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...) askinfo_pak askinfo; // 61 bytes msaskinfo_pak msaskinfo; // 22 bytes - plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?) - plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?) + plrinfo_pak playerinfo[MAXPLAYERS]; // 576 bytes(?) + plrconfig_pak playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?) INT32 filesneedednum; // 4 bytes filesneededconfig_pak filesneededcfg; // ??? bytes UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes diff --git a/src/netcode/server_connection.c b/src/netcode/server_connection.c index e37c45951..924aa82d6 100644 --- a/src/netcode/server_connection.c +++ b/src/netcode/server_connection.c @@ -219,7 +219,7 @@ static void SV_SendPlayerInfo(INT32 node) netbuffer->u.playerinfo[i].data |= 0x80; } - HSendPacket(node, false, 0, sizeof(plrinfo) * MAXPLAYERS); + HSendPacket(node, false, 0, sizeof(plrinfo_pak) * MAXPLAYERS); } /** Sends a PT_SERVERCFG packet From fef13b630cd674ec23876d9fcc022a2d9c75776b Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 8 Jan 2023 00:43:18 +0100 Subject: [PATCH 59/96] Remove outdated or misleading comments --- src/netcode/client_connection.c | 11 ++--------- src/netcode/d_clisrv.c | 14 ++------------ src/netcode/protocol.h | 32 ++++++++++++++++---------------- src/netcode/server_connection.c | 2 +- src/netcode/tic_command.c | 8 -------- 5 files changed, 21 insertions(+), 46 deletions(-) diff --git a/src/netcode/client_connection.c b/src/netcode/client_connection.c index bed445a64..1adc3a65e 100644 --- a/src/netcode/client_connection.c +++ b/src/netcode/client_connection.c @@ -36,7 +36,7 @@ cl_mode_t cl_mode = CL_SEARCHING; static UINT16 cl_lastcheckedfilecount = 0; // used for full file list boolean serverisfull = false; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not tic_t firstconnectattempttime = 0; -UINT8 mynode; // my address pointofview server +UINT8 mynode; static void *snake = NULL; static void CL_DrawConnectionStatusBox(void) @@ -226,12 +226,9 @@ static boolean CL_AskFileList(INT32 firstfile) return HSendPacket(servernode, false, 0, sizeof (INT32)); } -/** Sends a special packet to declare how many players in local - * Used only in arbitratrenetstart() - * Sends a PT_CLIENTJOIN packet to the server +/** Sends a PT_CLIENTJOIN packet to the server * * \return True if the packet was successfully sent - * \todo Improve the description... * */ boolean CL_SendJoin(void) @@ -928,10 +925,6 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic if (client && (cl_mode == CL_DOWNLOADFILES || cl_mode == CL_DOWNLOADSAVEGAME)) FileReceiveTicker(); - // why are these here? this is for servers, we're a client - //if (key == 's' && server) - // doomcom->numnodes = (INT16)pnumnodes; - //FileSendTicker(); *oldtic = I_GetTime(); if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED) diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index 4589c83d3..eef9bdfe5 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -99,13 +99,8 @@ boolean adminpasswordset = false; tic_t neededtic; SINT8 servernode = 0; // the number of the server node -/// \brief do we accept new players? -/// \todo WORK! boolean acceptnewnode = true; -// Some software don't support largest packet -// (original sersetup, not exactely, but the probability of sending a packet -// of 512 bytes is like 0.1) UINT16 software_MAXPACKETLENGTH; typedef struct banreason_s @@ -300,9 +295,6 @@ static void Command_connect(void) return; } - // modified game check: no longer handled - // we don't request a restart unless the filelist differs - server = false; /* if (!stricmp(COM_Argv(1), "self")) @@ -1768,7 +1760,7 @@ boolean TryRunTics(tic_t realtics) boolean ticking; // the machine has lagged but it is not so bad - if (realtics > TICRATE/7) // FIXME: consistency failure!! + if (realtics > TICRATE/7) { if (server) realtics = 1; @@ -1802,8 +1794,6 @@ boolean TryRunTics(tic_t realtics) #ifdef DEBUGFILE if (debugfile && (realtics || neededtic > gametic)) { - //SoM: 3/30/2000: Need long INT32 in the format string for args 4 & 5. - //Shut up stupid warning! fprintf(debugfile, "------------ Tryruntic: REAL:%d NEED:%d GAME:%d LOAD: %d\n", realtics, neededtic, gametic, debugload); debugload = 100000; @@ -1983,7 +1973,7 @@ void NetUpdate(void) if (client) maketic = neededtic; - Local_Maketic(realtics); // make local tic, and call menu? + Local_Maketic(realtics); if (server) CL_SendClientCmd(); // send it diff --git a/src/netcode/protocol.h b/src/netcode/protocol.h index 1eba9286b..cbeb37f36 100644 --- a/src/netcode/protocol.h +++ b/src/netcode/protocol.h @@ -294,25 +294,25 @@ typedef struct UINT8 reserved; // Padding union { - clientcmd_pak clientpak; // 144 bytes - client2cmd_pak client2pak; // 200 bytes - servertics_pak serverpak; // 132495 bytes (more around 360, no?) - serverconfig_pak servercfg; // 773 bytes - UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...) - filetx_pak filetxpak; // 139 bytes + clientcmd_pak clientpak; + client2cmd_pak client2pak; + servertics_pak serverpak; + serverconfig_pak servercfg; + UINT8 textcmd[MAXTEXTCMD+1]; + filetx_pak filetxpak; fileack_pak fileack; UINT8 filereceived; - clientconfig_pak clientcfg; // 136 bytes + clientconfig_pak clientcfg; UINT8 md5sum[16]; - serverinfo_pak serverinfo; // 1024 bytes - serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...) - askinfo_pak askinfo; // 61 bytes - msaskinfo_pak msaskinfo; // 22 bytes - plrinfo_pak playerinfo[MAXPLAYERS]; // 576 bytes(?) - plrconfig_pak playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?) - INT32 filesneedednum; // 4 bytes - filesneededconfig_pak filesneededcfg; // ??? bytes - UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes + serverinfo_pak serverinfo; + serverrefuse_pak serverrefuse; + askinfo_pak askinfo; + msaskinfo_pak msaskinfo; + plrinfo_pak playerinfo[MAXPLAYERS]; + plrconfig_pak playerconfig[MAXPLAYERS]; + INT32 filesneedednum; + filesneededconfig_pak filesneededcfg; + UINT32 pingtable[MAXPLAYERS+1]; } u; // This is needed to pack diff packet types data together } ATTRPACK doomdata_t; diff --git a/src/netcode/server_connection.c b/src/netcode/server_connection.c index 924aa82d6..f2b0306e6 100644 --- a/src/netcode/server_connection.c +++ b/src/netcode/server_connection.c @@ -460,7 +460,7 @@ void PT_Connect(SINT8 node) ResetNode(node); SV_SendRefuse(node, M_GetText("Server couldn't send info, please try again")); /// \todo fix this !!! - return; // restart the while + return; } DEBFILE("new node joined\n"); diff --git a/src/netcode/tic_command.c b/src/netcode/tic_command.c index 180d54e69..bab0fad0a 100644 --- a/src/netcode/tic_command.c +++ b/src/netcode/tic_command.c @@ -262,11 +262,6 @@ void PT_ServerTics(SINT8 node, INT32 netconsole) else { DEBFILE(va("frame not in bound: %u\n", neededtic)); - /*if (realend < neededtic - 2 * TICRATE || neededtic + 2 * TICRATE < realstart) - I_Error("Received an out of order PT_SERVERTICS packet!\n" - "Got tics %d-%d, needed tic %d\n\n" - "Please report this crash on the Master Board,\n" - "IRC or Discord so it can be fixed.\n", (INT32)realstart, (INT32)realend, (INT32)neededtic);*/ } } @@ -447,9 +442,6 @@ void SV_SendTics(void) netnodes[0].supposedtic = maketic; } -// -// TryRunTics -// void Local_Maketic(INT32 realtics) { I_OsPolling(); // I_Getevent From db85e956c993bd52b4feff5b528c91d1616c9a7b Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 8 Jan 2023 00:46:12 +0100 Subject: [PATCH 60/96] Rename packet handlers to match their associated PT_ constants --- src/netcode/client_connection.c | 2 +- src/netcode/d_clisrv.c | 4 ++-- src/netcode/server_connection.c | 2 +- src/netcode/server_connection.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/netcode/client_connection.c b/src/netcode/client_connection.c index 1adc3a65e..ff20a6fc7 100644 --- a/src/netcode/client_connection.c +++ b/src/netcode/client_connection.c @@ -1166,7 +1166,7 @@ void PT_ServerCFG(SINT8 node) /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? /// Shouldn't them be downloaded even at intermission time? - /// Also, according to PT_Connect, the server will send the savegame even during intermission... + /// Also, according to PT_ClientJoin, the server will send the savegame even during intermission... if (netbuffer->u.servercfg.gamestate == GS_LEVEL/* || netbuffer->u.servercfg.gamestate == GS_INTERMISSION*/) cl_mode = CL_DOWNLOADSAVEGAME; diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index eef9bdfe5..7fc64b456 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -1350,7 +1350,7 @@ void SV_StartSinglePlayerServer(void) * \param node The packet sender (should be the server) * */ -static void PT_Shutdown(SINT8 node) +static void PT_ServerShutdown(SINT8 node) { (void)node; LUA_HookBool(false, HOOK(GameQuit)); @@ -1365,7 +1365,7 @@ static void PT_Shutdown(SINT8 node) * \param node The packet sender (should be the server) * */ -static void PT_Timeout(SINT8 node) +static void PT_NodeTimeout(SINT8 node) { (void)node; LUA_HookBool(false, HOOK(GameQuit)); diff --git a/src/netcode/server_connection.c b/src/netcode/server_connection.c index f2b0306e6..3e7d46ef6 100644 --- a/src/netcode/server_connection.c +++ b/src/netcode/server_connection.c @@ -422,7 +422,7 @@ GetRefuseMessage (SINT8 node, INT32 rejoinernum) * \param node The packet sender * */ -void PT_Connect(SINT8 node) +void PT_ClientJoin(SINT8 node) { char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1]; INT32 numplayers = netbuffer->u.clientcfg.localplayers; diff --git a/src/netcode/server_connection.h b/src/netcode/server_connection.h index 585c9e428..96f7566ba 100644 --- a/src/netcode/server_connection.h +++ b/src/netcode/server_connection.h @@ -17,7 +17,7 @@ #include "../doomdef.h" #include "../doomtype.h" -void PT_Connect(SINT8 node); +void PT_ClientJoin(SINT8 node); void PT_AskInfoViaMS(SINT8 node); void PT_TellFilesNeeded(SINT8 node); void PT_AskInfo(SINT8 node); From 75b52171d2908896617d77cfb8a943876439773b Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 8 Jan 2023 00:47:33 +0100 Subject: [PATCH 61/96] Call all packet handlers from the same place --- src/netcode/d_clisrv.c | 41 +++++++++++---------------------- src/netcode/server_connection.c | 2 +- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index 7fc64b456..c004eeede 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -1352,6 +1352,9 @@ void SV_StartSinglePlayerServer(void) */ static void PT_ServerShutdown(SINT8 node) { + if (node != servernode || server || cl_mode == CL_SEARCHING) + return; + (void)node; LUA_HookBool(false, HOOK(GameQuit)); D_QuitNetGame(); @@ -1412,7 +1415,11 @@ static void PT_Login(SINT8 node, INT32 netconsole) static void PT_ClientQuit(SINT8 node, INT32 netconsole) { if (client) + { + if (node == servernode && cl_mode != CL_SEARCHING && netbuffer->packettype == PT_NODETIMEOUT) + PT_NodeTimeout(node); return; + } if (!netnodes[node].ingame) { @@ -1505,6 +1512,7 @@ static void HandlePacketFromAwayNode(SINT8 node) switch (netbuffer->packettype) { case PT_ASKINFOVIAMS : PT_AskInfoViaMS (node ); break; + case PT_SERVERINFO : PT_ServerInfo (node ); break; case PT_TELLFILESNEEDED: PT_TellFilesNeeded(node ); break; case PT_MOREFILESNEEDED: PT_MoreFilesNeeded(node ); break; case PT_ASKINFO : PT_AskInfo (node ); break; @@ -1517,6 +1525,8 @@ static void HandlePacketFromAwayNode(SINT8 node) case PT_NODETIMEOUT : PT_ClientQuit (node, -1); break; case PT_CLIENTQUIT : PT_ClientQuit (node, -1); break; case PT_SERVERTICS : PT_ServerTics (node, -1); break; + case PT_CLIENTJOIN : PT_ClientJoin (node ); break; + case PT_SERVERSHUTDOWN : PT_ServerShutdown (node ); break; case PT_CLIENTCMD : break; // This is not an "unknown packet" default: @@ -1566,6 +1576,7 @@ static void HandlePacketFromPlayer(SINT8 node) case PT_ASKLUAFILE : PT_AskLuaFile (node ); break; case PT_HASLUAFILE : PT_HasLuaFile (node ); break; case PT_RECEIVEDGAMESTATE : PT_ReceivedGamestate (node ); break; + case PT_SERVERINFO : PT_ServerInfo (node ); break; // CLIENT RECEIVE case PT_SERVERTICS : PT_ServerTics (node, netconsole); break; @@ -1575,7 +1586,9 @@ static void HandlePacketFromPlayer(SINT8 node) case PT_FILERECEIVED : PT_FileReceived (node ); break; case PT_WILLRESENDGAMESTATE: PT_WillResendGamestate(node ); break; case PT_SENDINGLUAFILE : PT_SendingLuaFile (node ); break; + case PT_SERVERSHUTDOWN : PT_ServerShutdown (node ); break; case PT_SERVERCFG : break; + case PT_CLIENTJOIN : break; default: DEBFILE(va("UNKNOWN PACKET TYPE RECEIVED %d from host %d\n", @@ -1598,34 +1611,6 @@ void GetPackets(void) { node = (SINT8)doomcom->remotenode; - if (netbuffer->packettype == PT_CLIENTJOIN && server) - { - PT_Connect(node); - continue; - } - if (node == servernode && client && cl_mode != CL_SEARCHING) - { - if (netbuffer->packettype == PT_SERVERSHUTDOWN) - { - PT_Shutdown(node); - continue; - } - if (netbuffer->packettype == PT_NODETIMEOUT) - { - PT_Timeout(node); - continue; - } - } - - if (netbuffer->packettype == PT_SERVERINFO) - { - PT_ServerInfo(node); - continue; - } - - if (netbuffer->packettype == PT_PLAYERINFO) - continue; // We do nothing with PLAYERINFO, that's for the MS browser. - // Packet received from someone already playing if (netnodes[node].ingame) HandlePacketFromPlayer(node); diff --git a/src/netcode/server_connection.c b/src/netcode/server_connection.c index 3e7d46ef6..9b41da920 100644 --- a/src/netcode/server_connection.c +++ b/src/netcode/server_connection.c @@ -430,7 +430,7 @@ void PT_ClientJoin(SINT8 node) INT32 i; // Ignore duplicate packets - if (netnodes[node].ingame) + if (client || netnodes[node].ingame) return; rejoinernum = FindRejoinerNum(node); From 62986da9da31cce87a7c551c63239fdf3c695378 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 8 Jan 2023 13:27:08 +0100 Subject: [PATCH 62/96] Remove useless variable --- src/netcode/d_clisrv.c | 9 --------- src/netcode/server_connection.c | 3 --- src/netcode/server_connection.h | 1 - 3 files changed, 13 deletions(-) diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index c004eeede..ecd7c9bbe 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -1605,8 +1605,6 @@ void GetPackets(void) { SINT8 node; // The packet sender - player_joining = false; - while (HGetPacket()) { node = (SINT8)doomcom->remotenode; @@ -1793,13 +1791,6 @@ boolean TryRunTics(tic_t realtics) hu_stopped = false; } - if (player_joining) - { - if (realtics) - hu_stopped = true; - return false; - } - if (ticking) { if (advancedemo) diff --git a/src/netcode/server_connection.c b/src/netcode/server_connection.c index 9b41da920..ed0e28309 100644 --- a/src/netcode/server_connection.c +++ b/src/netcode/server_connection.c @@ -37,8 +37,6 @@ tic_t joindelay = 0; // The actual timeout will be longer depending on the savegame length char playeraddress[MAXPLAYERS][64]; -UINT8 player_joining = false; - consvar_t cv_showjoinaddress = CVAR_INIT ("showjoinaddress", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); consvar_t cv_allownewplayer = CVAR_INIT ("allowjoin", "On", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); @@ -475,7 +473,6 @@ void PT_ClientJoin(SINT8 node) SV_AddPlayer(node, names[i]); joindelay += cv_joindelay.value * TICRATE; - player_joining = true; } void PT_AskInfoViaMS(SINT8 node) diff --git a/src/netcode/server_connection.h b/src/netcode/server_connection.h index 96f7566ba..7481d0eb5 100644 --- a/src/netcode/server_connection.h +++ b/src/netcode/server_connection.h @@ -25,7 +25,6 @@ void PT_AskInfo(SINT8 node); extern tic_t jointimeout; extern tic_t joindelay; extern char playeraddress[MAXPLAYERS][64]; -extern UINT8 player_joining; extern consvar_t cv_showjoinaddress, cv_allownewplayer, cv_maxplayers, cv_joindelay, cv_rejointimeout; #endif From 5a608120ff577c645ca7ec5732394c74a6520c8a Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 8 Jan 2023 16:28:41 +0100 Subject: [PATCH 63/96] Simplify convoluted code --- src/netcode/d_clisrv.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index ecd7c9bbe..5bb2c4600 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -1421,15 +1421,9 @@ static void PT_ClientQuit(SINT8 node, INT32 netconsole) return; } - if (!netnodes[node].ingame) - { - Net_CloseConnection(node); - return; - } - // nodeingame will be put false in the execution of kick command // this allow to send some packets to the quitting client to have their ack back - if (netconsole != -1 && playeringame[netconsole]) + if (netnodes[node].ingame && netconsole != -1 && playeringame[netconsole]) { UINT8 kickmsg; @@ -1440,17 +1434,18 @@ static void PT_ClientQuit(SINT8 node, INT32 netconsole) kickmsg |= KICK_MSG_KEEP_BODY; SendKick(netconsole, kickmsg); - netnodes[node].player = -1; if (netnodes[node].player2 != -1 && netnodes[node].player2 >= 0 && playeringame[(UINT8)netnodes[node].player2]) { SendKick(netnodes[node].player2, kickmsg); - netnodes[node].player2 = -1; } } + Net_CloseConnection(node); netnodes[node].ingame = false; + netnodes[node].player = -1; + netnodes[node].player2 = -1; } static void PT_AskLuaFile(SINT8 node) @@ -1603,11 +1598,9 @@ static void HandlePacketFromPlayer(SINT8 node) */ void GetPackets(void) { - SINT8 node; // The packet sender - while (HGetPacket()) { - node = (SINT8)doomcom->remotenode; + SINT8 node = doomcom->remotenode; // Packet received from someone already playing if (netnodes[node].ingame) @@ -1740,8 +1733,6 @@ If they're not lagging, decrement the timer by 1. Of course, reset all of this i boolean TryRunTics(tic_t realtics) { - boolean ticking; - // the machine has lagged but it is not so bad if (realtics > TICRATE/7) { @@ -1783,16 +1774,11 @@ boolean TryRunTics(tic_t realtics) } #endif - ticking = neededtic > gametic; - - if (ticking) + if (neededtic > gametic) { if (realtics) hu_stopped = false; - } - if (ticking) - { if (advancedemo) { if (timedemo_quit) @@ -1826,16 +1812,19 @@ boolean TryRunTics(tic_t realtics) if (client && gamestate == GS_LEVEL && leveltime > 3 && neededtic <= gametic + cv_netticbuffer.value) break; } + + return true; } else { if (realtics) hu_stopped = true; - } - return ticking; + return false; + } } + static INT32 pingtimeout[MAXPLAYERS]; static inline void PingUpdate(void) @@ -1976,8 +1965,6 @@ void NetUpdate(void) { if (!demoplayback) { - INT32 counts; - hu_redownloadinggamestate = false; firstticstosend = gametic; @@ -1991,8 +1978,7 @@ void NetUpdate(void) } // Don't erase tics not acknowledged - counts = realtics; - + INT32 counts = realtics; if (maketic + counts >= firstticstosend + BACKUPTICS) counts = firstticstosend+BACKUPTICS-maketic-1; From 1eb801399b2e8c9a181c4924cb9be939a7898c9e Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 8 Jan 2023 16:33:21 +0100 Subject: [PATCH 64/96] Move comment to an appropriate place --- src/netcode/d_clisrv.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index 5bb2c4600..b0d534b84 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -1725,12 +1725,6 @@ INT16 Consistancy(void) return (INT16)(ret & 0xFFFF); } -/* -Ping Update except better: -We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out. -If they're not lagging, decrement the timer by 1. Of course, reset all of this if they leave. -*/ - boolean TryRunTics(tic_t realtics) { // the machine has lagged but it is not so bad @@ -1824,6 +1818,11 @@ boolean TryRunTics(tic_t realtics) } } +/* +Ping Update except better: +We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out. +If they're not lagging, decrement the timer by 1. Of course, reset all of this if they leave. +*/ static INT32 pingtimeout[MAXPLAYERS]; From 62cfb0eb81ac9e3216afbced1c02fe8092ba880b Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Mon, 9 Jan 2023 21:39:33 +0100 Subject: [PATCH 65/96] Fix clients not being able to join servers --- src/netcode/d_clisrv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index b0d534b84..6680c7e42 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -1523,6 +1523,7 @@ static void HandlePacketFromAwayNode(SINT8 node) case PT_CLIENTJOIN : PT_ClientJoin (node ); break; case PT_SERVERSHUTDOWN : PT_ServerShutdown (node ); break; case PT_CLIENTCMD : break; // This is not an "unknown packet" + case PT_PLAYERINFO : break; // This is not an "unknown packet" default: DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype)); From 18bfc3266aa30c81acb6ae91926231ba29126329 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Mon, 9 Jan 2023 22:14:58 +0100 Subject: [PATCH 66/96] Remove reboundstore timeout hack --- src/netcode/d_clisrv.c | 50 ++++++++------------------------------- src/netcode/d_clisrv.h | 1 + src/netcode/d_net.c | 19 +++++---------- src/netcode/net_command.c | 10 ++++++++ src/netcode/net_command.h | 1 + src/netcode/protocol.h | 1 - 6 files changed, 28 insertions(+), 54 deletions(-) diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index 6680c7e42..81d7e5543 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -479,6 +479,15 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason) P_CheckRacers(); } +void CL_HandleTimeout(void) +{ + LUA_HookBool(false, HOOK(GameQuit)); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText("Server Timeout\n\nPress Esc\n"), NULL, MM_NOTHING); +} + void CL_Reset(void) { if (metalrecording) @@ -1363,21 +1372,6 @@ static void PT_ServerShutdown(SINT8 node) M_StartMessage(M_GetText("Server has shutdown\n\nPress Esc\n"), NULL, MM_NOTHING); } -/** Called when a PT_NODETIMEOUT packet is received - * - * \param node The packet sender (should be the server) - * - */ -static void PT_NodeTimeout(SINT8 node) -{ - (void)node; - LUA_HookBool(false, HOOK(GameQuit)); - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText("Server Timeout\n\nPress Esc\n"), NULL, MM_NOTHING); -} - static void PT_Login(SINT8 node, INT32 netconsole) { (void)node; @@ -1415,32 +1409,10 @@ static void PT_Login(SINT8 node, INT32 netconsole) static void PT_ClientQuit(SINT8 node, INT32 netconsole) { if (client) - { - if (node == servernode && cl_mode != CL_SEARCHING && netbuffer->packettype == PT_NODETIMEOUT) - PT_NodeTimeout(node); return; - } - // nodeingame will be put false in the execution of kick command - // this allow to send some packets to the quitting client to have their ack back if (netnodes[node].ingame && netconsole != -1 && playeringame[netconsole]) - { - UINT8 kickmsg; - - if (netbuffer->packettype == PT_NODETIMEOUT) - kickmsg = KICK_MSG_TIMEOUT; - else - kickmsg = KICK_MSG_PLAYER_QUIT; - kickmsg |= KICK_MSG_KEEP_BODY; - - SendKick(netconsole, kickmsg); - - if (netnodes[node].player2 != -1 && netnodes[node].player2 >= 0 - && playeringame[(UINT8)netnodes[node].player2]) - { - SendKick(netnodes[node].player2, kickmsg); - } - } + SendKicksForNode(node, KICK_MSG_PLAYER_QUIT | KICK_MSG_KEEP_BODY); Net_CloseConnection(node); netnodes[node].ingame = false; @@ -1517,7 +1489,6 @@ static void HandlePacketFromAwayNode(SINT8 node) case PT_FILEACK : PT_FileAck (node ); break; case PT_FILERECEIVED : PT_FileReceived (node ); break; case PT_REQUESTFILE : PT_RequestFile (node ); break; - case PT_NODETIMEOUT : PT_ClientQuit (node, -1); break; case PT_CLIENTQUIT : PT_ClientQuit (node, -1); break; case PT_SERVERTICS : PT_ServerTics (node, -1); break; case PT_CLIENTJOIN : PT_ClientJoin (node ); break; @@ -1566,7 +1537,6 @@ static void HandlePacketFromPlayer(SINT8 node) case PT_TEXTCMD : PT_TextCmd (node, netconsole); break; case PT_TEXTCMD2 : PT_TextCmd (node, netconsole); break; case PT_LOGIN : PT_Login (node, netconsole); break; - case PT_NODETIMEOUT : PT_ClientQuit (node, netconsole); break; case PT_CLIENTQUIT : PT_ClientQuit (node, netconsole); break; case PT_CANRECEIVEGAMESTATE: PT_CanReceiveGamestate(node ); break; case PT_ASKLUAFILE : PT_AskLuaFile (node ); break; diff --git a/src/netcode/d_clisrv.h b/src/netcode/d_clisrv.h index 9cb3ef3e8..0abd638ce 100644 --- a/src/netcode/d_clisrv.h +++ b/src/netcode/d_clisrv.h @@ -94,6 +94,7 @@ void CL_RemoveSplitscreenPlayer(void); void CL_Reset(void); void CL_ClearPlayer(INT32 playernum); void CL_RemovePlayer(INT32 playernum, kickreason_t reason); +void CL_HandleTimeout(void); // Is there a game running boolean Playing(void); diff --git a/src/netcode/d_net.c b/src/netcode/d_net.c index 972342282..3c16392d0 100644 --- a/src/netcode/d_net.c +++ b/src/netcode/d_net.c @@ -27,6 +27,7 @@ #include "d_netfil.h" #include "d_clisrv.h" #include "tic_command.h" +#include "net_command.h" #include "../z_zone.h" #include "i_tcp.h" #include "../d_main.h" // srb2home @@ -461,14 +462,10 @@ void Net_ConnectionTimeout(INT32 node) return; nodes[node].flags |= NF_TIMEOUT; - // Send a very special packet to self (hack the reboundstore queue) - // Main code will handle it - reboundstore[rebound_head].packettype = PT_NODETIMEOUT; - reboundstore[rebound_head].ack = 0; - reboundstore[rebound_head].ackreturn = 0; - reboundstore[rebound_head].u.textcmd[0] = (UINT8)node; - reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1); - rebound_head = (rebound_head+1) % MAXREBOUND; + if (server) + SendKicksForNode(node, KICK_MSG_TIMEOUT | KICK_MSG_KEEP_BODY); + else + CL_HandleTimeout(); // Do not redo it quickly (if we do not close connection it is // for a good reason!) @@ -782,7 +779,6 @@ static const char *packettypename[NUMPACKETTYPE] = "TEXTCMD", "TEXTCMD2", "CLIENTJOIN", - "NODETIMEOUT", "LOGIN", "TELLFILESNEEDED", "MOREFILESNEEDED", @@ -1065,10 +1061,7 @@ boolean HGetPacket(void) { M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]); doomcom->datalength = reboundsize[rebound_tail]; - if (netbuffer->packettype == PT_NODETIMEOUT) - doomcom->remotenode = netbuffer->u.textcmd[0]; - else - doomcom->remotenode = 0; + doomcom->remotenode = 0; rebound_tail = (rebound_tail+1) % MAXREBOUND; #ifdef DEBUGFILE diff --git a/src/netcode/net_command.c b/src/netcode/net_command.c index 95a49a959..13477d42d 100644 --- a/src/netcode/net_command.c +++ b/src/netcode/net_command.c @@ -315,3 +315,13 @@ void SendKick(UINT8 playernum, UINT8 msg) buf[1] = msg; SendNetXCmd(XD_KICK, &buf, 2); } + +void SendKicksForNode(SINT8 node, UINT8 msg) +{ + if (!netnodes[node].ingame) + return; + + for (INT32 playernum = netnodes[node].player; playernum != -1; playernum = netnodes[node].player2) + if (playernum != -1 && playeringame[playernum]) + SendKick(playernum, msg); +} diff --git a/src/netcode/net_command.h b/src/netcode/net_command.h index 1fc5035c8..f1b4b2f3f 100644 --- a/src/netcode/net_command.h +++ b/src/netcode/net_command.h @@ -58,5 +58,6 @@ size_t TotalTextCmdPerTic(tic_t tic); void PT_TextCmd(SINT8 node, INT32 netconsole); void SendKick(UINT8 playernum, UINT8 msg); +void SendKicksForNode(SINT8 node, UINT8 msg); #endif diff --git a/src/netcode/protocol.h b/src/netcode/protocol.h index cbeb37f36..374cc5bff 100644 --- a/src/netcode/protocol.h +++ b/src/netcode/protocol.h @@ -85,7 +85,6 @@ typedef enum PT_TEXTCMD, // Extra text commands from the client. PT_TEXTCMD2, // Splitscreen text commands. PT_CLIENTJOIN, // Client wants to join; used in start game. - PT_NODETIMEOUT, // Packet sent to self if the connection times out. PT_LOGIN, // Login attempt from the client. From ab23b445b027ef35af52eb513defc37d58339e22 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Thu, 12 Jan 2023 19:40:31 +0100 Subject: [PATCH 67/96] Move netgame commands to a new file --- src/netcode/Sourcefile | 1 + src/netcode/commands.c | 489 +++++++++++++++++++++++++++++++++++++++++ src/netcode/commands.h | 33 +++ src/netcode/d_clisrv.c | 460 +------------------------------------- src/netcode/d_net.h | 1 - 5 files changed, 524 insertions(+), 460 deletions(-) create mode 100644 src/netcode/commands.c create mode 100644 src/netcode/commands.h diff --git a/src/netcode/Sourcefile b/src/netcode/Sourcefile index c59050367..7c0354714 100644 --- a/src/netcode/Sourcefile +++ b/src/netcode/Sourcefile @@ -4,6 +4,7 @@ client_connection.c tic_command.c net_command.c gamestate.c +commands.c d_net.c d_netcmd.c d_netfil.c diff --git a/src/netcode/commands.c b/src/netcode/commands.c new file mode 100644 index 000000000..834e1c666 --- /dev/null +++ b/src/netcode/commands.c @@ -0,0 +1,489 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file commands.c +/// \brief Various netgame commands, such as kick and ban + +#include "commands.h" +#include "d_clisrv.h" +#include "client_connection.h" +#include "net_command.h" +#include "d_netcmd.h" +#include "d_net.h" +#include "i_net.h" +#include "protocol.h" +#include "../byteptr.h" +#include "../d_main.h" +#include "../g_game.h" +#include "../w_wad.h" +#include "../z_zone.h" +#include "../doomstat.h" +#include "../doomdef.h" +#include "../r_local.h" +#include +#include +#include +#include + +typedef struct banreason_s +{ + char *reason; + struct banreason_s *prev; //-1 + struct banreason_s *next; //+1 +} banreason_t; + +static banreason_t *reasontail = NULL; //last entry, use prev +static banreason_t *reasonhead = NULL; //1st entry, use next + +void Ban_Add(const char *reason) +{ + banreason_t *reasonlist = malloc(sizeof(*reasonlist)); + + if (!reasonlist) + return; + if (!reason) + reason = "NA"; + + reasonlist->next = NULL; + reasonlist->reason = Z_StrDup(reason); + if ((reasonlist->prev = reasontail) == NULL) + reasonhead = reasonlist; + else + reasontail->next = reasonlist; + reasontail = reasonlist; +} + +static void Ban_Clear(void) +{ + banreason_t *temp; + + I_ClearBans(); + + reasontail = NULL; + + while (reasonhead) + { + temp = reasonhead->next; + Z_Free(reasonhead->reason); + free(reasonhead); + reasonhead = temp; + } +} + +void Ban_Load_File(boolean warning) +{ + FILE *f; + size_t i; + const char *address, *mask; + char buffer[MAX_WADPATH]; + + if (!I_ClearBans) + return; + + f = fopen(va("%s"PATHSEP"%s", srb2home, "ban.txt"), "r"); + + if (!f) + { + if (warning) + CONS_Alert(CONS_WARNING, M_GetText("Could not open ban.txt for ban list\n")); + return; + } + + Ban_Clear(); + + for (i=0; fgets(buffer, (int)sizeof(buffer), f); i++) + { + address = strtok(buffer, " \t\r\n"); + mask = strtok(NULL, " \t\r\n"); + + I_SetBanAddress(address, mask); + + Ban_Add(strtok(NULL, "\r\n")); + } + + fclose(f); +} + +void D_SaveBan(void) +{ + FILE *f; + size_t i; + banreason_t *reasonlist = reasonhead; + const char *address, *mask; + const char *path = va("%s"PATHSEP"%s", srb2home, "ban.txt"); + + if (!reasonhead) + { + remove(path); + return; + } + + f = fopen(path, "w"); + + if (!f) + { + CONS_Alert(CONS_WARNING, M_GetText("Could not save ban list into ban.txt\n")); + return; + } + + for (i = 0;(address = I_GetBanAddress(i)) != NULL;i++) + { + if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL) + fprintf(f, "%s 0", address); + else + fprintf(f, "%s %s", address, mask); + + if (reasonlist && reasonlist->reason) + fprintf(f, " %s\n", reasonlist->reason); + else + fprintf(f, " %s\n", "NA"); + + if (reasonlist) reasonlist = reasonlist->next; + } + + fclose(f); +} + +void Command_ShowBan(void) //Print out ban list +{ + size_t i; + const char *address, *mask; + banreason_t *reasonlist = reasonhead; + + if (I_GetBanAddress) + CONS_Printf(M_GetText("Ban List:\n")); + else + return; + + for (i = 0;(address = I_GetBanAddress(i)) != NULL;i++) + { + if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL) + CONS_Printf("%s: %s ", sizeu1(i+1), address); + else + CONS_Printf("%s: %s/%s ", sizeu1(i+1), address, mask); + + if (reasonlist && reasonlist->reason) + CONS_Printf("(%s)\n", reasonlist->reason); + else + CONS_Printf("\n"); + + if (reasonlist) reasonlist = reasonlist->next; + } + + if (i == 0 && !address) + CONS_Printf(M_GetText("(empty)\n")); +} + +void Command_ClearBans(void) +{ + if (!I_ClearBans) + return; + + Ban_Clear(); + D_SaveBan(); +} + +void Command_Ban(void) +{ + if (COM_Argc() < 2) + { + CONS_Printf(M_GetText("Ban : ban and kick a player\n")); + return; + } + + if (!netgame) // Don't kick Tails in splitscreen! + { + CONS_Printf(M_GetText("This only works in a netgame.\n")); + return; + } + + if (server || IsPlayerAdmin(consoleplayer)) + { + UINT8 buf[3 + MAX_REASONLENGTH]; + UINT8 *p = buf; + const SINT8 pn = nametonum(COM_Argv(1)); + const INT32 node = playernode[(INT32)pn]; + + if (pn == -1 || pn == 0) + return; + + WRITEUINT8(p, pn); + + if (server && I_Ban && !I_Ban(node)) // only the server is allowed to do this right now + { + CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n")); + WRITEUINT8(p, KICK_MSG_GO_AWAY); + SendNetXCmd(XD_KICK, &buf, 2); + } + else + { + if (server) // only the server is allowed to do this right now + { + Ban_Add(COM_Argv(2)); + D_SaveBan(); // save the ban list + } + + if (COM_Argc() == 2) + { + WRITEUINT8(p, KICK_MSG_BANNED); + SendNetXCmd(XD_KICK, &buf, 2); + } + else + { + size_t i, j = COM_Argc(); + char message[MAX_REASONLENGTH]; + + //Steal from the motd code so you don't have to put the reason in quotes. + strlcpy(message, COM_Argv(2), sizeof message); + for (i = 3; i < j; i++) + { + strlcat(message, " ", sizeof message); + strlcat(message, COM_Argv(i), sizeof message); + } + + WRITEUINT8(p, KICK_MSG_CUSTOM_BAN); + WRITESTRINGN(p, message, MAX_REASONLENGTH); + SendNetXCmd(XD_KICK, &buf, p - buf); + } + } + } + else + CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); + +} + +void Command_BanIP(void) +{ + if (COM_Argc() < 2) + { + CONS_Printf(M_GetText("banip : ban an ip address\n")); + return; + } + + if (server) // Only the server can use this, otherwise does nothing. + { + const char *address = (COM_Argv(1)); + const char *reason; + + if (COM_Argc() == 2) + reason = NULL; + else + reason = COM_Argv(2); + + + if (I_SetBanAddress && I_SetBanAddress(address, NULL)) + { + if (reason) + CONS_Printf("Banned IP address %s for: %s\n", address, reason); + else + CONS_Printf("Banned IP address %s\n", address); + + Ban_Add(reason); + D_SaveBan(); + } + else + { + return; + } + } +} + +void Command_ReloadBan(void) //recheck ban.txt +{ + Ban_Load_File(true); +} + +void Command_Kick(void) +{ + if (COM_Argc() < 2) + { + CONS_Printf(M_GetText("kick : kick a player\n")); + return; + } + + if (!netgame) // Don't kick Tails in splitscreen! + { + CONS_Printf(M_GetText("This only works in a netgame.\n")); + return; + } + + if (server || IsPlayerAdmin(consoleplayer)) + { + UINT8 buf[3 + MAX_REASONLENGTH]; + UINT8 *p = buf; + const SINT8 pn = nametonum(COM_Argv(1)); + + if (pn == -1 || pn == 0) + return; + + // Special case if we are trying to kick a player who is downloading the game state: + // trigger a timeout instead of kicking them, because a kick would only + // take effect after they have finished downloading + if (server && playernode[pn] != UINT8_MAX && netnodes[playernode[pn]].sendingsavegame) + { + Net_ConnectionTimeout(playernode[pn]); + return; + } + + WRITESINT8(p, pn); + + if (COM_Argc() == 2) + { + WRITEUINT8(p, KICK_MSG_GO_AWAY); + SendNetXCmd(XD_KICK, &buf, 2); + } + else + { + size_t i, j = COM_Argc(); + char message[MAX_REASONLENGTH]; + + //Steal from the motd code so you don't have to put the reason in quotes. + strlcpy(message, COM_Argv(2), sizeof message); + for (i = 3; i < j; i++) + { + strlcat(message, " ", sizeof message); + strlcat(message, COM_Argv(i), sizeof message); + } + + WRITEUINT8(p, KICK_MSG_CUSTOM_KICK); + WRITESTRINGN(p, message, MAX_REASONLENGTH); + SendNetXCmd(XD_KICK, &buf, p - buf); + } + } + else + CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); +} + +void Command_connect(void) +{ + if (COM_Argc() < 2 || *COM_Argv(1) == 0) + { + CONS_Printf(M_GetText( + "Connect (port): connect to a server\n" + "Connect ANY: connect to the first lan server found\n" + //"Connect SELF: connect to your own server.\n" + )); + return; + } + + if (Playing() || titledemo) + { + CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n")); + return; + } + + server = false; +/* + if (!stricmp(COM_Argv(1), "self")) + { + servernode = 0; + server = true; + /// \bug should be but... + //SV_SpawnServer(); + } + else +*/ + { + // used in menu to connect to a server in the list + if (netgame && !stricmp(COM_Argv(1), "node")) + { + servernode = (SINT8)atoi(COM_Argv(2)); + } + else if (netgame) + { + CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n")); + return; + } + else if (I_NetOpenSocket) + { + I_NetOpenSocket(); + netgame = true; + multiplayer = true; + + if (!stricmp(COM_Argv(1), "any")) + servernode = BROADCASTADDR; + else if (I_NetMakeNodewPort) + { + if (COM_Argc() >= 3) // address AND port + servernode = I_NetMakeNodewPort(COM_Argv(1), COM_Argv(2)); + else // address only, or address:port + servernode = I_NetMakeNode(COM_Argv(1)); + } + else + { + CONS_Alert(CONS_ERROR, M_GetText("There is no server identification with this network driver\n")); + D_CloseConnection(); + return; + } + } + else + CONS_Alert(CONS_ERROR, M_GetText("There is no network driver\n")); + } + + splitscreen = false; + SplitScreen_OnChange(); + botingame = false; + botskin = 0; + CL_ConnectToServer(); +} + +void Command_GetPlayerNum(void) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i]) + { + if (serverplayer == i) + CONS_Printf(M_GetText("num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]); + else + CONS_Printf(M_GetText("\x82num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]); + } +} + +/** Lists all players and their player numbers. + * + * \sa Command_GetPlayerNum + */ +void Command_Nodes(void) +{ + INT32 i; + size_t maxlen = 0; + const char *address; + + for (i = 0; i < MAXPLAYERS; i++) + { + const size_t plen = strlen(player_names[i]); + if (playeringame[i] && plen > maxlen) + maxlen = plen; + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + { + CONS_Printf("%.2u: %*s", i, (int)maxlen, player_names[i]); + + if (playernode[i] != UINT8_MAX) + { + CONS_Printf(" - node %.2d", playernode[i]); + if (I_GetNodeAddress && (address = I_GetNodeAddress(playernode[i])) != NULL) + CONS_Printf(" - %s", address); + } + + if (IsPlayerAdmin(i)) + CONS_Printf(M_GetText(" (verified admin)")); + + if (players[i].spectator) + CONS_Printf(M_GetText(" (spectator)")); + + CONS_Printf("\n"); + } + } +} diff --git a/src/netcode/commands.h b/src/netcode/commands.h new file mode 100644 index 000000000..5ff4d1cae --- /dev/null +++ b/src/netcode/commands.h @@ -0,0 +1,33 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file commands.h +/// \brief Various netgame commands, such as kick and ban + +#ifndef __COMMANDS__ +#define __COMMANDS__ + +#include "../doomdef.h" + +#define MAX_REASONLENGTH 30 + +void Ban_Add(const char *reason); +void D_SaveBan(void); +void Ban_Load_File(boolean warning); +void Command_ShowBan(void); +void Command_ClearBans(void); +void Command_Ban(void); +void Command_BanIP(void); +void Command_ReloadBan(void); +void Command_Kick(void); +void Command_connect(void); +void Command_GetPlayerNum(void); +void Command_Nodes(void); + +#endif diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index 81d7e5543..506de8c02 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -54,6 +54,7 @@ #include "tic_command.h" #include "net_command.h" #include "gamestate.h" +#include "commands.h" #include "protocol.h" // @@ -69,8 +70,6 @@ // firstticstosend is used to optimize a condition // Normally maketic >= gametic > 0 -#define MAX_REASONLENGTH 30 - boolean server = true; // true or false but !server == client boolean serverrunning = false; INT32 serverplayer = 0; @@ -103,16 +102,6 @@ boolean acceptnewnode = true; UINT16 software_MAXPACKETLENGTH; -typedef struct banreason_s -{ - char *reason; - struct banreason_s *prev; //-1 - struct banreason_s *next; //+1 -} banreason_t; - -static banreason_t *reasontail = NULL; //last entry, use prev -static banreason_t *reasonhead = NULL; //1st entry, use next - static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL); @@ -124,232 +113,6 @@ consvar_t cv_blamecfail = CVAR_INIT ("blamecfail", "Off", CV_SAVE|CV_NETVAR, CV_ static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}}; consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_cons_t, NULL); -static void Command_ShowBan(void) //Print out ban list -{ - size_t i; - const char *address, *mask; - banreason_t *reasonlist = reasonhead; - - if (I_GetBanAddress) - CONS_Printf(M_GetText("Ban List:\n")); - else - return; - - for (i = 0;(address = I_GetBanAddress(i)) != NULL;i++) - { - if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL) - CONS_Printf("%s: %s ", sizeu1(i+1), address); - else - CONS_Printf("%s: %s/%s ", sizeu1(i+1), address, mask); - - if (reasonlist && reasonlist->reason) - CONS_Printf("(%s)\n", reasonlist->reason); - else - CONS_Printf("\n"); - - if (reasonlist) reasonlist = reasonlist->next; - } - - if (i == 0 && !address) - CONS_Printf(M_GetText("(empty)\n")); -} - -void D_SaveBan(void) -{ - FILE *f; - size_t i; - banreason_t *reasonlist = reasonhead; - const char *address, *mask; - const char *path = va("%s"PATHSEP"%s", srb2home, "ban.txt"); - - if (!reasonhead) - { - remove(path); - return; - } - - f = fopen(path, "w"); - - if (!f) - { - CONS_Alert(CONS_WARNING, M_GetText("Could not save ban list into ban.txt\n")); - return; - } - - for (i = 0;(address = I_GetBanAddress(i)) != NULL;i++) - { - if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL) - fprintf(f, "%s 0", address); - else - fprintf(f, "%s %s", address, mask); - - if (reasonlist && reasonlist->reason) - fprintf(f, " %s\n", reasonlist->reason); - else - fprintf(f, " %s\n", "NA"); - - if (reasonlist) reasonlist = reasonlist->next; - } - - fclose(f); -} - -static void Ban_Add(const char *reason) -{ - banreason_t *reasonlist = malloc(sizeof(*reasonlist)); - - if (!reasonlist) - return; - if (!reason) - reason = "NA"; - - reasonlist->next = NULL; - reasonlist->reason = Z_StrDup(reason); - if ((reasonlist->prev = reasontail) == NULL) - reasonhead = reasonlist; - else - reasontail->next = reasonlist; - reasontail = reasonlist; -} - -static void Ban_Clear(void) -{ - banreason_t *temp; - - I_ClearBans(); - - reasontail = NULL; - - while (reasonhead) - { - temp = reasonhead->next; - Z_Free(reasonhead->reason); - free(reasonhead); - reasonhead = temp; - } -} - -static void Command_ClearBans(void) -{ - if (!I_ClearBans) - return; - - Ban_Clear(); - D_SaveBan(); -} - -static void Ban_Load_File(boolean warning) -{ - FILE *f; - size_t i; - const char *address, *mask; - char buffer[MAX_WADPATH]; - - if (!I_ClearBans) - return; - - f = fopen(va("%s"PATHSEP"%s", srb2home, "ban.txt"), "r"); - - if (!f) - { - if (warning) - CONS_Alert(CONS_WARNING, M_GetText("Could not open ban.txt for ban list\n")); - return; - } - - Ban_Clear(); - - for (i=0; fgets(buffer, (int)sizeof(buffer), f); i++) - { - address = strtok(buffer, " \t\r\n"); - mask = strtok(NULL, " \t\r\n"); - - I_SetBanAddress(address, mask); - - Ban_Add(strtok(NULL, "\r\n")); - } - - fclose(f); -} - -static void Command_ReloadBan(void) //recheck ban.txt -{ - Ban_Load_File(true); -} - -static void Command_connect(void) -{ - if (COM_Argc() < 2 || *COM_Argv(1) == 0) - { - CONS_Printf(M_GetText( - "Connect (port): connect to a server\n" - "Connect ANY: connect to the first lan server found\n" - //"Connect SELF: connect to your own server.\n" - )); - return; - } - - if (Playing() || titledemo) - { - CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n")); - return; - } - - server = false; -/* - if (!stricmp(COM_Argv(1), "self")) - { - servernode = 0; - server = true; - /// \bug should be but... - //SV_SpawnServer(); - } - else -*/ - { - // used in menu to connect to a server in the list - if (netgame && !stricmp(COM_Argv(1), "node")) - { - servernode = (SINT8)atoi(COM_Argv(2)); - } - else if (netgame) - { - CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n")); - return; - } - else if (I_NetOpenSocket) - { - I_NetOpenSocket(); - netgame = true; - multiplayer = true; - - if (!stricmp(COM_Argv(1), "any")) - servernode = BROADCASTADDR; - else if (I_NetMakeNodewPort) - { - if (COM_Argc() >= 3) // address AND port - servernode = I_NetMakeNodewPort(COM_Argv(1), COM_Argv(2)); - else // address only, or address:port - servernode = I_NetMakeNode(COM_Argv(1)); - } - else - { - CONS_Alert(CONS_ERROR, M_GetText("There is no server identification with this network driver\n")); - D_CloseConnection(); - return; - } - } - else - CONS_Alert(CONS_ERROR, M_GetText("There is no network driver\n")); - } - - splitscreen = false; - SplitScreen_OnChange(); - botingame = false; - botskin = 0; - CL_ConnectToServer(); -} - void ResetNode(INT32 node) { memset(&netnodes[node], 0, sizeof(*netnodes)); @@ -527,20 +290,6 @@ void CL_Reset(void) // D_StartTitle should get done now, but the calling function will handle it } -static void Command_GetPlayerNum(void) -{ - INT32 i; - - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - { - if (serverplayer == i) - CONS_Printf(M_GetText("num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]); - else - CONS_Printf(M_GetText("\x82num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]); - } -} - SINT8 nametonum(const char *name) { INT32 playernum, i; @@ -570,213 +319,6 @@ SINT8 nametonum(const char *name) return -1; } -/** Lists all players and their player numbers. - * - * \sa Command_GetPlayerNum - */ -static void Command_Nodes(void) -{ - INT32 i; - size_t maxlen = 0; - const char *address; - - for (i = 0; i < MAXPLAYERS; i++) - { - const size_t plen = strlen(player_names[i]); - if (playeringame[i] && plen > maxlen) - maxlen = plen; - } - - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i]) - { - CONS_Printf("%.2u: %*s", i, (int)maxlen, player_names[i]); - - if (playernode[i] != UINT8_MAX) - { - CONS_Printf(" - node %.2d", playernode[i]); - if (I_GetNodeAddress && (address = I_GetNodeAddress(playernode[i])) != NULL) - CONS_Printf(" - %s", address); - } - - if (IsPlayerAdmin(i)) - CONS_Printf(M_GetText(" (verified admin)")); - - if (players[i].spectator) - CONS_Printf(M_GetText(" (spectator)")); - - CONS_Printf("\n"); - } - } -} - -static void Command_Ban(void) -{ - if (COM_Argc() < 2) - { - CONS_Printf(M_GetText("Ban : ban and kick a player\n")); - return; - } - - if (!netgame) // Don't kick Tails in splitscreen! - { - CONS_Printf(M_GetText("This only works in a netgame.\n")); - return; - } - - if (server || IsPlayerAdmin(consoleplayer)) - { - UINT8 buf[3 + MAX_REASONLENGTH]; - UINT8 *p = buf; - const SINT8 pn = nametonum(COM_Argv(1)); - const INT32 node = playernode[(INT32)pn]; - - if (pn == -1 || pn == 0) - return; - - WRITEUINT8(p, pn); - - if (server && I_Ban && !I_Ban(node)) // only the server is allowed to do this right now - { - CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n")); - WRITEUINT8(p, KICK_MSG_GO_AWAY); - SendNetXCmd(XD_KICK, &buf, 2); - } - else - { - if (server) // only the server is allowed to do this right now - { - Ban_Add(COM_Argv(2)); - D_SaveBan(); // save the ban list - } - - if (COM_Argc() == 2) - { - WRITEUINT8(p, KICK_MSG_BANNED); - SendNetXCmd(XD_KICK, &buf, 2); - } - else - { - size_t i, j = COM_Argc(); - char message[MAX_REASONLENGTH]; - - //Steal from the motd code so you don't have to put the reason in quotes. - strlcpy(message, COM_Argv(2), sizeof message); - for (i = 3; i < j; i++) - { - strlcat(message, " ", sizeof message); - strlcat(message, COM_Argv(i), sizeof message); - } - - WRITEUINT8(p, KICK_MSG_CUSTOM_BAN); - WRITESTRINGN(p, message, MAX_REASONLENGTH); - SendNetXCmd(XD_KICK, &buf, p - buf); - } - } - } - else - CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); - -} - -static void Command_BanIP(void) -{ - if (COM_Argc() < 2) - { - CONS_Printf(M_GetText("banip : ban an ip address\n")); - return; - } - - if (server) // Only the server can use this, otherwise does nothing. - { - const char *address = (COM_Argv(1)); - const char *reason; - - if (COM_Argc() == 2) - reason = NULL; - else - reason = COM_Argv(2); - - - if (I_SetBanAddress && I_SetBanAddress(address, NULL)) - { - if (reason) - CONS_Printf("Banned IP address %s for: %s\n", address, reason); - else - CONS_Printf("Banned IP address %s\n", address); - - Ban_Add(reason); - D_SaveBan(); - } - else - { - return; - } - } -} - -static void Command_Kick(void) -{ - if (COM_Argc() < 2) - { - CONS_Printf(M_GetText("kick : kick a player\n")); - return; - } - - if (!netgame) // Don't kick Tails in splitscreen! - { - CONS_Printf(M_GetText("This only works in a netgame.\n")); - return; - } - - if (server || IsPlayerAdmin(consoleplayer)) - { - UINT8 buf[3 + MAX_REASONLENGTH]; - UINT8 *p = buf; - const SINT8 pn = nametonum(COM_Argv(1)); - - if (pn == -1 || pn == 0) - return; - - // Special case if we are trying to kick a player who is downloading the game state: - // trigger a timeout instead of kicking them, because a kick would only - // take effect after they have finished downloading - if (server && playernode[pn] != UINT8_MAX && netnodes[playernode[pn]].sendingsavegame) - { - Net_ConnectionTimeout(playernode[pn]); - return; - } - - WRITESINT8(p, pn); - - if (COM_Argc() == 2) - { - WRITEUINT8(p, KICK_MSG_GO_AWAY); - SendNetXCmd(XD_KICK, &buf, 2); - } - else - { - size_t i, j = COM_Argc(); - char message[MAX_REASONLENGTH]; - - //Steal from the motd code so you don't have to put the reason in quotes. - strlcpy(message, COM_Argv(2), sizeof message); - for (i = 3; i < j; i++) - { - strlcat(message, " ", sizeof message); - strlcat(message, COM_Argv(i), sizeof message); - } - - WRITEUINT8(p, KICK_MSG_CUSTOM_KICK); - WRITESTRINGN(p, message, MAX_REASONLENGTH); - SendNetXCmd(XD_KICK, &buf, p - buf); - } - } - else - CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); -} - static void Got_KickCmd(UINT8 **p, INT32 playernum) { INT32 pnum, msg; diff --git a/src/netcode/d_net.h b/src/netcode/d_net.h index 857c3463c..039f5b3b4 100644 --- a/src/netcode/d_net.h +++ b/src/netcode/d_net.h @@ -68,7 +68,6 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength); boolean HGetPacket(void); void D_SetDoomcom(void); -void D_SaveBan(void); boolean D_CheckNetGame(void); void D_CloseConnection(void); void Net_UnAcknowledgePacket(INT32 node); From 207053a0237b5e016afd9cba5baf7af4146626c5 Mon Sep 17 00:00:00 2001 From: spherallic Date: Fri, 13 Jan 2023 17:10:50 +0100 Subject: [PATCH 68/96] Prevent A_LobShot from dividing by 0 --- src/p_enemy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 373f09123..3305709fc 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -2671,7 +2671,7 @@ void A_LobShot(mobj_t *actor) fixed_t z; fixed_t dist; fixed_t vertical, horizontal; - fixed_t airtime = var2 & 65535; + fixed_t airtime = max(1, var2 & 65535); if (LUA_CallAction(A_LOBSHOT, actor)) return; From 2a360a4201beb717ed82a97f746c9bfec8689f79 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Fri, 13 Jan 2023 22:05:57 +0100 Subject: [PATCH 69/96] Reorder functions in d_clisrv.c --- src/netcode/d_clisrv.c | 1249 ++++++++++++++++++++-------------------- 1 file changed, 623 insertions(+), 626 deletions(-) diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index 506de8c02..1658856b6 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -83,6 +83,7 @@ UINT8 playernode[MAXPLAYERS]; UINT16 pingmeasurecount = 1; UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone. UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values. +static INT32 pingtimeout[MAXPLAYERS]; tic_t servermaxping = 800; // server's max ping. Defaults to 800 tic_t maketic; @@ -120,137 +121,6 @@ void ResetNode(INT32 node) netnodes[node].player2 = -1; } -// -// CL_ClearPlayer -// -// Clears the player data so that a future client can use this slot -// -void CL_ClearPlayer(INT32 playernum) -{ - if (players[playernum].mo) - P_RemoveMobj(players[playernum].mo); - memset(&players[playernum], 0, sizeof (player_t)); - memset(playeraddress[playernum], 0, sizeof(*playeraddress)); -} - -static void UnlinkPlayerFromNode(INT32 playernum) -{ - INT32 node = playernode[playernum]; - - if (node == UINT8_MAX) - return; - - playernode[playernum] = UINT8_MAX; - - netnodes[node].numplayers--; - if (netnodes[node].numplayers <= 0) - { - netnodes[node].ingame = false; - Net_CloseConnection(node); - ResetNode(node); - } -} - -// If in a special stage, redistribute the player's -// spheres across the remaining players. -// I feel like this shouldn't even be in this file at all, but well. -static void RedistributeSpecialStageSpheres(INT32 playernum) -{ - if (!G_IsSpecialStage(gamemap) || D_NumPlayers() <= 1) - return; - - INT32 count = D_NumPlayers() - 1; - INT32 spheres = players[playernum].spheres; - INT32 rings = players[playernum].rings; - - while (spheres || rings) - { - INT32 sincrement = max(spheres / count, 1); - INT32 rincrement = max(rings / count, 1); - - INT32 i, n; - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || i == playernum) - continue; - - n = min(spheres, sincrement); - P_GivePlayerSpheres(&players[i], n); - spheres -= n; - - n = min(rings, rincrement); - P_GivePlayerRings(&players[i], n); - rings -= n; - } - } -} - -// -// CL_RemovePlayer -// -// Removes a player from the current game -// -void CL_RemovePlayer(INT32 playernum, kickreason_t reason) -{ - // Sanity check: exceptional cases (i.e. c-fails) can cause multiple - // kick commands to be issued for the same player. - if (!playeringame[playernum]) - return; - - if (server) - UnlinkPlayerFromNode(playernum); - - if (gametyperules & GTR_TEAMFLAGS) - P_PlayerFlagBurst(&players[playernum], false); // Don't take the flag with you! - - RedistributeSpecialStageSpheres(playernum); - - LUA_HookPlayerQuit(&players[playernum], reason); // Lua hook for player quitting - - // don't look through someone's view who isn't there - if (playernum == displayplayer) - { - // Call ViewpointSwitch hooks here. - // The viewpoint was forcibly changed. - LUA_HookViewpointSwitch(&players[consoleplayer], &players[consoleplayer], true); - displayplayer = consoleplayer; - } - - // Reset player data - CL_ClearPlayer(playernum); - - // remove avatar of player - playeringame[playernum] = false; - while (!playeringame[doomcom->numslots-1] && doomcom->numslots > 1) - doomcom->numslots--; - - // Reset the name - sprintf(player_names[playernum], "Player %d", playernum+1); - - player_name_changes[playernum] = 0; - - if (IsPlayerAdmin(playernum)) - { - RemoveAdminPlayer(playernum); // don't stay admin after you're gone - } - - LUA_InvalidatePlayer(&players[playernum]); - - if (G_TagGametype()) //Check if you still have a game. Location flexible. =P - P_CheckSurvivors(); - else if (gametyperules & GTR_RACE) - P_CheckRacers(); -} - -void CL_HandleTimeout(void) -{ - LUA_HookBool(false, HOOK(GameQuit)); - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText("Server Timeout\n\nPress Esc\n"), NULL, MM_NOTHING); -} - void CL_Reset(void) { if (metalrecording) @@ -290,33 +160,181 @@ void CL_Reset(void) // D_StartTitle should get done now, but the calling function will handle it } -SINT8 nametonum(const char *name) +// +// CL_ClearPlayer +// +// Clears the player data so that a future client can use this slot +// +void CL_ClearPlayer(INT32 playernum) { - INT32 playernum, i; + if (players[playernum].mo) + P_RemoveMobj(players[playernum].mo); + memset(&players[playernum], 0, sizeof (player_t)); + memset(playeraddress[playernum], 0, sizeof(*playeraddress)); +} - if (!strcmp(name, "0")) - return 0; +// Xcmd XD_ADDPLAYER +static void Got_AddPlayer(UINT8 **p, INT32 playernum) +{ + INT16 node, newplayernum; + boolean splitscreenplayer; + boolean rejoined; + player_t *newplayer; - playernum = (SINT8)atoi(name); - - if (playernum < 0 || playernum >= MAXPLAYERS) - return -1; - - if (playernum) + if (playernum != serverplayer && !IsPlayerAdmin(playernum)) { - if (playeringame[playernum]) - return (SINT8)playernum; - else - return -1; + // protect against hacked/buggy client + CONS_Alert(CONS_WARNING, M_GetText("Illegal add player command received from %s\n"), player_names[playernum]); + if (server) + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + return; } - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && !stricmp(player_names[i], name)) - return (SINT8)i; + node = READUINT8(*p); + newplayernum = READUINT8(*p); + splitscreenplayer = newplayernum & 0x80; + newplayernum &= ~0x80; - CONS_Printf(M_GetText("There is no player named \"%s\"\n"), name); + rejoined = playeringame[newplayernum]; - return -1; + if (!rejoined) + { + // Clear player before joining, lest some things get set incorrectly + // HACK: don't do this for splitscreen, it relies on preset values + if (!splitscreen && !botingame) + CL_ClearPlayer(newplayernum); + playeringame[newplayernum] = true; + G_AddPlayer(newplayernum); + if (newplayernum+1 > doomcom->numslots) + doomcom->numslots = (INT16)(newplayernum+1); + + if (server && I_GetNodeAddress) + { + const char *address = I_GetNodeAddress(node); + char *port = NULL; + if (address) // MI: fix msvcrt.dll!_mbscat crash? + { + strcpy(playeraddress[newplayernum], address); + port = strchr(playeraddress[newplayernum], ':'); + if (port) + *port = '\0'; + } + } + } + + newplayer = &players[newplayernum]; + + newplayer->jointime = 0; + newplayer->quittime = 0; + + READSTRINGN(*p, player_names[newplayernum], MAXPLAYERNAME); + + // the server is creating my player + if (node == mynode) + { + playernode[newplayernum] = 0; // for information only + if (!splitscreenplayer) + { + consoleplayer = newplayernum; + displayplayer = newplayernum; + secondarydisplayplayer = newplayernum; + DEBFILE("spawning me\n"); + ticcmd_oldangleturn[0] = newplayer->oldrelangleturn; + } + else + { + secondarydisplayplayer = newplayernum; + DEBFILE("spawning my brother\n"); + if (botingame) + newplayer->bot = 1; + ticcmd_oldangleturn[1] = newplayer->oldrelangleturn; + } + P_ForceLocalAngle(newplayer, (angle_t)(newplayer->angleturn << 16)); + D_SendPlayerConfig(); + addedtogame = true; + + if (rejoined) + { + if (newplayer->mo) + { + newplayer->viewheight = 41*newplayer->height/48; + + if (newplayer->mo->eflags & MFE_VERTICALFLIP) + newplayer->viewz = newplayer->mo->z + newplayer->mo->height - newplayer->viewheight; + else + newplayer->viewz = newplayer->mo->z + newplayer->viewheight; + } + + // wake up the status bar + ST_Start(); + // wake up the heads up text + HU_Start(); + + if (camera.chase && !splitscreenplayer) + P_ResetCamera(newplayer, &camera); + if (camera2.chase && splitscreenplayer) + P_ResetCamera(newplayer, &camera2); + } + } + + if (netgame) + { + char joinmsg[256]; + + if (rejoined) + strcpy(joinmsg, M_GetText("\x82*%s has rejoined the game (player %d)")); + else + strcpy(joinmsg, M_GetText("\x82*%s has joined the game (player %d)")); + strcpy(joinmsg, va(joinmsg, player_names[newplayernum], newplayernum)); + + // Merge join notification + IP to avoid clogging console/chat + if (server && cv_showjoinaddress.value && I_GetNodeAddress) + { + const char *address = I_GetNodeAddress(node); + if (address) + strcat(joinmsg, va(" (%s)", address)); + } + + HU_AddChatText(joinmsg, false); + } + + if (server && multiplayer && motd[0] != '\0') + COM_BufAddText(va("sayto %d %s\n", newplayernum, motd)); + + if (!rejoined) + LUA_HookInt(newplayernum, HOOK(PlayerJoin)); +} + +static void UnlinkPlayerFromNode(INT32 playernum) +{ + INT32 node = playernode[playernum]; + + if (node == UINT8_MAX) + return; + + playernode[playernum] = UINT8_MAX; + + netnodes[node].numplayers--; + if (netnodes[node].numplayers <= 0) + { + netnodes[node].ingame = false; + Net_CloseConnection(node); + ResetNode(node); + } +} + +static void PT_ClientQuit(SINT8 node, INT32 netconsole) +{ + if (client) + return; + + if (netnodes[node].ingame && netconsole != -1 && playeringame[netconsole]) + SendKicksForNode(node, KICK_MSG_PLAYER_QUIT | KICK_MSG_KEEP_BODY); + + Net_CloseConnection(node); + netnodes[node].ingame = false; + netnodes[node].player = -1; + netnodes[node].player2 = -1; } static void Got_KickCmd(UINT8 **p, INT32 playernum) @@ -510,47 +528,175 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) CL_RemovePlayer(pnum, kickreason); } -static void Got_AddPlayer(UINT8 **p, INT32 playernum); - -// called one time at init -void D_ClientServerInit(void) +// If in a special stage, redistribute the player's +// spheres across the remaining players. +// I feel like this shouldn't even be in this file at all, but well. +static void RedistributeSpecialStageSpheres(INT32 playernum) { - DEBFILE(va("- - -== SRB2 v%d.%.2d.%d "VERSIONSTRING" debugfile ==- - -\n", - VERSION/100, VERSION%100, SUBVERSION)); + if (!G_IsSpecialStage(gamemap) || D_NumPlayers() <= 1) + return; - COM_AddCommand("getplayernum", Command_GetPlayerNum); - COM_AddCommand("kick", Command_Kick); - COM_AddCommand("ban", Command_Ban); - COM_AddCommand("banip", Command_BanIP); - COM_AddCommand("clearbans", Command_ClearBans); - COM_AddCommand("showbanlist", Command_ShowBan); - COM_AddCommand("reloadbans", Command_ReloadBan); - COM_AddCommand("connect", Command_connect); - COM_AddCommand("nodes", Command_Nodes); - COM_AddCommand("resendgamestate", Command_ResendGamestate); -#ifdef PACKETDROP - COM_AddCommand("drop", Command_Drop); - COM_AddCommand("droprate", Command_Droprate); + INT32 count = D_NumPlayers() - 1; + INT32 spheres = players[playernum].spheres; + INT32 rings = players[playernum].rings; + + while (spheres || rings) + { + INT32 sincrement = max(spheres / count, 1); + INT32 rincrement = max(rings / count, 1); + + INT32 i, n; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || i == playernum) + continue; + + n = min(spheres, sincrement); + P_GivePlayerSpheres(&players[i], n); + spheres -= n; + + n = min(rings, rincrement); + P_GivePlayerRings(&players[i], n); + rings -= n; + } + } +} + +// +// CL_RemovePlayer +// +// Removes a player from the current game +// +void CL_RemovePlayer(INT32 playernum, kickreason_t reason) +{ + // Sanity check: exceptional cases (i.e. c-fails) can cause multiple + // kick commands to be issued for the same player. + if (!playeringame[playernum]) + return; + + if (server) + UnlinkPlayerFromNode(playernum); + + if (gametyperules & GTR_TEAMFLAGS) + P_PlayerFlagBurst(&players[playernum], false); // Don't take the flag with you! + + RedistributeSpecialStageSpheres(playernum); + + LUA_HookPlayerQuit(&players[playernum], reason); // Lua hook for player quitting + + // don't look through someone's view who isn't there + if (playernum == displayplayer) + { + // Call ViewpointSwitch hooks here. + // The viewpoint was forcibly changed. + LUA_HookViewpointSwitch(&players[consoleplayer], &players[consoleplayer], true); + displayplayer = consoleplayer; + } + + // Reset player data + CL_ClearPlayer(playernum); + + // remove avatar of player + playeringame[playernum] = false; + while (!playeringame[doomcom->numslots-1] && doomcom->numslots > 1) + doomcom->numslots--; + + // Reset the name + sprintf(player_names[playernum], "Player %d", playernum+1); + + player_name_changes[playernum] = 0; + + if (IsPlayerAdmin(playernum)) + { + RemoveAdminPlayer(playernum); // don't stay admin after you're gone + } + + LUA_InvalidatePlayer(&players[playernum]); + + if (G_TagGametype()) //Check if you still have a game. Location flexible. =P + P_CheckSurvivors(); + else if (gametyperules & GTR_RACE) + P_CheckRacers(); +} + +// +// D_QuitNetGame +// Called before quitting to leave a net game +// without hanging the other players +// +void D_QuitNetGame(void) +{ + mousegrabbedbylua = true; + I_UpdateMouseGrab(); + + if (!netgame || !netbuffer) + return; + + DEBFILE("===========================================================================\n" + " Quitting Game, closing connection\n" + "===========================================================================\n"); + + // abort send/receive of files + CloseNetFile(); + RemoveAllLuaFileTransfers(); + waitingforluafiletransfer = false; + waitingforluafilecommand = false; + + if (server) + { + INT32 i; + + netbuffer->packettype = PT_SERVERSHUTDOWN; + for (i = 0; i < MAXNETNODES; i++) + if (netnodes[i].ingame) + HSendPacket(i, true, 0, 0); +#ifdef MASTERSERVER + if (serverrunning && ms_RoomId > 0) + UnregisterServer(); #endif -#ifdef _DEBUG - COM_AddCommand("numnodes", Command_Numnodes); + } + else if (servernode > 0 && servernode < MAXNETNODES && netnodes[(UINT8)servernode].ingame) + { + netbuffer->packettype = PT_CLIENTQUIT; + HSendPacket(servernode, true, 0, 0); + } + + D_CloseConnection(); + ClearAdminPlayers(); + + DEBFILE("===========================================================================\n" + " Log finish\n" + "===========================================================================\n"); +#ifdef DEBUGFILE + if (debugfile) + { + fclose(debugfile); + debugfile = NULL; + } #endif +} - RegisterNetXCmd(XD_KICK, Got_KickCmd); - RegisterNetXCmd(XD_ADDPLAYER, Got_AddPlayer); -#ifdef DUMPCONSISTENCY - CV_RegisterVar(&cv_dumpconsistency); -#endif - Ban_Load_File(false); +void CL_HandleTimeout(void) +{ + LUA_HookBool(false, HOOK(GameQuit)); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText("Server Timeout\n\nPress Esc\n"), NULL, MM_NOTHING); +} - gametic = 0; - localgametic = 0; +void CL_AddSplitscreenPlayer(void) +{ + if (cl_mode == CL_CONNECTED) + CL_SendJoin(); +} - // do not send anything before the real begin - SV_StopServer(); - SV_ResetServer(); - if (dedicated) - SV_SpawnServer(); +void CL_RemoveSplitscreenPlayer(void) +{ + if (cl_mode != CL_CONNECTED) + return; + + SendKick(secondarydisplayplayer, KICK_MSG_PLAYER_QUIT); } void SV_ResetServer(void) @@ -622,215 +768,6 @@ static inline void SV_GenContext(void) } } -// -// D_QuitNetGame -// Called before quitting to leave a net game -// without hanging the other players -// -void D_QuitNetGame(void) -{ - mousegrabbedbylua = true; - I_UpdateMouseGrab(); - - if (!netgame || !netbuffer) - return; - - DEBFILE("===========================================================================\n" - " Quitting Game, closing connection\n" - "===========================================================================\n"); - - // abort send/receive of files - CloseNetFile(); - RemoveAllLuaFileTransfers(); - waitingforluafiletransfer = false; - waitingforluafilecommand = false; - - if (server) - { - INT32 i; - - netbuffer->packettype = PT_SERVERSHUTDOWN; - for (i = 0; i < MAXNETNODES; i++) - if (netnodes[i].ingame) - HSendPacket(i, true, 0, 0); -#ifdef MASTERSERVER - if (serverrunning && ms_RoomId > 0) - UnregisterServer(); -#endif - } - else if (servernode > 0 && servernode < MAXNETNODES && netnodes[(UINT8)servernode].ingame) - { - netbuffer->packettype = PT_CLIENTQUIT; - HSendPacket(servernode, true, 0, 0); - } - - D_CloseConnection(); - ClearAdminPlayers(); - - DEBFILE("===========================================================================\n" - " Log finish\n" - "===========================================================================\n"); -#ifdef DEBUGFILE - if (debugfile) - { - fclose(debugfile); - debugfile = NULL; - } -#endif -} - -// Xcmd XD_ADDPLAYER -static void Got_AddPlayer(UINT8 **p, INT32 playernum) -{ - INT16 node, newplayernum; - boolean splitscreenplayer; - boolean rejoined; - player_t *newplayer; - - if (playernum != serverplayer && !IsPlayerAdmin(playernum)) - { - // protect against hacked/buggy client - CONS_Alert(CONS_WARNING, M_GetText("Illegal add player command received from %s\n"), player_names[playernum]); - if (server) - SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - return; - } - - node = READUINT8(*p); - newplayernum = READUINT8(*p); - splitscreenplayer = newplayernum & 0x80; - newplayernum &= ~0x80; - - rejoined = playeringame[newplayernum]; - - if (!rejoined) - { - // Clear player before joining, lest some things get set incorrectly - // HACK: don't do this for splitscreen, it relies on preset values - if (!splitscreen && !botingame) - CL_ClearPlayer(newplayernum); - playeringame[newplayernum] = true; - G_AddPlayer(newplayernum); - if (newplayernum+1 > doomcom->numslots) - doomcom->numslots = (INT16)(newplayernum+1); - - if (server && I_GetNodeAddress) - { - const char *address = I_GetNodeAddress(node); - char *port = NULL; - if (address) // MI: fix msvcrt.dll!_mbscat crash? - { - strcpy(playeraddress[newplayernum], address); - port = strchr(playeraddress[newplayernum], ':'); - if (port) - *port = '\0'; - } - } - } - - newplayer = &players[newplayernum]; - - newplayer->jointime = 0; - newplayer->quittime = 0; - - READSTRINGN(*p, player_names[newplayernum], MAXPLAYERNAME); - - // the server is creating my player - if (node == mynode) - { - playernode[newplayernum] = 0; // for information only - if (!splitscreenplayer) - { - consoleplayer = newplayernum; - displayplayer = newplayernum; - secondarydisplayplayer = newplayernum; - DEBFILE("spawning me\n"); - ticcmd_oldangleturn[0] = newplayer->oldrelangleturn; - } - else - { - secondarydisplayplayer = newplayernum; - DEBFILE("spawning my brother\n"); - if (botingame) - newplayer->bot = 1; - ticcmd_oldangleturn[1] = newplayer->oldrelangleturn; - } - P_ForceLocalAngle(newplayer, (angle_t)(newplayer->angleturn << 16)); - D_SendPlayerConfig(); - addedtogame = true; - - if (rejoined) - { - if (newplayer->mo) - { - newplayer->viewheight = 41*newplayer->height/48; - - if (newplayer->mo->eflags & MFE_VERTICALFLIP) - newplayer->viewz = newplayer->mo->z + newplayer->mo->height - newplayer->viewheight; - else - newplayer->viewz = newplayer->mo->z + newplayer->viewheight; - } - - // wake up the status bar - ST_Start(); - // wake up the heads up text - HU_Start(); - - if (camera.chase && !splitscreenplayer) - P_ResetCamera(newplayer, &camera); - if (camera2.chase && splitscreenplayer) - P_ResetCamera(newplayer, &camera2); - } - } - - if (netgame) - { - char joinmsg[256]; - - if (rejoined) - strcpy(joinmsg, M_GetText("\x82*%s has rejoined the game (player %d)")); - else - strcpy(joinmsg, M_GetText("\x82*%s has joined the game (player %d)")); - strcpy(joinmsg, va(joinmsg, player_names[newplayernum], newplayernum)); - - // Merge join notification + IP to avoid clogging console/chat - if (server && cv_showjoinaddress.value && I_GetNodeAddress) - { - const char *address = I_GetNodeAddress(node); - if (address) - strcat(joinmsg, va(" (%s)", address)); - } - - HU_AddChatText(joinmsg, false); - } - - if (server && multiplayer && motd[0] != '\0') - COM_BufAddText(va("sayto %d %s\n", newplayernum, motd)); - - if (!rejoined) - LUA_HookInt(newplayernum, HOOK(PlayerJoin)); -} - -void CL_AddSplitscreenPlayer(void) -{ - if (cl_mode == CL_CONNECTED) - CL_SendJoin(); -} - -void CL_RemoveSplitscreenPlayer(void) -{ - if (cl_mode != CL_CONNECTED) - return; - - SendKick(secondarydisplayplayer, KICK_MSG_PLAYER_QUIT); -} - -// is there a game running -boolean Playing(void) -{ - return (server && serverrunning) || (client && cl_mode == CL_CONNECTED); -} - void SV_SpawnServer(void) { if (demoplayback) @@ -860,6 +797,21 @@ void SV_SpawnServer(void) } } +// called at singleplayer start and stopdemo +void SV_StartSinglePlayerServer(void) +{ + server = true; + netgame = false; + multiplayer = false; + G_SetGametype(GT_COOP); + + // no more tic the game with this settings! + SV_StopServer(); + + if (splitscreen) + multiplayer = true; +} + void SV_StopServer(void) { tic_t i; @@ -881,21 +833,6 @@ void SV_StopServer(void) serverrunning = false; } -// called at singleplayer start and stopdemo -void SV_StartSinglePlayerServer(void) -{ - server = true; - netgame = false; - multiplayer = false; - G_SetGametype(GT_COOP); - - // no more tic the game with this settings! - SV_StopServer(); - - if (splitscreen) - multiplayer = true; -} - /** Called when a PT_SERVERSHUTDOWN packet is received * * \param node The packet sender (should be the server) @@ -948,20 +885,6 @@ static void PT_Login(SINT8 node, INT32 netconsole) #endif } -static void PT_ClientQuit(SINT8 node, INT32 netconsole) -{ - if (client) - return; - - if (netnodes[node].ingame && netconsole != -1 && playeringame[netconsole]) - SendKicksForNode(node, KICK_MSG_PLAYER_QUIT | KICK_MSG_KEEP_BODY); - - Net_CloseConnection(node); - netnodes[node].ingame = false; - netnodes[node].player = -1; - netnodes[node].player2 = -1; -} - static void PT_AskLuaFile(SINT8 node) { if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_ASKED) @@ -974,6 +897,94 @@ static void PT_HasLuaFile(SINT8 node) SV_HandleLuaFileSent(node); } +static void PT_SendingLuaFile(SINT8 node) +{ + (void)node; + + if (client) + CL_PrepareDownloadLuaFile(); +} + +/* +Ping Update except better: +We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out. +If they're not lagging, decrement the timer by 1. Of course, reset all of this if they leave. +*/ + +static inline void PingUpdate(void) +{ + INT32 i; + boolean laggers[MAXPLAYERS]; + UINT8 numlaggers = 0; + memset(laggers, 0, sizeof(boolean) * MAXPLAYERS); + + netbuffer->packettype = PT_PING; + + //check for ping limit breakage. + if (cv_maxping.value) + { + for (i = 1; i < MAXPLAYERS; i++) + { + if (playeringame[i] && !players[i].quittime + && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value)) + { + if (players[i].jointime > 30 * TICRATE) + laggers[i] = true; + numlaggers++; + } + else + pingtimeout[i] = 0; + } + + //kick lagging players... unless everyone but the server's ping sucks. + //in that case, it is probably the server's fault. + if (numlaggers < D_NumPlayers() - 1) + { + for (i = 1; i < MAXPLAYERS; i++) + { + if (playeringame[i] && laggers[i]) + { + pingtimeout[i]++; + // ok your net has been bad for too long, you deserve to die. + if (pingtimeout[i] > cv_pingtimeout.value) + { + pingtimeout[i] = 0; + SendKick(i, KICK_MSG_PING_HIGH | KICK_MSG_KEEP_BODY); + } + } + /* + you aren't lagging, + but you aren't free yet. + In case you'll keep spiking, + we just make the timer go back down. (Very unstable net must still get kicked). + */ + else + pingtimeout[i] = (pingtimeout[i] == 0 ? 0 : pingtimeout[i]-1); + } + } + } + + //make the ping packet and clear server data for next one + for (i = 0; i < MAXPLAYERS; i++) + { + netbuffer->u.pingtable[i] = realpingtable[i] / pingmeasurecount; + //server takes a snapshot of the real ping for display. + //otherwise, pings fluctuate a lot and would be odd to look at. + playerpingtable[i] = realpingtable[i] / pingmeasurecount; + realpingtable[i] = 0; //Reset each as we go. + } + + // send the server's maxping as last element of our ping table. This is useful to let us know when we're about to get kicked. + netbuffer->u.pingtable[MAXPLAYERS] = cv_maxping.value; + + //send out our ping packets + for (i = 0; i < MAXNETNODES; i++) + if (netnodes[i].ingame) + HSendPacket(i, true, 0, sizeof(INT32) * (MAXPLAYERS+1)); + + pingmeasurecount = 1; //Reset count +} + static void PT_Ping(SINT8 node, INT32 netconsole) { // Only accept PT_PING from the server. @@ -997,14 +1008,6 @@ static void PT_Ping(SINT8 node, INT32 netconsole) } } -static void PT_SendingLuaFile(SINT8 node) -{ - (void)node; - - if (client) - CL_PrepareDownloadLuaFile(); -} - /** Handles a packet received from a node that isn't in game * * \param node The packet sender @@ -1124,120 +1127,6 @@ void GetPackets(void) } } -// -// NetUpdate -// Builds ticcmds for console player, -// sends out a packet -// -// no more use random generator, because at very first tic isn't yet synchronized -// Note: It is called consistAncy on purpose. -// -INT16 Consistancy(void) -{ - INT32 i; - UINT32 ret = 0; -#ifdef MOBJCONSISTANCY - thinker_t *th; - mobj_t *mo; -#endif - - DEBFILE(va("TIC %u ", gametic)); - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - ret ^= 0xCCCC; - else if (!players[i].mo); - else - { - ret += players[i].mo->x; - ret -= players[i].mo->y; - ret += players[i].powers[pw_shield]; - ret *= i+1; - } - } - // I give up - // Coop desynching enemies is painful - if (!G_PlatformGametype()) - ret += P_GetRandSeed(); - -#ifdef MOBJCONSISTANCY - if (gamestate == GS_LEVEL) - { - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo = (mobj_t *)th; - - if (mo->flags & (MF_SPECIAL | MF_SOLID | MF_PUSHABLE | MF_BOSS | MF_MISSILE | MF_SPRING | MF_MONITOR | MF_FIRE | MF_ENEMY | MF_PAIN | MF_STICKY)) - { - ret -= mo->type; - ret += mo->x; - ret -= mo->y; - ret += mo->z; - ret -= mo->momx; - ret += mo->momy; - ret -= mo->momz; - ret += mo->angle; - ret -= mo->flags; - ret += mo->flags2; - ret -= mo->eflags; - if (mo->target) - { - ret += mo->target->type; - ret -= mo->target->x; - ret += mo->target->y; - ret -= mo->target->z; - ret += mo->target->momx; - ret -= mo->target->momy; - ret += mo->target->momz; - ret -= mo->target->angle; - ret += mo->target->flags; - ret -= mo->target->flags2; - ret += mo->target->eflags; - ret -= mo->target->state - states; - ret += mo->target->tics; - ret -= mo->target->sprite; - ret += mo->target->frame; - } - else - ret ^= 0x3333; - if (mo->tracer && mo->tracer->type != MT_OVERLAY) - { - ret += mo->tracer->type; - ret -= mo->tracer->x; - ret += mo->tracer->y; - ret -= mo->tracer->z; - ret += mo->tracer->momx; - ret -= mo->tracer->momy; - ret += mo->tracer->momz; - ret -= mo->tracer->angle; - ret += mo->tracer->flags; - ret -= mo->tracer->flags2; - ret += mo->tracer->eflags; - ret -= mo->tracer->state - states; - ret += mo->tracer->tics; - ret -= mo->tracer->sprite; - ret += mo->tracer->frame; - } - else - ret ^= 0xAAAA; - ret -= mo->state - states; - ret += mo->tics; - ret -= mo->sprite; - ret += mo->frame; - } - } - } -#endif - - DEBFILE(va("Consistancy = %u\n", (ret & 0xFFFF))); - - return (INT16)(ret & 0xFFFF); -} - boolean TryRunTics(tic_t realtics) { // the machine has lagged but it is not so bad @@ -1331,88 +1220,6 @@ boolean TryRunTics(tic_t realtics) } } -/* -Ping Update except better: -We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out. -If they're not lagging, decrement the timer by 1. Of course, reset all of this if they leave. -*/ - -static INT32 pingtimeout[MAXPLAYERS]; - -static inline void PingUpdate(void) -{ - INT32 i; - boolean laggers[MAXPLAYERS]; - UINT8 numlaggers = 0; - memset(laggers, 0, sizeof(boolean) * MAXPLAYERS); - - netbuffer->packettype = PT_PING; - - //check for ping limit breakage. - if (cv_maxping.value) - { - for (i = 1; i < MAXPLAYERS; i++) - { - if (playeringame[i] && !players[i].quittime - && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value)) - { - if (players[i].jointime > 30 * TICRATE) - laggers[i] = true; - numlaggers++; - } - else - pingtimeout[i] = 0; - } - - //kick lagging players... unless everyone but the server's ping sucks. - //in that case, it is probably the server's fault. - if (numlaggers < D_NumPlayers() - 1) - { - for (i = 1; i < MAXPLAYERS; i++) - { - if (playeringame[i] && laggers[i]) - { - pingtimeout[i]++; - // ok your net has been bad for too long, you deserve to die. - if (pingtimeout[i] > cv_pingtimeout.value) - { - pingtimeout[i] = 0; - SendKick(i, KICK_MSG_PING_HIGH | KICK_MSG_KEEP_BODY); - } - } - /* - you aren't lagging, - but you aren't free yet. - In case you'll keep spiking, - we just make the timer go back down. (Very unstable net must still get kicked). - */ - else - pingtimeout[i] = (pingtimeout[i] == 0 ? 0 : pingtimeout[i]-1); - } - } - } - - //make the ping packet and clear server data for next one - for (i = 0; i < MAXPLAYERS; i++) - { - netbuffer->u.pingtable[i] = realpingtable[i] / pingmeasurecount; - //server takes a snapshot of the real ping for display. - //otherwise, pings fluctuate a lot and would be odd to look at. - playerpingtable[i] = realpingtable[i] / pingmeasurecount; - realpingtable[i] = 0; //Reset each as we go. - } - - // send the server's maxping as last element of our ping table. This is useful to let us know when we're about to get kicked. - netbuffer->u.pingtable[MAXPLAYERS] = cv_maxping.value; - - //send out our ping packets - for (i = 0; i < MAXNETNODES; i++) - if (netnodes[i].ingame) - HSendPacket(i, true, 0, sizeof(INT32) * (MAXPLAYERS+1)); - - pingmeasurecount = 1; //Reset count -} - void NetUpdate(void) { static tic_t gametime = 0; @@ -1537,6 +1344,82 @@ void NetUpdate(void) FileSendTicker(); } +// called one time at init +void D_ClientServerInit(void) +{ + DEBFILE(va("- - -== SRB2 v%d.%.2d.%d "VERSIONSTRING" debugfile ==- - -\n", + VERSION/100, VERSION%100, SUBVERSION)); + + COM_AddCommand("getplayernum", Command_GetPlayerNum); + COM_AddCommand("kick", Command_Kick); + COM_AddCommand("ban", Command_Ban); + COM_AddCommand("banip", Command_BanIP); + COM_AddCommand("clearbans", Command_ClearBans); + COM_AddCommand("showbanlist", Command_ShowBan); + COM_AddCommand("reloadbans", Command_ReloadBan); + COM_AddCommand("connect", Command_connect); + COM_AddCommand("nodes", Command_Nodes); + COM_AddCommand("resendgamestate", Command_ResendGamestate); +#ifdef PACKETDROP + COM_AddCommand("drop", Command_Drop); + COM_AddCommand("droprate", Command_Droprate); +#endif +#ifdef _DEBUG + COM_AddCommand("numnodes", Command_Numnodes); +#endif + + RegisterNetXCmd(XD_KICK, Got_KickCmd); + RegisterNetXCmd(XD_ADDPLAYER, Got_AddPlayer); +#ifdef DUMPCONSISTENCY + CV_RegisterVar(&cv_dumpconsistency); +#endif + Ban_Load_File(false); + + gametic = 0; + localgametic = 0; + + // do not send anything before the real begin + SV_StopServer(); + SV_ResetServer(); + if (dedicated) + SV_SpawnServer(); +} + +SINT8 nametonum(const char *name) +{ + INT32 playernum, i; + + if (!strcmp(name, "0")) + return 0; + + playernum = (SINT8)atoi(name); + + if (playernum < 0 || playernum >= MAXPLAYERS) + return -1; + + if (playernum) + { + if (playeringame[playernum]) + return (SINT8)playernum; + else + return -1; + } + + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && !stricmp(player_names[i], name)) + return (SINT8)i; + + CONS_Printf(M_GetText("There is no player named \"%s\"\n"), name); + + return -1; +} + +// is there a game running +boolean Playing(void) +{ + return (server && serverrunning) || (client && cl_mode == CL_CONNECTED); +} + /** Returns the number of players playing. * \return Number of players. Can be zero if we're running a ::dedicated * server. @@ -1551,6 +1434,120 @@ INT32 D_NumPlayers(void) return num; } +// +// NetUpdate +// Builds ticcmds for console player, +// sends out a packet +// +// no more use random generator, because at very first tic isn't yet synchronized +// Note: It is called consistAncy on purpose. +// +INT16 Consistancy(void) +{ + INT32 i; + UINT32 ret = 0; +#ifdef MOBJCONSISTANCY + thinker_t *th; + mobj_t *mo; +#endif + + DEBFILE(va("TIC %u ", gametic)); + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + ret ^= 0xCCCC; + else if (!players[i].mo); + else + { + ret += players[i].mo->x; + ret -= players[i].mo->y; + ret += players[i].powers[pw_shield]; + ret *= i+1; + } + } + // I give up + // Coop desynching enemies is painful + if (!G_PlatformGametype()) + ret += P_GetRandSeed(); + +#ifdef MOBJCONSISTANCY + if (gamestate == GS_LEVEL) + { + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + { + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + continue; + + mo = (mobj_t *)th; + + if (mo->flags & (MF_SPECIAL | MF_SOLID | MF_PUSHABLE | MF_BOSS | MF_MISSILE | MF_SPRING | MF_MONITOR | MF_FIRE | MF_ENEMY | MF_PAIN | MF_STICKY)) + { + ret -= mo->type; + ret += mo->x; + ret -= mo->y; + ret += mo->z; + ret -= mo->momx; + ret += mo->momy; + ret -= mo->momz; + ret += mo->angle; + ret -= mo->flags; + ret += mo->flags2; + ret -= mo->eflags; + if (mo->target) + { + ret += mo->target->type; + ret -= mo->target->x; + ret += mo->target->y; + ret -= mo->target->z; + ret += mo->target->momx; + ret -= mo->target->momy; + ret += mo->target->momz; + ret -= mo->target->angle; + ret += mo->target->flags; + ret -= mo->target->flags2; + ret += mo->target->eflags; + ret -= mo->target->state - states; + ret += mo->target->tics; + ret -= mo->target->sprite; + ret += mo->target->frame; + } + else + ret ^= 0x3333; + if (mo->tracer && mo->tracer->type != MT_OVERLAY) + { + ret += mo->tracer->type; + ret -= mo->tracer->x; + ret += mo->tracer->y; + ret -= mo->tracer->z; + ret += mo->tracer->momx; + ret -= mo->tracer->momy; + ret += mo->tracer->momz; + ret -= mo->tracer->angle; + ret += mo->tracer->flags; + ret -= mo->tracer->flags2; + ret += mo->tracer->eflags; + ret -= mo->tracer->state - states; + ret += mo->tracer->tics; + ret -= mo->tracer->sprite; + ret += mo->tracer->frame; + } + else + ret ^= 0xAAAA; + ret -= mo->state - states; + ret += mo->tics; + ret -= mo->sprite; + ret += mo->frame; + } + } + } +#endif + + DEBFILE(va("Consistancy = %u\n", (ret & 0xFFFF))); + + return (INT16)(ret & 0xFFFF); +} + tic_t GetLag(INT32 node) { return gametic - netnodes[node].tic; From 0859a1597f723f8cc10170e2cfe818a27d1104f9 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Fri, 13 Jan 2023 22:28:03 +0100 Subject: [PATCH 70/96] Add missing include directive --- src/sdl/i_system.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 7684045fc..47402e549 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -189,6 +189,7 @@ static char returnWadPath[256]; #include "../i_threads.h" #include "../screen.h" //vid.WndParent #include "../netcode/d_net.h" +#include "../netcode/commands.h" #include "../g_game.h" #include "../filesrch.h" #include "endtxt.h" From a7a3f97c7b5e2233caa565a99d138b5cfa3b25c0 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sat, 14 Jan 2023 14:49:33 +0100 Subject: [PATCH 71/96] Split PT_ClientCmd into functions --- src/netcode/tic_command.c | 95 +++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 44 deletions(-) diff --git a/src/netcode/tic_command.c b/src/netcode/tic_command.c index bab0fad0a..417a2fdfd 100644 --- a/src/netcode/tic_command.c +++ b/src/netcode/tic_command.c @@ -103,6 +103,55 @@ void D_ResetTiccmds(void) D_Clearticcmd(textcmds[i]->tic); } +// Check ticcmd for "speed hacks" +static void CheckTiccmdHacks(INT32 playernum) +{ + ticcmd_t *cmd = &netcmds[maketic%BACKUPTICS][playernum]; + if (cmd->forwardmove > MAXPLMOVE || cmd->forwardmove < -MAXPLMOVE + || cmd->sidemove > MAXPLMOVE || cmd->sidemove < -MAXPLMOVE) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), playernum); + SendKick(playernum, KICK_MSG_CON_FAIL); + } +} + +// Check player consistancy during the level +static void CheckConsistancy(SINT8 nodenum, tic_t tic) +{ + netnode_t *node = &netnodes[nodenum]; + INT16 neededconsistancy = consistancy[tic%BACKUPTICS]; + INT16 clientconsistancy = SHORT(netbuffer->u.clientpak.consistancy); + + if (tic > gametic || tic + BACKUPTICS - 1 <= gametic || gamestate != GS_LEVEL + || neededconsistancy == clientconsistancy || SV_ResendingSavegameToAnyone() + || node->resendingsavegame || node->savegameresendcooldown > I_GetTime()) + return; + + if (cv_resynchattempts.value) + { + // Tell the client we are about to resend them the gamestate + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + HSendPacket(nodenum, true, 0, 0); + + node->resendingsavegame = true; + + if (cv_blamecfail.value) + CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), + node->player+1, player_names[node->player], + neededconsistancy, clientconsistancy); + + DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", + node->player, tic, neededconsistancy, clientconsistancy)); + } + else + { + SendKick(node->player, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + + DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", + node->player, tic, neededconsistancy, clientconsistancy)); + } +} + void PT_ClientCmd(SINT8 node, INT32 netconsole) { tic_t realend, realstart; @@ -143,56 +192,14 @@ void PT_ClientCmd(SINT8 node, INT32 netconsole) // Copy ticcmd G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); - // Check ticcmd for "speed hacks" - if (netcmds[maketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE - || netcmds[maketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].sidemove < -MAXPLMOVE) - { - CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), netconsole); - //D_Clearticcmd(k); - - SendKick(netconsole, KICK_MSG_CON_FAIL); - return; - } - // Splitscreen cmd if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) && netnodes[node].player2 >= 0) G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)netnodes[node].player2], &netbuffer->u.client2pak.cmd2, 1); - // Check player consistancy during the level - if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL - && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) - && !SV_ResendingSavegameToAnyone() - && !netnodes[node].resendingsavegame && netnodes[node].savegameresendcooldown <= I_GetTime()) - { - if (cv_resynchattempts.value) - { - // Tell the client we are about to resend them the gamestate - netbuffer->packettype = PT_WILLRESENDGAMESTATE; - HSendPacket(node, true, 0, 0); - - netnodes[node].resendingsavegame = true; - - if (cv_blamecfail.value) - CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), - netconsole+1, player_names[netconsole], - consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy)); - DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", - netconsole, realstart, consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy))); - return; - } - else - { - SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", - netconsole, realstart, consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy))); - return; - } - } + CheckTiccmdHacks(netconsole); + CheckConsistancy(node, realstart); } void PT_ServerTics(SINT8 node, INT32 netconsole) From 4081dd8edfa32f0aa7126da280b257ed0294bba3 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sat, 14 Jan 2023 14:52:13 +0100 Subject: [PATCH 72/96] Move net command copying to a new function --- src/netcode/net_command.c | 20 ++++++++++++++++++++ src/netcode/net_command.h | 1 + src/netcode/tic_command.c | 21 +++------------------ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/netcode/net_command.c b/src/netcode/net_command.c index 13477d42d..227b78660 100644 --- a/src/netcode/net_command.c +++ b/src/netcode/net_command.c @@ -304,6 +304,26 @@ void PT_TextCmd(SINT8 node, INT32 netconsole) } } +void SV_CopyNetCommandsToServerPacket(tic_t tic) +{ + servertics_pak *packet = &netbuffer->u.serverpak; + UINT8 *cmds = (UINT8*)&packet->cmds[packet->numslots * packet->numtics]; + UINT8 numcmds; + + numcmds = *cmds++; + + for (UINT32 i = 0; i < numcmds; i++) + { + INT32 playernum = *cmds++; // playernum + size_t size = cmds[0]+1; + + if (tic >= gametic) // Don't copy old net commands + M_Memcpy(D_GetTextcmd(tic, playernum), cmds, size); + cmds += size; + } +} + +void CL_SendNetCommands(void) void SendKick(UINT8 playernum, UINT8 msg) { UINT8 buf[2]; diff --git a/src/netcode/net_command.h b/src/netcode/net_command.h index f1b4b2f3f..a9447ed7a 100644 --- a/src/netcode/net_command.h +++ b/src/netcode/net_command.h @@ -57,6 +57,7 @@ void ExtraDataTicker(void); size_t TotalTextCmdPerTic(tic_t tic); void PT_TextCmd(SINT8 node, INT32 netconsole); +void SV_CopyNetCommandsToServerPacket(tic_t tic); void SendKick(UINT8 playernum, UINT8 msg); void SendKicksForNode(SINT8 node, UINT8 msg); diff --git a/src/netcode/tic_command.c b/src/netcode/tic_command.c index 417a2fdfd..2eb3b10ac 100644 --- a/src/netcode/tic_command.c +++ b/src/netcode/tic_command.c @@ -204,7 +204,6 @@ void PT_ClientCmd(SINT8 node, INT32 netconsole) void PT_ServerTics(SINT8 node, INT32 netconsole) { - UINT8 *pak, *txtpak, numtxtpak; tic_t realend, realstart; if (!netnodes[node].ingame) @@ -230,19 +229,15 @@ void PT_ServerTics(SINT8 node, INT32 netconsole) realstart = netbuffer->u.serverpak.starttic; realend = realstart + netbuffer->u.serverpak.numtics; - txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots - * netbuffer->u.serverpak.numtics]; - if (realend > gametic + CLIENTBACKUPTICS) realend = gametic + CLIENTBACKUPTICS; cl_packetmissed = realstart > neededtic; if (realstart <= neededtic && realend > neededtic) { - tic_t i, j; - pak = (UINT8 *)&netbuffer->u.serverpak.cmds; + UINT8 *pak = (UINT8 *)&netbuffer->u.serverpak.cmds; - for (i = realstart; i < realend; i++) + for (tic_t i = realstart; i < realend; i++) { // clear first D_Clearticcmd(i); @@ -251,17 +246,7 @@ void PT_ServerTics(SINT8 node, INT32 netconsole) pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak, netbuffer->u.serverpak.numslots*sizeof (ticcmd_t)); - // copy the textcmds - numtxtpak = *txtpak++; - for (j = 0; j < numtxtpak; j++) - { - INT32 k = *txtpak++; // playernum - const size_t txtsize = txtpak[0]+1; - - if (i >= gametic) // Don't copy old net commands - M_Memcpy(D_GetTextcmd(i, k), txtpak, txtsize); - txtpak += txtsize; - } + SV_CopyNetCommandsToServerPacket(i); } neededtic = realend; From aa18d5c3ffebab326f21db8a360e8b8f674c48bc Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sat, 14 Jan 2023 14:53:27 +0100 Subject: [PATCH 73/96] Move net command sending to a new function --- src/netcode/net_command.c | 22 ++++++++++++++++++++++ src/netcode/net_command.h | 1 + src/netcode/tic_command.c | 22 +--------------------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/netcode/net_command.c b/src/netcode/net_command.c index 227b78660..9e089a1a2 100644 --- a/src/netcode/net_command.c +++ b/src/netcode/net_command.c @@ -324,6 +324,28 @@ void SV_CopyNetCommandsToServerPacket(tic_t tic) } void CL_SendNetCommands(void) +{ + // Send extra data if needed + if (localtextcmd[0]) + { + netbuffer->packettype = PT_TEXTCMD; + M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1); + // All extra data have been sent + if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail... + localtextcmd[0] = 0; + } + + // Send extra data if needed for player 2 (splitscreen) + if (localtextcmd2[0]) + { + netbuffer->packettype = PT_TEXTCMD2; + M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1); + // All extra data have been sent + if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail... + localtextcmd2[0] = 0; + } +} + void SendKick(UINT8 playernum, UINT8 msg) { UINT8 buf[2]; diff --git a/src/netcode/net_command.h b/src/netcode/net_command.h index a9447ed7a..3a433ebe4 100644 --- a/src/netcode/net_command.h +++ b/src/netcode/net_command.h @@ -58,6 +58,7 @@ size_t TotalTextCmdPerTic(tic_t tic); void PT_TextCmd(SINT8 node, INT32 netconsole); void SV_CopyNetCommandsToServerPacket(tic_t tic); +void CL_SendNetCommands(void); void SendKick(UINT8 playernum, UINT8 msg); void SendKicksForNode(SINT8 node, UINT8 msg); diff --git a/src/netcode/tic_command.c b/src/netcode/tic_command.c index 2eb3b10ac..76d46451f 100644 --- a/src/netcode/tic_command.c +++ b/src/netcode/tic_command.c @@ -295,27 +295,7 @@ void CL_SendClientCmd(void) } if (cl_mode == CL_CONNECTED || dedicated) - { - // Send extra data if needed - if (localtextcmd[0]) - { - netbuffer->packettype = PT_TEXTCMD; - M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1); - // All extra data have been sent - if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail... - localtextcmd[0] = 0; - } - - // Send extra data if needed for player 2 (splitscreen) - if (localtextcmd2[0]) - { - netbuffer->packettype = PT_TEXTCMD2; - M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1); - // All extra data have been sent - if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail... - localtextcmd2[0] = 0; - } - } + CL_SendNetCommands(); } // send the server packet From 530a03cc7dce25d7473a23f91004a8c1b532c37e Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sat, 14 Jan 2023 15:14:09 +0100 Subject: [PATCH 74/96] Fix function name --- src/netcode/net_command.c | 2 +- src/netcode/net_command.h | 2 +- src/netcode/tic_command.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/netcode/net_command.c b/src/netcode/net_command.c index 9e089a1a2..98c578b79 100644 --- a/src/netcode/net_command.c +++ b/src/netcode/net_command.c @@ -304,7 +304,7 @@ void PT_TextCmd(SINT8 node, INT32 netconsole) } } -void SV_CopyNetCommandsToServerPacket(tic_t tic) +void CL_CopyNetCommandsFromServerPacket(tic_t tic) { servertics_pak *packet = &netbuffer->u.serverpak; UINT8 *cmds = (UINT8*)&packet->cmds[packet->numslots * packet->numtics]; diff --git a/src/netcode/net_command.h b/src/netcode/net_command.h index 3a433ebe4..0e8339ef7 100644 --- a/src/netcode/net_command.h +++ b/src/netcode/net_command.h @@ -57,7 +57,7 @@ void ExtraDataTicker(void); size_t TotalTextCmdPerTic(tic_t tic); void PT_TextCmd(SINT8 node, INT32 netconsole); -void SV_CopyNetCommandsToServerPacket(tic_t tic); +void CL_CopyNetCommandsFromServerPacket(tic_t tic); void CL_SendNetCommands(void); void SendKick(UINT8 playernum, UINT8 msg); void SendKicksForNode(SINT8 node, UINT8 msg); diff --git a/src/netcode/tic_command.c b/src/netcode/tic_command.c index 76d46451f..6b237ed61 100644 --- a/src/netcode/tic_command.c +++ b/src/netcode/tic_command.c @@ -246,7 +246,7 @@ void PT_ServerTics(SINT8 node, INT32 netconsole) pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak, netbuffer->u.serverpak.numslots*sizeof (ticcmd_t)); - SV_CopyNetCommandsToServerPacket(i); + CL_CopyNetCommandsFromServerPacket(i); } neededtic = realend; From 9291416a90749b22b8c971a89a5ea39e3fe0955c Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sat, 14 Jan 2023 19:01:36 +0100 Subject: [PATCH 75/96] Split SV_SendTics into functions --- src/netcode/net_command.c | 21 +++++++++ src/netcode/net_command.h | 1 + src/netcode/tic_command.c | 95 ++++++++++++++++++--------------------- 3 files changed, 66 insertions(+), 51 deletions(-) diff --git a/src/netcode/net_command.c b/src/netcode/net_command.c index 98c578b79..11b351af7 100644 --- a/src/netcode/net_command.c +++ b/src/netcode/net_command.c @@ -304,6 +304,27 @@ void PT_TextCmd(SINT8 node, INT32 netconsole) } } +void SV_WriteNetCommandsForTic(tic_t tic, UINT8 **buf) +{ + UINT8 *numcmds; + + numcmds = (*buf)++; + *numcmds = 0; + for (INT32 i = 0; i < MAXPLAYERS; i++) + { + UINT8 *cmd = D_GetExistingTextcmd(tic, i); + INT32 size = cmd ? cmd[0] : 0; + + if ((!i || playeringame[i]) && size) + { + (*numcmds)++; + WRITEUINT8(*buf, i); + M_Memcpy(*buf, cmd, size + 1); + *buf += size + 1; + } + } +} + void CL_CopyNetCommandsFromServerPacket(tic_t tic) { servertics_pak *packet = &netbuffer->u.serverpak; diff --git a/src/netcode/net_command.h b/src/netcode/net_command.h index 0e8339ef7..cc26aeb0e 100644 --- a/src/netcode/net_command.h +++ b/src/netcode/net_command.h @@ -57,6 +57,7 @@ void ExtraDataTicker(void); size_t TotalTextCmdPerTic(tic_t tic); void PT_TextCmd(SINT8 node, INT32 netconsole); +void SV_WriteNetCommandsForTic(tic_t tic, UINT8 **buf); void CL_CopyNetCommandsFromServerPacket(tic_t tic); void CL_SendNetCommands(void); void SendKick(UINT8 playernum, UINT8 msg); diff --git a/src/netcode/tic_command.c b/src/netcode/tic_command.c index 6b237ed61..bf8c5d21d 100644 --- a/src/netcode/tic_command.c +++ b/src/netcode/tic_command.c @@ -298,16 +298,56 @@ void CL_SendClientCmd(void) CL_SendNetCommands(); } +// PT_SERVERTICS packets can grow too large for a single UDP packet, +// So this checks how many tics worth of data can be sent in one packet. +// The rest can be sent later, usually the next tic. +static tic_t SV_CalculateNumTicsForPacket(SINT8 nodenum, tic_t firsttic, tic_t lasttic) +{ + size_t size = BASESERVERTICSSIZE; + tic_t tic; + + for (tic = firsttic; tic < lasttic; tic++) + { + size += sizeof (ticcmd_t) * doomcom->numslots; + size += TotalTextCmdPerTic(tic); + + if (size > software_MAXPACKETLENGTH) + { + DEBFILE(va("packet too large (%s) at tic %d (should be from %d to %d)\n", + sizeu1(size), tic, firsttic, lasttic)); + lasttic = tic; + + // too bad: too much player have send extradata and there is too + // much data in one tic. + // To avoid it put the data on the next tic. (see getpacket + // textcmd case) but when numplayer changes the computation can be different + if (lasttic == firsttic) + { + if (size > MAXPACKETLENGTH) + I_Error("Too many players: can't send %s data for %d players to node %d\n" + "Well sorry nobody is perfect....\n", + sizeu1(size), doomcom->numslots, nodenum); + else + { + lasttic++; // send it anyway! + DEBFILE("sending it anyway\n"); + } + } + break; + } + } + + return lasttic - firsttic; +} + // send the server packet // send tic from firstticstosend to maketic-1 void SV_SendTics(void) { tic_t realfirsttic, lasttictosend, i; UINT32 n; - INT32 j; size_t packsize; UINT8 *bufpos; - UINT8 *ntextcmd; // send to all client but not to me // for each node create a packet with x tics and send it @@ -336,38 +376,7 @@ void SV_SendTics(void) if (realfirsttic < firstticstosend) realfirsttic = firstticstosend; - // compute the length of the packet and cut it if too large - packsize = BASESERVERTICSSIZE; - for (i = realfirsttic; i < lasttictosend; i++) - { - packsize += sizeof (ticcmd_t) * doomcom->numslots; - packsize += TotalTextCmdPerTic(i); - - if (packsize > software_MAXPACKETLENGTH) - { - DEBFILE(va("packet too large (%s) at tic %d (should be from %d to %d)\n", - sizeu1(packsize), i, realfirsttic, lasttictosend)); - lasttictosend = i; - - // too bad: too much player have send extradata and there is too - // much data in one tic. - // To avoid it put the data on the next tic. (see getpacket - // textcmd case) but when numplayer changes the computation can be different - if (lasttictosend == realfirsttic) - { - if (packsize > MAXPACKETLENGTH) - I_Error("Too many players: can't send %s data for %d players to node %d\n" - "Well sorry nobody is perfect....\n", - sizeu1(packsize), doomcom->numslots, n); - else - { - lasttictosend++; // send it anyway! - DEBFILE("sending it anyway\n"); - } - } - break; - } - } + lasttictosend = realfirsttic + SV_CalculateNumTicsForPacket(n, realfirsttic, lasttictosend); // Send the tics netbuffer->packettype = PT_SERVERTICS; @@ -383,23 +392,7 @@ void SV_SendTics(void) // add textcmds for (i = realfirsttic; i < lasttictosend; i++) - { - ntextcmd = bufpos++; - *ntextcmd = 0; - for (j = 0; j < MAXPLAYERS; j++) - { - UINT8 *textcmd = D_GetExistingTextcmd(i, j); - INT32 size = textcmd ? textcmd[0] : 0; - - if ((!j || playeringame[j]) && size) - { - (*ntextcmd)++; - WRITEUINT8(bufpos, j); - M_Memcpy(bufpos, textcmd, size + 1); - bufpos += size + 1; - } - } - } + SV_WriteNetCommandsForTic(); packsize = bufpos - (UINT8 *)&(netbuffer->u); HSendPacket(n, false, 0, packsize); From 823fa5d27bd7d581300851087277c5d721f5b421 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sat, 14 Jan 2023 20:02:06 +0100 Subject: [PATCH 76/96] Cleanup --- src/netcode/client_connection.c | 21 ++++------ src/netcode/commands.c | 23 +++++------ src/netcode/d_clisrv.c | 57 ++++++++++---------------- src/netcode/d_net.c | 66 ++++++++++++------------------ src/netcode/d_netfil.c | 71 ++++++++++++--------------------- src/netcode/gamestate.c | 8 +--- src/netcode/i_tcp.c | 34 ++++++---------- src/netcode/net_command.c | 11 ++--- src/netcode/server_connection.c | 11 ++--- src/netcode/tic_command.c | 56 +++++++++++--------------- 10 files changed, 132 insertions(+), 226 deletions(-) diff --git a/src/netcode/client_connection.c b/src/netcode/client_connection.c index ff20a6fc7..faa91b6d7 100644 --- a/src/netcode/client_connection.c +++ b/src/netcode/client_connection.c @@ -60,7 +60,7 @@ static inline void CL_DrawConnectionStatus(void) if (cl_mode != CL_DOWNLOADFILES && cl_mode != CL_LOADFILES) { - INT32 i, animtime = ((ccstime / 4) & 15) + 16; + INT32 animtime = ((ccstime / 4) & 15) + 16; UINT8 palstart; const char *cltext; @@ -75,7 +75,7 @@ static inline void CL_DrawConnectionStatus(void) palstart = 96; // Green if (!(cl_mode == CL_DOWNLOADSAVEGAME && lastfilenum != -1)) - for (i = 0; i < 16; ++i) // 15 pal entries total. + for (INT32 i = 0; i < 16; ++i) // 15 pal entries total. V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-16, 16, 8, palstart + ((animtime - i) & 15)); switch (cl_mode) @@ -134,14 +134,13 @@ static inline void CL_DrawConnectionStatus(void) { INT32 totalfileslength; INT32 loadcompletednum = 0; - INT32 i; V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); //ima just count files here if (fileneeded) { - for (i = 0; i < fileneedednum; i++) + for (INT32 i = 0; i < fileneedednum; i++) if (fileneeded[i].status == FS_OPEN) loadcompletednum++; } @@ -277,9 +276,7 @@ UINT32 serverlistcount = 0; static void SL_ClearServerList(INT32 connectedserver) { - UINT32 i; - - for (i = 0; i < serverlistcount; i++) + for (UINT32 i = 0; i < serverlistcount; i++) if (connectedserver != serverlist[i].node) { Net_CloseConnection(serverlist[i].node|FORCECLOSE); @@ -290,8 +287,7 @@ static void SL_ClearServerList(INT32 connectedserver) static UINT32 SL_SearchServer(INT32 node) { - UINT32 i; - for (i = 0; i < serverlistcount; i++) + for (UINT32 i = 0; i < serverlistcount; i++) if (serverlist[i].node == node) return i; @@ -388,9 +384,7 @@ Fetch_servers_thread (struct Fetch_servers_ctx *ctx) void CL_QueryServerList (msg_server_t *server_list) { - INT32 i; - - for (i = 0; server_list[i].header.buffer[0]; i++) + for (INT32 i = 0; server_list[i].header.buffer[0]; i++) { // Make sure MS version matches our own, to // thwart nefarious servers who lie to the MS. @@ -781,7 +775,6 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic_t *asksent) { boolean waitmore; - INT32 i; switch (cl_mode) { @@ -808,7 +801,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic break; case CL_DOWNLOADFILES: waitmore = false; - for (i = 0; i < fileneedednum; i++) + for (INT32 i = 0; i < fileneedednum; i++) if (fileneeded[i].status == FS_DOWNLOADING || fileneeded[i].status == FS_REQUESTED) { diff --git a/src/netcode/commands.c b/src/netcode/commands.c index 834e1c666..4d9a48b6b 100644 --- a/src/netcode/commands.c +++ b/src/netcode/commands.c @@ -79,7 +79,6 @@ static void Ban_Clear(void) void Ban_Load_File(boolean warning) { FILE *f; - size_t i; const char *address, *mask; char buffer[MAX_WADPATH]; @@ -97,7 +96,7 @@ void Ban_Load_File(boolean warning) Ban_Clear(); - for (i=0; fgets(buffer, (int)sizeof(buffer), f); i++) + for (size_t i=0; fgets(buffer, (int)sizeof(buffer), f); i++) { address = strtok(buffer, " \t\r\n"); mask = strtok(NULL, " \t\r\n"); @@ -113,7 +112,6 @@ void Ban_Load_File(boolean warning) void D_SaveBan(void) { FILE *f; - size_t i; banreason_t *reasonlist = reasonhead; const char *address, *mask; const char *path = va("%s"PATHSEP"%s", srb2home, "ban.txt"); @@ -132,7 +130,7 @@ void D_SaveBan(void) return; } - for (i = 0;(address = I_GetBanAddress(i)) != NULL;i++) + for (size_t i = 0;(address = I_GetBanAddress(i)) != NULL;i++) { if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL) fprintf(f, "%s 0", address); @@ -236,12 +234,12 @@ void Command_Ban(void) } else { - size_t i, j = COM_Argc(); + size_t j = COM_Argc(); char message[MAX_REASONLENGTH]; //Steal from the motd code so you don't have to put the reason in quotes. strlcpy(message, COM_Argv(2), sizeof message); - for (i = 3; i < j; i++) + for (size_t i = 3; i < j; i++) { strlcat(message, " ", sizeof message); strlcat(message, COM_Argv(i), sizeof message); @@ -340,12 +338,12 @@ void Command_Kick(void) } else { - size_t i, j = COM_Argc(); + size_t j = COM_Argc(); char message[MAX_REASONLENGTH]; //Steal from the motd code so you don't have to put the reason in quotes. strlcpy(message, COM_Argv(2), sizeof message); - for (i = 3; i < j; i++) + for (size_t i = 3; i < j; i++) { strlcat(message, " ", sizeof message); strlcat(message, COM_Argv(i), sizeof message); @@ -435,9 +433,7 @@ void Command_connect(void) void Command_GetPlayerNum(void) { - INT32 i; - - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) { if (serverplayer == i) @@ -453,18 +449,17 @@ void Command_GetPlayerNum(void) */ void Command_Nodes(void) { - INT32 i; size_t maxlen = 0; const char *address; - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) { const size_t plen = strlen(player_names[i]); if (playeringame[i] && plen > maxlen) maxlen = plen; } - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) { diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index 1658856b6..105526dd2 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -440,11 +440,9 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) if (M_CheckParm("-consisdump")) // Helps debugging some problems { - INT32 i; - CONS_Printf(M_GetText("Player kicked is #%d, dumping consistency...\n"), pnum); - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) continue; @@ -545,8 +543,8 @@ static void RedistributeSpecialStageSpheres(INT32 playernum) INT32 sincrement = max(spheres / count, 1); INT32 rincrement = max(rings / count, 1); - INT32 i, n; - for (i = 0; i < MAXPLAYERS; i++) + INT32 n; + for (INT32 i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i] || i == playernum) continue; @@ -644,10 +642,8 @@ void D_QuitNetGame(void) if (server) { - INT32 i; - netbuffer->packettype = PT_SERVERSHUTDOWN; - for (i = 0; i < MAXNETNODES; i++) + for (INT32 i = 0; i < MAXNETNODES; i++) if (netnodes[i].ingame) HSendPacket(i, true, 0, 0); #ifdef MASTERSERVER @@ -701,8 +697,6 @@ void CL_RemoveSplitscreenPlayer(void) void SV_ResetServer(void) { - INT32 i; - // +1 because this command will be executed in com_executebuffer in // tryruntic so gametic will be incremented, anyway maketic > gametic // is not an issue @@ -713,10 +707,10 @@ void SV_ResetServer(void) joindelay = 0; - for (i = 0; i < MAXNETNODES; i++) + for (INT32 i = 0; i < MAXNETNODES; i++) ResetNode(i); - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) { LUA_InvalidatePlayer(&players[i]); playeringame[i] = false; @@ -755,10 +749,9 @@ void SV_ResetServer(void) static inline void SV_GenContext(void) { - UINT8 i; // generate server_context, as exactly 8 bytes of randomly mixed A-Z and a-z // (hopefully M_Random is initialized!! if not this will be awfully silly!) - for (i = 0; i < 8; i++) + for (UINT8 i = 0; i < 8; i++) { const char a = M_RandomKey(26*2); if (a < 26) // uppercase @@ -814,8 +807,6 @@ void SV_StartSinglePlayerServer(void) void SV_StopServer(void) { - tic_t i; - if (gamestate == GS_INTERMISSION) Y_EndIntermission(); gamestate = wipegamestate = GS_NULL; @@ -823,7 +814,7 @@ void SV_StopServer(void) localtextcmd[0] = 0; localtextcmd2[0] = 0; - for (i = firstticstosend; i < firstticstosend + BACKUPTICS; i++) + for (tic_t i = firstticstosend; i < firstticstosend + BACKUPTICS; i++) D_Clearticcmd(i); consoleplayer = 0; @@ -913,7 +904,6 @@ If they're not lagging, decrement the timer by 1. Of course, reset all of this i static inline void PingUpdate(void) { - INT32 i; boolean laggers[MAXPLAYERS]; UINT8 numlaggers = 0; memset(laggers, 0, sizeof(boolean) * MAXPLAYERS); @@ -923,7 +913,7 @@ static inline void PingUpdate(void) //check for ping limit breakage. if (cv_maxping.value) { - for (i = 1; i < MAXPLAYERS; i++) + for (INT32 i = 1; i < MAXPLAYERS; i++) { if (playeringame[i] && !players[i].quittime && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value)) @@ -940,7 +930,7 @@ static inline void PingUpdate(void) //in that case, it is probably the server's fault. if (numlaggers < D_NumPlayers() - 1) { - for (i = 1; i < MAXPLAYERS; i++) + for (INT32 i = 1; i < MAXPLAYERS; i++) { if (playeringame[i] && laggers[i]) { @@ -965,7 +955,7 @@ static inline void PingUpdate(void) } //make the ping packet and clear server data for next one - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) { netbuffer->u.pingtable[i] = realpingtable[i] / pingmeasurecount; //server takes a snapshot of the real ping for display. @@ -978,7 +968,7 @@ static inline void PingUpdate(void) netbuffer->u.pingtable[MAXPLAYERS] = cv_maxping.value; //send out our ping packets - for (i = 0; i < MAXNETNODES; i++) + for (INT32 i = 0; i < MAXNETNODES; i++) if (netnodes[i].ingame) HSendPacket(i, true, 0, sizeof(INT32) * (MAXPLAYERS+1)); @@ -999,8 +989,7 @@ static void PT_Ping(SINT8 node, INT32 netconsole) //Update client ping table from the server. if (client) { - UINT8 i; - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i]; @@ -1225,7 +1214,6 @@ void NetUpdate(void) static tic_t gametime = 0; static tic_t resptime = 0; tic_t nowtime; - INT32 i; INT32 realtics; nowtime = I_GetTime(); @@ -1248,7 +1236,7 @@ void NetUpdate(void) if (netgame && !(gametime % 35)) // update once per second. PingUpdate(); // update node latency values so we can take an average later. - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && playernode[i] != UINT8_MAX) realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i])); pingmeasurecount++; @@ -1287,7 +1275,7 @@ void NetUpdate(void) hu_redownloadinggamestate = false; firstticstosend = gametic; - for (i = 0; i < MAXNETNODES; i++) + for (INT32 i = 0; i < MAXNETNODES; i++) if (netnodes[i].ingame && netnodes[i].tic < firstticstosend) { firstticstosend = netnodes[i].tic; @@ -1301,7 +1289,7 @@ void NetUpdate(void) if (maketic + counts >= firstticstosend + BACKUPTICS) counts = firstticstosend+BACKUPTICS-maketic-1; - for (i = 0; i < counts; i++) + for (INT32 i = 0; i < counts; i++) SV_Maketic(); // Create missed tics and increment maketic for (; tictoclear < firstticstosend; tictoclear++) // Clear only when acknowledged @@ -1318,7 +1306,7 @@ void NetUpdate(void) // Handle timeouts to prevent definitive freezes from happenning if (server) { - for (i = 1; i < MAXNETNODES; i++) + for (INT32 i = 1; i < MAXNETNODES; i++) if (netnodes[i].ingame && netnodes[i].freezetimeout < I_GetTime()) Net_ConnectionTimeout(i); @@ -1387,7 +1375,7 @@ void D_ClientServerInit(void) SINT8 nametonum(const char *name) { - INT32 playernum, i; + INT32 playernum; if (!strcmp(name, "0")) return 0; @@ -1405,7 +1393,7 @@ SINT8 nametonum(const char *name) return -1; } - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && !stricmp(player_names[i], name)) return (SINT8)i; @@ -1427,8 +1415,8 @@ boolean Playing(void) */ INT32 D_NumPlayers(void) { - INT32 num = 0, ix; - for (ix = 0; ix < MAXPLAYERS; ix++) + INT32 num = 0; + for (INT32 ix = 0; ix < MAXPLAYERS; ix++) if (playeringame[ix]) num++; return num; @@ -1444,7 +1432,6 @@ INT32 D_NumPlayers(void) // INT16 Consistancy(void) { - INT32 i; UINT32 ret = 0; #ifdef MOBJCONSISTANCY thinker_t *th; @@ -1453,7 +1440,7 @@ INT16 Consistancy(void) DEBFILE(va("TIC %u ", gametic)); - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) ret ^= 0xCCCC; diff --git a/src/netcode/d_net.c b/src/netcode/d_net.c index 3c16392d0..a4b0778e3 100644 --- a/src/netcode/d_net.c +++ b/src/netcode/d_net.c @@ -211,7 +211,7 @@ FUNCMATH static INT32 cmpack(UINT8 a, UINT8 b) static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer) { node_t *node = &nodes[doomcom->remotenode]; - INT32 i, numfreeslot = 0; + INT32 numfreeslot = 0; if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0) { @@ -219,7 +219,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer) return false; } - for (i = 0; i < MAXACKPACKETS; i++) + for (INT32 i = 0; i < MAXACKPACKETS; i++) if (!ackpak[i].acknum) { // For low priority packets, make sure to let freeslots so urgent packets can be sent @@ -276,10 +276,10 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer) */ INT32 Net_GetFreeAcks(boolean urgent) { - INT32 i, numfreeslot = 0; + INT32 numfreeslot = 0; INT32 n = 0; // Number of free acks found - for (i = 0; i < MAXACKPACKETS; i++) + for (INT32 i = 0; i < MAXACKPACKETS; i++) if (!ackpak[i].acknum) { // For low priority packets, make sure to let freeslots so urgent packets can be sent @@ -315,7 +315,6 @@ static void RemoveAck(INT32 i) // We have got a packet, proceed the ack request and ack return static boolean Processackpak(void) { - INT32 i; boolean goodpacket = true; node_t *node = &nodes[doomcom->remotenode]; @@ -324,7 +323,7 @@ static boolean Processackpak(void) { node->remotefirstack = netbuffer->ackreturn; // Search the ackbuffer and free it - for (i = 0; i < MAXACKPACKETS; i++) + for (INT32 i = 0; i < MAXACKPACKETS; i++) if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes && cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0) { @@ -346,7 +345,7 @@ static boolean Processackpak(void) else { // Check if it is not already in the queue - for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND) + for (INT32 i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND) if (node->acktosend[i] == ack) { DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack)); @@ -374,7 +373,7 @@ static boolean Processackpak(void) while (change) { change = false; - for (i = node->acktosend_tail; i != node->acktosend_head; + for (INT32 i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND) { if (cmpack(node->acktosend[i], nextfirstack) <= 0) @@ -434,11 +433,9 @@ void Net_SendAcks(INT32 node) static void GotAcks(void) { - INT32 i, j; - - for (j = 0; j < MAXACKTOSEND; j++) + for (INT32 j = 0; j < MAXACKTOSEND; j++) if (netbuffer->u.textcmd[j]) - for (i = 0; i < MAXACKPACKETS; i++) + for (INT32 i = 0; i < MAXACKPACKETS; i++) if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode) { if (ackpak[i].acknum == netbuffer->u.textcmd[j]) @@ -475,9 +472,8 @@ void Net_ConnectionTimeout(INT32 node) // Resend the data if needed void Net_AckTicker(void) { - INT32 i; - for (i = 0; i < MAXACKPACKETS; i++) + for (INT32 i = 0; i < MAXACKPACKETS; i++) { const INT32 nodei = ackpak[i].destinationnode; node_t *node = &nodes[nodei]; @@ -504,7 +500,7 @@ void Net_AckTicker(void) } } - for (i = 1; i < MAXNETNODES; i++) + for (INT32 i = 1; i < MAXNETNODES; i++) { // This is something like node open flag if (nodes[i].firstacktosend) @@ -567,9 +563,7 @@ void Net_UnAcknowledgePacket(INT32 node) */ static boolean Net_AllAcksReceived(void) { - INT32 i; - - for (i = 0; i < MAXACKPACKETS; i++) + for (INT32 i = 0; i < MAXACKPACKETS; i++) if (ackpak[i].acknum) return false; @@ -611,12 +605,10 @@ static void InitNode(node_t *node) static void InitAck(void) { - INT32 i; - - for (i = 0; i < MAXACKPACKETS; i++) + for (INT32 i = 0; i < MAXACKPACKETS; i++) ackpak[i].acknum = 0; - for (i = 0; i < MAXNETNODES; i++) + for (INT32 i = 0; i < MAXNETNODES; i++) InitNode(&nodes[i]); } @@ -627,8 +619,7 @@ static void InitAck(void) */ void Net_AbortPacketType(UINT8 packettype) { - INT32 i; - for (i = 0; i < MAXACKPACKETS; i++) + for (INT32 i = 0; i < MAXACKPACKETS; i++) if (ackpak[i].acknum && (ackpak[i].pak.data.packettype == packettype || packettype == UINT8_MAX)) { @@ -643,7 +634,6 @@ void Net_AbortPacketType(UINT8 packettype) // remove a node, clear all ack from this node and reset askret void Net_CloseConnection(INT32 node) { - INT32 i; boolean forceclose = (node & FORCECLOSE) != 0; if (node == -1) @@ -673,7 +663,7 @@ void Net_CloseConnection(INT32 node) } // check if we are waiting for an ack from this node - for (i = 0; i < MAXACKPACKETS; i++) + for (INT32 i = 0; i < MAXACKPACKETS; i++) if (ackpak[i].acknum && ackpak[i].destinationnode == node) { if (!forceclose) @@ -697,9 +687,8 @@ static UINT32 NetbufferChecksum(void) UINT32 c = 0x1234567; const INT32 l = doomcom->datalength - 4; const UINT8 *buf = (UINT8 *)netbuffer + 4; - INT32 i; - for (i = 0; i < l; i++, buf++) + for (INT32 i = 0; i < l; i++, buf++) c += (*buf) * (i+1); return LONG(c); @@ -710,9 +699,8 @@ static UINT32 NetbufferChecksum(void) static void fprintfstring(char *s, size_t len) { INT32 mode = 0; - size_t i; - for (i = 0; i < len; i++) + for (size_t i = 0; i < len; i++) if (s[i] < 32) { if (!mode) @@ -879,7 +867,6 @@ void Command_Drop(void) { INT32 packetquantity; const char *packetname; - size_t i; if (COM_Argc() < 2) { @@ -909,11 +896,11 @@ void Command_Drop(void) packetname = COM_Argv(1); if (!(stricmp(packetname, "all") && stricmp(packetname, "any"))) - for (i = 0; i < NUMPACKETTYPE; i++) + for (size_t i = 0; i < NUMPACKETTYPE; i++) packetdropquantity[i] = packetquantity; else { - for (i = 0; i < NUMPACKETTYPE; i++) + for (size_t i = 0; i < NUMPACKETTYPE; i++) if (!stricmp(packetname, packettypename[i])) { packetdropquantity[i] = packetquantity; @@ -1336,13 +1323,12 @@ void Command_Ping_f(void) int name_width = 0; int ms_width = 0; - int n; - INT32 i; - pingc = 0; - for (i = 1; i < MAXPLAYERS; ++i) + for (INT32 i = 1; i < MAXPLAYERS; ++i) if (playeringame[i]) { + int n; + n = strlen(player_names[i]); if (n > name_width) name_width = n; @@ -1362,7 +1348,7 @@ void Command_Ping_f(void) qsort(pingv, pingc, sizeof (struct pingcell), &pingcellcmp); - for (i = 0; i < pingc; ++i) + for (INT32 i = 0; i < pingc; ++i) { CONS_Printf("%02d : %-*s %*d ms\n", pingv[i].num, @@ -1378,15 +1364,13 @@ void Command_Ping_f(void) void D_CloseConnection(void) { - INT32 i; - if (netgame) { // wait the ackreturn with timout of 5 Sec Net_WaitAllAckReceived(5); // close all connection - for (i = 0; i < MAXNETNODES; i++) + for (INT32 i = 0; i < MAXNETNODES; i++) Net_CloseConnection(i|FORCECLOSE); InitAck(); diff --git a/src/netcode/d_netfil.c b/src/netcode/d_netfil.c index 205abf713..10b7359ad 100644 --- a/src/netcode/d_netfil.c +++ b/src/netcode/d_netfil.c @@ -128,9 +128,7 @@ consvar_t cv_downloadspeed = CVAR_INIT ("downloadspeed", "16", CV_SAVE|CV_NETVAR static UINT16 GetWadNumFromFileNeededId(UINT8 id) { - UINT16 wadnum; - - for (wadnum = mainwads; wadnum < numwadfiles; wadnum++) + for (UINT16 wadnum = mainwads; wadnum < numwadfiles; wadnum++) { if (!wadfiles[wadnum]->important) continue; @@ -150,14 +148,13 @@ static UINT16 GetWadNumFromFileNeededId(UINT8 id) */ UINT8 *PutFileNeeded(UINT16 firstfile) { - size_t i; UINT8 count = 0; UINT8 *p_start = netbuffer->packettype == PT_MOREFILESNEEDED ? netbuffer->u.filesneededcfg.files : netbuffer->u.serverinfo.fileneeded; UINT8 *p = p_start; char wadfilename[MAX_WADPATH] = ""; UINT8 filestatus, folder; - for (i = mainwads; i < numwadfiles; i++) //mainwads, otherwise we start on the first mainwad + for (size_t i = mainwads; i < numwadfiles; i++) //mainwads, otherwise we start on the first mainwad { // If it has only music/sound lumps, don't put it in the list if (!wadfiles[i]->important) @@ -232,7 +229,6 @@ void FreeFileNeeded(void) */ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile) { - INT32 i; UINT8 *p; UINT8 filestatus; @@ -241,7 +237,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 fi AllocFileNeeded(fileneedednum); - for (i = firstfile; i < fileneedednum; i++) + for (INT32 i = firstfile; i < fileneedednum; i++) { fileneeded[i].type = FILENEEDED_WAD; fileneeded[i].status = FS_NOTCHECKED; // We haven't even started looking for the file yet @@ -281,9 +277,9 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave) */ boolean CL_CheckDownloadable(void) { - UINT8 i,dlstatus = 0; + UINT8 dlstatus = 0; - for (i = 0; i < fileneedednum; i++) + for (UINT8 i = 0; i < fileneedednum; i++) if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN) { if (fileneeded[i].willsend == 1) @@ -304,7 +300,7 @@ boolean CL_CheckDownloadable(void) // not downloadable, put reason in console CONS_Alert(CONS_NOTICE, M_GetText("You need additional files to connect to this server:\n")); - for (i = 0; i < fileneedednum; i++) + for (UINT8 i = 0; i < fileneedednum; i++) if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN) { CONS_Printf(" * \"%s\" (%dK)", fileneeded[i].filename, fileneeded[i].totalsize >> 10); @@ -374,14 +370,13 @@ void CL_AbortDownloadResume(void) boolean CL_SendFileRequest(void) { char *p; - INT32 i; INT64 totalfreespaceneeded = 0, availablefreespace; #ifdef PARANOIA if (M_CheckParm("-nodownload")) I_Error("Attempted to download files in -nodownload mode"); - for (i = 0; i < fileneedednum; i++) + for (INT32 i = 0; i < fileneedednum; i++) if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN && (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2)) { @@ -391,7 +386,7 @@ boolean CL_SendFileRequest(void) netbuffer->packettype = PT_REQUESTFILE; p = (char *)netbuffer->u.textcmd; - for (i = 0; i < fileneedednum; i++) + for (INT32 i = 0; i < fileneedednum; i++) if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD)) { totalfreespaceneeded += fileneeded[i].totalsize; @@ -422,7 +417,6 @@ boolean CL_SendFileRequest(void) void PT_RequestFile(SINT8 node) { UINT8 *p = netbuffer->u.textcmd; - UINT8 id; if (client || !cv_downloading.value) { @@ -432,7 +426,7 @@ void PT_RequestFile(SINT8 node) while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow { - id = READUINT8(p); + UINT8 id = READUINT8(p); if (id == 0xFF) break; @@ -543,9 +537,7 @@ INT32 CL_CheckFiles(void) // Load it now boolean CL_LoadServerFiles(void) { - INT32 i; - - for (i = 0; i < fileneedednum; i++) + for (INT32 i = 0; i < fileneedednum; i++) { if (fileneeded[i].status == FS_OPEN) continue; // Already loaded @@ -641,11 +633,10 @@ void AddLuaFileTransfer(const char *filename, const char *mode) static void SV_PrepareSendLuaFileToNextNode(void) { - INT32 i; UINT8 success = 1; // Find a client to send the file to - for (i = 1; i < MAXNETNODES; i++) + for (INT32 i = 1; i < MAXNETNODES; i++) if (luafiletransfers->nodestatus[i] == LFTNS_WAITING) // Node waiting { // Tell the client we're about to send them the file @@ -667,12 +658,11 @@ static void SV_PrepareSendLuaFileToNextNode(void) void SV_PrepareSendLuaFile(void) { char *binfilename; - INT32 i; luafiletransfers->ongoing = true; // Set status to "waiting" for everyone - for (i = 0; i < MAXNETNODES; i++) + for (INT32 i = 0; i < MAXNETNODES; i++) luafiletransfers->nodestatus[i] = (netnodes[i].ingame ? LFTNS_WAITING : LFTNS_NONE); if (FIL_ReadFileOK(luafiletransfers->realfilename)) @@ -1153,7 +1143,6 @@ void PT_FileAck(SINT8 node) { fileack_pak *packet = &netbuffer->u.fileack; filetran_t *trans = &transfer[node]; - INT32 i, j; if (client) return; @@ -1175,11 +1164,11 @@ void PT_FileAck(SINT8 node) trans->dontsenduntil = 0; } - for (i = 0; i < packet->numsegments; i++) + for (INT32 i = 0; i < packet->numsegments; i++) { fileacksegment_t *segment = &packet->segments[i]; - for (j = 0; j < 32; j++) + for (INT32 j = 0; j < 32; j++) if (LONG(segment->acks) & (1 << j)) { if (LONG(segment->start) * FILEFRAGMENTSIZE >= trans->txlist->size) @@ -1215,13 +1204,12 @@ void PT_FileReceived(SINT8 node) static void SendAckPacket(fileack_pak *packet, UINT8 fileid) { size_t packetsize; - INT32 i; packetsize = sizeof(*packet) + packet->numsegments * sizeof(*packet->segments); // Finalise the packet packet->fileid = fileid; - for (i = 0; i < packet->numsegments; i++) + for (INT32 i = 0; i < packet->numsegments; i++) { packet->segments[i].start = LONG(packet->segments[i].start); packet->segments[i].acks = LONG(packet->segments[i].acks); @@ -1261,9 +1249,7 @@ static void AddFragmentToAckPacket(fileack_pak *packet, UINT8 iteration, UINT32 void FileReceiveTicker(void) { - INT32 i; - - for (i = 0; i < fileneedednum; i++) + for (INT32 i = 0; i < fileneedednum; i++) { fileneeded_t *file = &fileneeded[i]; @@ -1277,8 +1263,7 @@ void FileReceiveTicker(void) if (file->ackresendposition != UINT32_MAX && file->status == FS_DOWNLOADING) { // Acknowledge ~70 MB/s, whichs means the client sends ~18 KB/s - INT32 j; - for (j = 0; j < 2048; j++) + for (INT32 j = 0; j < 2048; j++) { if (file->receivedfragments[file->ackresendposition]) AddFragmentToAckPacket(file->ackpacket, file->iteration, file->ackresendposition, i); @@ -1500,15 +1485,14 @@ void SV_AbortSendFiles(INT32 node) void CloseNetFile(void) { - INT32 i; // Is sending? - for (i = 0; i < MAXNETNODES; i++) + for (INT32 i = 0; i < MAXNETNODES; i++) SV_AbortSendFiles(i); // Receiving a file? if (fileneeded) { - for (i = 0; i < fileneedednum; i++) + for (INT32 i = 0; i < fileneedednum; i++) if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file) { fclose(fileneeded[i].file); @@ -1541,9 +1525,7 @@ void CloseNetFile(void) void Command_Downloads_f(void) { - INT32 node; - - for (node = 0; node < MAXNETNODES; node++) + for (INT32 node = 0; node < MAXNETNODES; node++) if (transfer[node].txlist && transfer[node].txlist->ram == SF_FILE) // Node is downloading a file? { @@ -1577,14 +1559,11 @@ void Command_Downloads_f(void) void nameonly(char *s) { - size_t j, len; - void *ns; - - for (j = strlen(s); j != (size_t)-1; j--) + for (size_t j = strlen(s); j != (size_t)-1; j--) if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/')) { - ns = &(s[j+1]); - len = strlen(ns); + void *ns = &(s[j+1]); + size_t len = strlen(ns); #if 0 M_Memcpy(s, ns, len+1); #else @@ -1597,9 +1576,9 @@ void nameonly(char *s) // Returns the length in characters of the last element of a path. size_t nameonlylength(const char *s) { - size_t j, len = strlen(s); + size_t len = strlen(s); - for (j = len; j != (size_t)-1; j--) + for (size_t j = len; j != (size_t)-1; j--) if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/')) return len - j - 1; diff --git a/src/netcode/gamestate.c b/src/netcode/gamestate.c index 4a3e9f3af..d284164c0 100644 --- a/src/netcode/gamestate.c +++ b/src/netcode/gamestate.c @@ -43,9 +43,7 @@ boolean cl_redownloadinggamestate = false; boolean SV_ResendingSavegameToAnyone(void) { - INT32 i; - - for (i = 0; i < MAXNETNODES; i++) + for (INT32 i = 0; i < MAXNETNODES; i++) if (netnodes[i].resendingsavegame) return true; return false; @@ -236,9 +234,7 @@ void CL_LoadReceivedSavegame(boolean reloading) void CL_ReloadReceivedSavegame(void) { - INT32 i; - - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) { LUA_InvalidatePlayer(&players[i]); sprintf(player_names[i], "Player %d", i + 1); diff --git a/src/netcode/i_tcp.c b/src/netcode/i_tcp.c index 6baba6275..bd950c355 100644 --- a/src/netcode/i_tcp.c +++ b/src/netcode/i_tcp.c @@ -416,24 +416,20 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask) */ static void cleanupnodes(void) { - SINT8 j; - if (!Playing()) return; // Why can't I start at zero? - for (j = 1; j < MAXNETNODES; j++) + for (SINT8 j = 1; j < MAXNETNODES; j++) if (!(netnodes[j].ingame || SendingFile(j))) nodeconnected[j] = false; } static SINT8 getfreenode(void) { - SINT8 j; - cleanupnodes(); - for (j = 0; j < MAXNETNODES; j++) + for (SINT8 j = 0; j < MAXNETNODES; j++) if (!nodeconnected[j]) { nodeconnected[j] = true; @@ -446,7 +442,7 @@ static SINT8 getfreenode(void) * downloading a needed wad, but it's better than not letting anyone join... */ /*I_Error("No more free nodes!!1!11!11!!1111\n"); - for (j = 1; j < MAXNETNODES; j++) + for (SINT8 j = 1; j < MAXNETNODES; j++) if (!netnodes[j].ingame) return j;*/ @@ -458,9 +454,8 @@ void Command_Numnodes(void) { INT32 connected = 0; INT32 ingame = 0; - INT32 i; - for (i = 1; i < MAXNETNODES; i++) + for (INT32 i = 1; i < MAXNETNODES; i++) { if (!(nodeconnected[i] || netnodes[i].ingame)) continue; @@ -496,13 +491,13 @@ void Command_Numnodes(void) // Returns true if a packet was received from a new node, false in all other cases static boolean SOCK_Get(void) { - size_t i, n; + size_t i; int j; ssize_t c; mysockaddr_t fromaddress; socklen_t fromlen; - for (n = 0; n < mysocketses; n++) + for (size_t n = 0; n < mysocketses; n++) { fromlen = (socklen_t)sizeof(fromaddress); c = recvfrom(mysockets[n], (char *)&doomcom->data, MAXPACKETLENGTH, 0, @@ -563,10 +558,9 @@ static fd_set masterset; #ifdef SELECTTEST static boolean FD_CPY(fd_set *src, fd_set *dst, SOCKET_TYPE *fd, size_t len) { - size_t i; boolean testset = false; FD_ZERO(dst); - for (i = 0; i < len;i++) + for (size_t i = 0; i < len;i++) { if(fd[i] != (SOCKET_TYPE)ERRSOCKET && FD_ISSET(fd[i], src) && !FD_ISSET(fd[i], dst)) // no checking for dups @@ -630,16 +624,15 @@ static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr static void SOCK_Send(void) { ssize_t c = ERRSOCKET; - size_t i, j; if (!nodeconnected[doomcom->remotenode]) return; if (doomcom->remotenode == BROADCASTADDR) { - for (i = 0; i < mysocketses; i++) + for (size_t i = 0; i < mysocketses; i++) { - for (j = 0; j < broadcastaddresses; j++) + for (size_t j = 0; j < broadcastaddresses; j++) { if (myfamily[i] == broadcastaddress[j].any.sa_family) SOCK_SendToAddr(mysockets[i], &broadcastaddress[j]); @@ -649,7 +642,7 @@ static void SOCK_Send(void) } else if (nodesocket[doomcom->remotenode] == (SOCKET_TYPE)ERRSOCKET) { - for (i = 0; i < mysocketses; i++) + for (size_t i = 0; i < mysocketses; i++) { if (myfamily[i] == clientaddress[doomcom->remotenode].any.sa_family) SOCK_SendToAddr(mysockets[i], &clientaddress[doomcom->remotenode]); @@ -1082,8 +1075,7 @@ boolean I_InitTcpDriver(void) static void SOCK_CloseSocket(void) { - size_t i; - for (i=0; i < MAXNETNODES+1; i++) + for (size_t i=0; i < MAXNETNODES+1; i++) { if (mysockets[i] != (SOCKET_TYPE)ERRSOCKET && FD_ISSET(mysockets[i], &masterset)) @@ -1154,12 +1146,10 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port) static boolean SOCK_OpenSocket(void) { - size_t i; - memset(clientaddress, 0, sizeof (clientaddress)); nodeconnected[0] = true; // always connected to self - for (i = 1; i < MAXNETNODES; i++) + for (size_t i = 1; i < MAXNETNODES; i++) nodeconnected[i] = false; nodeconnected[BROADCASTADDR] = true; I_NetSend = SOCK_Send; diff --git a/src/netcode/net_command.c b/src/netcode/net_command.c index 11b351af7..887b7fa2a 100644 --- a/src/netcode/net_command.c +++ b/src/netcode/net_command.c @@ -90,13 +90,11 @@ void D_FreeTextcmd(tic_t tic) if (textcmdtic) { - INT32 i; - // Remove this tic from the list. *tctprev = textcmdtic->next; // Free all players. - for (i = 0; i < TEXTCMD_HASH_SIZE; i++) + for (INT32 i = 0; i < TEXTCMD_HASH_SIZE; i++) { textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[i]; @@ -174,9 +172,7 @@ UINT8* D_GetTextcmd(tic_t tic, INT32 playernum) void ExtraDataTicker(void) { - INT32 i; - - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) if (playeringame[i] || i == 0) { UINT8 *bufferstart = D_GetExistingTextcmd(gametic, i); @@ -221,10 +217,9 @@ void ExtraDataTicker(void) // used at txtcmds received to check packetsize bound size_t TotalTextCmdPerTic(tic_t tic) { - INT32 i; size_t total = 1; // num of textcmds in the tic (ntextcmd byte) - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) { UINT8 *textcmd = D_GetExistingTextcmd(tic, i); if ((!i || playeringame[i]) && textcmd) diff --git a/src/netcode/server_connection.c b/src/netcode/server_connection.c index ed0e28309..f8ec3c7bd 100644 --- a/src/netcode/server_connection.c +++ b/src/netcode/server_connection.c @@ -55,7 +55,6 @@ static INT32 FindRejoinerNum(SINT8 node) char strippednodeaddress[64]; const char *nodeaddress; char *port; - INT32 i; // Make sure there is no dead dress before proceeding to the stripping if (!I_GetNodeAddress) @@ -71,7 +70,7 @@ static INT32 FindRejoinerNum(SINT8 node) *port = '\0'; // Check if any player matches the stripped address - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) { if (playeringame[i] && playeraddress[i][0] && playernode[i] == UINT8_MAX && !strcmp(playeraddress[i], strippednodeaddress)) @@ -162,10 +161,9 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) static void SV_SendPlayerInfo(INT32 node) { - UINT8 i; netbuffer->packettype = PT_PLAYERINFO; - for (i = 0; i < MAXPLAYERS; i++) + for (UINT8 i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) { @@ -425,7 +423,6 @@ void PT_ClientJoin(SINT8 node) char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1]; INT32 numplayers = netbuffer->u.clientcfg.localplayers; INT32 rejoinernum; - INT32 i; // Ignore duplicate packets if (client || netnodes[node].ingame) @@ -440,7 +437,7 @@ void PT_ClientJoin(SINT8 node) return; } - for (i = 0; i < numplayers; i++) + for (INT32 i = 0; i < numplayers; i++) { strlcpy(names[i], netbuffer->u.clientcfg.names[i], MAXPLAYERNAME + 1); if (!EnsurePlayerNameIsGood(names[i], rejoinernum)) @@ -469,7 +466,7 @@ void PT_ClientJoin(SINT8 node) } // Splitscreen can allow 2 players in one node - for (i = 0; i < numplayers; i++) + for (INT32 i = 0; i < numplayers; i++) SV_AddPlayer(node, names[i]); joindelay += cv_joindelay.value * TICRATE; diff --git a/src/netcode/tic_command.c b/src/netcode/tic_command.c index bf8c5d21d..befe8a5cd 100644 --- a/src/netcode/tic_command.c +++ b/src/netcode/tic_command.c @@ -80,11 +80,9 @@ tic_t ExpandTics(INT32 low, INT32 node) void D_Clearticcmd(tic_t tic) { - INT32 i; - D_FreeTextcmd(tic); - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) netcmds[tic%BACKUPTICS][i].angleturn = 0; DEBFILE(va("clear tic %5u (%2u)\n", tic, tic%BACKUPTICS)); @@ -92,13 +90,11 @@ void D_Clearticcmd(tic_t tic) void D_ResetTiccmds(void) { - INT32 i; - memset(&localcmds, 0, sizeof(ticcmd_t)); memset(&localcmds2, 0, sizeof(ticcmd_t)); // Reset the net command list - for (i = 0; i < TEXTCMD_HASH_SIZE; i++) + for (INT32 i = 0; i < TEXTCMD_HASH_SIZE; i++) while (textcmds[i]) D_Clearticcmd(textcmds[i]->tic); } @@ -229,8 +225,7 @@ void PT_ServerTics(SINT8 node, INT32 netconsole) realstart = netbuffer->u.serverpak.starttic; realend = realstart + netbuffer->u.serverpak.numtics; - if (realend > gametic + CLIENTBACKUPTICS) - realend = gametic + CLIENTBACKUPTICS; + realend = min(realend, gametic + CLIENTBACKUPTICS); cl_packetmissed = realstart > neededtic; if (realstart <= neededtic && realend > neededtic) @@ -304,9 +299,8 @@ void CL_SendClientCmd(void) static tic_t SV_CalculateNumTicsForPacket(SINT8 nodenum, tic_t firsttic, tic_t lasttic) { size_t size = BASESERVERTICSSIZE; - tic_t tic; - for (tic = firsttic; tic < lasttic; tic++) + for (tic_t tic = firsttic; tic < lasttic; tic++) { size += sizeof (ticcmd_t) * doomcom->numslots; size += TotalTextCmdPerTic(tic); @@ -344,15 +338,12 @@ static tic_t SV_CalculateNumTicsForPacket(SINT8 nodenum, tic_t firsttic, tic_t l // send tic from firstticstosend to maketic-1 void SV_SendTics(void) { - tic_t realfirsttic, lasttictosend, i; - UINT32 n; - size_t packsize; - UINT8 *bufpos; + tic_t realfirsttic, lasttictosend; // send to all client but not to me // for each node create a packet with x tics and send it // x is computed using netnodes[n].supposedtic, max packet size and maketic - for (n = 1; n < MAXNETNODES; n++) + for (INT32 n = 1; n < MAXNETNODES; n++) if (netnodes[n].ingame) { // assert netnodes[n].supposedtic>=netnodes[n].tic @@ -367,42 +358,42 @@ void SV_SendTics(void) // (getpacket servertics case) DEBFILE(va("Nothing to send node %u mak=%u sup=%u net=%u \n", n, maketic, netnodes[n].supposedtic, netnodes[n].tic)); + realfirsttic = netnodes[n].tic; + if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3) // all tic are ok continue; + DEBFILE(va("Sent %d anyway\n", realfirsttic)); } - if (realfirsttic < firstticstosend) - realfirsttic = firstticstosend; + realfirsttic = max(realfirsttic, firstticstosend); lasttictosend = realfirsttic + SV_CalculateNumTicsForPacket(n, realfirsttic, lasttictosend); - // Send the tics + // Prepare the packet header netbuffer->packettype = PT_SERVERTICS; netbuffer->u.serverpak.starttic = realfirsttic; netbuffer->u.serverpak.numtics = (UINT8)(lasttictosend - realfirsttic); netbuffer->u.serverpak.numslots = (UINT8)SHORT(doomcom->numslots); - bufpos = (UINT8 *)&netbuffer->u.serverpak.cmds; - for (i = realfirsttic; i < lasttictosend; i++) - { + // Fill and send the packet + UINT8 *bufpos = (UINT8 *)&netbuffer->u.serverpak.cmds; + for (tic_t i = realfirsttic; i < lasttictosend; i++) bufpos = G_DcpyTiccmd(bufpos, netcmds[i%BACKUPTICS], doomcom->numslots * sizeof (ticcmd_t)); - } - - // add textcmds - for (i = realfirsttic; i < lasttictosend; i++) - SV_WriteNetCommandsForTic(); - packsize = bufpos - (UINT8 *)&(netbuffer->u); - + for (tic_t i = realfirsttic; i < lasttictosend; i++) + SV_WriteNetCommandsForTic(i, &bufpos); + size_t packsize = bufpos - (UINT8 *)&(netbuffer->u); HSendPacket(n, false, 0, packsize); + // when tic are too large, only one tic is sent so don't go backward! if (lasttictosend-doomcom->extratics > realfirsttic) netnodes[n].supposedtic = lasttictosend-doomcom->extratics; else netnodes[n].supposedtic = lasttictosend; - if (netnodes[n].supposedtic < netnodes[n].tic) netnodes[n].supposedtic = netnodes[n].tic; + netnodes[n].supposedtic = max(netnodes[n].supposedtic, netnodes[n].tic); } + // node 0 is me! netnodes[0].supposedtic = maketic; } @@ -413,7 +404,8 @@ void Local_Maketic(INT32 realtics) D_ProcessEvents(); // menu responder, cons responder, // game responder calls HU_Responder, AM_Responder, // and G_MapEventsToControls - if (!dedicated) rendergametic = gametic; + if (!dedicated) + rendergametic = gametic; // translate inputs (keyboard/mouse/gamepad) into game controls G_BuildTiccmd(&localcmds, realtics, 1); if (splitscreen || botingame) @@ -426,9 +418,7 @@ void Local_Maketic(INT32 realtics) // create missed tic void SV_Maketic(void) { - INT32 i; - - for (i = 0; i < MAXPLAYERS; i++) + for (INT32 i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) continue; From 425fce69c97dc61b1709ceaff03d984561a6c733 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sat, 14 Jan 2023 20:02:20 +0100 Subject: [PATCH 77/96] Add missing include directive --- src/netcode/net_command.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/netcode/net_command.c b/src/netcode/net_command.c index 887b7fa2a..efc8bd0ef 100644 --- a/src/netcode/net_command.c +++ b/src/netcode/net_command.c @@ -16,6 +16,7 @@ #include "server_connection.h" #include "d_clisrv.h" #include "i_net.h" +#include "../byteptr.h" #include "../g_game.h" #include "../z_zone.h" #include "../doomtype.h" From d1ba9e0afd0ea7c02a0566cd30e730d65c38b0d8 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 15 Jan 2023 13:08:31 +0100 Subject: [PATCH 78/96] Cleanup --- src/netcode/gamestate.c | 3 +-- src/netcode/tic_command.c | 43 +++++++++++++++++++++------------------ src/netcode/tic_command.h | 2 +- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/netcode/gamestate.c b/src/netcode/gamestate.c index d284164c0..c1ceb95b5 100644 --- a/src/netcode/gamestate.c +++ b/src/netcode/gamestate.c @@ -242,8 +242,7 @@ void CL_ReloadReceivedSavegame(void) CL_LoadReceivedSavegame(true); - if (neededtic < gametic) - neededtic = gametic; + neededtic = max(neededtic, gametic); maketic = neededtic; ticcmd_oldangleturn[0] = players[consoleplayer].oldrelangleturn; diff --git a/src/netcode/tic_command.c b/src/netcode/tic_command.c index befe8a5cd..0fbf87c0c 100644 --- a/src/netcode/tic_command.c +++ b/src/netcode/tic_command.c @@ -148,8 +148,9 @@ static void CheckConsistancy(SINT8 nodenum, tic_t tic) } } -void PT_ClientCmd(SINT8 node, INT32 netconsole) +void PT_ClientCmd(SINT8 nodenum, INT32 netconsole) { + netnode_t *node = &netnodes[nodenum]; tic_t realend, realstart; if (client) @@ -157,24 +158,24 @@ void PT_ClientCmd(SINT8 node, INT32 netconsole) // To save bytes, only the low byte of tic numbers are sent // Use ExpandTics to figure out what the rest of the bytes are - realstart = ExpandTics(netbuffer->u.clientpak.client_tic, node); - realend = ExpandTics(netbuffer->u.clientpak.resendfrom, node); + realstart = ExpandTics(netbuffer->u.clientpak.client_tic, nodenum); + realend = ExpandTics(netbuffer->u.clientpak.resendfrom, nodenum); if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS || netbuffer->packettype == PT_NODEKEEPALIVEMIS - || netnodes[node].supposedtic < realend) + || node->supposedtic < realend) { - netnodes[node].supposedtic = realend; + node->supposedtic = realend; } // Discard out of order packet - if (netnodes[node].tic > realend) + if (node->tic > realend) { - DEBFILE(va("out of order ticcmd discarded nettics = %u\n", netnodes[node].tic)); + DEBFILE(va("out of order ticcmd discarded nettics = %u\n", node->tic)); return; } // Update the nettics - netnodes[node].tic = realend; + node->tic = realend; // Don't do anything for packets of type NODEKEEPALIVE? if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE @@ -183,19 +184,19 @@ void PT_ClientCmd(SINT8 node, INT32 netconsole) // As long as clients send valid ticcmds, the server can keep running, so reset the timeout /// \todo Use a separate cvar for that kind of timeout? - netnodes[node].freezetimeout = I_GetTime() + connectiontimeout; + node->freezetimeout = I_GetTime() + connectiontimeout; // Copy ticcmd G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); // Splitscreen cmd if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) - && netnodes[node].player2 >= 0) - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)netnodes[node].player2], + && node->player2 >= 0) + G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)node->player2], &netbuffer->u.client2pak.cmd2, 1); CheckTiccmdHacks(netconsole); - CheckConsistancy(node, realstart); + CheckConsistancy(nodenum, realstart); } void PT_ServerTics(SINT8 node, INT32 netconsole) @@ -346,9 +347,11 @@ void SV_SendTics(void) for (INT32 n = 1; n < MAXNETNODES; n++) if (netnodes[n].ingame) { - // assert netnodes[n].supposedtic>=netnodes[n].tic - realfirsttic = netnodes[n].supposedtic; - lasttictosend = min(maketic, netnodes[n].tic + CLIENTBACKUPTICS); + netnode_t *node = netnodes[n]; + + // assert node->supposedtic>=node->tic + realfirsttic = node->supposedtic; + lasttictosend = min(maketic, node->tic + CLIENTBACKUPTICS); if (realfirsttic >= lasttictosend) { @@ -357,9 +360,9 @@ void SV_SendTics(void) // packet detection work when we have received packet with firsttic > neededtic // (getpacket servertics case) DEBFILE(va("Nothing to send node %u mak=%u sup=%u net=%u \n", - n, maketic, netnodes[n].supposedtic, netnodes[n].tic)); + n, maketic, node->supposedtic, node->tic)); - realfirsttic = netnodes[n].tic; + realfirsttic = node->tic; if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3) // all tic are ok @@ -388,10 +391,10 @@ void SV_SendTics(void) // when tic are too large, only one tic is sent so don't go backward! if (lasttictosend-doomcom->extratics > realfirsttic) - netnodes[n].supposedtic = lasttictosend-doomcom->extratics; + node->supposedtic = lasttictosend-doomcom->extratics; else - netnodes[n].supposedtic = lasttictosend; - netnodes[n].supposedtic = max(netnodes[n].supposedtic, netnodes[n].tic); + node->supposedtic = lasttictosend; + node->supposedtic = max(node->supposedtic, node->tic); } // node 0 is me! diff --git a/src/netcode/tic_command.h b/src/netcode/tic_command.h index d19f4c1aa..289750fb3 100644 --- a/src/netcode/tic_command.h +++ b/src/netcode/tic_command.h @@ -31,7 +31,7 @@ tic_t ExpandTics(INT32 low, INT32 node); void D_Clearticcmd(tic_t tic); void D_ResetTiccmds(void); -void PT_ClientCmd(SINT8 node, INT32 netconsole); +void PT_ClientCmd(SINT8 nodenum, INT32 netconsole); void PT_ServerTics(SINT8 node, INT32 netconsole); // send the client packet to the server From fe304ae2db6b81c630e0dae82463d03ea98f4c48 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 15 Jan 2023 13:10:23 +0100 Subject: [PATCH 79/96] Cleanup comments --- src/netcode/client_connection.c | 41 ++++++++++++++------------------- src/netcode/d_clisrv.c | 11 ++++----- src/netcode/protocol.h | 3 +-- src/netcode/tic_command.c | 35 ++++++++++++++-------------- 4 files changed, 39 insertions(+), 51 deletions(-) diff --git a/src/netcode/client_connection.c b/src/netcode/client_connection.c index faa91b6d7..d363d7d5a 100644 --- a/src/netcode/client_connection.c +++ b/src/netcode/client_connection.c @@ -34,7 +34,7 @@ cl_mode_t cl_mode = CL_SEARCHING; static UINT16 cl_lastcheckedfilecount = 0; // used for full file list -boolean serverisfull = false; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not +boolean serverisfull = false; // lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not tic_t firstconnectattempttime = 0; UINT8 mynode; static void *snake = NULL; @@ -137,7 +137,7 @@ static inline void CL_DrawConnectionStatus(void) V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); - //ima just count files here + // ima just count files here if (fileneeded) { for (INT32 i = 0; i < fileneedednum; i++) @@ -248,7 +248,7 @@ boolean CL_SendJoin(void) CleanupPlayerName(consoleplayer, cv_playername.zstring); if (splitscreen) - CleanupPlayerName(1, cv_playername2.zstring);/* 1 is a HACK? oh no */ + CleanupPlayerName(1, cv_playername2.zstring); // 1 is a HACK? oh no strncpy(netbuffer->u.clientcfg.names[0], cv_playername.zstring, MAXPLAYERNAME); strncpy(netbuffer->u.clientcfg.names[1], cv_playername2.zstring, MAXPLAYERNAME); @@ -306,14 +306,14 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node) if (serverlistcount >= MAXSERVERLIST) return; // list full - /* check it later if connecting to this one */ + // check it later if connecting to this one if (node != servernode) { if (info->_255 != 255) - return;/* old packet format */ + return; // Old packet format if (info->packetversion != PACKETVERSION) - return;/* old new packet format */ + return; // Old new packet format if (info->version != VERSION) return; // Not same version. @@ -322,7 +322,7 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node) return; // Close, but no cigar. if (strcmp(info->application, SRB2APPLICATION)) - return;/* that's a different mod */ + return; // That's a different mod } i = serverlistcount++; @@ -380,7 +380,7 @@ Fetch_servers_thread (struct Fetch_servers_ctx *ctx) free(ctx); } -#endif/*defined (MASTERSERVER) && defined (HAVE_THREADS)*/ +#endif // defined (MASTERSERVER) && defined (HAVE_THREADS) void CL_QueryServerList (msg_server_t *server_list) { @@ -389,7 +389,7 @@ void CL_QueryServerList (msg_server_t *server_list) // Make sure MS version matches our own, to // thwart nefarious servers who lie to the MS. - /* lol bruh, that version COMES from the servers */ + // lol bruh, that version COMES from the servers //if (strcmp(version, server_list[i].version) == 0) { INT32 node = I_NetMakeNodewPort(server_list[i].ip, server_list[i].port); @@ -441,7 +441,7 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room) ctx = malloc(sizeof *ctx); - /* This called from M_Refresh so I don't use a mutex */ + // This called from M_Refresh so I don't use a mutex m_waiting_mode = M_WAITING_SERVERS; I_lock_mutex(&ms_QueryId_mutex); @@ -465,7 +465,7 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room) } #endif } -#endif/*MASTERSERVER*/ +#endif // MASTERSERVER } static void M_ConfirmConnect(event_t *ev) @@ -619,7 +619,7 @@ static const char * InvalidServerReason (serverinfo_pak *info) { #define EOT "\nPress ESC\n" - /* magic number for new packet format */ + // Magic number for new packet format if (info->_255 != 255) { return @@ -691,10 +691,10 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) { INT32 i; - // serverlist is updated by GetPacket function + // serverlist is updated by GetPackets if (serverlistcount > 0) { - // this can be a responce to our broadcast request + // This can be a response to our broadcast request if (servernode == -1 || servernode >= MAXNETNODES) { i = 0; @@ -819,7 +819,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic if (CL_LoadServerFiles()) { FreeFileNeeded(); - *asksent = 0; //This ensure the first join ask is right away + *asksent = 0; // This ensures the first join request is right away firstconnectattempttime = I_GetTime(); cl_mode = CL_ASKJOIN; } @@ -841,9 +841,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic return false; } - // prepare structures to save the file - // WARNING: this can be useless in case of server not in GS_LEVEL - // but since the network layer doesn't provide ordered packets... + // Prepare structures to save the file CL_PrepareDownloadSaveGame(tmpsave); if (I_GetTime() >= *asksent && CL_SendJoin()) @@ -954,11 +952,6 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic #define TMPSAVENAME "$$$.sav" -/** Use adaptive send using net_bandwidth and stat.sendbytes - * - * \todo Better description... - * - */ void CL_ConnectToServer(void) { INT32 pnumnodes, nodewaited = doomcom->numnodes, i; @@ -1158,7 +1151,7 @@ void PT_ServerCFG(SINT8 node) DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode)); /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? - /// Shouldn't them be downloaded even at intermission time? + /// Shouldn't they be downloaded even at intermission time? /// Also, according to PT_ClientJoin, the server will send the savegame even during intermission... if (netbuffer->u.servercfg.gamestate == GS_LEVEL/* || netbuffer->u.servercfg.gamestate == GS_INTERMISSION*/) diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index 105526dd2..18eae580c 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -1252,8 +1252,8 @@ void NetUpdate(void) GetPackets(); // get packet from client or from server - // client send the command after a receive of the server - // the server send before because in single player is beter + // The client sends the command after receiving from the server + // The server sends it before because this is better in single player #ifdef MASTERSERVER MasterClient_Ticker(); // Acking the Master Server @@ -1402,7 +1402,7 @@ SINT8 nametonum(const char *name) return -1; } -// is there a game running +// Is there a game running? boolean Playing(void) { return (server && serverrunning) || (client && cl_mode == CL_CONNECTED); @@ -1423,11 +1423,8 @@ INT32 D_NumPlayers(void) } // -// NetUpdate -// Builds ticcmds for console player, -// sends out a packet +// Consistancy // -// no more use random generator, because at very first tic isn't yet synchronized // Note: It is called consistAncy on purpose. // INT16 Consistancy(void) diff --git a/src/netcode/protocol.h b/src/netcode/protocol.h index 374cc5bff..9866e4c5a 100644 --- a/src/netcode/protocol.h +++ b/src/netcode/protocol.h @@ -123,13 +123,12 @@ typedef struct #endif // Server to client packet -// this packet is too large typedef struct { tic_t starttic; UINT8 numtics; UINT8 numslots; // "Slots filled": Highest player number in use plus one. - ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large + ticcmd_t cmds[45]; } ATTRPACK servertics_pak; typedef struct diff --git a/src/netcode/tic_command.c b/src/netcode/tic_command.c index 0fbf87c0c..620a10f7a 100644 --- a/src/netcode/tic_command.c +++ b/src/netcode/tic_command.c @@ -24,8 +24,8 @@ #include "../doomstat.h" #include "../doomtype.h" -tic_t firstticstosend; // min of the nettics -tic_t tictoclear = 0; // optimize d_clearticcmd +tic_t firstticstosend; // Smallest netnode.tic +tic_t tictoclear = 0; // Optimize D_ClearTiccmd ticcmd_t localcmds; ticcmd_t localcmds2; boolean cl_packetmissed; @@ -312,10 +312,9 @@ static tic_t SV_CalculateNumTicsForPacket(SINT8 nodenum, tic_t firsttic, tic_t l sizeu1(size), tic, firsttic, lasttic)); lasttic = tic; - // too bad: too much player have send extradata and there is too - // much data in one tic. - // To avoid it put the data on the next tic. (see getpacket - // textcmd case) but when numplayer changes the computation can be different + // Too bad: too many players have sent extra data + // and there is too much data for a single tic. + // To avoid that, keep the data for the next tic (see PT_TEXTCMD). if (lasttic == firsttic) { if (size > MAXPACKETLENGTH) @@ -335,15 +334,15 @@ static tic_t SV_CalculateNumTicsForPacket(SINT8 nodenum, tic_t firsttic, tic_t l return lasttic - firsttic; } -// send the server packet -// send tic from firstticstosend to maketic-1 +// Sends the server packet +// Sends tic/net commands from firstticstosend to maketic-1 void SV_SendTics(void) { tic_t realfirsttic, lasttictosend; - // send to all client but not to me - // for each node create a packet with x tics and send it - // x is computed using netnodes[n].supposedtic, max packet size and maketic + // Send to all clients except yourself + // For each node, create a packet with x tics and send it + // x is computed using node.supposedtic, max packet size and maketic for (INT32 n = 1; n < MAXNETNODES; n++) if (netnodes[n].ingame) { @@ -355,17 +354,17 @@ void SV_SendTics(void) if (realfirsttic >= lasttictosend) { - // well we have sent all tics we will so use extrabandwidth - // to resent packet that are supposed lost (this is necessary since lost - // packet detection work when we have received packet with firsttic > neededtic - // (getpacket servertics case) + // Well, we have sent all the tics, so we will use extra bandwidth + // to resend packets that are supposed lost. + // This is necessary since lost packet detection + // works when we receive a packet with firsttic > neededtic (PT_SERVERTICS) DEBFILE(va("Nothing to send node %u mak=%u sup=%u net=%u \n", n, maketic, node->supposedtic, node->tic)); realfirsttic = node->tic; if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3) - // all tic are ok + // All tics are Ok continue; DEBFILE(va("Sent %d anyway\n", realfirsttic)); @@ -389,7 +388,7 @@ void SV_SendTics(void) size_t packsize = bufpos - (UINT8 *)&(netbuffer->u); HSendPacket(n, false, 0, packsize); - // when tic are too large, only one tic is sent so don't go backward! + // When tics are too large, only one tic is sent so don't go backwards! if (lasttictosend-doomcom->extratics > realfirsttic) node->supposedtic = lasttictosend-doomcom->extratics; else @@ -450,6 +449,6 @@ void SV_Maketic(void) } } - // all tic are now proceed make the next + // All tics have been processed, make the next maketic++; } From 379cc4207a6c8df5c7ffe77ceb3b86828735d729 Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Sun, 15 Jan 2023 17:57:23 +0000 Subject: [PATCH 80/96] Revert "Merge branch 'netcode-refactor' into merging" This reverts merge request !1920 --- src/Makefile | 2 +- src/Makefile.d/features.mk | 4 +- src/Makefile.d/win32.mk | 2 + src/Sourcefile | 8 +- src/android/i_net.c | 2 +- src/blua/liolib.c | 3 +- src/command.c | 5 +- src/d_clisrv.c | 5590 ++++++++++++++++++++++++ src/{netcode/protocol.h => d_clisrv.h} | 185 +- src/d_main.c | 6 +- src/{netcode => }/d_net.c | 152 +- src/{netcode => }/d_net.h | 27 +- src/{netcode => }/d_netcmd.c | 76 +- src/{netcode => }/d_netcmd.h | 2 +- src/{netcode => }/d_netfil.c | 168 +- src/{netcode => }/d_netfil.h | 14 +- src/deh_soc.c | 2 +- src/deh_soc.h | 2 +- src/deh_tables.c | 2 +- src/doomdef.h | 3 +- src/doomstat.h | 2 +- src/dummy/i_net.c | 2 +- src/f_finale.c | 2 +- src/filesrch.c | 2 +- src/filesrch.h | 2 +- src/g_demo.c | 2 +- src/g_game.c | 3 +- src/g_input.c | 2 +- src/hardware/hw_main.c | 6 +- src/{netcode => }/http-mserv.c | 11 +- src/hu_stuff.c | 35 +- src/{netcode => }/i_addrinfo.c | 0 src/{netcode => }/i_addrinfo.h | 0 src/{netcode => }/i_net.h | 4 +- src/{netcode => }/i_tcp.c | 294 +- src/{netcode => }/i_tcp.h | 0 src/i_time.c | 2 +- src/lua_baselib.c | 4 +- src/lua_consolelib.c | 1 - src/lua_hooklib.c | 2 +- src/lua_script.c | 2 +- src/m_cheat.c | 2 +- src/m_menu.c | 63 +- src/m_menu.h | 4 +- src/m_perfstats.c | 2 +- src/{netcode => }/mserv.c | 19 +- src/{netcode => }/mserv.h | 2 +- src/netcode/Sourcefile | 13 - src/netcode/client_connection.c | 1161 ----- src/netcode/client_connection.h | 61 - src/netcode/commands.c | 484 -- src/netcode/commands.h | 33 - src/netcode/d_clisrv.c | 1564 ------- src/netcode/d_clisrv.h | 131 - src/netcode/gamestate.c | 336 -- src/netcode/gamestate.h | 31 - src/netcode/net_command.c | 386 -- src/netcode/net_command.h | 66 - src/netcode/server_connection.c | 507 --- src/netcode/server_connection.h | 30 - src/netcode/tic_command.c | 454 -- src/netcode/tic_command.h | 44 - src/p_ceilng.c | 2 +- src/p_haptic.c | 2 +- src/p_inter.c | 1 - src/p_lights.c | 2 +- src/p_mobj.c | 1 - src/p_setup.c | 2 - src/p_tick.c | 2 - src/p_user.c | 3 +- src/r_segs.c | 2 +- src/r_things.c | 2 +- src/screen.c | 2 +- src/sdl/i_gamepad.c | 2 +- src/sdl/i_net.c | 6 +- src/sdl/i_system.c | 9 +- src/sdl/i_ttf.c | 2 +- src/snake.c | 535 --- src/snake.h | 20 - src/w_wad.c | 4 +- src/y_inter.c | 2 +- 81 files changed, 6349 insertions(+), 6278 deletions(-) create mode 100755 src/d_clisrv.c rename src/{netcode/protocol.h => d_clisrv.h} (60%) rename src/{netcode => }/d_net.c (93%) rename src/{netcode => }/d_net.h (74%) rename src/{netcode => }/d_netcmd.c (99%) rename src/{netcode => }/d_netcmd.h (99%) rename src/{netcode => }/d_netfil.c (93%) rename src/{netcode => }/d_netfil.h (94%) rename src/{netcode => }/http-mserv.c (98%) rename src/{netcode => }/i_addrinfo.c (100%) rename src/{netcode => }/i_addrinfo.h (100%) rename src/{netcode => }/i_net.h (98%) rename src/{netcode => }/i_tcp.c (88%) rename src/{netcode => }/i_tcp.h (100%) rename src/{netcode => }/mserv.c (97%) rename src/{netcode => }/mserv.h (99%) delete mode 100644 src/netcode/Sourcefile delete mode 100644 src/netcode/client_connection.c delete mode 100644 src/netcode/client_connection.h delete mode 100644 src/netcode/commands.c delete mode 100644 src/netcode/commands.h delete mode 100644 src/netcode/d_clisrv.c delete mode 100644 src/netcode/d_clisrv.h delete mode 100644 src/netcode/gamestate.c delete mode 100644 src/netcode/gamestate.h delete mode 100644 src/netcode/net_command.c delete mode 100644 src/netcode/net_command.h delete mode 100644 src/netcode/server_connection.c delete mode 100644 src/netcode/server_connection.h delete mode 100644 src/netcode/tic_command.c delete mode 100644 src/netcode/tic_command.h delete mode 100644 src/snake.c delete mode 100644 src/snake.h diff --git a/src/Makefile b/src/Makefile index 750e8ead5..7571c8089 100644 --- a/src/Makefile +++ b/src/Makefile @@ -64,6 +64,7 @@ # # Netplay incompatible # -------------------- +# NONET=1 - Disable online capability. # NOMD5=1 - Disable MD5 checksum (validation tool). # NOPOSTPROCESSING=1 - ? # MOBJCONSISTANCY=1 - ?? @@ -207,7 +208,6 @@ objdir:=$(makedir)/objs sources+=\ $(call List,Sourcefile)\ $(call List,blua/Sourcefile)\ - $(call List,netcode/Sourcefile)\ depends:=$(basename $(filter %.c %.s,$(sources))) objects:=$(basename $(filter %.c %.s %.nas,$(sources))) diff --git a/src/Makefile.d/features.mk b/src/Makefile.d/features.mk index 9acbb4d86..8ba33383b 100644 --- a/src/Makefile.d/features.mk +++ b/src/Makefile.d/features.mk @@ -3,7 +3,7 @@ # passthru_opts+=\ - NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\ + NONET NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\ MOBJCONSISTANCY PACKETDROP ZDEBUG\ HAVE_MINIUPNPC\ @@ -46,11 +46,13 @@ sources+=apng.c endif endif +ifndef NONET ifndef NOCURL CURLCONFIG?=curl-config $(eval $(call Configure,CURL,$(CURLCONFIG))) opts+=-DHAVE_CURL endif +endif ifdef HAVE_MINIUPNPC libs+=-lminiupnpc diff --git a/src/Makefile.d/win32.mk b/src/Makefile.d/win32.mk index e7269e1e7..0e48ed683 100644 --- a/src/Makefile.d/win32.mk +++ b/src/Makefile.d/win32.mk @@ -35,10 +35,12 @@ libs+=-lws2_32 endif endif +ifndef NONET ifndef MINGW64 # miniupnc is broken with MINGW64 opts+=-I../libs -DSTATIC_MINIUPNPC libs+=-L../libs/miniupnpc/mingw$(32) -lws2_32 -liphlpapi endif +endif ifndef MINGW64 32=32 diff --git a/src/Sourcefile b/src/Sourcefile index 7d2146411..9de90eee4 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -1,5 +1,9 @@ string.c d_main.c +d_clisrv.c +d_net.c +d_netfil.c +d_netcmd.c dehacked.c deh_soc.c deh_lua.c @@ -73,10 +77,12 @@ s_sound.c sounds.c w_wad.c filesrch.c +mserv.c +http-mserv.c +i_tcp.c lzf.c vid_copy.s b_bot.c -snake.c lua_script.c lua_baselib.c lua_mathlib.c diff --git a/src/android/i_net.c b/src/android/i_net.c index 4c30dc767..f6e642022 100644 --- a/src/android/i_net.c +++ b/src/android/i_net.c @@ -1,4 +1,4 @@ -#include "../netcode/i_net.h" +#include "../i_net.h" boolean I_InitNetwork(void) { diff --git a/src/blua/liolib.c b/src/blua/liolib.c index bce8e87cc..e029650c0 100644 --- a/src/blua/liolib.c +++ b/src/blua/liolib.c @@ -19,8 +19,7 @@ #include "lualib.h" #include "../i_system.h" #include "../g_game.h" -#include "../netcode/d_netfil.h" -#include "../netcode/net_command.h" +#include "../d_netfil.h" #include "../lua_libs.h" #include "../byteptr.h" #include "../lua_script.h" diff --git a/src/command.c b/src/command.c index 58d69e24d..d1db9f9c9 100644 --- a/src/command.c +++ b/src/command.c @@ -28,12 +28,11 @@ #include "byteptr.h" #include "p_saveg.h" #include "g_game.h" // for player_names -#include "netcode/d_netcmd.h" -#include "netcode/net_command.h" +#include "d_netcmd.h" #include "hu_stuff.h" #include "p_setup.h" #include "lua_script.h" -#include "netcode/d_netfil.h" // findfile +#include "d_netfil.h" // findfile #include "r_data.h" // Color_cons_t //======== diff --git a/src/d_clisrv.c b/src/d_clisrv.c new file mode 100755 index 000000000..3091f3344 --- /dev/null +++ b/src/d_clisrv.c @@ -0,0 +1,5590 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file d_clisrv.c +/// \brief SRB2 Network game communication and protocol, all OS independent parts. + +#include +#ifdef __GNUC__ +#include //for unlink +#endif + +#include "i_time.h" +#include "i_net.h" +#include "i_system.h" +#include "i_video.h" +#include "d_net.h" +#include "d_main.h" +#include "g_game.h" +#include "st_stuff.h" +#include "hu_stuff.h" +#include "keys.h" +#include "g_input.h" +#include "i_gamepad.h" +#include "m_menu.h" +#include "console.h" +#include "d_netfil.h" +#include "byteptr.h" +#include "p_saveg.h" +#include "z_zone.h" +#include "p_local.h" +#include "p_haptic.h" +#include "m_misc.h" +#include "am_map.h" +#include "m_random.h" +#include "mserv.h" +#include "y_inter.h" +#include "r_local.h" +#include "m_argv.h" +#include "p_setup.h" +#include "lzf.h" +#include "lua_script.h" +#include "lua_hook.h" +#include "lua_libs.h" +#include "md5.h" +#include "m_perfstats.h" + +// aaaaaa +#include "i_gamepad.h" + +#ifndef NONET +// cl loading screen +#include "v_video.h" +#include "f_finale.h" +#endif + +// +// NETWORKING +// +// gametic is the tic about to (or currently being) run +// Server: +// maketic is the tic that hasn't had control made for it yet +// nettics is the tic for each node +// firstticstosend is the lowest value of nettics +// Client: +// neededtic is the tic needed by the client to run the game +// firstticstosend is used to optimize a condition +// Normally maketic >= gametic > 0 + +#define PREDICTIONQUEUE BACKUPTICS +#define PREDICTIONMASK (PREDICTIONQUEUE-1) +#define MAX_REASONLENGTH 30 + +boolean server = true; // true or false but !server == client +#define client (!server) +boolean nodownload = false; +boolean serverrunning = false; +INT32 serverplayer = 0; +char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support) + +// Server specific vars +UINT8 playernode[MAXPLAYERS]; +char playeraddress[MAXPLAYERS][64]; + +// Minimum timeout for sending the savegame +// The actual timeout will be longer depending on the savegame length +tic_t jointimeout = (10*TICRATE); +static boolean sendingsavegame[MAXNETNODES]; // Are we sending the savegame? +static boolean resendingsavegame[MAXNETNODES]; // Are we resending the savegame? +static tic_t savegameresendcooldown[MAXNETNODES]; // How long before we can resend again? +static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout? + +// Incremented by cv_joindelay when a client joins, decremented each tic. +// If higher than cv_joindelay * 2 (3 joins in a short timespan), joins are temporarily disabled. +static tic_t joindelay = 0; + +UINT16 pingmeasurecount = 1; +UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone. +UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values. +SINT8 nodetoplayer[MAXNETNODES]; +SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen) +UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen +boolean nodeingame[MAXNETNODES]; // set false as nodes leave game +tic_t servermaxping = 800; // server's max ping. Defaults to 800 +static tic_t nettics[MAXNETNODES]; // what tic the client have received +static tic_t supposedtics[MAXNETNODES]; // nettics prevision for smaller packet +static UINT8 nodewaiting[MAXNETNODES]; +static tic_t firstticstosend; // min of the nettics +static tic_t tictoclear = 0; // optimize d_clearticcmd +static tic_t maketic; + +static INT16 consistancy[BACKUPTICS]; + +static UINT8 player_joining = false; +UINT8 hu_redownloadinggamestate = 0; + +// true when a player is connecting or disconnecting so that the gameplay has stopped in its tracks +boolean hu_stopped = false; + +UINT8 adminpassmd5[16]; +boolean adminpasswordset = false; + +// Client specific +static ticcmd_t localcmds; +static ticcmd_t localcmds2; +static boolean cl_packetmissed; +// here it is for the secondary local player (splitscreen) +static UINT8 mynode; // my address pointofview server +static boolean cl_redownloadinggamestate = false; + +static UINT8 localtextcmd[MAXTEXTCMD]; +static UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen +static tic_t neededtic; +SINT8 servernode = 0; // the number of the server node + +/// \brief do we accept new players? +/// \todo WORK! +boolean acceptnewnode = true; + +static boolean serverisfull = false; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not +static tic_t firstconnectattempttime = 0; + +// engine + +// Must be a power of two +#define TEXTCMD_HASH_SIZE 4 + +typedef struct textcmdplayer_s +{ + INT32 playernum; + UINT8 cmd[MAXTEXTCMD]; + struct textcmdplayer_s *next; +} textcmdplayer_t; + +typedef struct textcmdtic_s +{ + tic_t tic; + textcmdplayer_t *playercmds[TEXTCMD_HASH_SIZE]; + struct textcmdtic_s *next; +} textcmdtic_t; + +ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; +static textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL}; + + +consvar_t cv_showjoinaddress = CVAR_INIT ("showjoinaddress", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); + +static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}}; +consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_cons_t, NULL); + +static inline void *G_DcpyTiccmd(void* dest, const ticcmd_t* src, const size_t n) +{ + const size_t d = n / sizeof(ticcmd_t); + const size_t r = n % sizeof(ticcmd_t); + UINT8 *ret = dest; + + if (r) + M_Memcpy(dest, src, n); + else if (d) + G_MoveTiccmd(dest, src, d); + return ret+n; +} + +static inline void *G_ScpyTiccmd(ticcmd_t* dest, void* src, const size_t n) +{ + const size_t d = n / sizeof(ticcmd_t); + const size_t r = n % sizeof(ticcmd_t); + UINT8 *ret = src; + + if (r) + M_Memcpy(dest, src, n); + else if (d) + G_MoveTiccmd(dest, src, d); + return ret+n; +} + + + +// Some software don't support largest packet +// (original sersetup, not exactely, but the probability of sending a packet +// of 512 bytes is like 0.1) +UINT16 software_MAXPACKETLENGTH; + +/** Guesses the full value of a tic from its lowest byte, for a specific node + * + * \param low The lowest byte of the tic value + * \param node The node to deduce the tic for + * \return The full tic value + * + */ +tic_t ExpandTics(INT32 low, INT32 node) +{ + INT32 delta; + + delta = low - (nettics[node] & UINT8_MAX); + + if (delta >= -64 && delta <= 64) + return (nettics[node] & ~UINT8_MAX) + low; + else if (delta > 64) + return (nettics[node] & ~UINT8_MAX) - 256 + low; + else //if (delta < -64) + return (nettics[node] & ~UINT8_MAX) + 256 + low; +} + +// ----------------------------------------------------------------- +// Some extra data function for handle textcmd buffer +// ----------------------------------------------------------------- + +static void (*listnetxcmd[MAXNETXCMD])(UINT8 **p, INT32 playernum); + +void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)) +{ +#ifdef PARANOIA + if (id >= MAXNETXCMD) + I_Error("Command id %d too big", id); + if (listnetxcmd[id] != 0) + I_Error("Command id %d already used", id); +#endif + listnetxcmd[id] = cmd_f; +} + +void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam) +{ + if (localtextcmd[0]+2+nparam > MAXTEXTCMD) + { + // for future reference: if (cv_debug) != debug disabled. + CONS_Alert(CONS_ERROR, M_GetText("NetXCmd buffer full, cannot add netcmd %d! (size: %d, needed: %s)\n"), id, localtextcmd[0], sizeu1(nparam)); + return; + } + localtextcmd[0]++; + localtextcmd[localtextcmd[0]] = (UINT8)id; + if (param && nparam) + { + M_Memcpy(&localtextcmd[localtextcmd[0]+1], param, nparam); + localtextcmd[0] = (UINT8)(localtextcmd[0] + (UINT8)nparam); + } +} + +// splitscreen player +void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam) +{ + if (localtextcmd2[0]+2+nparam > MAXTEXTCMD) + { + I_Error("No more place in the buffer for netcmd %d\n",id); + return; + } + localtextcmd2[0]++; + localtextcmd2[localtextcmd2[0]] = (UINT8)id; + if (param && nparam) + { + M_Memcpy(&localtextcmd2[localtextcmd2[0]+1], param, nparam); + localtextcmd2[0] = (UINT8)(localtextcmd2[0] + (UINT8)nparam); + } +} + +UINT8 GetFreeXCmdSize(void) +{ + // -1 for the size and another -1 for the ID. + return (UINT8)(localtextcmd[0] - 2); +} + +// Frees all textcmd memory for the specified tic +static void D_FreeTextcmd(tic_t tic) +{ + textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; + textcmdtic_t *textcmdtic = *tctprev; + + while (textcmdtic && textcmdtic->tic != tic) + { + tctprev = &textcmdtic->next; + textcmdtic = textcmdtic->next; + } + + if (textcmdtic) + { + INT32 i; + + // Remove this tic from the list. + *tctprev = textcmdtic->next; + + // Free all players. + for (i = 0; i < TEXTCMD_HASH_SIZE; i++) + { + textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[i]; + + while (textcmdplayer) + { + textcmdplayer_t *tcpnext = textcmdplayer->next; + Z_Free(textcmdplayer); + textcmdplayer = tcpnext; + } + } + + // Free this tic's own memory. + Z_Free(textcmdtic); + } +} + +// Gets the buffer for the specified ticcmd, or NULL if there isn't one +static UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum) +{ + textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; + while (textcmdtic && textcmdtic->tic != tic) textcmdtic = textcmdtic->next; + + // Do we have an entry for the tic? If so, look for player. + if (textcmdtic) + { + textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)]; + while (textcmdplayer && textcmdplayer->playernum != playernum) textcmdplayer = textcmdplayer->next; + + if (textcmdplayer) return textcmdplayer->cmd; + } + + return NULL; +} + +// Gets the buffer for the specified ticcmd, creating one if necessary +static UINT8* D_GetTextcmd(tic_t tic, INT32 playernum) +{ + textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; + textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; + textcmdplayer_t *textcmdplayer, **tcpprev; + + // Look for the tic. + while (textcmdtic && textcmdtic->tic != tic) + { + tctprev = &textcmdtic->next; + textcmdtic = textcmdtic->next; + } + + // If we don't have an entry for the tic, make it. + if (!textcmdtic) + { + textcmdtic = *tctprev = Z_Calloc(sizeof (textcmdtic_t), PU_STATIC, NULL); + textcmdtic->tic = tic; + } + + tcpprev = &textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)]; + textcmdplayer = *tcpprev; + + // Look for the player. + while (textcmdplayer && textcmdplayer->playernum != playernum) + { + tcpprev = &textcmdplayer->next; + textcmdplayer = textcmdplayer->next; + } + + // If we don't have an entry for the player, make it. + if (!textcmdplayer) + { + textcmdplayer = *tcpprev = Z_Calloc(sizeof (textcmdplayer_t), PU_STATIC, NULL); + textcmdplayer->playernum = playernum; + } + + return textcmdplayer->cmd; +} + +static void ExtraDataTicker(void) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] || i == 0) + { + UINT8 *bufferstart = D_GetExistingTextcmd(gametic, i); + + if (bufferstart) + { + UINT8 *curpos = bufferstart; + UINT8 *bufferend = &curpos[curpos[0]+1]; + + curpos++; + while (curpos < bufferend) + { + if (*curpos < MAXNETXCMD && listnetxcmd[*curpos]) + { + const UINT8 id = *curpos; + curpos++; + DEBFILE(va("executing x_cmd %s ply %u ", netxcmdnames[id - 1], i)); + (listnetxcmd[id])(&curpos, i); + DEBFILE("done\n"); + } + else + { + if (server) + { + SendKick(i, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + DEBFILE(va("player %d kicked [gametic=%u] reason as follows:\n", i, gametic)); + } + CONS_Alert(CONS_WARNING, M_GetText("Got unknown net command [%s]=%d (max %d)\n"), sizeu1(curpos - bufferstart), *curpos, bufferstart[0]); + break; + } + } + } + } + + // If you are a client, you can safely forget the net commands for this tic + // If you are the server, you need to remember them until every client has been acknowledged, + // because if you need to resend a PT_SERVERTICS packet, you will need to put the commands in it + if (client) + D_FreeTextcmd(gametic); +} + +static void D_Clearticcmd(tic_t tic) +{ + INT32 i; + + D_FreeTextcmd(tic); + + for (i = 0; i < MAXPLAYERS; i++) + netcmds[tic%BACKUPTICS][i].angleturn = 0; + + DEBFILE(va("clear tic %5u (%2u)\n", tic, tic%BACKUPTICS)); +} + +void D_ResetTiccmds(void) +{ + INT32 i; + + memset(&localcmds, 0, sizeof(ticcmd_t)); + memset(&localcmds2, 0, sizeof(ticcmd_t)); + + // Reset the net command list + for (i = 0; i < TEXTCMD_HASH_SIZE; i++) + while (textcmds[i]) + D_Clearticcmd(textcmds[i]->tic); +} + +void SendKick(UINT8 playernum, UINT8 msg) +{ + UINT8 buf[2]; + + if (!(server && cv_rejointimeout.value)) + msg &= ~KICK_MSG_KEEP_BODY; + + buf[0] = playernum; + buf[1] = msg; + SendNetXCmd(XD_KICK, &buf, 2); +} + +// ----------------------------------------------------------------- +// end of extra data function +// ----------------------------------------------------------------- + +// ----------------------------------------------------------------- +// extra data function for lmps +// ----------------------------------------------------------------- + +// if extradatabit is set, after the ziped tic you find this: +// +// type | description +// ---------+-------------- +// byte | size of the extradata +// byte | the extradata (xd) bits: see XD_... +// with this byte you know what parameter folow +// if (xd & XDNAMEANDCOLOR) +// byte | color +// char[MAXPLAYERNAME] | name of the player +// endif +// if (xd & XD_WEAPON_PREF) +// byte | original weapon switch: boolean, true if use the old +// | weapon switch methode +// char[NUMWEAPONS] | the weapon switch priority +// byte | autoaim: true if use the old autoaim system +// endif +/*boolean AddLmpExtradata(UINT8 **demo_point, INT32 playernum) +{ + UINT8 *textcmd = D_GetExistingTextcmd(gametic, playernum); + + if (!textcmd) + return false; + + M_Memcpy(*demo_point, textcmd, textcmd[0]+1); + *demo_point += textcmd[0]+1; + return true; +} + +void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum) +{ + UINT8 nextra; + UINT8 *textcmd; + + if (!demo_pointer) + return; + + textcmd = D_GetTextcmd(gametic, playernum); + nextra = **demo_pointer; + M_Memcpy(textcmd, *demo_pointer, nextra + 1); + // increment demo pointer + *demo_pointer += nextra + 1; +}*/ + +// ----------------------------------------------------------------- +// end extra data function for lmps +// ----------------------------------------------------------------- + +static INT16 Consistancy(void); + +typedef enum +{ + CL_SEARCHING, + CL_CHECKFILES, + CL_DOWNLOADFILES, + CL_ASKJOIN, + CL_LOADFILES, + CL_WAITJOINRESPONSE, + CL_DOWNLOADSAVEGAME, + CL_CONNECTED, + CL_ABORTED, + CL_ASKFULLFILELIST, + CL_CONFIRMCONNECT +} cl_mode_t; + +static void GetPackets(void); + +static cl_mode_t cl_mode = CL_SEARCHING; + +static UINT16 cl_lastcheckedfilecount = 0; // used for full file list + +#ifndef NONET +#define SNAKE_SPEED 5 + +#define SNAKE_NUM_BLOCKS_X 20 +#define SNAKE_NUM_BLOCKS_Y 10 +#define SNAKE_BLOCK_SIZE 12 +#define SNAKE_BORDER_SIZE 12 + +#define SNAKE_MAP_WIDTH (SNAKE_NUM_BLOCKS_X * SNAKE_BLOCK_SIZE) +#define SNAKE_MAP_HEIGHT (SNAKE_NUM_BLOCKS_Y * SNAKE_BLOCK_SIZE) + +#define SNAKE_LEFT_X ((BASEVIDWIDTH - SNAKE_MAP_WIDTH) / 2 - SNAKE_BORDER_SIZE) +#define SNAKE_RIGHT_X (SNAKE_LEFT_X + SNAKE_MAP_WIDTH + SNAKE_BORDER_SIZE * 2 - 1) +#define SNAKE_BOTTOM_Y (BASEVIDHEIGHT - 48) +#define SNAKE_TOP_Y (SNAKE_BOTTOM_Y - SNAKE_MAP_HEIGHT - SNAKE_BORDER_SIZE * 2 + 1) + +enum snake_bonustype_s { + SNAKE_BONUS_NONE = 0, + SNAKE_BONUS_SLOW, + SNAKE_BONUS_FAST, + SNAKE_BONUS_GHOST, + SNAKE_BONUS_NUKE, + SNAKE_BONUS_SCISSORS, + SNAKE_BONUS_REVERSE, + SNAKE_BONUS_EGGMAN, + SNAKE_NUM_BONUSES, +}; + +static const char *snake_bonuspatches[] = { + NULL, + "DL_SLOW", + "TVSSC0", + "TVIVC0", + "TVARC0", + "DL_SCISSORS", + "TVRCC0", + "TVEGC0", +}; + +static const char *snake_backgrounds[] = { + "RVPUMICF", + "FRSTRCKF", + "TAR", + "MMFLRB4", + "RVDARKF1", + "RVZWALF1", + "RVZWALF4", + "RVZWALF5", + "RVZGRS02", + "RVZGRS04", +}; + +typedef struct snake_s +{ + boolean paused; + boolean pausepressed; + tic_t time; + tic_t nextupdate; + boolean gameover; + UINT8 background; + + UINT16 snakelength; + enum snake_bonustype_s snakebonus; + tic_t snakebonustime; + UINT8 snakex[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; + UINT8 snakey[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; + UINT8 snakedir[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; + + UINT8 applex; + UINT8 appley; + + enum snake_bonustype_s bonustype; + UINT8 bonusx; + UINT8 bonusy; +} snake_t; + +static snake_t *snake = NULL; + +static void Snake_Initialise(void) +{ + if (!snake) + snake = malloc(sizeof(snake_t)); + + snake->paused = false; + snake->pausepressed = false; + snake->time = 0; + snake->nextupdate = SNAKE_SPEED; + snake->gameover = false; + snake->background = M_RandomKey(sizeof(snake_backgrounds) / sizeof(*snake_backgrounds)); + + snake->snakelength = 1; + snake->snakebonus = SNAKE_BONUS_NONE; + snake->snakex[0] = M_RandomKey(SNAKE_NUM_BLOCKS_X); + snake->snakey[0] = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + snake->snakedir[0] = 0; + snake->snakedir[1] = 0; + + snake->applex = M_RandomKey(SNAKE_NUM_BLOCKS_X); + snake->appley = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + + snake->bonustype = SNAKE_BONUS_NONE; +} + +static UINT8 Snake_GetOppositeDir(UINT8 dir) +{ + if (dir == 1 || dir == 3) + return dir + 1; + else if (dir == 2 || dir == 4) + return dir - 1; + else + return 12 + 5 - dir; +} + +static void Snake_FindFreeSlot(UINT8 *freex, UINT8 *freey, UINT8 headx, UINT8 heady) +{ + UINT8 x, y; + UINT16 i; + + do + { + x = M_RandomKey(SNAKE_NUM_BLOCKS_X); + y = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + + for (i = 0; i < snake->snakelength; i++) + if (x == snake->snakex[i] && y == snake->snakey[i]) + break; + } while (i < snake->snakelength || (x == headx && y == heady) + || (x == snake->applex && y == snake->appley) + || (snake->bonustype != SNAKE_BONUS_NONE && x == snake->bonusx && y == snake->bonusy)); + + *freex = x; + *freey = y; +} + +static void Snake_Handle(void) +{ + UINT8 x, y; + UINT8 oldx, oldy; + UINT16 i; + UINT16 joystate = 0; + + // Handle retry + if (snake->gameover && (G_PlayerInputDown(0, GC_JUMP) || gamekeydown[KEY_ENTER])) + { + Snake_Initialise(); + snake->pausepressed = true; // Avoid accidental pause on respawn + } + + // Handle pause + if (G_PlayerInputDown(0, GC_PAUSE) || gamekeydown[KEY_ENTER]) + { + if (!snake->pausepressed) + snake->paused = !snake->paused; + snake->pausepressed = true; + } + else + snake->pausepressed = false; + + if (snake->paused) + return; + + snake->time++; + + x = snake->snakex[0]; + y = snake->snakey[0]; + oldx = snake->snakex[1]; + oldy = snake->snakey[1]; + + // Update direction + if (G_PlayerInputDown(0, GC_STRAFELEFT) || gamekeydown[KEY_LEFTARROW] || joystate == 3) + { + if (snake->snakelength < 2 || x <= oldx) + snake->snakedir[0] = 1; + } + else if (G_PlayerInputDown(0, GC_STRAFERIGHT) || gamekeydown[KEY_RIGHTARROW] || joystate == 4) + { + if (snake->snakelength < 2 || x >= oldx) + snake->snakedir[0] = 2; + } + else if (G_PlayerInputDown(0, GC_FORWARD) || gamekeydown[KEY_UPARROW] || joystate == 1) + { + if (snake->snakelength < 2 || y <= oldy) + snake->snakedir[0] = 3; + } + else if (G_PlayerInputDown(0, GC_BACKWARD) || gamekeydown[KEY_DOWNARROW] || joystate == 2) + { + if (snake->snakelength < 2 || y >= oldy) + snake->snakedir[0] = 4; + } + + if (snake->snakebonustime) + { + snake->snakebonustime--; + if (!snake->snakebonustime) + snake->snakebonus = SNAKE_BONUS_NONE; + } + + snake->nextupdate--; + if (snake->nextupdate) + return; + if (snake->snakebonus == SNAKE_BONUS_SLOW) + snake->nextupdate = SNAKE_SPEED * 2; + else if (snake->snakebonus == SNAKE_BONUS_FAST) + snake->nextupdate = SNAKE_SPEED * 2 / 3; + else + snake->nextupdate = SNAKE_SPEED; + + if (snake->gameover) + return; + + // Find new position + switch (snake->snakedir[0]) + { + case 1: + if (x > 0) + x--; + else + snake->gameover = true; + break; + case 2: + if (x < SNAKE_NUM_BLOCKS_X - 1) + x++; + else + snake->gameover = true; + break; + case 3: + if (y > 0) + y--; + else + snake->gameover = true; + break; + case 4: + if (y < SNAKE_NUM_BLOCKS_Y - 1) + y++; + else + snake->gameover = true; + break; + } + + // Check collision with snake + if (snake->snakebonus != SNAKE_BONUS_GHOST) + for (i = 1; i < snake->snakelength - 1; i++) + if (x == snake->snakex[i] && y == snake->snakey[i]) + { + if (snake->snakebonus == SNAKE_BONUS_SCISSORS) + { + snake->snakebonus = SNAKE_BONUS_NONE; + snake->snakelength = i; + S_StartSound(NULL, sfx_adderr); + } + else + snake->gameover = true; + } + + if (snake->gameover) + { + S_StartSound(NULL, sfx_lose); + return; + } + + // Check collision with apple + if (x == snake->applex && y == snake->appley) + { + if (snake->snakelength + 3 < SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y) + { + snake->snakelength++; + snake->snakex [snake->snakelength - 1] = snake->snakex [snake->snakelength - 2]; + snake->snakey [snake->snakelength - 1] = snake->snakey [snake->snakelength - 2]; + snake->snakedir[snake->snakelength - 1] = snake->snakedir[snake->snakelength - 2]; + } + + // Spawn new apple + Snake_FindFreeSlot(&snake->applex, &snake->appley, x, y); + + // Spawn new bonus + if (!(snake->snakelength % 5)) + { + do + { + snake->bonustype = M_RandomKey(SNAKE_NUM_BONUSES - 1) + 1; + } while (snake->snakelength > SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y * 3 / 4 + && (snake->bonustype == SNAKE_BONUS_EGGMAN || snake->bonustype == SNAKE_BONUS_FAST || snake->bonustype == SNAKE_BONUS_REVERSE)); + + Snake_FindFreeSlot(&snake->bonusx, &snake->bonusy, x, y); + } + + S_StartSound(NULL, sfx_s3k6b); + } + + if (snake->snakelength > 1 && snake->snakedir[0]) + { + UINT8 dir = snake->snakedir[0]; + + oldx = snake->snakex[1]; + oldy = snake->snakey[1]; + + // Move + for (i = snake->snakelength - 1; i > 0; i--) + { + snake->snakex[i] = snake->snakex[i - 1]; + snake->snakey[i] = snake->snakey[i - 1]; + snake->snakedir[i] = snake->snakedir[i - 1]; + } + + // Handle corners + if (x < oldx && dir == 3) + dir = 5; + else if (x > oldx && dir == 3) + dir = 6; + else if (x < oldx && dir == 4) + dir = 7; + else if (x > oldx && dir == 4) + dir = 8; + else if (y < oldy && dir == 1) + dir = 9; + else if (y < oldy && dir == 2) + dir = 10; + else if (y > oldy && dir == 1) + dir = 11; + else if (y > oldy && dir == 2) + dir = 12; + snake->snakedir[1] = dir; + } + + snake->snakex[0] = x; + snake->snakey[0] = y; + + // Check collision with bonus + if (snake->bonustype != SNAKE_BONUS_NONE && x == snake->bonusx && y == snake->bonusy) + { + S_StartSound(NULL, sfx_ncchip); + + switch (snake->bonustype) + { + case SNAKE_BONUS_SLOW: + snake->snakebonus = SNAKE_BONUS_SLOW; + snake->snakebonustime = 20 * TICRATE; + break; + case SNAKE_BONUS_FAST: + snake->snakebonus = SNAKE_BONUS_FAST; + snake->snakebonustime = 20 * TICRATE; + break; + case SNAKE_BONUS_GHOST: + snake->snakebonus = SNAKE_BONUS_GHOST; + snake->snakebonustime = 10 * TICRATE; + break; + case SNAKE_BONUS_NUKE: + for (i = 0; i < snake->snakelength; i++) + { + snake->snakex [i] = snake->snakex [0]; + snake->snakey [i] = snake->snakey [0]; + snake->snakedir[i] = snake->snakedir[0]; + } + + S_StartSound(NULL, sfx_bkpoof); + break; + case SNAKE_BONUS_SCISSORS: + snake->snakebonus = SNAKE_BONUS_SCISSORS; + snake->snakebonustime = 60 * TICRATE; + break; + case SNAKE_BONUS_REVERSE: + for (i = 0; i < (snake->snakelength + 1) / 2; i++) + { + UINT16 i2 = snake->snakelength - 1 - i; + UINT8 tmpx = snake->snakex [i]; + UINT8 tmpy = snake->snakey [i]; + UINT8 tmpdir = snake->snakedir[i]; + + // Swap first segment with last segment + snake->snakex [i] = snake->snakex [i2]; + snake->snakey [i] = snake->snakey [i2]; + snake->snakedir[i] = Snake_GetOppositeDir(snake->snakedir[i2]); + snake->snakex [i2] = tmpx; + snake->snakey [i2] = tmpy; + snake->snakedir[i2] = Snake_GetOppositeDir(tmpdir); + } + + snake->snakedir[0] = 0; + + S_StartSound(NULL, sfx_gravch); + break; + default: + if (snake->snakebonus != SNAKE_BONUS_GHOST) + { + snake->gameover = true; + S_StartSound(NULL, sfx_lose); + } + } + + snake->bonustype = SNAKE_BONUS_NONE; + } +} + +static void Snake_Draw(void) +{ + INT16 i; + + // Background + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); + + V_DrawFlatFill( + SNAKE_LEFT_X + SNAKE_BORDER_SIZE, + SNAKE_TOP_Y + SNAKE_BORDER_SIZE, + SNAKE_MAP_WIDTH, + SNAKE_MAP_HEIGHT, + W_GetNumForName(snake_backgrounds[snake->background]) + ); + + // Borders + V_DrawFill(SNAKE_LEFT_X, SNAKE_TOP_Y, SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_BORDER_SIZE, 242); // Top + V_DrawFill(SNAKE_LEFT_X + SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_TOP_Y, SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, 242); // Right + V_DrawFill(SNAKE_LEFT_X + SNAKE_BORDER_SIZE, SNAKE_TOP_Y + SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_BORDER_SIZE, 242); // Bottom + V_DrawFill(SNAKE_LEFT_X, SNAKE_TOP_Y + SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, 242); // Left + + // Apple + V_DrawFixedPatch( + (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->applex * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->appley * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + FRACUNIT / 4, + 0, + W_CachePatchLongName("DL_APPLE", PU_HUDGFX), + NULL + ); + + // Bonus + if (snake->bonustype != SNAKE_BONUS_NONE) + V_DrawFixedPatch( + (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->bonusx * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2 ) * FRACUNIT, + (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->bonusy * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2 + 4) * FRACUNIT, + FRACUNIT / 2, + 0, + W_CachePatchLongName(snake_bonuspatches[snake->bonustype], PU_HUDGFX), + NULL + ); + + // Snake + if (!snake->gameover || snake->time % 8 < 8 / 2) // Blink if game over + { + for (i = snake->snakelength - 1; i >= 0; i--) + { + const char *patchname; + UINT8 dir = snake->snakedir[i]; + + if (i == 0) // Head + { + switch (dir) + { + case 1: patchname = "DL_SNAKEHEAD_L"; break; + case 2: patchname = "DL_SNAKEHEAD_R"; break; + case 3: patchname = "DL_SNAKEHEAD_T"; break; + case 4: patchname = "DL_SNAKEHEAD_B"; break; + default: patchname = "DL_SNAKEHEAD_M"; + } + } + else // Body + { + switch (dir) + { + case 1: patchname = "DL_SNAKEBODY_L"; break; + case 2: patchname = "DL_SNAKEBODY_R"; break; + case 3: patchname = "DL_SNAKEBODY_T"; break; + case 4: patchname = "DL_SNAKEBODY_B"; break; + case 5: patchname = "DL_SNAKEBODY_LT"; break; + case 6: patchname = "DL_SNAKEBODY_RT"; break; + case 7: patchname = "DL_SNAKEBODY_LB"; break; + case 8: patchname = "DL_SNAKEBODY_RB"; break; + case 9: patchname = "DL_SNAKEBODY_TL"; break; + case 10: patchname = "DL_SNAKEBODY_TR"; break; + case 11: patchname = "DL_SNAKEBODY_BL"; break; + case 12: patchname = "DL_SNAKEBODY_BR"; break; + default: patchname = "DL_SNAKEBODY_B"; + } + } + + V_DrawFixedPatch( + (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->snakex[i] * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->snakey[i] * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + i == 0 && dir == 0 ? FRACUNIT / 5 : FRACUNIT / 2, + snake->snakebonus == SNAKE_BONUS_GHOST ? V_TRANSLUCENT : 0, + W_CachePatchLongName(patchname, PU_HUDGFX), + NULL + ); + } + } + + // Length + V_DrawString(SNAKE_RIGHT_X + 4, SNAKE_TOP_Y, V_MONOSPACE, va("%u", snake->snakelength)); + + // Bonus + if (snake->snakebonus != SNAKE_BONUS_NONE + && (snake->snakebonustime >= 3 * TICRATE || snake->time % 4 < 4 / 2)) + V_DrawFixedPatch( + (SNAKE_RIGHT_X + 10) * FRACUNIT, + (SNAKE_TOP_Y + 24) * FRACUNIT, + FRACUNIT / 2, + 0, + W_CachePatchLongName(snake_bonuspatches[snake->snakebonus], PU_HUDGFX), + NULL + ); +} + +static void CL_DrawConnectionStatusBox(void) +{ + M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1); + if (cl_mode != CL_CONFIRMCONNECT) + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); +} + +// +// CL_DrawConnectionStatus +// +// Keep the local client informed of our status. +// +static inline void CL_DrawConnectionStatus(void) +{ + INT32 ccstime = I_GetTime(); + + // Draw background fade + V_DrawFadeScreen(0xFF00, 16); // force default + + if (cl_mode != CL_DOWNLOADFILES && cl_mode != CL_LOADFILES) + { + INT32 i, animtime = ((ccstime / 4) & 15) + 16; + UINT8 palstart; + const char *cltext; + + // Draw the bottom box. + CL_DrawConnectionStatusBox(); + + if (cl_mode == CL_SEARCHING) + palstart = 32; // Red + else if (cl_mode == CL_CONFIRMCONNECT) + palstart = 48; // Orange + else + palstart = 96; // Green + + if (!(cl_mode == CL_DOWNLOADSAVEGAME && lastfilenum != -1)) + for (i = 0; i < 16; ++i) // 15 pal entries total. + V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-16, 16, 8, palstart + ((animtime - i) & 15)); + + switch (cl_mode) + { + case CL_DOWNLOADSAVEGAME: + if (fileneeded && lastfilenum != -1) + { + UINT32 currentsize = fileneeded[lastfilenum].currentsize; + UINT32 totalsize = fileneeded[lastfilenum].totalsize; + INT32 dldlength; + + cltext = M_GetText("Downloading game state..."); + Net_GetNetStat(); + + dldlength = (INT32)((currentsize/(double)totalsize) * 256); + if (dldlength > 256) + dldlength = 256; + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, dldlength, 8, 96); + + V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, + va(" %4uK/%4uK",currentsize>>10,totalsize>>10)); + + V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, + va("%3.1fK/s ", ((double)getbps)/1024)); + } + else + cltext = M_GetText("Waiting to download game state..."); + break; + case CL_ASKFULLFILELIST: + case CL_CHECKFILES: + cltext = M_GetText("Checking server addon list..."); + break; + case CL_CONFIRMCONNECT: + cltext = ""; + break; + case CL_LOADFILES: + cltext = M_GetText("Loading server addons..."); + break; + case CL_ASKJOIN: + case CL_WAITJOINRESPONSE: + if (serverisfull) + cltext = M_GetText("Server full, waiting for a slot..."); + else + cltext = M_GetText("Requesting to join..."); + break; + default: + cltext = M_GetText("Connecting to server..."); + break; + } + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, cltext); + } + else + { + if (cl_mode == CL_LOADFILES) + { + INT32 totalfileslength; + INT32 loadcompletednum = 0; + INT32 i; + + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); + + //ima just count files here + if (fileneeded) + { + for (i = 0; i < fileneedednum; i++) + if (fileneeded[i].status == FS_OPEN) + loadcompletednum++; + } + + // Loading progress + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, "Loading server addons..."); + totalfileslength = (INT32)((loadcompletednum/(double)(fileneedednum)) * 256); + M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, totalfileslength, 8, 96); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, + va(" %2u/%2u Files",loadcompletednum,fileneedednum)); + } + else if (lastfilenum != -1) + { + INT32 dldlength; + static char tempname[28]; + fileneeded_t *file; + char *filename; + + if (snake) + Snake_Draw(); + + // Draw the bottom box. + CL_DrawConnectionStatusBox(); + + if (fileneeded) + { + file = &fileneeded[lastfilenum]; + filename = file->filename; + } + else + return; + + Net_GetNetStat(); + dldlength = (INT32)((file->currentsize/(double)file->totalsize) * 256); + if (dldlength > 256) + dldlength = 256; + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, dldlength, 8, 96); + + memset(tempname, 0, sizeof(tempname)); + // offset filename to just the name only part + filename += strlen(filename) - nameonlylength(filename); + + if (strlen(filename) > sizeof(tempname)-1) // too long to display fully + { + size_t endhalfpos = strlen(filename)-10; + // display as first 14 chars + ... + last 10 chars + // which should add up to 27 if our math(s) is correct + snprintf(tempname, sizeof(tempname), "%.14s...%.10s", filename, filename+endhalfpos); + } + else // we can copy the whole thing in safely + { + strncpy(tempname, filename, sizeof(tempname)-1); + } + + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, + va(M_GetText("Downloading \"%s\""), tempname)); + V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, + va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,file->totalsize>>10)); + V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, + va("%3.1fK/s ", ((double)getbps)/1024)); + } + else + { + if (snake) + Snake_Draw(); + + CL_DrawConnectionStatusBox(); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, + M_GetText("Waiting to download files...")); + } + } +} +#endif + +static boolean CL_AskFileList(INT32 firstfile) +{ + netbuffer->packettype = PT_TELLFILESNEEDED; + netbuffer->u.filesneedednum = firstfile; + + return HSendPacket(servernode, false, 0, sizeof (INT32)); +} + +/** Sends a special packet to declare how many players in local + * Used only in arbitratrenetstart() + * Sends a PT_CLIENTJOIN packet to the server + * + * \return True if the packet was successfully sent + * \todo Improve the description... + * + */ +static boolean CL_SendJoin(void) +{ + UINT8 localplayers = 1; + if (netgame) + CONS_Printf(M_GetText("Sending join request...\n")); + netbuffer->packettype = PT_CLIENTJOIN; + + netbuffer->u.clientcfg.modversion = MODVERSION; + strncpy(netbuffer->u.clientcfg.application, + SRB2APPLICATION, + sizeof netbuffer->u.clientcfg.application); + + if (splitscreen || botingame) + localplayers++; + netbuffer->u.clientcfg.localplayers = localplayers; + + CleanupPlayerName(consoleplayer, cv_playername.zstring); + if (splitscreen) + CleanupPlayerName(1, cv_playername2.zstring);/* 1 is a HACK? oh no */ + + strncpy(netbuffer->u.clientcfg.names[0], cv_playername.zstring, MAXPLAYERNAME); + strncpy(netbuffer->u.clientcfg.names[1], cv_playername2.zstring, MAXPLAYERNAME); + + return HSendPacket(servernode, true, 0, sizeof (clientconfig_pak)); +} + +static INT32 FindRejoinerNum(SINT8 node) +{ + char strippednodeaddress[64]; + const char *nodeaddress; + char *port; + INT32 i; + + // Make sure there is no dead dress before proceeding to the stripping + if (!I_GetNodeAddress) + return -1; + nodeaddress = I_GetNodeAddress(node); + if (!nodeaddress) + return -1; + + // Strip the address of its port + strcpy(strippednodeaddress, nodeaddress); + port = strchr(strippednodeaddress, ':'); + if (port) + *port = '\0'; + + // Check if any player matches the stripped address + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && playeraddress[i][0] && playernode[i] == UINT8_MAX + && !strcmp(playeraddress[i], strippednodeaddress)) + return i; + } + + return -1; +} + +static UINT8 +GetRefuseReason (INT32 node) +{ + if (!node || FindRejoinerNum(node) != -1) + return 0; + else if (bannednode && bannednode[node]) + return REFUSE_BANNED; + else if (!cv_allownewplayer.value) + return REFUSE_JOINS_DISABLED; + else if (D_NumPlayers() >= cv_maxplayers.value) + return REFUSE_SLOTS_FULL; + else + return 0; +} + +static void SV_SendServerInfo(INT32 node, tic_t servertime) +{ + UINT8 *p; + + netbuffer->packettype = PT_SERVERINFO; + netbuffer->u.serverinfo._255 = 255; + netbuffer->u.serverinfo.packetversion = PACKETVERSION; + netbuffer->u.serverinfo.version = VERSION; + netbuffer->u.serverinfo.subversion = SUBVERSION; + strncpy(netbuffer->u.serverinfo.application, SRB2APPLICATION, + sizeof netbuffer->u.serverinfo.application); + // return back the time value so client can compute their ping + netbuffer->u.serverinfo.time = (tic_t)LONG(servertime); + netbuffer->u.serverinfo.leveltime = (tic_t)LONG(leveltime); + + netbuffer->u.serverinfo.numberofplayer = (UINT8)D_NumPlayers(); + netbuffer->u.serverinfo.maxplayer = (UINT8)cv_maxplayers.value; + + netbuffer->u.serverinfo.refusereason = GetRefuseReason(node); + + strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype], + sizeof netbuffer->u.serverinfo.gametypename); + netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame; + netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled(); + netbuffer->u.serverinfo.flags = (dedicated ? SV_DEDICATED : 0); + strncpy(netbuffer->u.serverinfo.servername, cv_servername.string, + MAXSERVERNAME); + strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7); + + M_Memcpy(netbuffer->u.serverinfo.mapmd5, mapmd5, 16); + + memset(netbuffer->u.serverinfo.maptitle, 0, sizeof netbuffer->u.serverinfo.maptitle); + + if (mapheaderinfo[gamemap-1] && *mapheaderinfo[gamemap-1]->lvlttl) + { + char *read = mapheaderinfo[gamemap-1]->lvlttl, *writ = netbuffer->u.serverinfo.maptitle; + while (writ < (netbuffer->u.serverinfo.maptitle+32) && *read != '\0') + { + if (!(*read & 0x80)) + { + *writ = toupper(*read); + writ++; + } + read++; + } + *writ = '\0'; + //strncpy(netbuffer->u.serverinfo.maptitle, (char *)mapheaderinfo[gamemap-1]->lvlttl, 33); + } + else + strncpy(netbuffer->u.serverinfo.maptitle, "UNKNOWN", 32); + + if (mapheaderinfo[gamemap-1] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) + netbuffer->u.serverinfo.iszone = 1; + else + netbuffer->u.serverinfo.iszone = 0; + + if (mapheaderinfo[gamemap-1]) + netbuffer->u.serverinfo.actnum = mapheaderinfo[gamemap-1]->actnum; + + p = PutFileNeeded(0); + + HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); +} + +static void SV_SendPlayerInfo(INT32 node) +{ + UINT8 i; + netbuffer->packettype = PT_PLAYERINFO; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + { + netbuffer->u.playerinfo[i].num = 255; // This slot is empty. + continue; + } + + netbuffer->u.playerinfo[i].num = i; + strncpy(netbuffer->u.playerinfo[i].name, (const char *)&player_names[i], MAXPLAYERNAME+1); + netbuffer->u.playerinfo[i].name[MAXPLAYERNAME] = '\0'; + + //fetch IP address + //No, don't do that, you fuckface. + memset(netbuffer->u.playerinfo[i].address, 0, 4); + + if (G_GametypeHasTeams()) + { + if (!players[i].ctfteam) + netbuffer->u.playerinfo[i].team = 255; + else + netbuffer->u.playerinfo[i].team = (UINT8)players[i].ctfteam; + } + else + { + if (players[i].spectator) + netbuffer->u.playerinfo[i].team = 255; + else + netbuffer->u.playerinfo[i].team = 0; + } + + netbuffer->u.playerinfo[i].score = LONG(players[i].score); + netbuffer->u.playerinfo[i].timeinserver = SHORT((UINT16)(players[i].jointime / TICRATE)); + netbuffer->u.playerinfo[i].skin = (UINT8)(players[i].skin +#ifdef DEVELOP // it's safe to do this only because PLAYERINFO isn't read by the game itself + % 3 +#endif + ); + + // Extra data + netbuffer->u.playerinfo[i].data = 0; //players[i].skincolor; + + if (players[i].pflags & PF_TAGIT) + netbuffer->u.playerinfo[i].data |= 0x20; + + if (players[i].gotflag) + netbuffer->u.playerinfo[i].data |= 0x40; + + if (players[i].powers[pw_super]) + netbuffer->u.playerinfo[i].data |= 0x80; + } + + HSendPacket(node, false, 0, sizeof(plrinfo) * MAXPLAYERS); +} + +/** Sends a PT_SERVERCFG packet + * + * \param node The destination + * \return True if the packet was successfully sent + * + */ +static boolean SV_SendServerConfig(INT32 node) +{ + boolean waspacketsent; + + netbuffer->packettype = PT_SERVERCFG; + + netbuffer->u.servercfg.serverplayer = (UINT8)serverplayer; + netbuffer->u.servercfg.totalslotnum = (UINT8)(doomcom->numslots); + netbuffer->u.servercfg.gametic = (tic_t)LONG(gametic); + netbuffer->u.servercfg.clientnode = (UINT8)node; + netbuffer->u.servercfg.gamestate = (UINT8)gamestate; + netbuffer->u.servercfg.gametype = (UINT8)gametype; + netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame; + + memcpy(netbuffer->u.servercfg.server_context, server_context, 8); + + { + const size_t len = sizeof (serverconfig_pak); + +#ifdef DEBUGFILE + if (debugfile) + { + fprintf(debugfile, "ServerConfig Packet about to be sent, size of packet:%s to node:%d\n", + sizeu1(len), node); + } +#endif + + waspacketsent = HSendPacket(node, true, 0, len); + } + +#ifdef DEBUGFILE + if (debugfile) + { + if (waspacketsent) + { + fprintf(debugfile, "ServerConfig Packet was sent\n"); + } + else + { + fprintf(debugfile, "ServerConfig Packet could not be sent right now\n"); + } + } +#endif + + return waspacketsent; +} + +#ifndef NONET +#define SAVEGAMESIZE (768*1024) + +static boolean SV_ResendingSavegameToAnyone(void) +{ + INT32 i; + + for (i = 0; i < MAXNETNODES; i++) + if (resendingsavegame[i]) + return true; + return false; +} + +static void SV_SendSaveGame(INT32 node, boolean resending) +{ + size_t length, compressedlen; + UINT8 *savebuffer; + UINT8 *compressedsave; + UINT8 *buffertosend; + + // first save it in a malloced buffer + savebuffer = (UINT8 *)malloc(SAVEGAMESIZE); + if (!savebuffer) + { + CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); + return; + } + + // Leave room for the uncompressed length. + save_p = savebuffer + sizeof(UINT32); + + P_SaveNetGame(resending); + + length = save_p - savebuffer; + if (length > SAVEGAMESIZE) + { + free(savebuffer); + save_p = NULL; + I_Error("Savegame buffer overrun"); + } + + // Allocate space for compressed save: one byte fewer than for the + // uncompressed data to ensure that the compression is worthwhile. + compressedsave = malloc(length - 1); + if (!compressedsave) + { + CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); + return; + } + + // Attempt to compress it. + if((compressedlen = lzf_compress(savebuffer + sizeof(UINT32), length - sizeof(UINT32), compressedsave + sizeof(UINT32), length - sizeof(UINT32) - 1))) + { + // Compressing succeeded; send compressed data + + free(savebuffer); + + // State that we're compressed. + buffertosend = compressedsave; + WRITEUINT32(compressedsave, length - sizeof(UINT32)); + length = compressedlen + sizeof(UINT32); + } + else + { + // Compression failed to make it smaller; send original + + free(compressedsave); + + // State that we're not compressed + buffertosend = savebuffer; + WRITEUINT32(savebuffer, 0); + } + + AddRamToSendQueue(node, buffertosend, length, SF_RAM, 0); + save_p = NULL; + + // Remember when we started sending the savegame so we can handle timeouts + sendingsavegame[node] = true; + freezetimeout[node] = I_GetTime() + jointimeout + length / 1024; // 1 extra tic for each kilobyte +} + +#ifdef DUMPCONSISTENCY +#define TMPSAVENAME "badmath.sav" +static consvar_t cv_dumpconsistency = CVAR_INIT ("dumpconsistency", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); + +static void SV_SavedGame(void) +{ + size_t length; + UINT8 *savebuffer; + char tmpsave[256]; + + if (!cv_dumpconsistency.value) + return; + + sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); + + // first save it in a malloced buffer + save_p = savebuffer = (UINT8 *)malloc(SAVEGAMESIZE); + if (!save_p) + { + CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); + return; + } + + P_SaveNetGame(false); + + length = save_p - savebuffer; + if (length > SAVEGAMESIZE) + { + free(savebuffer); + save_p = NULL; + I_Error("Savegame buffer overrun"); + } + + // then save it! + if (!FIL_WriteFile(tmpsave, savebuffer, length)) + CONS_Printf(M_GetText("Didn't save %s for netgame"), tmpsave); + + free(savebuffer); + save_p = NULL; +} + +#undef TMPSAVENAME +#endif +#define TMPSAVENAME "$$$.sav" + + +static void CL_LoadReceivedSavegame(boolean reloading) +{ + UINT8 *savebuffer = NULL; + size_t length, decompressedlen; + char tmpsave[256]; + + FreeFileNeeded(); + + sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); + + length = FIL_ReadFile(tmpsave, &savebuffer); + + CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(length)); + if (!length) + { + I_Error("Can't read savegame sent"); + return; + } + + save_p = savebuffer; + + // Decompress saved game if necessary. + decompressedlen = READUINT32(save_p); + if(decompressedlen > 0) + { + UINT8 *decompressedbuffer = Z_Malloc(decompressedlen, PU_STATIC, NULL); + lzf_decompress(save_p, length - sizeof(UINT32), decompressedbuffer, decompressedlen); + Z_Free(savebuffer); + save_p = savebuffer = decompressedbuffer; + } + + paused = false; + demoplayback = false; + titlemapinaction = TITLEMAP_OFF; + titledemo = false; + automapactive = false; + + P_StopRumble(NULL); + + // load a base level + if (P_LoadNetGame(reloading)) + { + const UINT8 actnum = mapheaderinfo[gamemap-1]->actnum; + CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap)); + if (strcmp(mapheaderinfo[gamemap-1]->lvlttl, "")) + { + CONS_Printf(": %s", mapheaderinfo[gamemap-1]->lvlttl); + if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) + CONS_Printf(M_GetText(" Zone")); + if (actnum > 0) + CONS_Printf(" %2d", actnum); + } + CONS_Printf("\"\n"); + } + + // done + Z_Free(savebuffer); + save_p = NULL; + if (unlink(tmpsave) == -1) + CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave); + consistancy[gametic%BACKUPTICS] = Consistancy(); + CON_ToggleOff(); + + // Tell the server we have received and reloaded the gamestate + // so they know they can resume the game + netbuffer->packettype = PT_RECEIVEDGAMESTATE; + HSendPacket(servernode, true, 0, 0); +} + +static void CL_ReloadReceivedSavegame(void) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + LUA_InvalidatePlayer(&players[i]); + sprintf(player_names[i], "Player %d", i + 1); + } + + CL_LoadReceivedSavegame(true); + + if (neededtic < gametic) + neededtic = gametic; + maketic = neededtic; + + ticcmd_oldangleturn[0] = players[consoleplayer].oldrelangleturn; + P_ForceLocalAngle(&players[consoleplayer], (angle_t)(players[consoleplayer].angleturn << 16)); + if (splitscreen) + { + ticcmd_oldangleturn[1] = players[secondarydisplayplayer].oldrelangleturn; + P_ForceLocalAngle(&players[secondarydisplayplayer], (angle_t)(players[secondarydisplayplayer].angleturn << 16)); + } + + camera.subsector = R_PointInSubsector(camera.x, camera.y); + camera2.subsector = R_PointInSubsector(camera2.x, camera2.y); + + cl_redownloadinggamestate = false; + + CONS_Printf(M_GetText("Game state reloaded\n")); +} +#endif + +#ifndef NONET +static void SendAskInfo(INT32 node) +{ + const tic_t asktime = I_GetTime(); + netbuffer->packettype = PT_ASKINFO; + netbuffer->u.askinfo.version = VERSION; + netbuffer->u.askinfo.time = (tic_t)LONG(asktime); + + // Even if this never arrives due to the host being firewalled, we've + // now allowed traffic from the host to us in, so once the MS relays + // our address to the host, it'll be able to speak to us. + HSendPacket(node, false, 0, sizeof (askinfo_pak)); +} + +serverelem_t serverlist[MAXSERVERLIST]; +UINT32 serverlistcount = 0; + +#define FORCECLOSE 0x8000 + +static void SL_ClearServerList(INT32 connectedserver) +{ + UINT32 i; + + for (i = 0; i < serverlistcount; i++) + if (connectedserver != serverlist[i].node) + { + Net_CloseConnection(serverlist[i].node|FORCECLOSE); + serverlist[i].node = 0; + } + serverlistcount = 0; +} + +static UINT32 SL_SearchServer(INT32 node) +{ + UINT32 i; + for (i = 0; i < serverlistcount; i++) + if (serverlist[i].node == node) + return i; + + return UINT32_MAX; +} + +static void SL_InsertServer(serverinfo_pak* info, SINT8 node) +{ + UINT32 i; + + // search if not already on it + i = SL_SearchServer(node); + if (i == UINT32_MAX) + { + // not found add it + if (serverlistcount >= MAXSERVERLIST) + return; // list full + + /* check it later if connecting to this one */ + if (node != servernode) + { + if (info->_255 != 255) + return;/* old packet format */ + + if (info->packetversion != PACKETVERSION) + return;/* old new packet format */ + + if (info->version != VERSION) + return; // Not same version. + + if (info->subversion != SUBVERSION) + return; // Close, but no cigar. + + if (strcmp(info->application, SRB2APPLICATION)) + return;/* that's a different mod */ + } + + i = serverlistcount++; + } + + serverlist[i].info = *info; + serverlist[i].node = node; + + // resort server list + M_SortServerList(); +} + +#if defined (MASTERSERVER) && defined (HAVE_THREADS) +struct Fetch_servers_ctx +{ + int room; + int id; +}; + +static void +Fetch_servers_thread (struct Fetch_servers_ctx *ctx) +{ + msg_server_t *server_list; + + server_list = GetShortServersList(ctx->room, ctx->id); + + if (server_list) + { + I_lock_mutex(&ms_QueryId_mutex); + { + if (ctx->id != ms_QueryId) + { + free(server_list); + server_list = NULL; + } + } + I_unlock_mutex(ms_QueryId_mutex); + + if (server_list) + { + I_lock_mutex(&m_menu_mutex); + { + if (m_waiting_mode == M_WAITING_SERVERS) + m_waiting_mode = M_NOT_WAITING; + } + I_unlock_mutex(m_menu_mutex); + + I_lock_mutex(&ms_ServerList_mutex); + { + ms_ServerList = server_list; + } + I_unlock_mutex(ms_ServerList_mutex); + } + } + + free(ctx); +} +#endif/*defined (MASTERSERVER) && defined (HAVE_THREADS)*/ + +void CL_QueryServerList (msg_server_t *server_list) +{ + INT32 i; + + for (i = 0; server_list[i].header.buffer[0]; i++) + { + // Make sure MS version matches our own, to + // thwart nefarious servers who lie to the MS. + + /* lol bruh, that version COMES from the servers */ + //if (strcmp(version, server_list[i].version) == 0) + { + INT32 node = I_NetMakeNodewPort(server_list[i].ip, server_list[i].port); + if (node == -1) + break; // no more node free + SendAskInfo(node); + // Force close the connection so that servers can't eat + // up nodes forever if we never get a reply back from them + // (usually when they've not forwarded their ports). + // + // Don't worry, we'll get in contact with the working + // servers again when they send SERVERINFO to us later! + // + // (Note: as a side effect this probably means every + // server in the list will probably be using the same node (e.g. node 1), + // not that it matters which nodes they use when + // the connections are closed afterwards anyway) + // -- Monster Iestyn 12/11/18 + Net_CloseConnection(node|FORCECLOSE); + } + } +} + +void CL_UpdateServerList(boolean internetsearch, INT32 room) +{ + (void)internetsearch; + (void)room; + + SL_ClearServerList(0); + + if (!netgame && I_NetOpenSocket) + { + if (I_NetOpenSocket()) + { + netgame = true; + multiplayer = true; + } + } + + // search for local servers + if (netgame) + SendAskInfo(BROADCASTADDR); + +#ifdef MASTERSERVER + if (internetsearch) + { +#ifdef HAVE_THREADS + struct Fetch_servers_ctx *ctx; + + ctx = malloc(sizeof *ctx); + + /* This called from M_Refresh so I don't use a mutex */ + m_waiting_mode = M_WAITING_SERVERS; + + I_lock_mutex(&ms_QueryId_mutex); + { + ctx->id = ms_QueryId; + } + I_unlock_mutex(ms_QueryId_mutex); + + ctx->room = room; + + I_spawn_thread("fetch-servers", (I_thread_fn)Fetch_servers_thread, ctx); +#else + msg_server_t *server_list; + + server_list = GetShortServersList(room, 0); + + if (server_list) + { + CL_QueryServerList(server_list); + free(server_list); + } +#endif + } +#endif/*MASTERSERVER*/ +} + +#endif // ifndef NONET + +static void M_ConfirmConnect(event_t *ev) +{ +#ifndef NONET + + if (ev->type == ev_keydown || ev->type == ev_gamepad_down) + { + if ((ev->type == ev_keydown && (ev->key == ' ' || ev->key == 'y' || ev->key == KEY_ENTER)) || (ev->type == ev_gamepad_down && ev->which == 0 && ev->key == GAMEPAD_BUTTON_A)) + { + if (totalfilesrequestednum > 0) + { + if (CL_SendFileRequest()) + { + cl_mode = CL_DOWNLOADFILES; + Snake_Initialise(); + } + } + else + cl_mode = CL_LOADFILES; + + M_ClearMenus(true); + } + else if ((ev->type == ev_keydown && (ev->key == 'n' || ev->key == KEY_ESCAPE)) || (ev->type == ev_gamepad_down && ev->which == 0 && ev->key == GAMEPAD_BUTTON_B)) + { + cl_mode = CL_ABORTED; + M_ClearMenus(true); + } + } +#else + (void)ev; +#endif +} + +static boolean CL_FinishedFileList(void) +{ + INT32 i; + char *downloadsize = NULL; + + //CONS_Printf(M_GetText("Checking files...\n")); + i = CL_CheckFiles(); + if (i == 4) // still checking ... + { + return true; + } + else if (i == 3) // too many files + { + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "You have too many WAD files loaded\n" + "to add ones the server is using.\n" + "Please restart SRB2 before connecting.\n\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } + else if (i == 2) // cannot join for some reason + { + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "You have the wrong addons loaded.\n\n" + "To play on this server, restart\n" + "the game and don't load any addons.\n" + "SRB2 will automatically add\n" + "everything you need when you join.\n\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } + else if (i == 1) + { + if (serverisfull) + { + M_StartMessage(M_GetText( + "This server is full!\n" + "\n" + "You may load server addons (if any), and wait for a slot.\n" + "\n" + "Press ENTER to continue\nor ESC to cancel.\n\n" + ), M_ConfirmConnect, MM_EVENTHANDLER); + cl_mode = CL_CONFIRMCONNECT; + curfadevalue = 0; + } + else + cl_mode = CL_LOADFILES; + } + else + { + // must download something + // can we, though? + if (!CL_CheckDownloadable()) // nope! + { + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "An error occured when trying to\n" + "download missing addons.\n" + "(This is almost always a problem\n" + "with the server, not your game.)\n\n" + "See the console or log file\n" + "for additional details.\n\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } + +#ifndef NONET + downloadcompletednum = 0; + downloadcompletedsize = 0; + totalfilesrequestednum = 0; + totalfilesrequestedsize = 0; + + if (fileneeded == NULL) + I_Error("CL_FinishedFileList: fileneeded == NULL"); + + for (i = 0; i < fileneedednum; i++) + if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD) + { + totalfilesrequestednum++; + totalfilesrequestedsize += fileneeded[i].totalsize; + } + + if (totalfilesrequestedsize>>20 >= 100) + downloadsize = Z_StrDup(va("%uM",totalfilesrequestedsize>>20)); + else + downloadsize = Z_StrDup(va("%uK",totalfilesrequestedsize>>10)); +#endif + + if (serverisfull) + M_StartMessage(va(M_GetText( + "This server is full!\n" + "Download of %s additional content\nis required to join.\n" + "\n" + "You may download, load server addons,\nand wait for a slot.\n" + "\n" + "Press ENTER to continue\nor ESC to cancel.\n" + ), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER); + else + M_StartMessage(va(M_GetText( + "Download of %s additional content\nis required to join.\n" + "\n" + "Press ENTER to continue\nor ESC to cancel.\n" + ), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER); + + Z_Free(downloadsize); + cl_mode = CL_CONFIRMCONNECT; + curfadevalue = 0; + } + return true; +} + +#ifndef NONET +static const char * InvalidServerReason (serverinfo_pak *info) +{ +#define EOT "\nPress ESC\n" + + /* magic number for new packet format */ + if (info->_255 != 255) + { + return + "Outdated server (version unknown).\n" EOT; + } + + if (strncmp(info->application, SRB2APPLICATION, sizeof + info->application)) + { + return va( + "%s cannot connect\n" + "to %s servers.\n" EOT, + SRB2APPLICATION, + info->application); + } + + if ( + info->packetversion != PACKETVERSION || + info->version != VERSION || + info->subversion != SUBVERSION + ){ + return va( + "Incompatible %s versions.\n" + "(server version %d.%d.%d)\n" EOT, + SRB2APPLICATION, + info->version / 100, + info->version % 100, + info->subversion); + } + + switch (info->refusereason) + { + case REFUSE_BANNED: + return + "You have been banned\n" + "from the server.\n" EOT; + case REFUSE_JOINS_DISABLED: + return + "The server is not accepting\n" + "joins for the moment.\n" EOT; + case REFUSE_SLOTS_FULL: + return va( + "Maximum players reached: %d\n" EOT, + info->maxplayer); + default: + if (info->refusereason) + { + return + "You can't join.\n" + "I don't know why,\n" + "but you can't join.\n" EOT; + } + } + + return NULL; + +#undef EOT +} +#endif // ifndef NONET + +/** Called by CL_ServerConnectionTicker + * + * \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit. + * \return False if the connection was aborted + * \sa CL_ServerConnectionTicker + * \sa CL_ConnectToServer + * + */ +static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) +{ +#ifndef NONET + INT32 i; + + // serverlist is updated by GetPacket function + if (serverlistcount > 0) + { + // this can be a responce to our broadcast request + if (servernode == -1 || servernode >= MAXNETNODES) + { + i = 0; + servernode = serverlist[i].node; + CONS_Printf(M_GetText("Found, ")); + } + else + { + i = SL_SearchServer(servernode); + if (i < 0) + return true; + } + + if (client) + { + serverinfo_pak *info = &serverlist[i].info; + + if (info->refusereason == REFUSE_SLOTS_FULL) + serverisfull = true; + else + { + const char *reason = InvalidServerReason(info); + + // Quit here rather than downloading files + // and being refused later. + if (reason) + { + char *message = Z_StrDup(reason); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(message, NULL, MM_NOTHING); + Z_Free(message); + return false; + } + } + + D_ParseFileneeded(info->fileneedednum, info->fileneeded, 0); + + if (info->flags & SV_LOTSOFADDONS) + { + cl_mode = CL_ASKFULLFILELIST; + cl_lastcheckedfilecount = 0; + return true; + } + + cl_mode = CL_CHECKFILES; + } + else + { + cl_mode = CL_ASKJOIN; // files need not be checked for the server. + *asksent = 0; + } + + return true; + } + + // Ask the info to the server (askinfo packet) + if (*asksent + NEWTICRATE < I_GetTime()) + { + SendAskInfo(servernode); + *asksent = I_GetTime(); + } +#else + (void)asksent; + // No netgames, so we skip this state. + cl_mode = CL_ASKJOIN; +#endif // ifndef NONET/else + + return true; +} + +/** Called by CL_ConnectToServer + * + * \param tmpsave The name of the gamestate file??? + * \param oldtic Used for knowing when to poll events and redraw + * \param asksent ??? + * \return False if the connection was aborted + * \sa CL_ServerConnectionSearchTicker + * \sa CL_ConnectToServer + * + */ +static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic_t *asksent) +{ + boolean waitmore; + INT32 i; + +#ifdef NONET + (void)tmpsave; +#endif + + switch (cl_mode) + { + case CL_SEARCHING: + if (!CL_ServerConnectionSearchTicker(asksent)) + return false; + break; + + case CL_ASKFULLFILELIST: + if (cl_lastcheckedfilecount == UINT16_MAX) // All files retrieved + cl_mode = CL_CHECKFILES; + else if (fileneedednum != cl_lastcheckedfilecount || I_GetTime() >= *asksent) + { + if (CL_AskFileList(fileneedednum)) + { + cl_lastcheckedfilecount = fileneedednum; + *asksent = I_GetTime() + NEWTICRATE; + } + } + break; + case CL_CHECKFILES: + if (!CL_FinishedFileList()) + return false; + break; + case CL_DOWNLOADFILES: + waitmore = false; + for (i = 0; i < fileneedednum; i++) + if (fileneeded[i].status == FS_DOWNLOADING + || fileneeded[i].status == FS_REQUESTED) + { + waitmore = true; + break; + } + if (waitmore) + break; // exit the case + +#ifndef NONET + if (snake) + { + free(snake); + snake = NULL; + } +#endif + + cl_mode = CL_LOADFILES; + break; + case CL_LOADFILES: + if (CL_LoadServerFiles()) + { + FreeFileNeeded(); + *asksent = 0; //This ensure the first join ask is right away + firstconnectattempttime = I_GetTime(); + cl_mode = CL_ASKJOIN; + } + break; + case CL_ASKJOIN: + if (firstconnectattempttime + NEWTICRATE*300 < I_GetTime() && !server) + { + CONS_Printf(M_GetText("5 minute wait time exceeded.\n")); + CONS_Printf(M_GetText("Network game synchronization aborted.\n")); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "5 minute wait time exceeded.\n" + "You may retry connection.\n" + "\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } +#ifndef NONET + // prepare structures to save the file + // WARNING: this can be useless in case of server not in GS_LEVEL + // but since the network layer doesn't provide ordered packets... + CL_PrepareDownloadSaveGame(tmpsave); +#endif + if (I_GetTime() >= *asksent && CL_SendJoin()) + { + *asksent = I_GetTime() + NEWTICRATE*3; + cl_mode = CL_WAITJOINRESPONSE; + } + break; + case CL_WAITJOINRESPONSE: + if (I_GetTime() >= *asksent) + { + cl_mode = CL_ASKJOIN; + } + break; +#ifndef NONET + case CL_DOWNLOADSAVEGAME: + // At this state, the first (and only) needed file is the gamestate + if (fileneeded[0].status == FS_FOUND) + { + // Gamestate is now handled within CL_LoadReceivedSavegame() + CL_LoadReceivedSavegame(false); + cl_mode = CL_CONNECTED; + } // don't break case continue to CL_CONNECTED + else + break; +#endif + + case CL_CONNECTED: + case CL_CONFIRMCONNECT: //logic is handled by M_ConfirmConnect + default: + break; + + // Connection closed by cancel, timeout or refusal. + case CL_ABORTED: + cl_mode = CL_SEARCHING; + return false; + } + + GetPackets(); + Net_AckTicker(); + + // Call it only once by tic + if (*oldtic != I_GetTime()) + { + I_OsPolling(); + + if (cl_mode == CL_CONFIRMCONNECT) + D_ProcessEvents(); //needed for menu system to receive inputs + else + { + // my hand has been forced and I am dearly sorry for this awful hack :vomit: + for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) + { + G_MapEventsToControls(&events[eventtail]); + } + } + + if (gamekeydown[KEY_ESCAPE] || gamepads[0].buttons[GAMEPAD_BUTTON_B] || cl_mode == CL_ABORTED) + { + CONS_Printf(M_GetText("Network game synchronization aborted.\n")); + M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); + +#ifndef NONET + if (snake) + { + free(snake); + snake = NULL; + } +#endif + + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + memset(gamekeydown, 0, NUMKEYS); + return false; + } +#ifndef NONET + else if (cl_mode == CL_DOWNLOADFILES && snake) + Snake_Handle(); +#endif + + if (client && (cl_mode == CL_DOWNLOADFILES || cl_mode == CL_DOWNLOADSAVEGAME)) + FileReceiveTicker(); + + // why are these here? this is for servers, we're a client + //if (key == 's' && server) + // doomcom->numnodes = (INT16)pnumnodes; + //FileSendTicker(); + *oldtic = I_GetTime(); + +#ifndef NONET + if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED) + { + if (!snake) + { + F_MenuPresTicker(true); // title sky + F_TitleScreenTicker(true); + F_TitleScreenDrawer(); + } + CL_DrawConnectionStatus(); +#ifdef HAVE_THREADS + I_lock_mutex(&m_menu_mutex); +#endif + M_Drawer(); //Needed for drawing messageboxes on the connection screen +#ifdef HAVE_THREADS + I_unlock_mutex(m_menu_mutex); +#endif + I_UpdateNoVsync(); // page flip or blit buffer + if (moviemode) + M_SaveFrame(); + S_UpdateSounds(); + S_UpdateClosedCaptions(); + } +#else + CON_Drawer(); + I_UpdateNoVsync(); +#endif + } + else + { + I_Sleep(cv_sleep.value); + I_UpdateTime(cv_timescale.value); + } + + return true; +} + +/** Use adaptive send using net_bandwidth and stat.sendbytes + * + * \todo Better description... + * + */ +static void CL_ConnectToServer(void) +{ + INT32 pnumnodes, nodewaited = doomcom->numnodes, i; + tic_t oldtic; +#ifndef NONET + tic_t asksent; + char tmpsave[256]; + + sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); + + lastfilenum = -1; +#endif + + cl_mode = CL_SEARCHING; + +#ifndef NONET + // Don't get a corrupt savegame error because tmpsave already exists + if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1) + I_Error("Can't delete %s\n", tmpsave); +#endif + + if (netgame) + { + if (servernode < 0 || servernode >= MAXNETNODES) + CONS_Printf(M_GetText("Searching for a server...\n")); + else + CONS_Printf(M_GetText("Contacting the server...\n")); + } + + if (gamestate == GS_INTERMISSION) + Y_EndIntermission(); // clean up intermission graphics etc + + DEBFILE(va("waiting %d nodes\n", doomcom->numnodes)); + G_SetGamestate(GS_WAITINGPLAYERS); + wipegamestate = GS_WAITINGPLAYERS; + + ClearAdminPlayers(); + pnumnodes = 1; + oldtic = I_GetTime() - 1; + +#ifndef NONET + asksent = (tic_t) - TICRATE; + firstconnectattempttime = I_GetTime(); + + i = SL_SearchServer(servernode); + + if (i != -1) + { + char *gametypestr = serverlist[i].info.gametypename; + CONS_Printf(M_GetText("Connecting to: %s\n"), serverlist[i].info.servername); + gametypestr[sizeof serverlist[i].info.gametypename - 1] = '\0'; + CONS_Printf(M_GetText("Gametype: %s\n"), gametypestr); + CONS_Printf(M_GetText("Version: %d.%d.%u\n"), serverlist[i].info.version/100, + serverlist[i].info.version%100, serverlist[i].info.subversion); + } + SL_ClearServerList(servernode); +#endif + + do + { + // If the connection was aborted for some reason, leave +#ifndef NONET + if (!CL_ServerConnectionTicker(tmpsave, &oldtic, &asksent)) +#else + if (!CL_ServerConnectionTicker((char*)NULL, &oldtic, (tic_t *)NULL)) +#endif + return; + + if (server) + { + pnumnodes = 0; + for (i = 0; i < MAXNETNODES; i++) + if (nodeingame[i]) + pnumnodes++; + } + } + while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes)))); + + DEBFILE(va("Synchronisation Finished\n")); + + displayplayer = consoleplayer; +} + +#ifndef NONET +typedef struct banreason_s +{ + char *reason; + struct banreason_s *prev; //-1 + struct banreason_s *next; //+1 +} banreason_t; + +static banreason_t *reasontail = NULL; //last entry, use prev +static banreason_t *reasonhead = NULL; //1st entry, use next + +static void Command_ShowBan(void) //Print out ban list +{ + size_t i; + const char *address, *mask; + banreason_t *reasonlist = reasonhead; + + if (I_GetBanAddress) + CONS_Printf(M_GetText("Ban List:\n")); + else + return; + + for (i = 0;(address = I_GetBanAddress(i)) != NULL;i++) + { + if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL) + CONS_Printf("%s: %s ", sizeu1(i+1), address); + else + CONS_Printf("%s: %s/%s ", sizeu1(i+1), address, mask); + + if (reasonlist && reasonlist->reason) + CONS_Printf("(%s)\n", reasonlist->reason); + else + CONS_Printf("\n"); + + if (reasonlist) reasonlist = reasonlist->next; + } + + if (i == 0 && !address) + CONS_Printf(M_GetText("(empty)\n")); +} + +void D_SaveBan(void) +{ + FILE *f; + size_t i; + banreason_t *reasonlist = reasonhead; + const char *address, *mask; + const char *path = va("%s"PATHSEP"%s", srb2home, "ban.txt"); + + if (!reasonhead) + { + remove(path); + return; + } + + f = fopen(path, "w"); + + if (!f) + { + CONS_Alert(CONS_WARNING, M_GetText("Could not save ban list into ban.txt\n")); + return; + } + + for (i = 0;(address = I_GetBanAddress(i)) != NULL;i++) + { + if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL) + fprintf(f, "%s 0", address); + else + fprintf(f, "%s %s", address, mask); + + if (reasonlist && reasonlist->reason) + fprintf(f, " %s\n", reasonlist->reason); + else + fprintf(f, " %s\n", "NA"); + + if (reasonlist) reasonlist = reasonlist->next; + } + + fclose(f); +} + +static void Ban_Add(const char *reason) +{ + banreason_t *reasonlist = malloc(sizeof(*reasonlist)); + + if (!reasonlist) + return; + if (!reason) + reason = "NA"; + + reasonlist->next = NULL; + reasonlist->reason = Z_StrDup(reason); + if ((reasonlist->prev = reasontail) == NULL) + reasonhead = reasonlist; + else + reasontail->next = reasonlist; + reasontail = reasonlist; +} + +static void Ban_Clear(void) +{ + banreason_t *temp; + + I_ClearBans(); + + reasontail = NULL; + + while (reasonhead) + { + temp = reasonhead->next; + Z_Free(reasonhead->reason); + free(reasonhead); + reasonhead = temp; + } +} + +static void Command_ClearBans(void) +{ + if (!I_ClearBans) + return; + + Ban_Clear(); + D_SaveBan(); +} + +static void Ban_Load_File(boolean warning) +{ + FILE *f; + size_t i; + const char *address, *mask; + char buffer[MAX_WADPATH]; + + if (!I_ClearBans) + return; + + f = fopen(va("%s"PATHSEP"%s", srb2home, "ban.txt"), "r"); + + if (!f) + { + if (warning) + CONS_Alert(CONS_WARNING, M_GetText("Could not open ban.txt for ban list\n")); + return; + } + + Ban_Clear(); + + for (i=0; fgets(buffer, (int)sizeof(buffer), f); i++) + { + address = strtok(buffer, " \t\r\n"); + mask = strtok(NULL, " \t\r\n"); + + I_SetBanAddress(address, mask); + + Ban_Add(strtok(NULL, "\r\n")); + } + + fclose(f); +} + +static void Command_ReloadBan(void) //recheck ban.txt +{ + Ban_Load_File(true); +} + +static void Command_connect(void) +{ + if (COM_Argc() < 2 || *COM_Argv(1) == 0) + { + CONS_Printf(M_GetText( + "Connect (port): connect to a server\n" + "Connect ANY: connect to the first lan server found\n" + //"Connect SELF: connect to your own server.\n" + )); + return; + } + + if (Playing() || titledemo) + { + CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n")); + return; + } + + // modified game check: no longer handled + // we don't request a restart unless the filelist differs + + server = false; +/* + if (!stricmp(COM_Argv(1), "self")) + { + servernode = 0; + server = true; + /// \bug should be but... + //SV_SpawnServer(); + } + else +*/ + { + // used in menu to connect to a server in the list + if (netgame && !stricmp(COM_Argv(1), "node")) + { + servernode = (SINT8)atoi(COM_Argv(2)); + } + else if (netgame) + { + CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n")); + return; + } + else if (I_NetOpenSocket) + { + I_NetOpenSocket(); + netgame = true; + multiplayer = true; + + if (!stricmp(COM_Argv(1), "any")) + servernode = BROADCASTADDR; + else if (I_NetMakeNodewPort) + { + if (COM_Argc() >= 3) // address AND port + servernode = I_NetMakeNodewPort(COM_Argv(1), COM_Argv(2)); + else // address only, or address:port + servernode = I_NetMakeNode(COM_Argv(1)); + } + else + { + CONS_Alert(CONS_ERROR, M_GetText("There is no server identification with this network driver\n")); + D_CloseConnection(); + return; + } + } + else + CONS_Alert(CONS_ERROR, M_GetText("There is no network driver\n")); + } + + splitscreen = false; + SplitScreen_OnChange(); + botingame = false; + botskin = 0; + CL_ConnectToServer(); +} +#endif + +static void ResetNode(INT32 node); + +// +// CL_ClearPlayer +// +// Clears the player data so that a future client can use this slot +// +void CL_ClearPlayer(INT32 playernum) +{ + if (players[playernum].mo) + P_RemoveMobj(players[playernum].mo); + memset(&players[playernum], 0, sizeof (player_t)); + memset(playeraddress[playernum], 0, sizeof(*playeraddress)); +} + +// +// CL_RemovePlayer +// +// Removes a player from the current game +// +void CL_RemovePlayer(INT32 playernum, kickreason_t reason) +{ + // Sanity check: exceptional cases (i.e. c-fails) can cause multiple + // kick commands to be issued for the same player. + if (!playeringame[playernum]) + return; + + if (server && !demoplayback && playernode[playernum] != UINT8_MAX) + { + INT32 node = playernode[playernum]; + playerpernode[node]--; + if (playerpernode[node] <= 0) + { + nodeingame[node] = false; + Net_CloseConnection(node); + ResetNode(node); + } + } + + if (gametyperules & GTR_TEAMFLAGS) + P_PlayerFlagBurst(&players[playernum], false); // Don't take the flag with you! + + // If in a special stage, redistribute the player's spheres across + // the remaining players. + if (G_IsSpecialStage(gamemap)) + { + INT32 i, count, sincrement, spheres, rincrement, rings; + + for (i = 0, count = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + count++; + } + + count--; + sincrement = spheres = players[playernum].spheres; + rincrement = rings = players[playernum].rings; + + if (count) + { + sincrement /= count; + rincrement /= count; + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && i != playernum) + { + if (spheres < 2*sincrement) + { + P_GivePlayerSpheres(&players[i], spheres); + spheres = 0; + } + else + { + P_GivePlayerSpheres(&players[i], sincrement); + spheres -= sincrement; + } + + if (rings < 2*rincrement) + { + P_GivePlayerRings(&players[i], rings); + rings = 0; + } + else + { + P_GivePlayerRings(&players[i], rincrement); + rings -= rincrement; + } + } + } + } + + LUA_HookPlayerQuit(&players[playernum], reason); // Lua hook for player quitting + + // don't look through someone's view who isn't there + if (playernum == displayplayer) + { + // Call ViewpointSwitch hooks here. + // The viewpoint was forcibly changed. + LUA_HookViewpointSwitch(&players[consoleplayer], &players[consoleplayer], true); + displayplayer = consoleplayer; + } + + // Reset player data + CL_ClearPlayer(playernum); + + // remove avatar of player + playeringame[playernum] = false; + playernode[playernum] = UINT8_MAX; + while (!playeringame[doomcom->numslots-1] && doomcom->numslots > 1) + doomcom->numslots--; + + // Reset the name + sprintf(player_names[playernum], "Player %d", playernum+1); + + player_name_changes[playernum] = 0; + + if (IsPlayerAdmin(playernum)) + { + RemoveAdminPlayer(playernum); // don't stay admin after you're gone + } + + LUA_InvalidatePlayer(&players[playernum]); + + if (G_TagGametype()) //Check if you still have a game. Location flexible. =P + P_CheckSurvivors(); + else if (gametyperules & GTR_RACE) + P_CheckRacers(); +} + +void CL_Reset(void) +{ + if (metalrecording) + G_StopMetalRecording(false); + if (metalplayback) + G_StopMetalDemo(); + if (demorecording) + G_CheckDemoStatus(); + + // reset client/server code + DEBFILE(va("\n-=-=-=-=-=-=-= Client reset =-=-=-=-=-=-=-\n\n")); + + if (servernode > 0 && servernode < MAXNETNODES) + { + nodeingame[(UINT8)servernode] = false; + Net_CloseConnection(servernode); + } + D_CloseConnection(); // netgame = false + multiplayer = false; + servernode = 0; + server = true; + doomcom->numnodes = 1; + doomcom->numslots = 1; + SV_StopServer(); + SV_ResetServer(); + + // make sure we don't leave any fileneeded gunk over from a failed join + FreeFileNeeded(); + fileneedednum = 0; + +#ifndef NONET + totalfilesrequestednum = 0; + totalfilesrequestedsize = 0; +#endif + firstconnectattempttime = 0; + serverisfull = false; + connectiontimeout = (tic_t)cv_nettimeout.value; //reset this temporary hack + + // D_StartTitle should get done now, but the calling function will handle it +} + +#ifndef NONET +static void Command_GetPlayerNum(void) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i]) + { + if (serverplayer == i) + CONS_Printf(M_GetText("num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]); + else + CONS_Printf(M_GetText("\x82num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]); + } +} + +SINT8 nametonum(const char *name) +{ + INT32 playernum, i; + + if (!strcmp(name, "0")) + return 0; + + playernum = (SINT8)atoi(name); + + if (playernum < 0 || playernum >= MAXPLAYERS) + return -1; + + if (playernum) + { + if (playeringame[playernum]) + return (SINT8)playernum; + else + return -1; + } + + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && !stricmp(player_names[i], name)) + return (SINT8)i; + + CONS_Printf(M_GetText("There is no player named \"%s\"\n"), name); + + return -1; +} + +/** Lists all players and their player numbers. + * + * \sa Command_GetPlayerNum + */ +static void Command_Nodes(void) +{ + INT32 i; + size_t maxlen = 0; + const char *address; + + for (i = 0; i < MAXPLAYERS; i++) + { + const size_t plen = strlen(player_names[i]); + if (playeringame[i] && plen > maxlen) + maxlen = plen; + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + { + CONS_Printf("%.2u: %*s", i, (int)maxlen, player_names[i]); + + if (playernode[i] != UINT8_MAX) + { + CONS_Printf(" - node %.2d", playernode[i]); + if (I_GetNodeAddress && (address = I_GetNodeAddress(playernode[i])) != NULL) + CONS_Printf(" - %s", address); + } + + if (IsPlayerAdmin(i)) + CONS_Printf(M_GetText(" (verified admin)")); + + if (players[i].spectator) + CONS_Printf(M_GetText(" (spectator)")); + + CONS_Printf("\n"); + } + } +} + +static void Command_Ban(void) +{ + if (COM_Argc() < 2) + { + CONS_Printf(M_GetText("Ban : ban and kick a player\n")); + return; + } + + if (!netgame) // Don't kick Tails in splitscreen! + { + CONS_Printf(M_GetText("This only works in a netgame.\n")); + return; + } + + if (server || IsPlayerAdmin(consoleplayer)) + { + UINT8 buf[3 + MAX_REASONLENGTH]; + UINT8 *p = buf; + const SINT8 pn = nametonum(COM_Argv(1)); + const INT32 node = playernode[(INT32)pn]; + + if (pn == -1 || pn == 0) + return; + + WRITEUINT8(p, pn); + + if (server && I_Ban && !I_Ban(node)) // only the server is allowed to do this right now + { + CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n")); + WRITEUINT8(p, KICK_MSG_GO_AWAY); + SendNetXCmd(XD_KICK, &buf, 2); + } + else + { + if (server) // only the server is allowed to do this right now + { + Ban_Add(COM_Argv(2)); + D_SaveBan(); // save the ban list + } + + if (COM_Argc() == 2) + { + WRITEUINT8(p, KICK_MSG_BANNED); + SendNetXCmd(XD_KICK, &buf, 2); + } + else + { + size_t i, j = COM_Argc(); + char message[MAX_REASONLENGTH]; + + //Steal from the motd code so you don't have to put the reason in quotes. + strlcpy(message, COM_Argv(2), sizeof message); + for (i = 3; i < j; i++) + { + strlcat(message, " ", sizeof message); + strlcat(message, COM_Argv(i), sizeof message); + } + + WRITEUINT8(p, KICK_MSG_CUSTOM_BAN); + WRITESTRINGN(p, message, MAX_REASONLENGTH); + SendNetXCmd(XD_KICK, &buf, p - buf); + } + } + } + else + CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); + +} + +static void Command_BanIP(void) +{ + if (COM_Argc() < 2) + { + CONS_Printf(M_GetText("banip : ban an ip address\n")); + return; + } + + if (server) // Only the server can use this, otherwise does nothing. + { + const char *address = (COM_Argv(1)); + const char *reason; + + if (COM_Argc() == 2) + reason = NULL; + else + reason = COM_Argv(2); + + + if (I_SetBanAddress && I_SetBanAddress(address, NULL)) + { + if (reason) + CONS_Printf("Banned IP address %s for: %s\n", address, reason); + else + CONS_Printf("Banned IP address %s\n", address); + + Ban_Add(reason); + D_SaveBan(); + } + else + { + return; + } + } +} + +static void Command_Kick(void) +{ + if (COM_Argc() < 2) + { + CONS_Printf(M_GetText("kick : kick a player\n")); + return; + } + + if (!netgame) // Don't kick Tails in splitscreen! + { + CONS_Printf(M_GetText("This only works in a netgame.\n")); + return; + } + + if (server || IsPlayerAdmin(consoleplayer)) + { + UINT8 buf[3 + MAX_REASONLENGTH]; + UINT8 *p = buf; + const SINT8 pn = nametonum(COM_Argv(1)); + + if (pn == -1 || pn == 0) + return; + + // Special case if we are trying to kick a player who is downloading the game state: + // trigger a timeout instead of kicking them, because a kick would only + // take effect after they have finished downloading + if (server && playernode[pn] != UINT8_MAX && sendingsavegame[playernode[pn]]) + { + Net_ConnectionTimeout(playernode[pn]); + return; + } + + WRITESINT8(p, pn); + + if (COM_Argc() == 2) + { + WRITEUINT8(p, KICK_MSG_GO_AWAY); + SendNetXCmd(XD_KICK, &buf, 2); + } + else + { + size_t i, j = COM_Argc(); + char message[MAX_REASONLENGTH]; + + //Steal from the motd code so you don't have to put the reason in quotes. + strlcpy(message, COM_Argv(2), sizeof message); + for (i = 3; i < j; i++) + { + strlcat(message, " ", sizeof message); + strlcat(message, COM_Argv(i), sizeof message); + } + + WRITEUINT8(p, KICK_MSG_CUSTOM_KICK); + WRITESTRINGN(p, message, MAX_REASONLENGTH); + SendNetXCmd(XD_KICK, &buf, p - buf); + } + } + else + CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); +} + +static void Command_ResendGamestate(void) +{ + SINT8 playernum; + + if (COM_Argc() == 1) + { + CONS_Printf(M_GetText("resendgamestate : resend the game state to a player\n")); + return; + } + else if (client) + { + CONS_Printf(M_GetText("Only the server can use this.\n")); + return; + } + + playernum = nametonum(COM_Argv(1)); + if (playernum == -1 || playernum == 0) + return; + + // Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + if (!HSendPacket(playernode[playernum], true, 0, 0)) + { + CONS_Alert(CONS_ERROR, M_GetText("A problem occured, please try again.\n")); + return; + } +} +#endif + +static void Got_KickCmd(UINT8 **p, INT32 playernum) +{ + INT32 pnum, msg; + char buf[3 + MAX_REASONLENGTH]; + char *reason = buf; + kickreason_t kickreason = KR_KICK; + boolean keepbody; + + pnum = READUINT8(*p); + msg = READUINT8(*p); + keepbody = (msg & KICK_MSG_KEEP_BODY) != 0; + msg &= ~KICK_MSG_KEEP_BODY; + + if (pnum == serverplayer && IsPlayerAdmin(playernum)) + { + CONS_Printf(M_GetText("Server is being shut down remotely. Goodbye!\n")); + + if (server) + COM_BufAddText("quit\n"); + + return; + } + + // Is playernum authorized to make this kick? + if (playernum != serverplayer && !IsPlayerAdmin(playernum) + && !(playernode[playernum] != UINT8_MAX && playerpernode[playernode[playernum]] == 2 + && nodetoplayer2[playernode[playernum]] == pnum)) + { + // We received a kick command from someone who isn't the + // server or admin, and who isn't in splitscreen removing + // player 2. Thus, it must be someone with a modified + // binary, trying to kick someone but without having + // authorization. + + // We deal with this by changing the kick reason to + // "consistency failure" and kicking the offending user + // instead. + + // Note: Splitscreen in netgames is broken because of + // this. Only the server has any idea of which players + // are using splitscreen on the same computer, so + // clients cannot always determine if a kick is + // legitimate. + + CONS_Alert(CONS_WARNING, M_GetText("Illegal kick command received from %s for player %d\n"), player_names[playernum], pnum); + + // In debug, print a longer message with more details. + // TODO Callum: Should we translate this? +/* + CONS_Debug(DBG_NETPLAY, + "So, you must be asking, why is this an illegal kick?\n" + "Well, let's take a look at the facts, shall we?\n" + "\n" + "playernum (this is the guy who did it), he's %d.\n" + "pnum (the guy he's trying to kick) is %d.\n" + "playernum's node is %d.\n" + "That node has %d players.\n" + "Player 2 on that node is %d.\n" + "pnum's node is %d.\n" + "That node has %d players.\n" + "Player 2 on that node is %d.\n" + "\n" + "If you think this is a bug, please report it, including all of the details above.\n", + playernum, pnum, + playernode[playernum], playerpernode[playernode[playernum]], + nodetoplayer2[playernode[playernum]], + playernode[pnum], playerpernode[playernode[pnum]], + nodetoplayer2[playernode[pnum]]); +*/ + pnum = playernum; + msg = KICK_MSG_CON_FAIL; + keepbody = true; + } + + //CONS_Printf("\x82%s ", player_names[pnum]); + + // If a verified admin banned someone, the server needs to know about it. + // If the playernum isn't zero (the server) then the server needs to record the ban. + if (server && playernum && (msg == KICK_MSG_BANNED || msg == KICK_MSG_CUSTOM_BAN)) + { + if (I_Ban && !I_Ban(playernode[(INT32)pnum])) + CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n")); +#ifndef NONET + else + Ban_Add(reason); +#endif + } + + switch (msg) + { + case KICK_MSG_GO_AWAY: + if (!players[pnum].quittime) + HU_AddChatText(va("\x82*%s has been kicked (No reason given)", player_names[pnum]), false); + kickreason = KR_KICK; + break; + case KICK_MSG_PING_HIGH: + HU_AddChatText(va("\x82*%s left the game (Broke ping limit)", player_names[pnum]), false); + kickreason = KR_PINGLIMIT; + break; + case KICK_MSG_CON_FAIL: + HU_AddChatText(va("\x82*%s left the game (Synch failure)", player_names[pnum]), false); + kickreason = KR_SYNCH; + + if (M_CheckParm("-consisdump")) // Helps debugging some problems + { + INT32 i; + + CONS_Printf(M_GetText("Player kicked is #%d, dumping consistency...\n"), pnum); + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + CONS_Printf("-------------------------------------\n"); + CONS_Printf("Player %d: %s\n", i, player_names[i]); + CONS_Printf("Skin: %d\n", players[i].skin); + CONS_Printf("Color: %d\n", players[i].skincolor); + CONS_Printf("Speed: %d\n",players[i].speed>>FRACBITS); + if (players[i].mo) + { + if (!players[i].mo->skin) + CONS_Printf("Mobj skin: NULL!\n"); + else + CONS_Printf("Mobj skin: %s\n", ((skin_t *)players[i].mo->skin)->name); + CONS_Printf("Position: %d, %d, %d\n", players[i].mo->x, players[i].mo->y, players[i].mo->z); + if (!players[i].mo->state) + CONS_Printf("State: S_NULL\n"); + else + CONS_Printf("State: %d\n", (statenum_t)(players[i].mo->state-states)); + } + else + CONS_Printf("Mobj: NULL\n"); + CONS_Printf("-------------------------------------\n"); + } + } + break; + case KICK_MSG_TIMEOUT: + HU_AddChatText(va("\x82*%s left the game (Connection timeout)", player_names[pnum]), false); + kickreason = KR_TIMEOUT; + break; + case KICK_MSG_PLAYER_QUIT: + if (netgame && !players[pnum].quittime) // not splitscreen/bots or soulless body + HU_AddChatText(va("\x82*%s left the game", player_names[pnum]), false); + kickreason = KR_LEAVE; + break; + case KICK_MSG_BANNED: + HU_AddChatText(va("\x82*%s has been banned (No reason given)", player_names[pnum]), false); + kickreason = KR_BAN; + break; + case KICK_MSG_CUSTOM_KICK: + READSTRINGN(*p, reason, MAX_REASONLENGTH+1); + HU_AddChatText(va("\x82*%s has been kicked (%s)", player_names[pnum], reason), false); + kickreason = KR_KICK; + break; + case KICK_MSG_CUSTOM_BAN: + READSTRINGN(*p, reason, MAX_REASONLENGTH+1); + HU_AddChatText(va("\x82*%s has been banned (%s)", player_names[pnum], reason), false); + kickreason = KR_BAN; + break; + } + + if (pnum == consoleplayer) + { + LUA_HookBool(false, HOOK(GameQuit)); +#ifdef DUMPCONSISTENCY + if (msg == KICK_MSG_CON_FAIL) SV_SavedGame(); +#endif + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + if (msg == KICK_MSG_CON_FAIL) + M_StartMessage(M_GetText("Server closed connection\n(synch failure)\nPress ESC\n"), NULL, MM_NOTHING); + else if (msg == KICK_MSG_PING_HIGH) + M_StartMessage(M_GetText("Server closed connection\n(Broke ping limit)\nPress ESC\n"), NULL, MM_NOTHING); + else if (msg == KICK_MSG_BANNED) + M_StartMessage(M_GetText("You have been banned by the server\n\nPress ESC\n"), NULL, MM_NOTHING); + else if (msg == KICK_MSG_CUSTOM_KICK) + M_StartMessage(va(M_GetText("You have been kicked\n(%s)\nPress ESC\n"), reason), NULL, MM_NOTHING); + else if (msg == KICK_MSG_CUSTOM_BAN) + M_StartMessage(va(M_GetText("You have been banned\n(%s)\nPress ESC\n"), reason), NULL, MM_NOTHING); + else + M_StartMessage(M_GetText("You have been kicked by the server\n\nPress ESC\n"), NULL, MM_NOTHING); + } + else if (keepbody) + { + if (server && !demoplayback && playernode[pnum] != UINT8_MAX) + { + INT32 node = playernode[pnum]; + playerpernode[node]--; + if (playerpernode[node] <= 0) + { + nodeingame[node] = false; + Net_CloseConnection(node); + ResetNode(node); + } + } + + playernode[pnum] = UINT8_MAX; + + players[pnum].quittime = 1; + } + else + CL_RemovePlayer(pnum, kickreason); +} + +static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; +consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL); + +consvar_t cv_allownewplayer = CVAR_INIT ("allowjoin", "On", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_joinnextround = CVAR_INIT ("joinnextround", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); /// \todo not done +static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}}; +consvar_t cv_maxplayers = CVAR_INIT ("maxplayers", "8", CV_SAVE|CV_NETVAR, maxplayers_cons_t, NULL); +static CV_PossibleValue_t joindelay_cons_t[] = {{1, "MIN"}, {3600, "MAX"}, {0, "Off"}, {0, NULL}}; +consvar_t cv_joindelay = CVAR_INIT ("joindelay", "10", CV_SAVE|CV_NETVAR, joindelay_cons_t, NULL); +static CV_PossibleValue_t rejointimeout_cons_t[] = {{1, "MIN"}, {60 * FRACUNIT, "MAX"}, {0, "Off"}, {0, NULL}}; +consvar_t cv_rejointimeout = CVAR_INIT ("rejointimeout", "2", CV_SAVE|CV_NETVAR|CV_FLOAT, rejointimeout_cons_t, NULL); + +static CV_PossibleValue_t resynchattempts_cons_t[] = {{1, "MIN"}, {20, "MAX"}, {0, "No"}, {0, NULL}}; +consvar_t cv_resynchattempts = CVAR_INIT ("resynchattempts", "10", CV_SAVE|CV_NETVAR, resynchattempts_cons_t, NULL); +consvar_t cv_blamecfail = CVAR_INIT ("blamecfail", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); + +// max file size to send to a player (in kilobytes) +static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {204800, "MAX"}, {0, NULL}}; +consvar_t cv_maxsend = CVAR_INIT ("maxsend", "4096", CV_SAVE|CV_NETVAR, maxsend_cons_t, NULL); +consvar_t cv_noticedownload = CVAR_INIT ("noticedownload", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); + +// Speed of file downloading (in packets per tic) +static CV_PossibleValue_t downloadspeed_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}}; +consvar_t cv_downloadspeed = CVAR_INIT ("downloadspeed", "16", CV_SAVE|CV_NETVAR, downloadspeed_cons_t, NULL); + +static void Got_AddPlayer(UINT8 **p, INT32 playernum); + +// called one time at init +void D_ClientServerInit(void) +{ + DEBFILE(va("- - -== SRB2 v%d.%.2d.%d "VERSIONSTRING" debugfile ==- - -\n", + VERSION/100, VERSION%100, SUBVERSION)); + +#ifndef NONET + COM_AddCommand("getplayernum", Command_GetPlayerNum); + COM_AddCommand("kick", Command_Kick); + COM_AddCommand("ban", Command_Ban); + COM_AddCommand("banip", Command_BanIP); + COM_AddCommand("clearbans", Command_ClearBans); + COM_AddCommand("showbanlist", Command_ShowBan); + COM_AddCommand("reloadbans", Command_ReloadBan); + COM_AddCommand("connect", Command_connect); + COM_AddCommand("nodes", Command_Nodes); + COM_AddCommand("resendgamestate", Command_ResendGamestate); +#ifdef PACKETDROP + COM_AddCommand("drop", Command_Drop); + COM_AddCommand("droprate", Command_Droprate); +#endif +#ifdef _DEBUG + COM_AddCommand("numnodes", Command_Numnodes); +#endif +#endif + + RegisterNetXCmd(XD_KICK, Got_KickCmd); + RegisterNetXCmd(XD_ADDPLAYER, Got_AddPlayer); +#ifndef NONET +#ifdef DUMPCONSISTENCY + CV_RegisterVar(&cv_dumpconsistency); +#endif + Ban_Load_File(false); +#endif + + gametic = 0; + localgametic = 0; + + // do not send anything before the real begin + SV_StopServer(); + SV_ResetServer(); + if (dedicated) + SV_SpawnServer(); +} + +static void ResetNode(INT32 node) +{ + nodeingame[node] = false; + nodewaiting[node] = 0; + + nettics[node] = gametic; + supposedtics[node] = gametic; + + nodetoplayer[node] = -1; + nodetoplayer2[node] = -1; + playerpernode[node] = 0; + + sendingsavegame[node] = false; + resendingsavegame[node] = false; + savegameresendcooldown[node] = 0; +} + +void SV_ResetServer(void) +{ + INT32 i; + + // +1 because this command will be executed in com_executebuffer in + // tryruntic so gametic will be incremented, anyway maketic > gametic + // is not an issue + + maketic = gametic + 1; + neededtic = maketic; + tictoclear = maketic; + + joindelay = 0; + + for (i = 0; i < MAXNETNODES; i++) + ResetNode(i); + + for (i = 0; i < MAXPLAYERS; i++) + { + LUA_InvalidatePlayer(&players[i]); + playeringame[i] = false; + playernode[i] = UINT8_MAX; + memset(playeraddress[i], 0, sizeof(*playeraddress)); + sprintf(player_names[i], "Player %d", i + 1); + adminplayers[i] = -1; // Populate the entire adminplayers array with -1. + } + + memset(player_name_changes, 0, sizeof player_name_changes); + + mynode = 0; + cl_packetmissed = false; + cl_redownloadinggamestate = false; + + if (dedicated) + { + nodeingame[0] = true; + serverplayer = 0; + } + else + serverplayer = consoleplayer; + + if (server) + servernode = 0; + + doomcom->numslots = 0; + + // clear server_context + memset(server_context, '-', 8); + + CV_RevertNetVars(); + + DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n"); +} + +static inline void SV_GenContext(void) +{ + UINT8 i; + // generate server_context, as exactly 8 bytes of randomly mixed A-Z and a-z + // (hopefully M_Random is initialized!! if not this will be awfully silly!) + for (i = 0; i < 8; i++) + { + const char a = M_RandomKey(26*2); + if (a < 26) // uppercase + server_context[i] = 'A'+a; + else // lowercase + server_context[i] = 'a'+(a-26); + } +} + +// +// D_QuitNetGame +// Called before quitting to leave a net game +// without hanging the other players +// +void D_QuitNetGame(void) +{ + mousegrabbedbylua = true; + I_UpdateMouseGrab(); + + if (!netgame || !netbuffer) + return; + + DEBFILE("===========================================================================\n" + " Quitting Game, closing connection\n" + "===========================================================================\n"); + + // abort send/receive of files + CloseNetFile(); + RemoveAllLuaFileTransfers(); + waitingforluafiletransfer = false; + waitingforluafilecommand = false; + + if (server) + { + INT32 i; + + netbuffer->packettype = PT_SERVERSHUTDOWN; + for (i = 0; i < MAXNETNODES; i++) + if (nodeingame[i]) + HSendPacket(i, true, 0, 0); +#ifdef MASTERSERVER + if (serverrunning && ms_RoomId > 0) + UnregisterServer(); +#endif + } + else if (servernode > 0 && servernode < MAXNETNODES && nodeingame[(UINT8)servernode]) + { + netbuffer->packettype = PT_CLIENTQUIT; + HSendPacket(servernode, true, 0, 0); + } + + D_CloseConnection(); + ClearAdminPlayers(); + + DEBFILE("===========================================================================\n" + " Log finish\n" + "===========================================================================\n"); +#ifdef DEBUGFILE + if (debugfile) + { + fclose(debugfile); + debugfile = NULL; + } +#endif +} + +// Adds a node to the game (player will follow at map change or at savegame....) +static inline void SV_AddNode(INT32 node) +{ + nettics[node] = gametic; + supposedtics[node] = gametic; + // little hack because the server connects to itself and puts + // nodeingame when connected not here + if (node) + nodeingame[node] = true; +} + +// Xcmd XD_ADDPLAYER +static void Got_AddPlayer(UINT8 **p, INT32 playernum) +{ + INT16 node, newplayernum; + boolean splitscreenplayer; + boolean rejoined; + player_t *newplayer; + + if (playernum != serverplayer && !IsPlayerAdmin(playernum)) + { + // protect against hacked/buggy client + CONS_Alert(CONS_WARNING, M_GetText("Illegal add player command received from %s\n"), player_names[playernum]); + if (server) + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + return; + } + + node = READUINT8(*p); + newplayernum = READUINT8(*p); + splitscreenplayer = newplayernum & 0x80; + newplayernum &= ~0x80; + + rejoined = playeringame[newplayernum]; + + if (!rejoined) + { + // Clear player before joining, lest some things get set incorrectly + // HACK: don't do this for splitscreen, it relies on preset values + if (!splitscreen && !botingame) + CL_ClearPlayer(newplayernum); + playeringame[newplayernum] = true; + G_AddPlayer(newplayernum); + if (newplayernum+1 > doomcom->numslots) + doomcom->numslots = (INT16)(newplayernum+1); + + if (server && I_GetNodeAddress) + { + const char *address = I_GetNodeAddress(node); + char *port = NULL; + if (address) // MI: fix msvcrt.dll!_mbscat crash? + { + strcpy(playeraddress[newplayernum], address); + port = strchr(playeraddress[newplayernum], ':'); + if (port) + *port = '\0'; + } + } + } + + newplayer = &players[newplayernum]; + + newplayer->jointime = 0; + newplayer->quittime = 0; + + READSTRINGN(*p, player_names[newplayernum], MAXPLAYERNAME); + + // the server is creating my player + if (node == mynode) + { + playernode[newplayernum] = 0; // for information only + if (!splitscreenplayer) + { + consoleplayer = newplayernum; + displayplayer = newplayernum; + secondarydisplayplayer = newplayernum; + DEBFILE("spawning me\n"); + ticcmd_oldangleturn[0] = newplayer->oldrelangleturn; + } + else + { + secondarydisplayplayer = newplayernum; + DEBFILE("spawning my brother\n"); + if (botingame) + newplayer->bot = 1; + ticcmd_oldangleturn[1] = newplayer->oldrelangleturn; + } + P_ForceLocalAngle(newplayer, (angle_t)(newplayer->angleturn << 16)); + D_SendPlayerConfig(); + addedtogame = true; + + if (rejoined) + { + if (newplayer->mo) + { + newplayer->viewheight = 41*newplayer->height/48; + + if (newplayer->mo->eflags & MFE_VERTICALFLIP) + newplayer->viewz = newplayer->mo->z + newplayer->mo->height - newplayer->viewheight; + else + newplayer->viewz = newplayer->mo->z + newplayer->viewheight; + } + + // wake up the status bar + ST_Start(); + // wake up the heads up text + HU_Start(); + + if (camera.chase && !splitscreenplayer) + P_ResetCamera(newplayer, &camera); + if (camera2.chase && splitscreenplayer) + P_ResetCamera(newplayer, &camera2); + } + } + + if (netgame) + { + char joinmsg[256]; + + if (rejoined) + strcpy(joinmsg, M_GetText("\x82*%s has rejoined the game (player %d)")); + else + strcpy(joinmsg, M_GetText("\x82*%s has joined the game (player %d)")); + strcpy(joinmsg, va(joinmsg, player_names[newplayernum], newplayernum)); + + // Merge join notification + IP to avoid clogging console/chat + if (server && cv_showjoinaddress.value && I_GetNodeAddress) + { + const char *address = I_GetNodeAddress(node); + if (address) + strcat(joinmsg, va(" (%s)", address)); + } + + HU_AddChatText(joinmsg, false); + } + + if (server && multiplayer && motd[0] != '\0') + COM_BufAddText(va("sayto %d %s\n", newplayernum, motd)); + + if (!rejoined) + LUA_HookInt(newplayernum, HOOK(PlayerJoin)); +} + +static boolean SV_AddWaitingPlayers(const char *name, const char *name2) +{ + INT32 node, n, newplayer = false; + UINT8 buf[2 + MAXPLAYERNAME]; + UINT8 *p; + INT32 newplayernum; + + for (node = 0; node < MAXNETNODES; node++) + { + // splitscreen can allow 2 player in one node + for (; nodewaiting[node] > 0; nodewaiting[node]--) + { + newplayer = true; + + newplayernum = FindRejoinerNum(node); + if (newplayernum == -1) + { + // search for a free playernum + // we can't use playeringame since it is not updated here + for (newplayernum = dedicated ? 1 : 0; newplayernum < MAXPLAYERS; newplayernum++) + { + if (playeringame[newplayernum]) + continue; + for (n = 0; n < MAXNETNODES; n++) + if (nodetoplayer[n] == newplayernum || nodetoplayer2[n] == newplayernum) + break; + if (n == MAXNETNODES) + break; + } + } + + // should never happen since we check the playernum + // before accepting the join + I_Assert(newplayernum < MAXPLAYERS); + + playernode[newplayernum] = (UINT8)node; + + p = buf + 2; + buf[0] = (UINT8)node; + buf[1] = newplayernum; + if (playerpernode[node] < 1) + { + nodetoplayer[node] = newplayernum; + WRITESTRINGN(p, name, MAXPLAYERNAME); + } + else + { + nodetoplayer2[node] = newplayernum; + buf[1] |= 0x80; + WRITESTRINGN(p, name2, MAXPLAYERNAME); + } + playerpernode[node]++; + + SendNetXCmd(XD_ADDPLAYER, &buf, p - buf); + + DEBFILE(va("Server added player %d node %d\n", newplayernum, node)); + } + } + + return newplayer; +} + +void CL_AddSplitscreenPlayer(void) +{ + if (cl_mode == CL_CONNECTED) + CL_SendJoin(); +} + +void CL_RemoveSplitscreenPlayer(void) +{ + if (cl_mode != CL_CONNECTED) + return; + + SendKick(secondarydisplayplayer, KICK_MSG_PLAYER_QUIT); +} + +// is there a game running +boolean Playing(void) +{ + return (server && serverrunning) || (client && cl_mode == CL_CONNECTED); +} + +boolean SV_SpawnServer(void) +{ + if (demoplayback) + G_StopDemo(); // reset engine parameter + if (metalplayback) + G_StopMetalDemo(); + + if (!serverrunning) + { + CONS_Printf(M_GetText("Starting Server....\n")); + serverrunning = true; + SV_ResetServer(); + SV_GenContext(); + if (netgame && I_NetOpenSocket) + { + I_NetOpenSocket(); +#ifdef MASTERSERVER + if (ms_RoomId > 0) + RegisterServer(); +#endif + } + + // non dedicated server just connect to itself + if (!dedicated) + CL_ConnectToServer(); + else doomcom->numslots = 1; + } + + return SV_AddWaitingPlayers(cv_playername.zstring, cv_playername2.zstring); +} + +void SV_StopServer(void) +{ + tic_t i; + + if (gamestate == GS_INTERMISSION) + Y_EndIntermission(); + gamestate = wipegamestate = GS_NULL; + + localtextcmd[0] = 0; + localtextcmd2[0] = 0; + + for (i = firstticstosend; i < firstticstosend + BACKUPTICS; i++) + D_Clearticcmd(i); + + consoleplayer = 0; + cl_mode = CL_SEARCHING; + maketic = gametic+1; + neededtic = maketic; + serverrunning = false; +} + +// called at singleplayer start and stopdemo +void SV_StartSinglePlayerServer(void) +{ + server = true; + netgame = false; + multiplayer = false; + G_SetGametype(GT_COOP); + + // no more tic the game with this settings! + SV_StopServer(); + + if (splitscreen) + multiplayer = true; +} + +static void SV_SendRefuse(INT32 node, const char *reason) +{ + strcpy(netbuffer->u.serverrefuse.reason, reason); + + netbuffer->packettype = PT_SERVERREFUSE; + HSendPacket(node, true, 0, strlen(netbuffer->u.serverrefuse.reason) + 1); + Net_CloseConnection(node); +} + +// used at txtcmds received to check packetsize bound +static size_t TotalTextCmdPerTic(tic_t tic) +{ + INT32 i; + size_t total = 1; // num of textcmds in the tic (ntextcmd byte) + + for (i = 0; i < MAXPLAYERS; i++) + { + UINT8 *textcmd = D_GetExistingTextcmd(tic, i); + if ((!i || playeringame[i]) && textcmd) + total += 2 + textcmd[0]; // "+2" for size and playernum + } + + return total; +} + +static const char * +ConnectionRefused (SINT8 node, INT32 rejoinernum) +{ + clientconfig_pak *cc = &netbuffer->u.clientcfg; + + boolean rejoining = (rejoinernum != -1); + + if (!node)/* server connecting to itself */ + return NULL; + + if ( + cc->modversion != MODVERSION || + strncmp(cc->application, SRB2APPLICATION, + sizeof cc->application) + ){ + return/* this is probably client's fault */ + "Incompatible."; + } + else if (bannednode && bannednode[node]) + { + return + "You have been banned\n" + "from the server."; + } + else if (cc->localplayers != 1) + { + return + "Wrong player count."; + } + + if (!rejoining) + { + if (!cv_allownewplayer.value) + { + return + "The server is not accepting\n" + "joins for the moment."; + } + else if (D_NumPlayers() >= cv_maxplayers.value) + { + return va( + "Maximum players reached: %d", + cv_maxplayers.value); + } + } + + if (luafiletransfers) + { + return + "The serveris broadcasting a file\n" + "requested by a Lua script.\n" + "Please wait a bit and then\n" + "try rejoining."; + } + + if (netgame) + { + const tic_t th = 2 * cv_joindelay.value * TICRATE; + + if (joindelay > th) + { + return va( + "Too many people are connecting.\n" + "Please wait %d seconds and then\n" + "try rejoining.", + (joindelay - th) / TICRATE); + } + } + + return NULL; +} + +/** Called when a PT_CLIENTJOIN packet is received + * + * \param node The packet sender + * + */ +static void HandleConnect(SINT8 node) +{ + char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1]; + INT32 rejoinernum; + INT32 i; + const char *refuse; + + rejoinernum = FindRejoinerNum(node); + + refuse = ConnectionRefused(node, rejoinernum); + + if (refuse) + SV_SendRefuse(node, refuse); + else + { +#ifndef NONET + boolean newnode = false; +#endif + + for (i = 0; i < netbuffer->u.clientcfg.localplayers - playerpernode[node]; i++) + { + strlcpy(names[i], netbuffer->u.clientcfg.names[i], MAXPLAYERNAME + 1); + if (!EnsurePlayerNameIsGood(names[i], rejoinernum)) + { + SV_SendRefuse(node, "Bad player name"); + return; + } + } + + // client authorised to join + nodewaiting[node] = (UINT8)(netbuffer->u.clientcfg.localplayers - playerpernode[node]); + if (!nodeingame[node]) + { + gamestate_t backupstate = gamestate; +#ifndef NONET + newnode = true; +#endif + SV_AddNode(node); + + if (cv_joinnextround.value && gameaction == ga_nothing) + G_SetGamestate(GS_WAITINGPLAYERS); + if (!SV_SendServerConfig(node)) + { + G_SetGamestate(backupstate); + /// \note Shouldn't SV_SendRefuse be called before ResetNode? + ResetNode(node); + SV_SendRefuse(node, M_GetText("Server couldn't send info, please try again")); + /// \todo fix this !!! + return; // restart the while + } + //if (gamestate != GS_LEVEL) // GS_INTERMISSION, etc? + // SV_SendPlayerConfigs(node); // send bare minimum player info + G_SetGamestate(backupstate); + DEBFILE("new node joined\n"); + } +#ifndef NONET + if (nodewaiting[node]) + { + if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) && newnode) + { + SV_SendSaveGame(node, false); // send a complete game state + DEBFILE("send savegame\n"); + } + SV_AddWaitingPlayers(names[0], names[1]); + joindelay += cv_joindelay.value * TICRATE; + player_joining = true; + } +#endif + } +} + +/** Called when a PT_SERVERSHUTDOWN packet is received + * + * \param node The packet sender (should be the server) + * + */ +static void HandleShutdown(SINT8 node) +{ + (void)node; + LUA_HookBool(false, HOOK(GameQuit)); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText("Server has shutdown\n\nPress Esc\n"), NULL, MM_NOTHING); +} + +/** Called when a PT_NODETIMEOUT packet is received + * + * \param node The packet sender (should be the server) + * + */ +static void HandleTimeout(SINT8 node) +{ + (void)node; + LUA_HookBool(false, HOOK(GameQuit)); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText("Server Timeout\n\nPress Esc\n"), NULL, MM_NOTHING); +} + +#ifndef NONET +/** Called when a PT_SERVERINFO packet is received + * + * \param node The packet sender + * \note What happens if the packet comes from a client or something like that? + * + */ +static void HandleServerInfo(SINT8 node) +{ + // compute ping in ms + const tic_t ticnow = I_GetTime(); + const tic_t ticthen = (tic_t)LONG(netbuffer->u.serverinfo.time); + const tic_t ticdiff = (ticnow - ticthen)*1000/NEWTICRATE; + netbuffer->u.serverinfo.time = (tic_t)LONG(ticdiff); + netbuffer->u.serverinfo.servername[MAXSERVERNAME-1] = 0; + netbuffer->u.serverinfo.application + [sizeof netbuffer->u.serverinfo.application - 1] = '\0'; + netbuffer->u.serverinfo.gametypename + [sizeof netbuffer->u.serverinfo.gametypename - 1] = '\0'; + + SL_InsertServer(&netbuffer->u.serverinfo, node); +} +#endif + +static void PT_WillResendGamestate(void) +{ +#ifndef NONET + char tmpsave[256]; + + if (server || cl_redownloadinggamestate) + return; + + // Send back a PT_CANRECEIVEGAMESTATE packet to the server + // so they know they can start sending the game state + netbuffer->packettype = PT_CANRECEIVEGAMESTATE; + if (!HSendPacket(servernode, true, 0, 0)) + return; + + CONS_Printf(M_GetText("Reloading game state...\n")); + + sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); + + // Don't get a corrupt savegame error because tmpsave already exists + if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1) + I_Error("Can't delete %s\n", tmpsave); + + CL_PrepareDownloadSaveGame(tmpsave); + + cl_redownloadinggamestate = true; +#endif +} + +static void PT_CanReceiveGamestate(SINT8 node) +{ +#ifndef NONET + if (client || sendingsavegame[node]) + return; + + CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[nodetoplayer[node]]); + + SV_SendSaveGame(node, true); // Resend a complete game state + resendingsavegame[node] = true; +#else + (void)node; +#endif +} + +/** Handles a packet received from a node that isn't in game + * + * \param node The packet sender + * \todo Choose a better name, as the packet can also come from the server apparently? + * \sa HandlePacketFromPlayer + * \sa GetPackets + * + */ +static void HandlePacketFromAwayNode(SINT8 node) +{ + if (node != servernode) + DEBFILE(va("Received packet from unknown host %d\n", node)); + +// macro for packets that should only be sent by the server +// if it is NOT from the server, bail out and close the connection! +#define SERVERONLY \ + if (node != servernode) \ + { \ + Net_CloseConnection(node); \ + break; \ + } + switch (netbuffer->packettype) + { + case PT_ASKINFOVIAMS: + Net_CloseConnection(node); + break; + + case PT_TELLFILESNEEDED: + if (server && serverrunning) + { + UINT8 *p; + INT32 firstfile = netbuffer->u.filesneedednum; + + netbuffer->packettype = PT_MOREFILESNEEDED; + netbuffer->u.filesneededcfg.first = firstfile; + netbuffer->u.filesneededcfg.more = 0; + + p = PutFileNeeded(firstfile); + + HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); + } + else // Shouldn't get this if you aren't the server...? + Net_CloseConnection(node); + break; + + case PT_MOREFILESNEEDED: + if (server && serverrunning) + { // But wait I thought I'm the server? + Net_CloseConnection(node); + break; + } + SERVERONLY + if (cl_mode == CL_ASKFULLFILELIST && netbuffer->u.filesneededcfg.first == fileneedednum) + { + D_ParseFileneeded(netbuffer->u.filesneededcfg.num, netbuffer->u.filesneededcfg.files, netbuffer->u.filesneededcfg.first); + if (!netbuffer->u.filesneededcfg.more) + cl_lastcheckedfilecount = UINT16_MAX; // Got the whole file list + } + break; + + case PT_ASKINFO: + if (server && serverrunning) + { + SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time)); + SV_SendPlayerInfo(node); // Send extra info + } + Net_CloseConnection(node); + break; + + case PT_SERVERREFUSE: // Negative response of client join request + if (server && serverrunning) + { // But wait I thought I'm the server? + Net_CloseConnection(node); + break; + } + SERVERONLY + if (cl_mode == CL_WAITJOINRESPONSE) + { + // Save the reason so it can be displayed after quitting the netgame + char *reason = strdup(netbuffer->u.serverrefuse.reason); + if (!reason) + I_Error("Out of memory!\n"); + + if (strstr(reason, "Maximum players reached")) + { + serverisfull = true; + //Special timeout for when refusing due to player cap. The client will wait 3 seconds between join requests when waiting for a slot, so we need this to be much longer + //We set it back to the value of cv_nettimeout.value in CL_Reset + connectiontimeout = NEWTICRATE*7; + cl_mode = CL_ASKJOIN; + free(reason); + break; + } + + M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"), + reason), NULL, MM_NOTHING); + + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + + free(reason); + + // Will be reset by caller. Signals refusal. + cl_mode = CL_ABORTED; + } + break; + + case PT_SERVERCFG: // Positive response of client join request + { + if (server && serverrunning && node != servernode) + { // but wait I thought I'm the server? + Net_CloseConnection(node); + break; + } + SERVERONLY + /// \note how would this happen? and is it doing the right thing if it does? + if (cl_mode != CL_WAITJOINRESPONSE) + break; + + if (client) + { + maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); + G_SetGametype(netbuffer->u.servercfg.gametype); + modifiedgame = netbuffer->u.servercfg.modifiedgame; + memcpy(server_context, netbuffer->u.servercfg.server_context, 8); + } + + nodeingame[(UINT8)servernode] = true; + serverplayer = netbuffer->u.servercfg.serverplayer; + doomcom->numslots = SHORT(netbuffer->u.servercfg.totalslotnum); + mynode = netbuffer->u.servercfg.clientnode; + if (serverplayer >= 0) + playernode[(UINT8)serverplayer] = servernode; + + if (netgame) +#ifndef NONET + CONS_Printf(M_GetText("Join accepted, waiting for complete game state...\n")); +#else + CONS_Printf(M_GetText("Join accepted, waiting for next level change...\n")); +#endif + DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode)); + +#ifndef NONET + /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? + /// Shouldn't them be downloaded even at intermission time? + /// Also, according to HandleConnect, the server will send the savegame even during intermission... + if (netbuffer->u.servercfg.gamestate == GS_LEVEL/* || + netbuffer->u.servercfg.gamestate == GS_INTERMISSION*/) + cl_mode = CL_DOWNLOADSAVEGAME; + else +#endif + cl_mode = CL_CONNECTED; + break; + } + + // Handled in d_netfil.c + case PT_FILEFRAGMENT: + if (server) + { // But wait I thought I'm the server? + Net_CloseConnection(node); + break; + } + SERVERONLY + PT_FileFragment(); + break; + + case PT_FILEACK: + if (server) + PT_FileAck(); + break; + + case PT_FILERECEIVED: + if (server) + PT_FileReceived(); + break; + + case PT_REQUESTFILE: + if (server) + { + if (!cv_downloading.value || !PT_RequestFile(node)) + Net_CloseConnection(node); // close connection if one of the requested files could not be sent, or you disabled downloading anyway + } + else + Net_CloseConnection(node); // nope + break; + + case PT_NODETIMEOUT: + case PT_CLIENTQUIT: + if (server) + Net_CloseConnection(node); + break; + + case PT_CLIENTCMD: + break; // This is not an "unknown packet" + + case PT_SERVERTICS: + // Do not remove my own server (we have just get a out of order packet) + if (node == servernode) + break; + /* FALLTHRU */ + + default: + DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype)); + Net_CloseConnection(node); + break; // Ignore it + + } +#undef SERVERONLY +} + +/** Handles a packet received from a node that is in game + * + * \param node The packet sender + * \todo Choose a better name + * \sa HandlePacketFromAwayNode + * \sa GetPackets + * + */ +static void HandlePacketFromPlayer(SINT8 node) +{ + INT32 netconsole; + tic_t realend, realstart; + UINT8 *pak, *txtpak, numtxtpak; +#ifndef NOMD5 + UINT8 finalmd5[16];/* Well, it's the cool thing to do? */ +#endif + + txtpak = NULL; + + if (dedicated && node == 0) + netconsole = 0; + else + netconsole = nodetoplayer[node]; +#ifdef PARANOIA + if (netconsole >= MAXPLAYERS) + I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole); +#endif + + switch (netbuffer->packettype) + { +// -------------------------------------------- SERVER RECEIVE ---------- + case PT_CLIENTCMD: + case PT_CLIENT2CMD: + case PT_CLIENTMIS: + case PT_CLIENT2MIS: + case PT_NODEKEEPALIVE: + case PT_NODEKEEPALIVEMIS: + if (client) + break; + + // To save bytes, only the low byte of tic numbers are sent + // Use ExpandTics to figure out what the rest of the bytes are + realstart = ExpandTics(netbuffer->u.clientpak.client_tic, node); + realend = ExpandTics(netbuffer->u.clientpak.resendfrom, node); + + if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS + || netbuffer->packettype == PT_NODEKEEPALIVEMIS + || supposedtics[node] < realend) + { + supposedtics[node] = realend; + } + // Discard out of order packet + if (nettics[node] > realend) + { + DEBFILE(va("out of order ticcmd discarded nettics = %u\n", nettics[node])); + break; + } + + // Update the nettics + nettics[node] = realend; + + // Don't do anything for packets of type NODEKEEPALIVE? + if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE + || netbuffer->packettype == PT_NODEKEEPALIVEMIS) + break; + + // As long as clients send valid ticcmds, the server can keep running, so reset the timeout + /// \todo Use a separate cvar for that kind of timeout? + freezetimeout[node] = I_GetTime() + connectiontimeout; + + // Copy ticcmd + G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); + + // Check ticcmd for "speed hacks" + if (netcmds[maketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE + || netcmds[maketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].sidemove < -MAXPLMOVE) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), netconsole); + //D_Clearticcmd(k); + + SendKick(netconsole, KICK_MSG_CON_FAIL); + break; + } + + // Splitscreen cmd + if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) + && nodetoplayer2[node] >= 0) + G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], + &netbuffer->u.client2pak.cmd2, 1); + + // Check player consistancy during the level + if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL + && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) +#ifndef NONET + && !SV_ResendingSavegameToAnyone() +#endif + && !resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime()) + { + if (cv_resynchattempts.value) + { + // Tell the client we are about to resend them the gamestate + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + HSendPacket(node, true, 0, 0); + + resendingsavegame[node] = true; + + if (cv_blamecfail.value) + CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), + netconsole+1, player_names[netconsole], + consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy)); + DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", + netconsole, realstart, consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy))); + break; + } + else + { + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", + netconsole, realstart, consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy))); + break; + } + } + break; + case PT_TEXTCMD2: // splitscreen special + netconsole = nodetoplayer2[node]; + /* FALLTHRU */ + case PT_TEXTCMD: + if (client) + break; + + if (netconsole < 0 || netconsole >= MAXPLAYERS) + Net_UnAcknowledgePacket(node); + else + { + size_t j; + tic_t tic = maketic; + UINT8 *textcmd; + + // ignore if the textcmd has a reported size of zero + // this shouldn't be sent at all + if (!netbuffer->u.textcmd[0]) + { + DEBFILE(va("GetPacket: Textcmd with size 0 detected! (node %u, player %d)\n", + node, netconsole)); + Net_UnAcknowledgePacket(node); + break; + } + + // ignore if the textcmd size var is actually larger than it should be + // BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength + if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1) + { + DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n", + netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1), + node, netconsole)); + Net_UnAcknowledgePacket(node); + break; + } + + // check if tic that we are making isn't too large else we cannot send it :( + // doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time + j = software_MAXPACKETLENGTH + - (netbuffer->u.textcmd[0]+2+BASESERVERTICSSIZE + + (doomcom->numslots+1)*sizeof(ticcmd_t)); + + // search a tic that have enougth space in the ticcmd + while ((textcmd = D_GetExistingTextcmd(tic, netconsole)), + (TotalTextCmdPerTic(tic) > j || netbuffer->u.textcmd[0] + (textcmd ? textcmd[0] : 0) > MAXTEXTCMD) + && tic < firstticstosend + BACKUPTICS) + tic++; + + if (tic >= firstticstosend + BACKUPTICS) + { + DEBFILE(va("GetPacket: Textcmd too long (max %s, used %s, mak %d, " + "tosend %u, node %u, player %d)\n", sizeu1(j), sizeu2(TotalTextCmdPerTic(maketic)), + maketic, firstticstosend, node, netconsole)); + Net_UnAcknowledgePacket(node); + break; + } + + // Make sure we have a buffer + if (!textcmd) textcmd = D_GetTextcmd(tic, netconsole); + + DEBFILE(va("textcmd put in tic %u at position %d (player %d) ftts %u mk %u\n", + tic, textcmd[0]+1, netconsole, firstticstosend, maketic)); + + M_Memcpy(&textcmd[textcmd[0]+1], netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]); + textcmd[0] += (UINT8)netbuffer->u.textcmd[0]; + } + break; + case PT_LOGIN: + if (client) + break; + +#ifndef NOMD5 + if (doomcom->datalength < 16)/* ignore partial sends */ + break; + + if (!adminpasswordset) + { + CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[netconsole]); + break; + } + + // Do the final pass to compare with the sent md5 + D_MD5PasswordPass(adminpassmd5, 16, va("PNUM%02d", netconsole), &finalmd5); + + if (!memcmp(netbuffer->u.md5sum, finalmd5, 16)) + { + CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[netconsole]); + COM_BufInsertText(va("promote %d\n", netconsole)); // do this immediately + } + else + CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[netconsole]); +#endif + break; + case PT_NODETIMEOUT: + case PT_CLIENTQUIT: + if (client) + break; + + // nodeingame will be put false in the execution of kick command + // this allow to send some packets to the quitting client to have their ack back + nodewaiting[node] = 0; + if (netconsole != -1 && playeringame[netconsole]) + { + UINT8 kickmsg; + + if (netbuffer->packettype == PT_NODETIMEOUT) + kickmsg = KICK_MSG_TIMEOUT; + else + kickmsg = KICK_MSG_PLAYER_QUIT; + kickmsg |= KICK_MSG_KEEP_BODY; + + SendKick(netconsole, kickmsg); + nodetoplayer[node] = -1; + + if (nodetoplayer2[node] != -1 && nodetoplayer2[node] >= 0 + && playeringame[(UINT8)nodetoplayer2[node]]) + { + SendKick(nodetoplayer2[node], kickmsg); + nodetoplayer2[node] = -1; + } + } + Net_CloseConnection(node); + nodeingame[node] = false; + break; + case PT_CANRECEIVEGAMESTATE: + PT_CanReceiveGamestate(node); + break; + case PT_ASKLUAFILE: + if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_ASKED) + AddLuaFileToSendQueue(node, luafiletransfers->realfilename); + break; + case PT_HASLUAFILE: + if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_SENDING) + SV_HandleLuaFileSent(node); + break; + case PT_RECEIVEDGAMESTATE: + sendingsavegame[node] = false; + resendingsavegame[node] = false; + savegameresendcooldown[node] = I_GetTime() + 5 * TICRATE; + break; +// -------------------------------------------- CLIENT RECEIVE ---------- + case PT_SERVERTICS: + // Only accept PT_SERVERTICS from the server. + if (node != servernode) + { + CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_SERVERTICS", node); + if (server) + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + break; + } + + realstart = netbuffer->u.serverpak.starttic; + realend = realstart + netbuffer->u.serverpak.numtics; + + if (!txtpak) + txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots + * netbuffer->u.serverpak.numtics]; + + if (realend > gametic + CLIENTBACKUPTICS) + realend = gametic + CLIENTBACKUPTICS; + cl_packetmissed = realstart > neededtic; + + if (realstart <= neededtic && realend > neededtic) + { + tic_t i, j; + pak = (UINT8 *)&netbuffer->u.serverpak.cmds; + + for (i = realstart; i < realend; i++) + { + // clear first + D_Clearticcmd(i); + + // copy the tics + pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak, + netbuffer->u.serverpak.numslots*sizeof (ticcmd_t)); + + // copy the textcmds + numtxtpak = *txtpak++; + for (j = 0; j < numtxtpak; j++) + { + INT32 k = *txtpak++; // playernum + const size_t txtsize = txtpak[0]+1; + + if (i >= gametic) // Don't copy old net commands + M_Memcpy(D_GetTextcmd(i, k), txtpak, txtsize); + txtpak += txtsize; + } + } + + neededtic = realend; + } + else + { + DEBFILE(va("frame not in bound: %u\n", neededtic)); + /*if (realend < neededtic - 2 * TICRATE || neededtic + 2 * TICRATE < realstart) + I_Error("Received an out of order PT_SERVERTICS packet!\n" + "Got tics %d-%d, needed tic %d\n\n" + "Please report this crash on the Master Board,\n" + "IRC or Discord so it can be fixed.\n", (INT32)realstart, (INT32)realend, (INT32)neededtic);*/ + } + break; + case PT_PING: + // Only accept PT_PING from the server. + if (node != servernode) + { + CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_PING", node); + if (server) + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + break; + } + + //Update client ping table from the server. + if (client) + { + UINT8 i; + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i]) + playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i]; + + servermaxping = (tic_t)netbuffer->u.pingtable[MAXPLAYERS]; + } + + break; + case PT_SERVERCFG: + break; + case PT_FILEFRAGMENT: + // Only accept PT_FILEFRAGMENT from the server. + if (node != servernode) + { + CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_FILEFRAGMENT", node); + if (server) + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + break; + } + if (client) + PT_FileFragment(); + break; + case PT_FILEACK: + if (server) + PT_FileAck(); + break; + case PT_FILERECEIVED: + if (server) + PT_FileReceived(); + break; + case PT_WILLRESENDGAMESTATE: + PT_WillResendGamestate(); + break; + case PT_SENDINGLUAFILE: + if (client) + CL_PrepareDownloadLuaFile(); + break; + default: + DEBFILE(va("UNKNOWN PACKET TYPE RECEIVED %d from host %d\n", + netbuffer->packettype, node)); + } // end switch +} + +/** Handles all received packets, if any + * + * \todo Add details to this description (lol) + * + */ +static void GetPackets(void) +{ + SINT8 node; // The packet sender + + player_joining = false; + + while (HGetPacket()) + { + node = (SINT8)doomcom->remotenode; + + if (netbuffer->packettype == PT_CLIENTJOIN && server) + { + HandleConnect(node); + continue; + } + if (node == servernode && client && cl_mode != CL_SEARCHING) + { + if (netbuffer->packettype == PT_SERVERSHUTDOWN) + { + HandleShutdown(node); + continue; + } + if (netbuffer->packettype == PT_NODETIMEOUT) + { + HandleTimeout(node); + continue; + } + } + +#ifndef NONET + if (netbuffer->packettype == PT_SERVERINFO) + { + HandleServerInfo(node); + continue; + } +#endif + + if (netbuffer->packettype == PT_PLAYERINFO) + continue; // We do nothing with PLAYERINFO, that's for the MS browser. + + // Packet received from someone already playing + if (nodeingame[node]) + HandlePacketFromPlayer(node); + // Packet received from someone not playing + else + HandlePacketFromAwayNode(node); + } +} + +// +// NetUpdate +// Builds ticcmds for console player, +// sends out a packet +// +// no more use random generator, because at very first tic isn't yet synchronized +// Note: It is called consistAncy on purpose. +// +static INT16 Consistancy(void) +{ + INT32 i; + UINT32 ret = 0; +#ifdef MOBJCONSISTANCY + thinker_t *th; + mobj_t *mo; +#endif + + DEBFILE(va("TIC %u ", gametic)); + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + ret ^= 0xCCCC; + else if (!players[i].mo); + else + { + ret += players[i].mo->x; + ret -= players[i].mo->y; + ret += players[i].powers[pw_shield]; + ret *= i+1; + } + } + // I give up + // Coop desynching enemies is painful + if (!G_PlatformGametype()) + ret += P_GetRandSeed(); + +#ifdef MOBJCONSISTANCY + if (gamestate == GS_LEVEL) + { + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + { + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + continue; + + mo = (mobj_t *)th; + + if (mo->flags & (MF_SPECIAL | MF_SOLID | MF_PUSHABLE | MF_BOSS | MF_MISSILE | MF_SPRING | MF_MONITOR | MF_FIRE | MF_ENEMY | MF_PAIN | MF_STICKY)) + { + ret -= mo->type; + ret += mo->x; + ret -= mo->y; + ret += mo->z; + ret -= mo->momx; + ret += mo->momy; + ret -= mo->momz; + ret += mo->angle; + ret -= mo->flags; + ret += mo->flags2; + ret -= mo->eflags; + if (mo->target) + { + ret += mo->target->type; + ret -= mo->target->x; + ret += mo->target->y; + ret -= mo->target->z; + ret += mo->target->momx; + ret -= mo->target->momy; + ret += mo->target->momz; + ret -= mo->target->angle; + ret += mo->target->flags; + ret -= mo->target->flags2; + ret += mo->target->eflags; + ret -= mo->target->state - states; + ret += mo->target->tics; + ret -= mo->target->sprite; + ret += mo->target->frame; + } + else + ret ^= 0x3333; + if (mo->tracer && mo->tracer->type != MT_OVERLAY) + { + ret += mo->tracer->type; + ret -= mo->tracer->x; + ret += mo->tracer->y; + ret -= mo->tracer->z; + ret += mo->tracer->momx; + ret -= mo->tracer->momy; + ret += mo->tracer->momz; + ret -= mo->tracer->angle; + ret += mo->tracer->flags; + ret -= mo->tracer->flags2; + ret += mo->tracer->eflags; + ret -= mo->tracer->state - states; + ret += mo->tracer->tics; + ret -= mo->tracer->sprite; + ret += mo->tracer->frame; + } + else + ret ^= 0xAAAA; + ret -= mo->state - states; + ret += mo->tics; + ret -= mo->sprite; + ret += mo->frame; + } + } + } +#endif + + DEBFILE(va("Consistancy = %u\n", (ret & 0xFFFF))); + + return (INT16)(ret & 0xFFFF); +} + +// send the client packet to the server +static void CL_SendClientCmd(void) +{ + size_t packetsize = 0; + + netbuffer->packettype = PT_CLIENTCMD; + + if (cl_packetmissed) + netbuffer->packettype++; + netbuffer->u.clientpak.resendfrom = (UINT8)(neededtic & UINT8_MAX); + netbuffer->u.clientpak.client_tic = (UINT8)(gametic & UINT8_MAX); + + if (gamestate == GS_WAITINGPLAYERS) + { + // Send PT_NODEKEEPALIVE packet + netbuffer->packettype += 4; + packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16); + HSendPacket(servernode, false, 0, packetsize); + } + else if (gamestate != GS_NULL && (addedtogame || dedicated)) + { + G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1); + netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]); + + // Send a special packet with 2 cmd for splitscreen + if (splitscreen || botingame) + { + netbuffer->packettype += 2; + G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1); + packetsize = sizeof (client2cmd_pak); + } + else + packetsize = sizeof (clientcmd_pak); + + HSendPacket(servernode, false, 0, packetsize); + } + + if (cl_mode == CL_CONNECTED || dedicated) + { + // Send extra data if needed + if (localtextcmd[0]) + { + netbuffer->packettype = PT_TEXTCMD; + M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1); + // All extra data have been sent + if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail... + localtextcmd[0] = 0; + } + + // Send extra data if needed for player 2 (splitscreen) + if (localtextcmd2[0]) + { + netbuffer->packettype = PT_TEXTCMD2; + M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1); + // All extra data have been sent + if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail... + localtextcmd2[0] = 0; + } + } +} + +// send the server packet +// send tic from firstticstosend to maketic-1 +static void SV_SendTics(void) +{ + tic_t realfirsttic, lasttictosend, i; + UINT32 n; + INT32 j; + size_t packsize; + UINT8 *bufpos; + UINT8 *ntextcmd; + + // send to all client but not to me + // for each node create a packet with x tics and send it + // x is computed using supposedtics[n], max packet size and maketic + for (n = 1; n < MAXNETNODES; n++) + if (nodeingame[n]) + { + // assert supposedtics[n]>=nettics[n] + realfirsttic = supposedtics[n]; + lasttictosend = min(maketic, nettics[n] + CLIENTBACKUPTICS); + + if (realfirsttic >= lasttictosend) + { + // well we have sent all tics we will so use extrabandwidth + // to resent packet that are supposed lost (this is necessary since lost + // packet detection work when we have received packet with firsttic > neededtic + // (getpacket servertics case) + DEBFILE(va("Nothing to send node %u mak=%u sup=%u net=%u \n", + n, maketic, supposedtics[n], nettics[n])); + realfirsttic = nettics[n]; + if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3) + // all tic are ok + continue; + DEBFILE(va("Sent %d anyway\n", realfirsttic)); + } + if (realfirsttic < firstticstosend) + realfirsttic = firstticstosend; + + // compute the length of the packet and cut it if too large + packsize = BASESERVERTICSSIZE; + for (i = realfirsttic; i < lasttictosend; i++) + { + packsize += sizeof (ticcmd_t) * doomcom->numslots; + packsize += TotalTextCmdPerTic(i); + + if (packsize > software_MAXPACKETLENGTH) + { + DEBFILE(va("packet too large (%s) at tic %d (should be from %d to %d)\n", + sizeu1(packsize), i, realfirsttic, lasttictosend)); + lasttictosend = i; + + // too bad: too much player have send extradata and there is too + // much data in one tic. + // To avoid it put the data on the next tic. (see getpacket + // textcmd case) but when numplayer changes the computation can be different + if (lasttictosend == realfirsttic) + { + if (packsize > MAXPACKETLENGTH) + I_Error("Too many players: can't send %s data for %d players to node %d\n" + "Well sorry nobody is perfect....\n", + sizeu1(packsize), doomcom->numslots, n); + else + { + lasttictosend++; // send it anyway! + DEBFILE("sending it anyway\n"); + } + } + break; + } + } + + // Send the tics + netbuffer->packettype = PT_SERVERTICS; + netbuffer->u.serverpak.starttic = realfirsttic; + netbuffer->u.serverpak.numtics = (UINT8)(lasttictosend - realfirsttic); + netbuffer->u.serverpak.numslots = (UINT8)SHORT(doomcom->numslots); + bufpos = (UINT8 *)&netbuffer->u.serverpak.cmds; + + for (i = realfirsttic; i < lasttictosend; i++) + { + bufpos = G_DcpyTiccmd(bufpos, netcmds[i%BACKUPTICS], doomcom->numslots * sizeof (ticcmd_t)); + } + + // add textcmds + for (i = realfirsttic; i < lasttictosend; i++) + { + ntextcmd = bufpos++; + *ntextcmd = 0; + for (j = 0; j < MAXPLAYERS; j++) + { + UINT8 *textcmd = D_GetExistingTextcmd(i, j); + INT32 size = textcmd ? textcmd[0] : 0; + + if ((!j || playeringame[j]) && size) + { + (*ntextcmd)++; + WRITEUINT8(bufpos, j); + M_Memcpy(bufpos, textcmd, size + 1); + bufpos += size + 1; + } + } + } + packsize = bufpos - (UINT8 *)&(netbuffer->u); + + HSendPacket(n, false, 0, packsize); + // when tic are too large, only one tic is sent so don't go backward! + if (lasttictosend-doomcom->extratics > realfirsttic) + supposedtics[n] = lasttictosend-doomcom->extratics; + else + supposedtics[n] = lasttictosend; + if (supposedtics[n] < nettics[n]) supposedtics[n] = nettics[n]; + } + // node 0 is me! + supposedtics[0] = maketic; +} + +// +// TryRunTics +// +static void Local_Maketic(INT32 realtics) +{ + I_OsPolling(); // I_Getevent + D_ProcessEvents(); // menu responder, cons responder, + // game responder calls HU_Responder, AM_Responder, + // and G_MapEventsToControls + if (!dedicated) rendergametic = gametic; + // translate inputs (keyboard/mouse/gamepad) into game controls + G_BuildTiccmd(&localcmds, realtics, 1); + if (splitscreen || botingame) + G_BuildTiccmd(&localcmds2, realtics, 2); + + localcmds.angleturn |= TICCMD_RECEIVED; + localcmds2.angleturn |= TICCMD_RECEIVED; +} + +// create missed tic +static void SV_Maketic(void) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + // We didn't receive this tic + if ((netcmds[maketic % BACKUPTICS][i].angleturn & TICCMD_RECEIVED) == 0) + { + ticcmd_t * ticcmd = &netcmds[(maketic ) % BACKUPTICS][i]; + ticcmd_t *prevticcmd = &netcmds[(maketic - 1) % BACKUPTICS][i]; + + if (players[i].quittime) + { + // Copy the angle/aiming from the previous tic + // and empty the other inputs + memset(ticcmd, 0, sizeof(netcmds[0][0])); + ticcmd->angleturn = prevticcmd->angleturn | TICCMD_RECEIVED; + ticcmd->aiming = prevticcmd->aiming; + } + else + { + DEBFILE(va("MISS tic%4d for player %d\n", maketic, i)); + // Copy the input from the previous tic + *ticcmd = *prevticcmd; + ticcmd->angleturn &= ~TICCMD_RECEIVED; + } + } + } + + // all tic are now proceed make the next + maketic++; +} + +boolean TryRunTics(tic_t realtics) +{ + boolean ticking; + + // the machine has lagged but it is not so bad + if (realtics > TICRATE/7) // FIXME: consistency failure!! + { + if (server) + realtics = 1; + else + realtics = TICRATE/7; + } + + if (singletics) + realtics = 1; + + if (realtics >= 1) + { + COM_BufTicker(); + if (mapchangepending) + D_MapChange(-1, 0, ultimatemode, false, 2, false, fromlevelselect); // finish the map change + } + + NetUpdate(); + + if (demoplayback) + { + neededtic = gametic + realtics; + // start a game after a demo + maketic += realtics; + firstticstosend = maketic; + tictoclear = firstticstosend; + } + + GetPackets(); + +#ifdef DEBUGFILE + if (debugfile && (realtics || neededtic > gametic)) + { + //SoM: 3/30/2000: Need long INT32 in the format string for args 4 & 5. + //Shut up stupid warning! + fprintf(debugfile, "------------ Tryruntic: REAL:%d NEED:%d GAME:%d LOAD: %d\n", + realtics, neededtic, gametic, debugload); + debugload = 100000; + } +#endif + + ticking = neededtic > gametic; + + if (ticking) + { + if (realtics) + hu_stopped = false; + } + + if (player_joining) + { + if (realtics) + hu_stopped = true; + return false; + } + + if (ticking) + { + if (advancedemo) + { + if (timedemo_quit) + COM_ImmedExecute("quit"); + else + D_StartTitle(); + } + else + // run the count * tics + while (neededtic > gametic) + { + boolean update_stats = !(paused || P_AutoPause()); + + DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic)); + + if (update_stats) + PS_START_TIMING(ps_tictime); + + G_Ticker((gametic % NEWTICRATERATIO) == 0); + ExtraDataTicker(); + gametic++; + consistancy[gametic%BACKUPTICS] = Consistancy(); + + if (update_stats) + { + PS_STOP_TIMING(ps_tictime); + PS_UpdateTickStats(); + } + + // Leave a certain amount of tics present in the net buffer as long as we've ran at least one tic this frame. + if (client && gamestate == GS_LEVEL && leveltime > 3 && neededtic <= gametic + cv_netticbuffer.value) + break; + } + } + else + { + if (realtics) + hu_stopped = true; + } + + return ticking; +} + +/* +Ping Update except better: +We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out. +If they're not lagging, decrement the timer by 1. Of course, reset all of this if they leave. +*/ + +static INT32 pingtimeout[MAXPLAYERS]; + +static inline void PingUpdate(void) +{ + INT32 i; + boolean laggers[MAXPLAYERS]; + UINT8 numlaggers = 0; + memset(laggers, 0, sizeof(boolean) * MAXPLAYERS); + + netbuffer->packettype = PT_PING; + + //check for ping limit breakage. + if (cv_maxping.value) + { + for (i = 1; i < MAXPLAYERS; i++) + { + if (playeringame[i] && !players[i].quittime + && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value)) + { + if (players[i].jointime > 30 * TICRATE) + laggers[i] = true; + numlaggers++; + } + else + pingtimeout[i] = 0; + } + + //kick lagging players... unless everyone but the server's ping sucks. + //in that case, it is probably the server's fault. + if (numlaggers < D_NumPlayers() - 1) + { + for (i = 1; i < MAXPLAYERS; i++) + { + if (playeringame[i] && laggers[i]) + { + pingtimeout[i]++; + // ok your net has been bad for too long, you deserve to die. + if (pingtimeout[i] > cv_pingtimeout.value) + { + pingtimeout[i] = 0; + SendKick(i, KICK_MSG_PING_HIGH | KICK_MSG_KEEP_BODY); + } + } + /* + you aren't lagging, + but you aren't free yet. + In case you'll keep spiking, + we just make the timer go back down. (Very unstable net must still get kicked). + */ + else + pingtimeout[i] = (pingtimeout[i] == 0 ? 0 : pingtimeout[i]-1); + } + } + } + + //make the ping packet and clear server data for next one + for (i = 0; i < MAXPLAYERS; i++) + { + netbuffer->u.pingtable[i] = realpingtable[i] / pingmeasurecount; + //server takes a snapshot of the real ping for display. + //otherwise, pings fluctuate a lot and would be odd to look at. + playerpingtable[i] = realpingtable[i] / pingmeasurecount; + realpingtable[i] = 0; //Reset each as we go. + } + + // send the server's maxping as last element of our ping table. This is useful to let us know when we're about to get kicked. + netbuffer->u.pingtable[MAXPLAYERS] = cv_maxping.value; + + //send out our ping packets + for (i = 0; i < MAXNETNODES; i++) + if (nodeingame[i]) + HSendPacket(i, true, 0, sizeof(INT32) * (MAXPLAYERS+1)); + + pingmeasurecount = 1; //Reset count +} + +void NetUpdate(void) +{ + static tic_t gametime = 0; + static tic_t resptime = 0; + tic_t nowtime; + INT32 i; + INT32 realtics; + + nowtime = I_GetTime(); + realtics = nowtime - gametime; + + if (realtics <= 0) // nothing new to update + return; + if (realtics > 5) + { + if (server) + realtics = 1; + else + realtics = 5; + } + + gametime = nowtime; + + if (server) + { + if (netgame && !(gametime % 35)) // update once per second. + PingUpdate(); + // update node latency values so we can take an average later. + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && playernode[i] != UINT8_MAX) + realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i])); + pingmeasurecount++; + } + + if (client) + maketic = neededtic; + + Local_Maketic(realtics); // make local tic, and call menu? + + if (server) + CL_SendClientCmd(); // send it + + GetPackets(); // get packet from client or from server + + // client send the command after a receive of the server + // the server send before because in single player is beter + +#ifdef MASTERSERVER + MasterClient_Ticker(); // Acking the Master Server +#endif + + if (client) + { +#ifndef NONET + // If the client just finished redownloading the game state, load it + if (cl_redownloadinggamestate && fileneeded[0].status == FS_FOUND) + CL_ReloadReceivedSavegame(); +#endif + + CL_SendClientCmd(); // Send tic cmd + hu_redownloadinggamestate = cl_redownloadinggamestate; + } + else + { + if (!demoplayback) + { + INT32 counts; + + hu_redownloadinggamestate = false; + + firstticstosend = gametic; + for (i = 0; i < MAXNETNODES; i++) + if (nodeingame[i] && nettics[i] < firstticstosend) + { + firstticstosend = nettics[i]; + + if (maketic + 1 >= nettics[i] + BACKUPTICS) + Net_ConnectionTimeout(i); + } + + // Don't erase tics not acknowledged + counts = realtics; + + if (maketic + counts >= firstticstosend + BACKUPTICS) + counts = firstticstosend+BACKUPTICS-maketic-1; + + for (i = 0; i < counts; i++) + SV_Maketic(); // Create missed tics and increment maketic + + for (; tictoclear < firstticstosend; tictoclear++) // Clear only when acknowledged + D_Clearticcmd(tictoclear); // Clear the maketic the new tic + + SV_SendTics(); + + neededtic = maketic; // The server is a client too + } + } + + Net_AckTicker(); + + // Handle timeouts to prevent definitive freezes from happenning + if (server) + { + for (i = 1; i < MAXNETNODES; i++) + if (nodeingame[i] && freezetimeout[i] < I_GetTime()) + Net_ConnectionTimeout(i); + + // In case the cvar value was lowered + if (joindelay) + joindelay = min(joindelay - 1, 3 * (tic_t)cv_joindelay.value * TICRATE); + } + + nowtime /= NEWTICRATERATIO; + if (nowtime > resptime) + { + resptime = nowtime; +#ifdef HAVE_THREADS + I_lock_mutex(&m_menu_mutex); +#endif + M_Ticker(); +#ifdef HAVE_THREADS + I_unlock_mutex(m_menu_mutex); +#endif + CON_Ticker(); + } + + FileSendTicker(); +} + +/** Returns the number of players playing. + * \return Number of players. Can be zero if we're running a ::dedicated + * server. + * \author Graue + */ +INT32 D_NumPlayers(void) +{ + INT32 num = 0, ix; + for (ix = 0; ix < MAXPLAYERS; ix++) + if (playeringame[ix]) + num++; + return num; +} + +tic_t GetLag(INT32 node) +{ + return gametic - nettics[node]; +} + +void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest) +{ +#ifdef NOMD5 + (void)buffer; + (void)len; + (void)salt; + memset(dest, 0, 16); +#else + char tmpbuf[256]; + const size_t sl = strlen(salt); + + if (len > 256-sl) + len = 256-sl; + + memcpy(tmpbuf, buffer, len); + memmove(&tmpbuf[len], salt, sl); + //strcpy(&tmpbuf[len], salt); + len += strlen(salt); + if (len < 256) + memset(&tmpbuf[len],0,256-len); + + // Yes, we intentionally md5 the ENTIRE buffer regardless of size... + md5_buffer(tmpbuf, 256, dest); +#endif +} diff --git a/src/netcode/protocol.h b/src/d_clisrv.h similarity index 60% rename from src/netcode/protocol.h rename to src/d_clisrv.h index 9866e4c5a..e07864122 100644 --- a/src/netcode/protocol.h +++ b/src/d_clisrv.h @@ -7,15 +7,19 @@ // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file protocol.h -/// \brief Data exchanged through the network +/// \file d_clisrv.h +/// \brief high level networking stuff -#ifndef __PROTOCOL__ -#define __PROTOCOL__ +#ifndef __D_CLISRV__ +#define __D_CLISRV__ +#include "d_ticcmd.h" #include "d_net.h" -#include "../d_ticcmd.h" -#include "../doomdef.h" +#include "d_netcmd.h" +#include "d_net.h" +#include "tables.h" +#include "d_player.h" +#include "mserv.h" /* The 'packet version' is used to distinguish packet @@ -34,9 +38,10 @@ therein, increment this number. // one that defines the actual packets to // be transmitted. +// Networking and tick handling related. #define BACKUPTICS 1024 +#define CLIENTBACKUPTICS 32 #define MAXTEXTCMD 256 - // // Packet structure // @@ -85,6 +90,7 @@ typedef enum PT_TEXTCMD, // Extra text commands from the client. PT_TEXTCMD2, // Splitscreen text commands. PT_CLIENTJOIN, // Client wants to join; used in start game. + PT_NODETIMEOUT, // Packet sent to self if the connection times out. PT_LOGIN, // Login attempt from the client. @@ -95,6 +101,14 @@ typedef enum NUMPACKETTYPE } packettype_t; +#ifdef PACKETDROP +void Command_Drop(void); +void Command_Droprate(void); +#endif +#ifdef _DEBUG +void Command_Numnodes(void); +#endif + #if defined(_MSC_VER) #pragma pack(1) #endif @@ -123,12 +137,13 @@ typedef struct #endif // Server to client packet +// this packet is too large typedef struct { tic_t starttic; UINT8 numtics; UINT8 numslots; // "Slots filled": Highest player number in use plus one. - ticcmd_t cmds[45]; + ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large } ATTRPACK servertics_pak; typedef struct @@ -197,7 +212,6 @@ enum { #define MAXSERVERNAME 32 #define MAXFILENEEDED 915 - // This packet is too large typedef struct { @@ -258,7 +272,7 @@ typedef struct UINT8 data; // Color is first four bits, hasflag, isit and issuper have one bit each, the last is unused. UINT32 score; UINT16 timeinserver; // In seconds. -} ATTRPACK plrinfo_pak; +} ATTRPACK plrinfo; // Shortest player information for join during intermission. typedef struct @@ -269,7 +283,7 @@ typedef struct UINT32 pflags; UINT32 score; UINT8 ctfteam; -} ATTRPACK plrconfig_pak; +} ATTRPACK plrconfig; typedef struct { @@ -292,25 +306,25 @@ typedef struct UINT8 reserved; // Padding union { - clientcmd_pak clientpak; - client2cmd_pak client2pak; - servertics_pak serverpak; - serverconfig_pak servercfg; - UINT8 textcmd[MAXTEXTCMD+1]; - filetx_pak filetxpak; + clientcmd_pak clientpak; // 144 bytes + client2cmd_pak client2pak; // 200 bytes + servertics_pak serverpak; // 132495 bytes (more around 360, no?) + serverconfig_pak servercfg; // 773 bytes + UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...) + filetx_pak filetxpak; // 139 bytes fileack_pak fileack; UINT8 filereceived; - clientconfig_pak clientcfg; + clientconfig_pak clientcfg; // 136 bytes UINT8 md5sum[16]; - serverinfo_pak serverinfo; - serverrefuse_pak serverrefuse; - askinfo_pak askinfo; - msaskinfo_pak msaskinfo; - plrinfo_pak playerinfo[MAXPLAYERS]; - plrconfig_pak playerconfig[MAXPLAYERS]; - INT32 filesneedednum; - filesneededconfig_pak filesneededcfg; - UINT32 pingtable[MAXPLAYERS+1]; + serverinfo_pak serverinfo; // 1024 bytes + serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...) + askinfo_pak askinfo; // 61 bytes + msaskinfo_pak msaskinfo; // 22 bytes + plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?) + plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?) + INT32 filesneedednum; // 4 bytes + filesneededconfig_pak filesneededcfg; // ??? bytes + UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes } u; // This is needed to pack diff packet types data together } ATTRPACK doomdata_t; @@ -318,7 +332,26 @@ typedef struct #pragma pack() #endif +#define MAXSERVERLIST (MAXNETNODES-1) +typedef struct +{ + SINT8 node; + serverinfo_pak info; +} serverelem_t; + +extern serverelem_t serverlist[MAXSERVERLIST]; +extern UINT32 serverlistcount; +extern INT32 mapchangepending; + +// Points inside doomcom +extern doomdata_t *netbuffer; + +extern consvar_t cv_showjoinaddress; +extern consvar_t cv_playbackspeed; + +#define BASEPACKETSIZE offsetof(doomdata_t, u) #define FILETXHEADER offsetof(filetx_pak, data) +#define BASESERVERTICSSIZE offsetof(doomdata_t, u.serverpak.cmds[0]) #define KICK_MSG_GO_AWAY 1 #define KICK_MSG_CON_FAIL 2 @@ -330,4 +363,102 @@ typedef struct #define KICK_MSG_CUSTOM_BAN 8 #define KICK_MSG_KEEP_BODY 0x80 +typedef enum +{ + KR_KICK = 1, //Kicked by server + KR_PINGLIMIT = 2, //Broke Ping Limit + KR_SYNCH = 3, //Synch Failure + KR_TIMEOUT = 4, //Connection Timeout + KR_BAN = 5, //Banned by server + KR_LEAVE = 6, //Quit the game + +} kickreason_t; + +/* the max number of name changes in some time period */ +#define MAXNAMECHANGES (5) +#define NAMECHANGERATE (60*TICRATE) + +extern boolean server; +extern boolean serverrunning; +#define client (!server) +extern boolean dedicated; // For dedicated server +extern UINT16 software_MAXPACKETLENGTH; +extern boolean acceptnewnode; +extern SINT8 servernode; + +void Command_Ping_f(void); +extern tic_t connectiontimeout; +extern tic_t jointimeout; +extern UINT16 pingmeasurecount; +extern UINT32 realpingtable[MAXPLAYERS]; +extern UINT32 playerpingtable[MAXPLAYERS]; +extern tic_t servermaxping; + +extern consvar_t cv_netticbuffer, cv_allownewplayer, cv_joinnextround, cv_maxplayers, cv_joindelay, cv_rejointimeout; +extern consvar_t cv_resynchattempts, cv_blamecfail; +extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed; + +// Used in d_net, the only dependence +tic_t ExpandTics(INT32 low, INT32 node); +void D_ClientServerInit(void); + +// Initialise the other field +void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)); +void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam); +void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player +void SendKick(UINT8 playernum, UINT8 msg); + +// Create any new ticcmds and broadcast to other players. +void NetUpdate(void); + +void SV_StartSinglePlayerServer(void); +boolean SV_SpawnServer(void); +void SV_StopServer(void); +void SV_ResetServer(void); +void CL_AddSplitscreenPlayer(void); +void CL_RemoveSplitscreenPlayer(void); +void CL_Reset(void); +void CL_ClearPlayer(INT32 playernum); +void CL_QueryServerList(msg_server_t *list); +void CL_UpdateServerList(boolean internetsearch, INT32 room); +void CL_RemovePlayer(INT32 playernum, kickreason_t reason); +// Is there a game running +boolean Playing(void); + +// Broadcasts special packets to other players +// to notify of game exit +void D_QuitNetGame(void); + +//? How many ticks to run? +boolean TryRunTics(tic_t realtic); + +// extra data for lmps +// these functions scare me. they contain magic. +/*boolean AddLmpExtradata(UINT8 **demo_p, INT32 playernum); +void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum);*/ + +#ifndef NONET +// translate a playername in a player number return -1 if not found and +// print a error message in the console +SINT8 nametonum(const char *name); +#endif + +extern char motd[254], server_context[8]; +extern UINT8 playernode[MAXPLAYERS]; + +INT32 D_NumPlayers(void); +void D_ResetTiccmds(void); + +tic_t GetLag(INT32 node); +UINT8 GetFreeXCmdSize(void); + +void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest); + +extern UINT8 hu_redownloadinggamestate; + +extern UINT8 adminpassmd5[16]; +extern boolean adminpasswordset; + +extern boolean hu_stopped; + #endif diff --git a/src/d_main.c b/src/d_main.c index 8b13dba89..1af8d090c 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -34,7 +34,7 @@ #include "doomdef.h" #include "am_map.h" #include "console.h" -#include "netcode/d_net.h" +#include "d_net.h" #include "f_finale.h" #include "g_game.h" #include "hu_stuff.h" @@ -57,11 +57,11 @@ #include "w_wad.h" #include "z_zone.h" #include "d_main.h" -#include "netcode/d_netfil.h" +#include "d_netfil.h" #include "m_cheat.h" #include "y_inter.h" #include "p_local.h" // chasecam -#include "netcode/mserv.h" // ms_RoomId +#include "mserv.h" // ms_RoomId #include "m_misc.h" // screenshot functionality #include "deh_tables.h" // Dehacked list test #include "m_cond.h" // condition initialization diff --git a/src/netcode/d_net.c b/src/d_net.c similarity index 93% rename from src/netcode/d_net.c rename to src/d_net.c index a4b0778e3..a7e1eb16d 100644 --- a/src/netcode/d_net.c +++ b/src/d_net.c @@ -16,21 +16,19 @@ /// This protocol uses a mix of "goback n" and "selective repeat" implementation /// The NOTHING packet is sent when connection is idle to acknowledge packets -#include "../doomdef.h" -#include "../g_game.h" -#include "../i_time.h" +#include "doomdef.h" +#include "g_game.h" +#include "i_time.h" #include "i_net.h" -#include "../i_system.h" -#include "../m_argv.h" +#include "i_system.h" +#include "m_argv.h" #include "d_net.h" -#include "../w_wad.h" +#include "w_wad.h" #include "d_netfil.h" #include "d_clisrv.h" -#include "tic_command.h" -#include "net_command.h" -#include "../z_zone.h" +#include "z_zone.h" #include "i_tcp.h" -#include "../d_main.h" // srb2home +#include "d_main.h" // srb2home // // NETWORKING @@ -140,6 +138,7 @@ boolean Net_GetNetStat(void) #define URGENTFREESLOTNUM 10 #define ACKTOSENDTIMEOUT (TICRATE/11) +#ifndef NONET typedef struct { UINT8 acknum; @@ -153,6 +152,7 @@ typedef struct doomdata_t data; } pak; } ackpak_t; +#endif typedef enum { @@ -160,8 +160,10 @@ typedef enum NF_TIMEOUT = 2, // Flag is set when the node got a timeout } node_flags_t; +#ifndef NONET // Table of packets that were not acknowleged can be resent (the sender window) static ackpak_t ackpak[MAXACKPACKETS]; +#endif typedef struct { @@ -189,6 +191,7 @@ typedef struct static node_t nodes[MAXNETNODES]; #define NODETIMEOUT 14 +#ifndef NONET // return <0 if a < b (mod 256) // 0 if a = n (mod 256) // >0 if a > b (mod 256) @@ -211,7 +214,7 @@ FUNCMATH static INT32 cmpack(UINT8 a, UINT8 b) static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer) { node_t *node = &nodes[doomcom->remotenode]; - INT32 numfreeslot = 0; + INT32 i, numfreeslot = 0; if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0) { @@ -219,7 +222,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer) return false; } - for (INT32 i = 0; i < MAXACKPACKETS; i++) + for (i = 0; i < MAXACKPACKETS; i++) if (!ackpak[i].acknum) { // For low priority packets, make sure to let freeslots so urgent packets can be sent @@ -276,10 +279,10 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer) */ INT32 Net_GetFreeAcks(boolean urgent) { - INT32 numfreeslot = 0; + INT32 i, numfreeslot = 0; INT32 n = 0; // Number of free acks found - for (INT32 i = 0; i < MAXACKPACKETS; i++) + for (i = 0; i < MAXACKPACKETS; i++) if (!ackpak[i].acknum) { // For low priority packets, make sure to let freeslots so urgent packets can be sent @@ -315,6 +318,7 @@ static void RemoveAck(INT32 i) // We have got a packet, proceed the ack request and ack return static boolean Processackpak(void) { + INT32 i; boolean goodpacket = true; node_t *node = &nodes[doomcom->remotenode]; @@ -323,7 +327,7 @@ static boolean Processackpak(void) { node->remotefirstack = netbuffer->ackreturn; // Search the ackbuffer and free it - for (INT32 i = 0; i < MAXACKPACKETS; i++) + for (i = 0; i < MAXACKPACKETS; i++) if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes && cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0) { @@ -345,7 +349,7 @@ static boolean Processackpak(void) else { // Check if it is not already in the queue - for (INT32 i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND) + for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND) if (node->acktosend[i] == ack) { DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack)); @@ -373,7 +377,7 @@ static boolean Processackpak(void) while (change) { change = false; - for (INT32 i = node->acktosend_tail; i != node->acktosend_head; + for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND) { if (cmpack(node->acktosend[i], nextfirstack) <= 0) @@ -422,20 +426,28 @@ static boolean Processackpak(void) } return goodpacket; } +#endif // send special packet with only ack on it void Net_SendAcks(INT32 node) { +#ifdef NONET + (void)node; +#else netbuffer->packettype = PT_NOTHING; M_Memcpy(netbuffer->u.textcmd, nodes[node].acktosend, MAXACKTOSEND); HSendPacket(node, false, 0, MAXACKTOSEND); +#endif } +#ifndef NONET static void GotAcks(void) { - for (INT32 j = 0; j < MAXACKTOSEND; j++) + INT32 i, j; + + for (j = 0; j < MAXACKTOSEND; j++) if (netbuffer->u.textcmd[j]) - for (INT32 i = 0; i < MAXACKPACKETS; i++) + for (i = 0; i < MAXACKPACKETS; i++) if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode) { if (ackpak[i].acknum == netbuffer->u.textcmd[j]) @@ -451,6 +463,7 @@ static void GotAcks(void) } } } +#endif void Net_ConnectionTimeout(INT32 node) { @@ -459,10 +472,14 @@ void Net_ConnectionTimeout(INT32 node) return; nodes[node].flags |= NF_TIMEOUT; - if (server) - SendKicksForNode(node, KICK_MSG_TIMEOUT | KICK_MSG_KEEP_BODY); - else - CL_HandleTimeout(); + // Send a very special packet to self (hack the reboundstore queue) + // Main code will handle it + reboundstore[rebound_head].packettype = PT_NODETIMEOUT; + reboundstore[rebound_head].ack = 0; + reboundstore[rebound_head].ackreturn = 0; + reboundstore[rebound_head].u.textcmd[0] = (UINT8)node; + reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1); + rebound_head = (rebound_head+1) % MAXREBOUND; // Do not redo it quickly (if we do not close connection it is // for a good reason!) @@ -472,8 +489,10 @@ void Net_ConnectionTimeout(INT32 node) // Resend the data if needed void Net_AckTicker(void) { +#ifndef NONET + INT32 i; - for (INT32 i = 0; i < MAXACKPACKETS; i++) + for (i = 0; i < MAXACKPACKETS; i++) { const INT32 nodei = ackpak[i].destinationnode; node_t *node = &nodes[nodei]; @@ -500,7 +519,7 @@ void Net_AckTicker(void) } } - for (INT32 i = 1; i < MAXNETNODES; i++) + for (i = 1; i < MAXNETNODES; i++) { // This is something like node open flag if (nodes[i].firstacktosend) @@ -517,12 +536,16 @@ void Net_AckTicker(void) } } } +#endif } // Remove last packet received ack before resending the ackreturn // (the higher layer doesn't have room, or something else ....) void Net_UnAcknowledgePacket(INT32 node) { +#ifdef NONET + (void)node; +#else INT32 hm1 = (nodes[node].acktosend_head-1+MAXACKTOSEND) % MAXACKTOSEND; DEBFILE(va("UnAcknowledge node %d\n", node)); if (!node) @@ -554,8 +577,10 @@ void Net_UnAcknowledgePacket(INT32 node) if (!nodes[node].firstacktosend) nodes[node].firstacktosend = 1; } +#endif } +#ifndef NONET /** Checks if all acks have been received * * \return True if all acks have been received @@ -563,12 +588,15 @@ void Net_UnAcknowledgePacket(INT32 node) */ static boolean Net_AllAcksReceived(void) { - for (INT32 i = 0; i < MAXACKPACKETS; i++) + INT32 i; + + for (i = 0; i < MAXACKPACKETS; i++) if (ackpak[i].acknum) return false; return true; } +#endif /** Waits for all ackreturns * @@ -577,6 +605,9 @@ static boolean Net_AllAcksReceived(void) */ void Net_WaitAllAckReceived(UINT32 timeout) { +#ifdef NONET + (void)timeout; +#else tic_t tictac = I_GetTime(); timeout = tictac + timeout*NEWTICRATE; @@ -592,6 +623,7 @@ void Net_WaitAllAckReceived(UINT32 timeout) HGetPacket(); Net_AckTicker(); } +#endif } static void InitNode(node_t *node) @@ -605,10 +637,14 @@ static void InitNode(node_t *node) static void InitAck(void) { - for (INT32 i = 0; i < MAXACKPACKETS; i++) - ackpak[i].acknum = 0; + INT32 i; - for (INT32 i = 0; i < MAXNETNODES; i++) +#ifndef NONET + for (i = 0; i < MAXACKPACKETS; i++) + ackpak[i].acknum = 0; +#endif + + for (i = 0; i < MAXNETNODES; i++) InitNode(&nodes[i]); } @@ -619,12 +655,17 @@ static void InitAck(void) */ void Net_AbortPacketType(UINT8 packettype) { - for (INT32 i = 0; i < MAXACKPACKETS; i++) +#ifdef NONET + (void)packettype; +#else + INT32 i; + for (i = 0; i < MAXACKPACKETS; i++) if (ackpak[i].acknum && (ackpak[i].pak.data.packettype == packettype || packettype == UINT8_MAX)) { ackpak[i].acknum = 0; } +#endif } // ----------------------------------------------------------------- @@ -634,6 +675,10 @@ void Net_AbortPacketType(UINT8 packettype) // remove a node, clear all ack from this node and reset askret void Net_CloseConnection(INT32 node) { +#ifdef NONET + (void)node; +#else + INT32 i; boolean forceclose = (node & FORCECLOSE) != 0; if (node == -1) @@ -663,7 +708,7 @@ void Net_CloseConnection(INT32 node) } // check if we are waiting for an ack from this node - for (INT32 i = 0; i < MAXACKPACKETS; i++) + for (i = 0; i < MAXACKPACKETS; i++) if (ackpak[i].acknum && ackpak[i].destinationnode == node) { if (!forceclose) @@ -677,8 +722,10 @@ void Net_CloseConnection(INT32 node) if (server) SV_AbortLuaFileTransfer(node); I_NetFreeNodenum(node); +#endif } +#ifndef NONET // // Checksum // @@ -687,20 +734,23 @@ static UINT32 NetbufferChecksum(void) UINT32 c = 0x1234567; const INT32 l = doomcom->datalength - 4; const UINT8 *buf = (UINT8 *)netbuffer + 4; + INT32 i; - for (INT32 i = 0; i < l; i++, buf++) + for (i = 0; i < l; i++, buf++) c += (*buf) * (i+1); return LONG(c); } +#endif #ifdef DEBUGFILE static void fprintfstring(char *s, size_t len) { INT32 mode = 0; + size_t i; - for (size_t i = 0; i < len; i++) + for (i = 0; i < len; i++) if (s[i] < 32) { if (!mode) @@ -767,6 +817,7 @@ static const char *packettypename[NUMPACKETTYPE] = "TEXTCMD", "TEXTCMD2", "CLIENTJOIN", + "NODETIMEOUT", "LOGIN", "TELLFILESNEEDED", "MOREFILESNEEDED", @@ -867,6 +918,7 @@ void Command_Drop(void) { INT32 packetquantity; const char *packetname; + size_t i; if (COM_Argc() < 2) { @@ -896,11 +948,11 @@ void Command_Drop(void) packetname = COM_Argv(1); if (!(stricmp(packetname, "all") && stricmp(packetname, "any"))) - for (size_t i = 0; i < NUMPACKETTYPE; i++) + for (i = 0; i < NUMPACKETTYPE; i++) packetdropquantity[i] = packetquantity; else { - for (size_t i = 0; i < NUMPACKETTYPE; i++) + for (i = 0; i < NUMPACKETTYPE; i++) if (!stricmp(packetname, packettypename[i])) { packetdropquantity[i] = packetquantity; @@ -931,12 +983,14 @@ void Command_Droprate(void) packetdroprate = droprate; } +#ifndef NONET static boolean ShouldDropPacket(void) { return (packetdropquantity[netbuffer->packettype]) || (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100; } #endif +#endif // // HSendPacket @@ -971,6 +1025,11 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen if (!netgame) I_Error("Tried to transmit to another node"); +#ifdef NONET + (void)node; + (void)reliable; + (void)acknum; +#else // do this before GetFreeAcknum because this function backups // the current packet doomcom->remotenode = (INT16)node; @@ -1031,6 +1090,8 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen } #endif +#endif // ndef NONET + return true; } @@ -1048,7 +1109,10 @@ boolean HGetPacket(void) { M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]); doomcom->datalength = reboundsize[rebound_tail]; - doomcom->remotenode = 0; + if (netbuffer->packettype == PT_NODETIMEOUT) + doomcom->remotenode = netbuffer->u.textcmd[0]; + else + doomcom->remotenode = 0; rebound_tail = (rebound_tail+1) % MAXREBOUND; #ifdef DEBUGFILE @@ -1061,6 +1125,8 @@ boolean HGetPacket(void) if (!netgame) return false; +#ifndef NONET + while(true) { //nodejustjoined = I_NetGet(); @@ -1120,6 +1186,7 @@ boolean HGetPacket(void) } break; } +#endif // ndef NONET return true; } @@ -1323,12 +1390,13 @@ void Command_Ping_f(void) int name_width = 0; int ms_width = 0; + int n; + INT32 i; + pingc = 0; - for (INT32 i = 1; i < MAXPLAYERS; ++i) + for (i = 1; i < MAXPLAYERS; ++i) if (playeringame[i]) { - int n; - n = strlen(player_names[i]); if (n > name_width) name_width = n; @@ -1348,7 +1416,7 @@ void Command_Ping_f(void) qsort(pingv, pingc, sizeof (struct pingcell), &pingcellcmp); - for (INT32 i = 0; i < pingc; ++i) + for (i = 0; i < pingc; ++i) { CONS_Printf("%02d : %-*s %*d ms\n", pingv[i].num, @@ -1364,13 +1432,15 @@ void Command_Ping_f(void) void D_CloseConnection(void) { + INT32 i; + if (netgame) { // wait the ackreturn with timout of 5 Sec Net_WaitAllAckReceived(5); // close all connection - for (INT32 i = 0; i < MAXNETNODES; i++) + for (i = 0; i < MAXNETNODES; i++) Net_CloseConnection(i|FORCECLOSE); InitAck(); diff --git a/src/netcode/d_net.h b/src/d_net.h similarity index 74% rename from src/netcode/d_net.h rename to src/d_net.h index 039f5b3b4..5baa593a0 100644 --- a/src/netcode/d_net.h +++ b/src/d_net.h @@ -18,8 +18,6 @@ #ifndef __D_NET__ #define __D_NET__ -#include "../doomtype.h" - // Max computers in a game // 127 is probably as high as this can go, because // SINT8 is used for nodes sometimes >:( @@ -39,24 +37,10 @@ boolean Net_GetNetStat(void); extern INT32 getbytes; extern INT64 sendbytes; // Realtime updated -typedef struct netnode_s -{ - boolean ingame; // set false as nodes leave game - tic_t freezetimeout; // Until when can this node freeze the server before getting a timeout? - - SINT8 player; - SINT8 player2; // say the numplayer for this node if any (splitscreen) - UINT8 numplayers; // used specialy for scplitscreen - - tic_t tic; // what tic the client have received - tic_t supposedtic; // nettics prevision for smaller packet - - boolean sendingsavegame; // Are we sending the savegame? - boolean resendingsavegame; // Are we resending the savegame? - tic_t savegameresendcooldown; // How long before we can resend again? -} netnode_t; - -extern netnode_t netnodes[MAXNETNODES]; +extern SINT8 nodetoplayer[MAXNETNODES]; +extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen) +extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen +extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game extern boolean serverrunning; @@ -68,6 +52,9 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength); boolean HGetPacket(void); void D_SetDoomcom(void); +#ifndef NONET +void D_SaveBan(void); +#endif boolean D_CheckNetGame(void); void D_CloseConnection(void); void Net_UnAcknowledgePacket(INT32 node); diff --git a/src/netcode/d_netcmd.c b/src/d_netcmd.c similarity index 99% rename from src/netcode/d_netcmd.c rename to src/d_netcmd.c index dd9f811e3..f721aa75a 100644 --- a/src/netcode/d_netcmd.c +++ b/src/d_netcmd.c @@ -12,47 +12,45 @@ /// commands are executed through the command buffer /// like console commands, other miscellaneous commands (at the end) -#include "../doomdef.h" +#include "doomdef.h" -#include "../console.h" -#include "../command.h" -#include "../i_time.h" -#include "../i_system.h" -#include "../g_game.h" -#include "../hu_stuff.h" -#include "../g_input.h" -#include "../i_gamepad.h" -#include "../m_menu.h" -#include "../r_local.h" -#include "../r_skins.h" -#include "../p_local.h" -#include "../p_setup.h" -#include "../s_sound.h" -#include "../i_sound.h" -#include "../m_misc.h" -#include "../am_map.h" -#include "../byteptr.h" +#include "console.h" +#include "command.h" +#include "i_time.h" +#include "i_system.h" +#include "g_game.h" +#include "hu_stuff.h" +#include "g_input.h" +#include "i_gamepad.h" +#include "m_menu.h" +#include "r_local.h" +#include "r_skins.h" +#include "p_local.h" +#include "p_setup.h" +#include "s_sound.h" +#include "i_sound.h" +#include "m_misc.h" +#include "am_map.h" +#include "byteptr.h" #include "d_netfil.h" -#include "../p_spec.h" -#include "../m_cheat.h" +#include "p_spec.h" +#include "m_cheat.h" #include "d_clisrv.h" -#include "server_connection.h" -#include "net_command.h" #include "d_net.h" -#include "../v_video.h" -#include "../d_main.h" -#include "../m_random.h" -#include "../f_finale.h" -#include "../filesrch.h" +#include "v_video.h" +#include "d_main.h" +#include "m_random.h" +#include "f_finale.h" +#include "filesrch.h" #include "mserv.h" -#include "../z_zone.h" -#include "../lua_script.h" -#include "../lua_hook.h" -#include "../m_cond.h" -#include "../m_anigif.h" -#include "../md5.h" -#include "../m_perfstats.h" -#include "../hardware/u_list.h" // TODO: this should be a standard utility class +#include "z_zone.h" +#include "lua_script.h" +#include "lua_hook.h" +#include "m_cond.h" +#include "m_anigif.h" +#include "md5.h" +#include "m_perfstats.h" +#include "hardware/u_list.h" // TODO: this should be a standard utility class #ifdef NETGAME_DEVMODE #define CV_RESTRICT CV_NETVAR @@ -631,9 +629,12 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_maxsend); CV_RegisterVar(&cv_noticedownload); CV_RegisterVar(&cv_downloadspeed); +#ifndef NONET CV_RegisterVar(&cv_allownewplayer); + CV_RegisterVar(&cv_joinnextround); CV_RegisterVar(&cv_showjoinaddress); CV_RegisterVar(&cv_blamecfail); +#endif COM_AddCommand("ping", Command_Ping_f); CV_RegisterVar(&cv_nettimeout); @@ -1841,7 +1842,8 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese // reset players if there is a new one if (!IsPlayerAdmin(consoleplayer)) { - SV_SpawnServer(); + if (SV_SpawnServer()) + buf[0] &= ~(1<<1); if (!Playing()) // you failed to start a server somehow, so cancel the map change return; } diff --git a/src/netcode/d_netcmd.h b/src/d_netcmd.h similarity index 99% rename from src/netcode/d_netcmd.h rename to src/d_netcmd.h index 797a686a7..47f68a17e 100644 --- a/src/netcode/d_netcmd.h +++ b/src/d_netcmd.h @@ -15,7 +15,7 @@ #ifndef __D_NETCMD__ #define __D_NETCMD__ -#include "../command.h" +#include "command.h" // console vars extern consvar_t cv_playername; diff --git a/src/netcode/d_netfil.c b/src/d_netfil.c similarity index 93% rename from src/netcode/d_netfil.c rename to src/d_netfil.c index 10b7359ad..edbef30bb 100644 --- a/src/netcode/d_netfil.c +++ b/src/d_netfil.c @@ -31,25 +31,24 @@ #include #endif -#include "../doomdef.h" -#include "../doomstat.h" -#include "../d_main.h" -#include "../g_game.h" -#include "../i_time.h" +#include "doomdef.h" +#include "doomstat.h" +#include "d_main.h" +#include "g_game.h" +#include "i_time.h" #include "i_net.h" -#include "../i_system.h" -#include "../m_argv.h" +#include "i_system.h" +#include "m_argv.h" #include "d_net.h" -#include "../w_wad.h" +#include "w_wad.h" #include "d_netfil.h" -#include "net_command.h" -#include "../z_zone.h" -#include "../byteptr.h" -#include "../p_setup.h" -#include "../m_misc.h" -#include "../m_menu.h" -#include "../md5.h" -#include "../filesrch.h" +#include "z_zone.h" +#include "byteptr.h" +#include "p_setup.h" +#include "m_misc.h" +#include "m_menu.h" +#include "md5.h" +#include "filesrch.h" #include @@ -104,31 +103,26 @@ typedef struct } pauseddownload_t; static pauseddownload_t *pauseddownload = NULL; +#ifndef NONET // for cl loading screen INT32 lastfilenum = -1; INT32 downloadcompletednum = 0; UINT32 downloadcompletedsize = 0; INT32 totalfilesrequestednum = 0; UINT32 totalfilesrequestedsize = 0; +#endif luafiletransfer_t *luafiletransfers = NULL; boolean waitingforluafiletransfer = false; boolean waitingforluafilecommand = false; char luafiledir[256 + 16] = "luafiles"; -// max file size to send to a player (in kilobytes) -static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {204800, "MAX"}, {0, NULL}}; -consvar_t cv_maxsend = CVAR_INIT ("maxsend", "4096", CV_SAVE|CV_NETVAR, maxsend_cons_t, NULL); - -consvar_t cv_noticedownload = CVAR_INIT ("noticedownload", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); - -// Speed of file downloading (in packets per tic) -static CV_PossibleValue_t downloadspeed_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}}; -consvar_t cv_downloadspeed = CVAR_INIT ("downloadspeed", "16", CV_SAVE|CV_NETVAR, downloadspeed_cons_t, NULL); static UINT16 GetWadNumFromFileNeededId(UINT8 id) { - for (UINT16 wadnum = mainwads; wadnum < numwadfiles; wadnum++) + UINT16 wadnum; + + for (wadnum = mainwads; wadnum < numwadfiles; wadnum++) { if (!wadfiles[wadnum]->important) continue; @@ -148,13 +142,14 @@ static UINT16 GetWadNumFromFileNeededId(UINT8 id) */ UINT8 *PutFileNeeded(UINT16 firstfile) { + size_t i; UINT8 count = 0; UINT8 *p_start = netbuffer->packettype == PT_MOREFILESNEEDED ? netbuffer->u.filesneededcfg.files : netbuffer->u.serverinfo.fileneeded; UINT8 *p = p_start; char wadfilename[MAX_WADPATH] = ""; UINT8 filestatus, folder; - for (size_t i = mainwads; i < numwadfiles; i++) //mainwads, otherwise we start on the first mainwad + for (i = mainwads; i < numwadfiles; i++) //mainwads, otherwise we start on the first mainwad { // If it has only music/sound lumps, don't put it in the list if (!wadfiles[i]->important) @@ -229,6 +224,7 @@ void FreeFileNeeded(void) */ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile) { + INT32 i; UINT8 *p; UINT8 filestatus; @@ -237,7 +233,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 fi AllocFileNeeded(fileneedednum); - for (INT32 i = firstfile; i < fileneedednum; i++) + for (i = firstfile; i < fileneedednum; i++) { fileneeded[i].type = FILENEEDED_WAD; fileneeded[i].status = FS_NOTCHECKED; // We haven't even started looking for the file yet @@ -254,7 +250,9 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 fi void CL_PrepareDownloadSaveGame(const char *tmpsave) { +#ifndef NONET lastfilenum = -1; +#endif FreeFileNeeded(); AllocFileNeeded(1); @@ -277,9 +275,9 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave) */ boolean CL_CheckDownloadable(void) { - UINT8 dlstatus = 0; + UINT8 i,dlstatus = 0; - for (UINT8 i = 0; i < fileneedednum; i++) + for (i = 0; i < fileneedednum; i++) if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN) { if (fileneeded[i].willsend == 1) @@ -300,7 +298,7 @@ boolean CL_CheckDownloadable(void) // not downloadable, put reason in console CONS_Alert(CONS_NOTICE, M_GetText("You need additional files to connect to this server:\n")); - for (UINT8 i = 0; i < fileneedednum; i++) + for (i = 0; i < fileneedednum; i++) if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN) { CONS_Printf(" * \"%s\" (%dK)", fileneeded[i].filename, fileneeded[i].totalsize >> 10); @@ -370,13 +368,14 @@ void CL_AbortDownloadResume(void) boolean CL_SendFileRequest(void) { char *p; + INT32 i; INT64 totalfreespaceneeded = 0, availablefreespace; #ifdef PARANOIA if (M_CheckParm("-nodownload")) I_Error("Attempted to download files in -nodownload mode"); - for (INT32 i = 0; i < fileneedednum; i++) + for (i = 0; i < fileneedednum; i++) if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN && (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2)) { @@ -386,7 +385,7 @@ boolean CL_SendFileRequest(void) netbuffer->packettype = PT_REQUESTFILE; p = (char *)netbuffer->u.textcmd; - for (INT32 i = 0; i < fileneedednum; i++) + for (i = 0; i < fileneedednum; i++) if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD)) { totalfreespaceneeded += fileneeded[i].totalsize; @@ -414,31 +413,26 @@ boolean CL_SendFileRequest(void) } // get request filepak and put it on the send queue -void PT_RequestFile(SINT8 node) +// returns false if a requested file was not found or cannot be sent +boolean PT_RequestFile(INT32 node) { UINT8 *p = netbuffer->u.textcmd; - - if (client || !cv_downloading.value) - { - Net_CloseConnection(node); // close connection if you are not the server or disabled downloading - return; - } + UINT8 id; while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow { - UINT8 id = READUINT8(p); + id = READUINT8(p); if (id == 0xFF) break; if (!AddFileToSendQueue(node, id)) { SV_AbortSendFiles(node); - Net_CloseConnection(node); // close connection if one of the requested files could not be sent - return; // don't read the rest of the files + return false; // don't read the rest of the files } } - return; // no problems with any files + return true; // no problems with any files } /** Checks if the files needed aren't already loaded or on the disk @@ -537,7 +531,9 @@ INT32 CL_CheckFiles(void) // Load it now boolean CL_LoadServerFiles(void) { - for (INT32 i = 0; i < fileneedednum; i++) + INT32 i; + + for (i = 0; i < fileneedednum; i++) { if (fileneeded[i].status == FS_OPEN) continue; // Already loaded @@ -633,10 +629,11 @@ void AddLuaFileTransfer(const char *filename, const char *mode) static void SV_PrepareSendLuaFileToNextNode(void) { + INT32 i; UINT8 success = 1; // Find a client to send the file to - for (INT32 i = 1; i < MAXNETNODES; i++) + for (i = 1; i < MAXNETNODES; i++) if (luafiletransfers->nodestatus[i] == LFTNS_WAITING) // Node waiting { // Tell the client we're about to send them the file @@ -658,12 +655,13 @@ static void SV_PrepareSendLuaFileToNextNode(void) void SV_PrepareSendLuaFile(void) { char *binfilename; + INT32 i; luafiletransfers->ongoing = true; // Set status to "waiting" for everyone - for (INT32 i = 0; i < MAXNETNODES; i++) - luafiletransfers->nodestatus[i] = (netnodes[i].ingame ? LFTNS_WAITING : LFTNS_NONE); + for (i = 0; i < MAXNETNODES; i++) + luafiletransfers->nodestatus[i] = (nodeingame[i] ? LFTNS_WAITING : LFTNS_NONE); if (FIL_ReadFileOK(luafiletransfers->realfilename)) { @@ -1139,13 +1137,12 @@ void FileSendTicker(void) } } -void PT_FileAck(SINT8 node) +void PT_FileAck(void) { fileack_pak *packet = &netbuffer->u.fileack; + INT32 node = doomcom->remotenode; filetran_t *trans = &transfer[node]; - - if (client) - return; + INT32 i, j; // Wrong file id? Ignore it, it's probably a late packet if (!(trans->txlist && packet->fileid == trans->txlist->fileid)) @@ -1164,11 +1161,11 @@ void PT_FileAck(SINT8 node) trans->dontsenduntil = 0; } - for (INT32 i = 0; i < packet->numsegments; i++) + for (i = 0; i < packet->numsegments; i++) { fileacksegment_t *segment = &packet->segments[i]; - for (INT32 j = 0; j < 32; j++) + for (j = 0; j < 32; j++) if (LONG(segment->acks) & (1 << j)) { if (LONG(segment->start) * FILEFRAGMENTSIZE >= trans->txlist->size) @@ -1193,23 +1190,24 @@ void PT_FileAck(SINT8 node) } } -void PT_FileReceived(SINT8 node) +void PT_FileReceived(void) { - filetx_t *trans = transfer[node].txlist; + filetx_t *trans = transfer[doomcom->remotenode].txlist; - if (server && trans && netbuffer->u.filereceived == trans->fileid) - SV_EndFileSend(node); + if (trans && netbuffer->u.filereceived == trans->fileid) + SV_EndFileSend(doomcom->remotenode); } static void SendAckPacket(fileack_pak *packet, UINT8 fileid) { size_t packetsize; + INT32 i; packetsize = sizeof(*packet) + packet->numsegments * sizeof(*packet->segments); // Finalise the packet packet->fileid = fileid; - for (INT32 i = 0; i < packet->numsegments; i++) + for (i = 0; i < packet->numsegments; i++) { packet->segments[i].start = LONG(packet->segments[i].start); packet->segments[i].acks = LONG(packet->segments[i].acks); @@ -1249,7 +1247,9 @@ static void AddFragmentToAckPacket(fileack_pak *packet, UINT8 iteration, UINT32 void FileReceiveTicker(void) { - for (INT32 i = 0; i < fileneedednum; i++) + INT32 i; + + for (i = 0; i < fileneedednum; i++) { fileneeded_t *file = &fileneeded[i]; @@ -1263,7 +1263,8 @@ void FileReceiveTicker(void) if (file->ackresendposition != UINT32_MAX && file->status == FS_DOWNLOADING) { // Acknowledge ~70 MB/s, whichs means the client sends ~18 KB/s - for (INT32 j = 0; j < 2048; j++) + INT32 j; + for (j = 0; j < 2048; j++) { if (file->receivedfragments[file->ackresendposition]) AddFragmentToAckPacket(file->ackpacket, file->iteration, file->ackresendposition, i); @@ -1280,27 +1281,8 @@ void FileReceiveTicker(void) } } -void PT_FileFragment(SINT8 node, INT32 netconsole) +void PT_FileFragment(void) { - if (netnodes[node].ingame) - { - // Only accept PT_FILEFRAGMENT from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_FILEFRAGMENT", node); - if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - return; - } - if (server) - return; - } - else if (server || node != servernode) - { - Net_CloseConnection(node); - return; - } - INT32 filenum = netbuffer->u.filetxpak.fileid; fileneeded_t *file = &fileneeded[filenum]; UINT32 fragmentpos = LONG(netbuffer->u.filetxpak.position); @@ -1457,7 +1439,9 @@ void PT_FileFragment(SINT8 node, INT32 netconsole) I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s); } +#ifndef NONET lastfilenum = filenum; +#endif } /** \brief Checks if a node is downloading a file @@ -1485,14 +1469,15 @@ void SV_AbortSendFiles(INT32 node) void CloseNetFile(void) { + INT32 i; // Is sending? - for (INT32 i = 0; i < MAXNETNODES; i++) + for (i = 0; i < MAXNETNODES; i++) SV_AbortSendFiles(i); // Receiving a file? if (fileneeded) { - for (INT32 i = 0; i < fileneedednum; i++) + for (i = 0; i < fileneedednum; i++) if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file) { fclose(fileneeded[i].file); @@ -1525,7 +1510,9 @@ void CloseNetFile(void) void Command_Downloads_f(void) { - for (INT32 node = 0; node < MAXNETNODES; node++) + INT32 node; + + for (node = 0; node < MAXNETNODES; node++) if (transfer[node].txlist && transfer[node].txlist->ram == SF_FILE) // Node is downloading a file? { @@ -1559,11 +1546,14 @@ void Command_Downloads_f(void) void nameonly(char *s) { - for (size_t j = strlen(s); j != (size_t)-1; j--) + size_t j, len; + void *ns; + + for (j = strlen(s); j != (size_t)-1; j--) if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/')) { - void *ns = &(s[j+1]); - size_t len = strlen(ns); + ns = &(s[j+1]); + len = strlen(ns); #if 0 M_Memcpy(s, ns, len+1); #else @@ -1576,9 +1566,9 @@ void nameonly(char *s) // Returns the length in characters of the last element of a path. size_t nameonlylength(const char *s) { - size_t len = strlen(s); + size_t j, len = strlen(s); - for (size_t j = len; j != (size_t)-1; j--) + for (j = len; j != (size_t)-1; j--) if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/')) return len - j - 1; diff --git a/src/netcode/d_netfil.h b/src/d_netfil.h similarity index 94% rename from src/netcode/d_netfil.h rename to src/d_netfil.h index 850e24d49..f778a518f 100644 --- a/src/netcode/d_netfil.h +++ b/src/d_netfil.h @@ -15,7 +15,7 @@ #include "d_net.h" #include "d_clisrv.h" -#include "../w_wad.h" +#include "w_wad.h" typedef enum { @@ -70,13 +70,13 @@ extern INT32 fileneedednum; extern fileneeded_t *fileneeded; extern char downloaddir[512]; +#ifndef NONET extern INT32 lastfilenum; extern INT32 downloadcompletednum; extern UINT32 downloadcompletedsize; extern INT32 totalfilesrequestednum; extern UINT32 totalfilesrequestedsize; - -extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed; +#endif void AllocFileNeeded(INT32 size); void FreeFileNeeded(void); @@ -90,16 +90,16 @@ void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemet UINT8 fileid); void FileSendTicker(void); -void PT_FileAck(SINT8 node); -void PT_FileReceived(SINT8 node); +void PT_FileAck(void); +void PT_FileReceived(void); boolean SendingFile(INT32 node); void FileReceiveTicker(void); -void PT_FileFragment(SINT8 node, INT32 netconsole); +void PT_FileFragment(void); boolean CL_CheckDownloadable(void); boolean CL_SendFileRequest(void); -void PT_RequestFile(SINT8 node); +boolean PT_RequestFile(INT32 node); typedef enum { diff --git a/src/deh_soc.c b/src/deh_soc.c index 81b36479c..cbc7940f7 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -34,7 +34,7 @@ #include "r_sky.h" #include "fastcmp.h" #include "lua_script.h" // Reluctantly included for LUA_EvalMath -#include "netcode/d_clisrv.h" +#include "d_clisrv.h" #ifdef HWRENDER #include "hardware/hw_light.h" diff --git a/src/deh_soc.h b/src/deh_soc.h index cd55b665b..f972ec26e 100644 --- a/src/deh_soc.h +++ b/src/deh_soc.h @@ -35,7 +35,7 @@ #include "r_sky.h" #include "fastcmp.h" #include "lua_script.h" // Reluctantly included for LUA_EvalMath -#include "netcode/d_clisrv.h" +#include "d_clisrv.h" #ifdef HWRENDER #include "hardware/hw_light.h" diff --git a/src/deh_tables.c b/src/deh_tables.c index a119f792f..90c3047a8 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4831,7 +4831,7 @@ const char *const MENUTYPES_LIST[] = { "MP_SERVER", "MP_CONNECT", "MP_ROOM", - "MP_PLAYERSETUP", + "MP_PLAYERSETUP", // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET "MP_SERVER_OPTIONS", // Options diff --git a/src/doomdef.h b/src/doomdef.h index b70f0a47e..24b4fa980 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -56,6 +56,7 @@ #endif #ifdef _WINDOWS +#define NONET #if !defined (HWRENDER) && !defined (NOHW) #define HWRENDER #endif @@ -656,7 +657,7 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// Maintain compatibility with older 2.2 demos #define OLD22DEMOCOMPAT -#ifdef HAVE_CURL +#if defined (HAVE_CURL) && ! defined (NONET) #define MASTERSERVER #else #undef UPDATE_ALERT diff --git a/src/doomstat.h b/src/doomstat.h index 344a3daa4..bce43416b 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -683,7 +683,7 @@ extern boolean singletics; // Netgame stuff // ============= -#include "netcode/d_clisrv.h" +#include "d_clisrv.h" extern consvar_t cv_timetic; // display high resolution timer extern consvar_t cv_powerupdisplay; // display powerups diff --git a/src/dummy/i_net.c b/src/dummy/i_net.c index 4c30dc767..f6e642022 100644 --- a/src/dummy/i_net.c +++ b/src/dummy/i_net.c @@ -1,4 +1,4 @@ -#include "../netcode/i_net.h" +#include "../i_net.h" boolean I_InitNetwork(void) { diff --git a/src/f_finale.c b/src/f_finale.c index 2122cf34d..307e00aaa 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -14,7 +14,7 @@ #include "doomdef.h" #include "doomstat.h" #include "d_main.h" -#include "netcode/d_netcmd.h" +#include "d_netcmd.h" #include "f_finale.h" #include "g_game.h" #include "hu_stuff.h" diff --git a/src/filesrch.c b/src/filesrch.c index d68a7d5ed..23b8e7f40 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -26,7 +26,7 @@ #include #include "filesrch.h" -#include "netcode/d_netfil.h" +#include "d_netfil.h" #include "m_misc.h" #include "z_zone.h" #include "m_menu.h" // Addons_option_Onchange diff --git a/src/filesrch.h b/src/filesrch.h index a934c48d6..59ef5269b 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -5,7 +5,7 @@ #define __FILESRCH_H__ #include "doomdef.h" -#include "netcode/d_netfil.h" +#include "d_netfil.h" #include "m_menu.h" // MAXSTRINGLENGTH #include "w_wad.h" diff --git a/src/g_demo.c b/src/g_demo.c index 6167b3a09..9099adc71 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -15,7 +15,7 @@ #include "console.h" #include "d_main.h" #include "d_player.h" -#include "netcode/d_clisrv.h" +#include "d_clisrv.h" #include "p_setup.h" #include "i_time.h" #include "i_system.h" diff --git a/src/g_game.c b/src/g_game.c index 2aa2d7862..dc12c2bab 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -15,8 +15,7 @@ #include "console.h" #include "d_main.h" #include "d_player.h" -#include "netcode/d_clisrv.h" -#include "netcode/net_command.h" +#include "d_clisrv.h" #include "f_finale.h" #include "p_setup.h" #include "p_saveg.h" diff --git a/src/g_input.c b/src/g_input.c index d425c6ba8..87f4d5173 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -18,7 +18,7 @@ #include "i_gamepad.h" #include "keys.h" #include "hu_stuff.h" // need HUFONT start & end -#include "netcode/d_net.h" +#include "d_net.h" #include "console.h" #define MAXMOUSESENSITIVITY 100 // sensitivity steps diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 24a39e2fb..3a6baab71 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -29,7 +29,7 @@ #include "../r_patch.h" #include "../r_picformats.h" #include "../r_bsp.h" -#include "../netcode/d_clisrv.h" +#include "../d_clisrv.h" #include "../w_wad.h" #include "../z_zone.h" #include "../r_splats.h" @@ -5234,7 +5234,7 @@ static void HWR_ProjectSprite(mobj_t *thing) { interpmobjstate_t casterinterp = { 0 }; fixed_t groundz; - fixed_t floordiff; + fixed_t floordiff; if (R_UsingFrameInterpolation() && !paused) { @@ -5244,7 +5244,7 @@ static void HWR_ProjectSprite(mobj_t *thing) { R_InterpolateMobjState(caster, FRACUNIT, &casterinterp); } - + groundz = R_GetShadowZ(thing, NULL); floordiff = abs(((thing->eflags & MFE_VERTICALFLIP) ? caster->height : 0) + casterinterp.z - groundz); diff --git a/src/netcode/http-mserv.c b/src/http-mserv.c similarity index 98% rename from src/netcode/http-mserv.c rename to src/http-mserv.c index 1ef180935..7b418c99a 100644 --- a/src/netcode/http-mserv.c +++ b/src/http-mserv.c @@ -18,15 +18,14 @@ Documentation available here. #include #endif -#include "../doomdef.h" +#include "doomdef.h" #include "d_clisrv.h" -#include "client_connection.h" -#include "../command.h" -#include "../m_argv.h" -#include "../m_menu.h" +#include "command.h" +#include "m_argv.h" +#include "m_menu.h" #include "mserv.h" #include "i_tcp.h"/* for current_port */ -#include "../i_threads.h" +#include "i_threads.h" /* reasonable default I guess?? */ #define DEFAULT_BUFFER_SIZE (4096) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 7ec33bd79..805aa694f 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -19,9 +19,7 @@ #include "m_cond.h" // emblems #include "m_misc.h" // word jumping -#include "netcode/d_clisrv.h" -#include "netcode/net_command.h" -#include "netcode/gamestate.h" +#include "d_clisrv.h" #include "g_game.h" #include "g_input.h" @@ -177,12 +175,14 @@ static huddrawlist_h luahuddrawlist_scores; static tic_t resynch_ticker = 0; +#ifndef NONET // just after static void Command_Say_f(void); static void Command_Sayto_f(void); static void Command_Sayteam_f(void); static void Command_CSay_f(void); static void Got_Saycmd(UINT8 **p, INT32 playernum); +#endif void HU_LoadGraphics(void) { @@ -327,11 +327,13 @@ void HU_LoadGraphics(void) // void HU_Init(void) { +#ifndef NONET COM_AddCommand("say", Command_Say_f); COM_AddCommand("sayto", Command_Sayto_f); COM_AddCommand("sayteam", Command_Sayteam_f); COM_AddCommand("csay", Command_CSay_f); RegisterNetXCmd(XD_SAY, Got_Saycmd); +#endif // set shift translation table shiftxform = english_shiftxform; @@ -361,6 +363,8 @@ void HU_Start(void) // EXECUTION //====================================================================== +#ifndef NONET + // EVERY CHANGE IN THIS SCRIPT IS LOL XD! BY VINCYTM static UINT32 chat_nummsg_log = 0; @@ -408,9 +412,11 @@ static void HU_removeChatText_Log(void) } chat_nummsg_log--; // lost 1 msg. } +#endif void HU_AddChatText(const char *text, boolean playsound) { +#ifndef NONET if (playsound && cv_consolechat.value != 2) // Don't play the sound if we're using hidden chat. S_StartSound(NULL, sfx_radio); // reguardless of our preferences, put all of this in the chat buffer in case we decide to change from oldchat mid-game. @@ -432,8 +438,14 @@ void HU_AddChatText(const char *text, boolean playsound) CONS_Printf("%s\n", text); else // if we aren't, still save the message to log.txt CON_LogMessage(va("%s\n", text)); +#else + (void)playsound; + CONS_Printf("%s\n", text); +#endif } +#ifndef NONET + /** Runs a say command, sending an ::XD_SAY message. * A say command consists of a signed 8-bit integer for the target, an * unsigned 8-bit flag variable, and then the message itself. @@ -853,6 +865,8 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) #endif } +#endif + // // void HU_Ticker(void) @@ -868,6 +882,7 @@ void HU_Ticker(void) else hu_showscores = false; +#ifndef NONET if (chat_on) { // count down the scroll timer. @@ -895,6 +910,7 @@ void HU_Ticker(void) HU_removeChatText_Mini(); } } +#endif if (cechotimer > 0) --cechotimer; @@ -902,6 +918,8 @@ void HU_Ticker(void) resynch_ticker++; } +#ifndef NONET + static boolean teamtalk = false; static boolean justscrolleddown; static boolean justscrolledup; @@ -1009,6 +1027,8 @@ static void HU_sendChatMessage(void) } } +#endif + void HU_clearChatChars(void) { memset(w_chat, '\0', sizeof(w_chat)); @@ -1023,13 +1043,16 @@ void HU_clearChatChars(void) // boolean HU_Responder(event_t *ev) { +#ifndef NONET INT32 c=0; +#endif if (ev->type != ev_keydown) return false; // only KeyDown events now... +#ifndef NONET c = (INT32)ev->key; if (!chat_on) @@ -1179,6 +1202,7 @@ boolean HU_Responder(event_t *ev) return true; } +#endif return false; } @@ -1188,6 +1212,8 @@ boolean HU_Responder(event_t *ev) // HEADS UP DRAWING //====================================================================== +#ifndef NONET + // Precompile a wordwrapped string to any given width. // This is a muuuch better method than V_WORDWRAP. // again stolen and modified a bit from video.c, don't mind me, will need to rearrange this one day. @@ -1767,6 +1793,7 @@ static void HU_DrawChat_Old(void) if (hu_tick < 4) V_DrawCharacter(HU_INPUTX + c, y, '_' | cv_constextsize.value |V_NOSCALESTART|t, true); } +#endif // Draw crosshairs at the exact center of the view. // In splitscreen, crosshairs are stretched vertically to compensate for V_PERPLAYER squishing them. @@ -1906,6 +1933,7 @@ static void HU_DrawDemoInfo(void) // void HU_Drawer(void) { +#ifndef NONET // draw chat string plus cursor if (chat_on) { @@ -1922,6 +1950,7 @@ void HU_Drawer(void) if (!OLDCHAT && cv_consolechat.value < 2 && netgame) // Don't display minimized chat if you set the mode to Window (Hidden) HU_drawMiniChat(); // draw messages in a cool fashion. } +#endif if (cechotimer) HU_DrawCEcho(); diff --git a/src/netcode/i_addrinfo.c b/src/i_addrinfo.c similarity index 100% rename from src/netcode/i_addrinfo.c rename to src/i_addrinfo.c diff --git a/src/netcode/i_addrinfo.h b/src/i_addrinfo.h similarity index 100% rename from src/netcode/i_addrinfo.h rename to src/i_addrinfo.h diff --git a/src/netcode/i_net.h b/src/i_net.h similarity index 98% rename from src/netcode/i_net.h rename to src/i_net.h index 66126d050..62b7528d5 100644 --- a/src/netcode/i_net.h +++ b/src/i_net.h @@ -18,8 +18,8 @@ #pragma interface #endif -#include "../doomdef.h" -#include "../command.h" +#include "doomdef.h" +#include "command.h" /// \brief program net id #define DOOMCOM_ID (INT32)0x12345678l diff --git a/src/netcode/i_tcp.c b/src/i_tcp.c similarity index 88% rename from src/netcode/i_tcp.c rename to src/i_tcp.c index bd950c355..8838ba725 100644 --- a/src/netcode/i_tcp.c +++ b/src/i_tcp.c @@ -36,100 +36,109 @@ #include #endif -#include "../doomdef.h" +#include "doomdef.h" -#ifdef USE_WINSOCK1 - #include +#if defined (NOMD5) && !defined (NONET) + //#define NONET +#endif + +#ifdef NONET + #undef HAVE_MINIUPNPC #else - #ifndef USE_WINSOCK - #include - #ifdef __APPLE_CC__ - #ifndef _BSD_SOCKLEN_T_ - #define _BSD_SOCKLEN_T_ - #endif //_BSD_SOCKLEN_T_ - #endif //__APPLE_CC__ - #include - #include - #include - #include - #endif //normal BSD API + #ifdef USE_WINSOCK1 + #include + #else + #ifndef USE_WINSOCK + #include + #ifdef __APPLE_CC__ + #ifndef _BSD_SOCKLEN_T_ + #define _BSD_SOCKLEN_T_ + #endif //_BSD_SOCKLEN_T_ + #endif //__APPLE_CC__ + #include + #include + #include + #include + #endif //normal BSD API - #include - #include + #include + #include - #if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON) - #include - #endif // UNIXCOMMON -#endif + #if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON) + #include + #endif // UNIXCOMMON + #endif -#ifdef USE_WINSOCK - // some undefined under win32 - #undef errno - //#define errno WSAGetLastError() //Alam_GBC: this is the correct way, right? - #define errno h_errno // some very strange things happen when not using h_error?!? - #ifdef EWOULDBLOCK - #undef EWOULDBLOCK - #endif - #define EWOULDBLOCK WSAEWOULDBLOCK - #ifdef EMSGSIZE - #undef EMSGSIZE - #endif - #define EMSGSIZE WSAEMSGSIZE - #ifdef ECONNREFUSED - #undef ECONNREFUSED - #endif - #define ECONNREFUSED WSAECONNREFUSED - #ifdef ETIMEDOUT - #undef ETIMEDOUT - #endif - #define ETIMEDOUT WSAETIMEDOUT - #ifndef IOC_VENDOR - #define IOC_VENDOR 0x18000000 - #endif - #ifndef _WSAIOW - #define _WSAIOW(x,y) (IOC_IN|(x)|(y)) - #endif - #ifndef SIO_UDP_CONNRESET - #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) - #endif - #ifndef AI_ADDRCONFIG - #define AI_ADDRCONFIG 0x00000400 - #endif - #ifndef STATUS_INVALID_PARAMETER - #define STATUS_INVALID_PARAMETER 0xC000000D - #endif -#endif // USE_WINSOCK + #ifdef USE_WINSOCK + // some undefined under win32 + #undef errno + //#define errno WSAGetLastError() //Alam_GBC: this is the correct way, right? + #define errno h_errno // some very strange things happen when not using h_error?!? + #ifdef EWOULDBLOCK + #undef EWOULDBLOCK + #endif + #define EWOULDBLOCK WSAEWOULDBLOCK + #ifdef EMSGSIZE + #undef EMSGSIZE + #endif + #define EMSGSIZE WSAEMSGSIZE + #ifdef ECONNREFUSED + #undef ECONNREFUSED + #endif + #define ECONNREFUSED WSAECONNREFUSED + #ifdef ETIMEDOUT + #undef ETIMEDOUT + #endif + #define ETIMEDOUT WSAETIMEDOUT + #ifndef IOC_VENDOR + #define IOC_VENDOR 0x18000000 + #endif + #ifndef _WSAIOW + #define _WSAIOW(x,y) (IOC_IN|(x)|(y)) + #endif + #ifndef SIO_UDP_CONNRESET + #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) + #endif + #ifndef AI_ADDRCONFIG + #define AI_ADDRCONFIG 0x00000400 + #endif + #ifndef STATUS_INVALID_PARAMETER + #define STATUS_INVALID_PARAMETER 0xC000000D + #endif + #endif // USE_WINSOCK -typedef union -{ - struct sockaddr any; - struct sockaddr_in ip4; -#ifdef HAVE_IPV6 - struct sockaddr_in6 ip6; -#endif -} mysockaddr_t; - -#ifdef HAVE_MINIUPNPC - #ifdef STATIC_MINIUPNPC - #define STATICLIB + typedef union + { + struct sockaddr any; + struct sockaddr_in ip4; + #ifdef HAVE_IPV6 + struct sockaddr_in6 ip6; #endif - #include "miniupnpc/miniwget.h" - #include "miniupnpc/miniupnpc.h" - #include "miniupnpc/upnpcommands.h" - #undef STATICLIB - static UINT8 UPNP_support = TRUE; -#endif // HAVE_MINIUPNC + } mysockaddr_t; + + #ifdef HAVE_MINIUPNPC + #ifdef STATIC_MINIUPNPC + #define STATICLIB + #endif + #include "miniupnpc/miniwget.h" + #include "miniupnpc/miniupnpc.h" + #include "miniupnpc/upnpcommands.h" + #undef STATICLIB + static UINT8 UPNP_support = TRUE; + #endif // HAVE_MINIUPNC + +#endif // !NONET #define MAXBANS 100 -#include "../i_system.h" +#include "i_system.h" #include "i_net.h" #include "d_net.h" #include "d_netfil.h" #include "i_tcp.h" -#include "../m_argv.h" +#include "m_argv.h" -#include "../doomstat.h" +#include "doomstat.h" // win32 #ifdef USE_WINSOCK @@ -142,7 +151,7 @@ typedef union #define SELECTTEST #define DEFAULTPORT "5029" -#ifdef USE_WINSOCK +#if defined (USE_WINSOCK) && !defined (NONET) typedef SOCKET SOCKET_TYPE; #define ERRSOCKET (SOCKET_ERROR) #else @@ -154,20 +163,22 @@ typedef union #define ERRSOCKET (-1) #endif -// define socklen_t in DOS/Windows if it is not already defined -#ifdef USE_WINSOCK1 - typedef int socklen_t; +#ifndef NONET + // define socklen_t in DOS/Windows if it is not already defined + #ifdef USE_WINSOCK1 + typedef int socklen_t; + #endif + static SOCKET_TYPE mysockets[MAXNETNODES+1] = {ERRSOCKET}; + static size_t mysocketses = 0; + static int myfamily[MAXNETNODES+1] = {0}; + static SOCKET_TYPE nodesocket[MAXNETNODES+1] = {ERRSOCKET}; + static mysockaddr_t clientaddress[MAXNETNODES+1]; + static mysockaddr_t broadcastaddress[MAXNETNODES+1]; + static size_t broadcastaddresses = 0; + static boolean nodeconnected[MAXNETNODES+1]; + static mysockaddr_t banned[MAXBANS]; + static UINT8 bannedmask[MAXBANS]; #endif -static SOCKET_TYPE mysockets[MAXNETNODES+1] = {ERRSOCKET}; -static size_t mysocketses = 0; -static int myfamily[MAXNETNODES+1] = {0}; -static SOCKET_TYPE nodesocket[MAXNETNODES+1] = {ERRSOCKET}; -static mysockaddr_t clientaddress[MAXNETNODES+1]; -static mysockaddr_t broadcastaddress[MAXNETNODES+1]; -static size_t broadcastaddresses = 0; -static boolean nodeconnected[MAXNETNODES+1]; -static mysockaddr_t banned[MAXBANS]; -static UINT8 bannedmask[MAXBANS]; static size_t numbans = 0; static boolean SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1? @@ -176,6 +187,7 @@ static boolean init_tcp_driver = false; static const char *serverport_name = DEFAULTPORT; static const char *clientport_name;/* any port */ +#ifndef NONET #ifdef USE_WINSOCK // stupid microsoft makes things complicated static char *get_WSAErrorStr(int e) @@ -362,33 +374,47 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk) #endif return s; } +#endif static const char *SOCK_GetNodeAddress(INT32 node) { if (node == 0) return "self"; +#ifdef NONET + return NULL; +#else if (!nodeconnected[node]) return NULL; return SOCK_AddrToStr(&clientaddress[node]); +#endif } static const char *SOCK_GetBanAddress(size_t ban) { if (ban >= numbans) return NULL; +#ifdef NONET + return NULL; +#else return SOCK_AddrToStr(&banned[ban]); +#endif } static const char *SOCK_GetBanMask(size_t ban) { +#ifdef NONET + (void)ban; +#else static char s[16]; //255.255.255.255 netmask? no, just CDIR for only if (ban >= numbans) return NULL; if (sprintf(s,"%d",bannedmask[ban]) > 0) return s; +#endif return NULL; } +#ifndef NONET static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask) { UINT32 bitmask = INADDR_NONE; @@ -416,20 +442,24 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask) */ static void cleanupnodes(void) { + SINT8 j; + if (!Playing()) return; // Why can't I start at zero? - for (SINT8 j = 1; j < MAXNETNODES; j++) - if (!(netnodes[j].ingame || SendingFile(j))) + for (j = 1; j < MAXNETNODES; j++) + if (!(nodeingame[j] || SendingFile(j))) nodeconnected[j] = false; } static SINT8 getfreenode(void) { + SINT8 j; + cleanupnodes(); - for (SINT8 j = 0; j < MAXNETNODES; j++) + for (j = 0; j < MAXNETNODES; j++) if (!nodeconnected[j]) { nodeconnected[j] = true; @@ -442,8 +472,8 @@ static SINT8 getfreenode(void) * downloading a needed wad, but it's better than not letting anyone join... */ /*I_Error("No more free nodes!!1!11!11!!1111\n"); - for (SINT8 j = 1; j < MAXNETNODES; j++) - if (!netnodes[j].ingame) + for (j = 1; j < MAXNETNODES; j++) + if (!nodeingame[j]) return j;*/ return -1; @@ -454,27 +484,28 @@ void Command_Numnodes(void) { INT32 connected = 0; INT32 ingame = 0; + INT32 i; - for (INT32 i = 1; i < MAXNETNODES; i++) + for (i = 1; i < MAXNETNODES; i++) { - if (!(nodeconnected[i] || netnodes[i].ingame)) + if (!(nodeconnected[i] || nodeingame[i])) continue; if (nodeconnected[i]) connected++; - if (netnodes[i].ingame) + if (nodeingame[i]) ingame++; CONS_Printf("%2d - ", i); - if (netnodes[i].player != -1) - CONS_Printf("player %.2d", netnodes[i].player); + if (nodetoplayer[i] != -1) + CONS_Printf("player %.2d", nodetoplayer[i]); else CONS_Printf(" "); if (nodeconnected[i]) CONS_Printf(" - connected"); else CONS_Printf(" - "); - if (netnodes[i].ingame) + if (nodeingame[i]) CONS_Printf(" - ingame"); else CONS_Printf(" - "); @@ -487,17 +518,19 @@ void Command_Numnodes(void) connected, ingame); } #endif +#endif +#ifndef NONET // Returns true if a packet was received from a new node, false in all other cases static boolean SOCK_Get(void) { - size_t i; + size_t i, n; int j; ssize_t c; mysockaddr_t fromaddress; socklen_t fromlen; - for (size_t n = 0; n < mysocketses; n++) + for (n = 0; n < mysocketses; n++) { fromlen = (socklen_t)sizeof(fromaddress); c = recvfrom(mysockets[n], (char *)&doomcom->data, MAXPACKETLENGTH, 0, @@ -550,17 +583,20 @@ static boolean SOCK_Get(void) doomcom->remotenode = -1; // no packet return false; } +#endif // check if we can send (do not go over the buffer) +#ifndef NONET static fd_set masterset; #ifdef SELECTTEST static boolean FD_CPY(fd_set *src, fd_set *dst, SOCKET_TYPE *fd, size_t len) { + size_t i; boolean testset = false; FD_ZERO(dst); - for (size_t i = 0; i < len;i++) + for (i = 0; i < len;i++) { if(fd[i] != (SOCKET_TYPE)ERRSOCKET && FD_ISSET(fd[i], src) && !FD_ISSET(fd[i], dst)) // no checking for dups @@ -600,7 +636,9 @@ static boolean SOCK_CanGet(void) return false; } #endif +#endif +#ifndef NONET static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr) { socklen_t d4 = (socklen_t)sizeof(struct sockaddr_in); @@ -624,15 +662,16 @@ static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr static void SOCK_Send(void) { ssize_t c = ERRSOCKET; + size_t i, j; if (!nodeconnected[doomcom->remotenode]) return; if (doomcom->remotenode == BROADCASTADDR) { - for (size_t i = 0; i < mysocketses; i++) + for (i = 0; i < mysocketses; i++) { - for (size_t j = 0; j < broadcastaddresses; j++) + for (j = 0; j < broadcastaddresses; j++) { if (myfamily[i] == broadcastaddress[j].any.sa_family) SOCK_SendToAddr(mysockets[i], &broadcastaddress[j]); @@ -642,7 +681,7 @@ static void SOCK_Send(void) } else if (nodesocket[doomcom->remotenode] == (SOCKET_TYPE)ERRSOCKET) { - for (size_t i = 0; i < mysocketses; i++) + for (i = 0; i < mysocketses; i++) { if (myfamily[i] == clientaddress[doomcom->remotenode].any.sa_family) SOCK_SendToAddr(mysockets[i], &clientaddress[doomcom->remotenode]); @@ -662,7 +701,9 @@ static void SOCK_Send(void) SOCK_GetNodeAddress(doomcom->remotenode), e, strerror(e)); } } +#endif +#ifndef NONET static void SOCK_FreeNodenum(INT32 numnode) { // can't disconnect from self :) @@ -677,10 +718,12 @@ static void SOCK_FreeNodenum(INT32 numnode) // put invalid address memset(&clientaddress[numnode], 0, sizeof (clientaddress[numnode])); } +#endif // // UDPsocket // +#ifndef NONET // allocate a socket static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen) @@ -1001,10 +1044,12 @@ static boolean UDP_Socket(void) return true; } +#endif boolean I_InitTcpDriver(void) { boolean tcp_was_up = init_tcp_driver; +#ifndef NONET if (!init_tcp_driver) { #ifdef USE_WINSOCK @@ -1059,7 +1104,7 @@ boolean I_InitTcpDriver(void) #endif init_tcp_driver = true; } - +#endif if (!tcp_was_up && init_tcp_driver) { I_AddExitFunc(I_ShutdownTcpDriver); @@ -1073,9 +1118,11 @@ boolean I_InitTcpDriver(void) return init_tcp_driver; } +#ifndef NONET static void SOCK_CloseSocket(void) { - for (size_t i=0; i < MAXNETNODES+1; i++) + size_t i; + for (i=0; i < MAXNETNODES+1; i++) { if (mysockets[i] != (SOCKET_TYPE)ERRSOCKET && FD_ISSET(mysockets[i], &masterset)) @@ -1086,9 +1133,11 @@ static void SOCK_CloseSocket(void) mysockets[i] = ERRSOCKET; } } +#endif void I_ShutdownTcpDriver(void) { +#ifndef NONET SOCK_CloseSocket(); CONS_Printf("I_ShutdownTcpDriver: "); @@ -1098,8 +1147,10 @@ void I_ShutdownTcpDriver(void) #endif CONS_Printf("shut down\n"); init_tcp_driver = false; +#endif } +#ifndef NONET static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port) { SINT8 newnode = -1; @@ -1143,13 +1194,17 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port) I_freeaddrinfo(ai); return newnode; } +#endif static boolean SOCK_OpenSocket(void) { +#ifndef NONET + size_t i; + memset(clientaddress, 0, sizeof (clientaddress)); nodeconnected[0] = true; // always connected to self - for (size_t i = 1; i < MAXNETNODES; i++) + for (i = 1; i < MAXNETNODES; i++) nodeconnected[i] = false; nodeconnected[BROADCASTADDR] = true; I_NetSend = SOCK_Send; @@ -1167,12 +1222,18 @@ static boolean SOCK_OpenSocket(void) // build the socket but close it first SOCK_CloseSocket(); return UDP_Socket(); +#else + return false; +#endif } static boolean SOCK_Ban(INT32 node) { if (node > MAXNETNODES) return false; +#ifdef NONET + return false; +#else if (numbans == MAXBANS) return false; @@ -1191,10 +1252,16 @@ static boolean SOCK_Ban(INT32 node) #endif numbans++; return true; +#endif } static boolean SOCK_SetBanAddress(const char *address, const char *mask) { +#ifdef NONET + (void)address; + (void)mask; + return false; +#else struct my_addrinfo *ai, *runp, hints; int gaie; @@ -1239,6 +1306,7 @@ static boolean SOCK_SetBanAddress(const char *address, const char *mask) I_freeaddrinfo(ai); return true; +#endif } static void SOCK_ClearBans(void) diff --git a/src/netcode/i_tcp.h b/src/i_tcp.h similarity index 100% rename from src/netcode/i_tcp.h rename to src/i_tcp.h diff --git a/src/i_time.c b/src/i_time.c index 9303d7be7..c1cc9dfd4 100644 --- a/src/i_time.c +++ b/src/i_time.c @@ -17,7 +17,7 @@ #include "command.h" #include "doomtype.h" -#include "netcode/d_netcmd.h" +#include "d_netcmd.h" #include "m_fixed.h" #include "i_system.h" diff --git a/src/lua_baselib.c b/src/lua_baselib.c index ea519be55..c94e9e91e 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -27,11 +27,11 @@ #include "y_inter.h" #include "hu_stuff.h" // HU_AddChatText #include "console.h" -#include "netcode/d_netcmd.h" // IsPlayerAdmin +#include "d_netcmd.h" // IsPlayerAdmin #include "m_menu.h" // Player Setup menu color stuff #include "m_misc.h" // M_MapNumber #include "b_bot.h" // B_UpdateBotleader -#include "netcode/d_clisrv.h" // CL_RemovePlayer +#include "d_clisrv.h" // CL_RemovePlayer #include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision #include "lua_script.h" diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index a1bdf380d..816051199 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -16,7 +16,6 @@ #include "g_game.h" #include "byteptr.h" #include "z_zone.h" -#include "netcode/net_command.h" #include "lua_script.h" #include "lua_libs.h" diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 2b1fef238..ef8426d7a 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -25,7 +25,7 @@ #include "lua_hud.h" // hud_running errors #include "m_perfstats.h" -#include "netcode/d_netcmd.h" // for cv_perfstats +#include "d_netcmd.h" // for cv_perfstats #include "i_system.h" // I_GetPreciseTime /* ========================================================================= diff --git a/src/lua_script.c b/src/lua_script.c index f1c800df5..8d8fb295c 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -28,7 +28,7 @@ #include "p_slopes.h" // for P_SlopeById and slopelist #include "p_polyobj.h" // polyobj_t, PolyObjects #ifdef LUA_ALLOW_BYTECODE -#include "netcode/d_netfil.h" // for LUA_DumpFile +#include "d_netfil.h" // for LUA_DumpFile #endif #include "lua_script.h" diff --git a/src/m_cheat.c b/src/m_cheat.c index 36b2d1907..f94377450 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -19,7 +19,7 @@ #include "r_local.h" #include "p_local.h" #include "p_setup.h" -#include "netcode/d_net.h" +#include "d_net.h" #include "m_cheat.h" #include "m_menu.h" diff --git a/src/m_menu.c b/src/m_menu.c index eecac55a7..1e7e1a761 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -20,7 +20,7 @@ #include "doomdef.h" #include "d_main.h" -#include "netcode/d_netcmd.h" +#include "d_netcmd.h" #include "console.h" #include "r_fps.h" #include "r_local.h" @@ -55,10 +55,8 @@ #include "hardware/hw_main.h" #endif -#include "netcode/d_net.h" -#include "netcode/mserv.h" -#include "netcode/server_connection.h" -#include "netcode/client_connection.h" +#include "d_net.h" +#include "mserv.h" #include "m_misc.h" #include "m_anigif.h" #include "byteptr.h" @@ -149,7 +147,9 @@ static struct INT32 index; } gamepadInfo[MAX_CONNECTED_GAMEPADS + 1]; +#ifndef NONET static UINT32 serverlistpage; +#endif static UINT8 numsaves = 0; static saveinfo_t* savegameinfo = NULL; // Extra info about the save games. @@ -189,8 +189,10 @@ static void M_GoBack(INT32 choice); static void M_StopMessage(INT32 choice); static boolean stopstopmessage = false; +#ifndef NONET static void M_HandleServerPage(INT32 choice); static void M_RoomMenu(INT32 choice); +#endif // Prototyping is fun, innit? // ========================================================================== @@ -292,6 +294,7 @@ static void M_SetupMultiPlayer2(INT32 choice); static void M_StartSplitServerMenu(INT32 choice); static void M_StartServer(INT32 choice); static void M_ServerOptions(INT32 choice); +#ifndef NONET static void M_StartServerMenu(INT32 choice); static void M_ConnectMenu(INT32 choice); static void M_ConnectMenuModChecks(INT32 choice); @@ -299,6 +302,7 @@ static void M_Refresh(INT32 choice); static void M_Connect(INT32 choice); static void M_ChooseRoom(INT32 choice); menu_t MP_MainDef; +#endif // Options // Split into multiple parts due to size @@ -377,9 +381,11 @@ static void M_DrawVideoMode(void); static void M_DrawColorMenu(void); static void M_DrawScreenshotMenu(void); static void M_DrawMonitorToggles(void); +#ifndef NONET static void M_DrawConnectMenu(void); static void M_DrawMPMainMenu(void); static void M_DrawRoomMenu(void); +#endif static void M_DrawGamepadList(void); static void M_DrawSetupMultiPlayerMenu(void); @@ -393,8 +399,10 @@ static void M_HandleImageDef(INT32 choice); static void M_HandleLoadSave(INT32 choice); static void M_HandleLevelStats(INT32 choice); static void M_HandlePlaystyleMenu(INT32 choice); +#ifndef NONET static boolean M_CancelConnect(void); static void M_HandleConnectIP(INT32 choice); +#endif static void M_HandleSetupMultiPlayer(INT32 choice); static void M_HandleVideoMode(INT32 choice); @@ -493,7 +501,11 @@ consvar_t cv_dummyloadless = CVAR_INIT ("dummyloadless", "In-game", CV_HIDEN, lo static menuitem_t MainMenu[] = { {IT_STRING|IT_CALL, NULL, "1 Player", M_SinglePlayerMenu, 76}, +#ifndef NONET {IT_STRING|IT_SUBMENU, NULL, "Multiplayer", &MP_MainDef, 84}, +#else + {IT_STRING|IT_CALL, NULL, "Multiplayer", M_StartSplitServerMenu, 84}, +#endif {IT_STRING|IT_CALL, NULL, "Extras", M_SecretsMenu, 92}, {IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 100}, {IT_STRING|IT_CALL, NULL, "Options", M_Options, 108}, @@ -944,10 +956,16 @@ static menuitem_t SP_PlayerMenu[] = static menuitem_t MP_SplitServerMenu[] = { {IT_STRING|IT_CALL, NULL, "Select Gametype/Level...", M_MapChange, 100}, +#ifdef NONET // In order to keep player setup accessible. + {IT_STRING|IT_CALL, NULL, "Player 1 setup...", M_SetupMultiPlayer, 110}, + {IT_STRING|IT_CALL, NULL, "Player 2 setup...", M_SetupMultiPlayer2, 120}, +#endif {IT_STRING|IT_CALL, NULL, "More Options...", M_ServerOptions, 130}, {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 140}, }; +#ifndef NONET + static menuitem_t MP_MainMenu[] = { {IT_HEADER, NULL, "Join a game", NULL, 0}, @@ -1034,6 +1052,8 @@ menuitem_t MP_RoomMenu[] = {IT_DISABLED, NULL, "", M_ChooseRoom, 162}, }; +#endif + static menuitem_t MP_PlayerSetupMenu[] = { {IT_KEYHANDLER, NULL, "", M_HandleSetupMultiPlayer, 0}, // name @@ -1601,12 +1621,14 @@ enum static menuitem_t OP_ServerOptionsMenu[] = { {IT_HEADER, NULL, "General", NULL, 0}, +#ifndef NONET {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Server name", &cv_servername, 7}, {IT_STRING | IT_CVAR, NULL, "Max Players", &cv_maxplayers, 21}, {IT_STRING | IT_CVAR, NULL, "Allow Add-on Downloading", &cv_downloading, 26}, {IT_STRING | IT_CVAR, NULL, "Allow players to join", &cv_allownewplayer, 31}, {IT_STRING | IT_CVAR, NULL, "Minutes for reconnecting", &cv_rejointimeout, 36}, +#endif {IT_STRING | IT_CVAR, NULL, "Map progression", &cv_advancemap, 41}, {IT_STRING | IT_CVAR, NULL, "Intermission Timer", &cv_inttime, 46}, @@ -1645,6 +1667,7 @@ static menuitem_t OP_ServerOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Autobalance sizes", &cv_autobalance, 216}, {IT_STRING | IT_CVAR, NULL, "Scramble on Map Change", &cv_scrambleonchange, 221}, +#ifndef NONET {IT_HEADER, NULL, "Advanced", NULL, 230}, {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server", &cv_masterserver, 236}, @@ -1652,6 +1675,7 @@ static menuitem_t OP_ServerOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 256}, {IT_STRING | IT_CVAR, NULL, "Show IP Address of Joiners", &cv_showjoinaddress, 261}, +#endif }; static menuitem_t OP_MonitorToggleMenu[] = @@ -1961,7 +1985,11 @@ menu_t MP_SplitServerDef = MTREE2(MN_MP_MAIN, MN_MP_SPLITSCREEN), "M_MULTI", sizeof (MP_SplitServerMenu)/sizeof (menuitem_t), +#ifndef NONET &MP_MainDef, +#else + &MainDef, +#endif MP_SplitServerMenu, M_DrawServerMenu, 27, 30 - 50, @@ -1969,6 +1997,8 @@ menu_t MP_SplitServerDef = NULL }; +#ifndef NONET + menu_t MP_MainDef = { MN_MP_MAIN, @@ -2020,10 +2050,15 @@ menu_t MP_RoomDef = 0, NULL }; +#endif menu_t MP_PlayerSetupDef = { +#ifdef NONET + MTREE2(MN_MP_MAIN, MN_MP_PLAYERSETUP), +#else MTREE3(MN_MP_MAIN, MN_MP_SPLITSCREEN, MN_MP_PLAYERSETUP), +#endif "M_SPLAYR", sizeof (MP_PlayerSetupMenu)/sizeof (menuitem_t), &MainDef, // doesn't matter @@ -3973,7 +4008,9 @@ void M_Init(void) OP_GamepadSetMenu[i].itemaction = M_AssignGamepad; } +#ifndef NONET CV_RegisterVar(&cv_serversort); +#endif } void M_InitCharacterTables(void) @@ -10986,6 +11023,7 @@ static void M_EndGame(INT32 choice) #define S_LINEY(n) currentMenu->y + SERVERHEADERHEIGHT + (n * SERVERLINEHEIGHT) +#ifndef NONET static UINT32 localservercount; static void M_HandleServerPage(INT32 choice) @@ -11257,9 +11295,11 @@ static int ServerListEntryComparator_modified(const void *entry1, const void *en // Default to strcmp. return strcmp(sa->info.servername, sb->info.servername); } +#endif void M_SortServerList(void) { +#ifndef NONET switch(cv_serversort.value) { case 0: // Ping. @@ -11281,8 +11321,10 @@ void M_SortServerList(void) qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametypename); break; } +#endif } +#ifndef NONET #ifdef UPDATE_ALERT static boolean M_CheckMODVersion(int id) { @@ -11481,6 +11523,7 @@ static void M_ChooseRoom(INT32 choice) if (currentMenu == &MP_ConnectDef) M_Refresh(0); } +#endif //NONET //=========================================================================== // Start Server Menu @@ -11528,6 +11571,7 @@ static void M_DrawServerMenu(void) { M_DrawGenericMenu(); +#ifndef NONET // Room name if (currentMenu == &MP_ServerDef) { @@ -11539,10 +11583,15 @@ static void M_DrawServerMenu(void) V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey, V_YELLOWMAP, room_list[menuRoomIndex].name); } +#endif if (cv_nextmap.value) { +#ifndef NONET #define imgheight MP_ServerMenu[mp_server_levelgt].alphaKey +#else +#define imgheight 100 +#endif patch_t *PictureOfLevel; lumpnum_t lumpnum; char headerstr[40]; @@ -11594,6 +11643,7 @@ static void M_ServerOptions(INT32 choice) { (void)choice; +#ifndef NONET if ((splitscreen && !netgame) || currentMenu == &MP_SplitServerDef) { OP_ServerOptionsMenu[ 1].status = IT_GRAYEDOUT; // Server name @@ -11614,6 +11664,7 @@ static void M_ServerOptions(INT32 choice) OP_ServerOptionsMenu[37].status = IT_STRING | IT_CVAR; OP_ServerOptionsMenu[38].status = IT_STRING | IT_CVAR; } +#endif /* Disable fading because of different menu head. */ if (currentMenu == &OP_MainDef)/* from Options menu */ @@ -11625,6 +11676,7 @@ static void M_ServerOptions(INT32 choice) M_SetupNextMenu(&OP_ServerOptionsDef); } +#ifndef NONET static void M_StartServerMenu(INT32 choice) { (void)choice; @@ -11881,6 +11933,7 @@ static void M_HandleConnectIP(INT32 choice) M_ClearMenus(true); } } +#endif //!NONET // ======================== // MULTIPLAYER PLAYER SETUP diff --git a/src/m_menu.h b/src/m_menu.h index 809186a17..8d023811d 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -20,7 +20,7 @@ #include "command.h" #include "f_finale.h" // for ttmode_enum #include "i_threads.h" -#include "netcode/mserv.h" +#include "mserv.h" #include "r_things.h" // for SKINNAMESIZE // Compatibility with old-style named NiGHTS replay files. @@ -74,7 +74,7 @@ typedef enum MN_MP_SERVER, MN_MP_CONNECT, MN_MP_ROOM, - MN_MP_PLAYERSETUP, + MN_MP_PLAYERSETUP, // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET MN_MP_SERVER_OPTIONS, // Options diff --git a/src/m_perfstats.c b/src/m_perfstats.c index cca4c62ca..9f65a7616 100644 --- a/src/m_perfstats.c +++ b/src/m_perfstats.c @@ -12,7 +12,7 @@ #include "m_perfstats.h" #include "v_video.h" #include "i_video.h" -#include "netcode/d_netcmd.h" +#include "d_netcmd.h" #include "r_main.h" #include "i_system.h" #include "z_zone.h" diff --git a/src/netcode/mserv.c b/src/mserv.c similarity index 97% rename from src/netcode/mserv.c rename to src/mserv.c index f603d78e5..bff562c95 100644 --- a/src/netcode/mserv.c +++ b/src/mserv.c @@ -15,14 +15,13 @@ #include #endif -#include "../doomstat.h" -#include "../doomdef.h" -#include "../command.h" -#include "../i_threads.h" +#include "doomstat.h" +#include "doomdef.h" +#include "command.h" +#include "i_threads.h" #include "mserv.h" -#include "client_connection.h" -#include "../m_menu.h" -#include "../z_zone.h" +#include "m_menu.h" +#include "z_zone.h" #ifdef MASTERSERVER @@ -46,7 +45,9 @@ static I_cond MSCond; # define Unlock_state() #endif/*HAVE_THREADS*/ +#ifndef NONET static void Command_Listserv_f(void); +#endif #endif/*MASTERSERVER*/ @@ -88,6 +89,7 @@ msg_rooms_t room_list[NUM_LIST_ROOMS+1]; // +1 for easy test */ void AddMServCommands(void) { +#ifndef NONET CV_RegisterVar(&cv_masterserver); CV_RegisterVar(&cv_masterserver_update_rate); CV_RegisterVar(&cv_masterserver_timeout); @@ -98,6 +100,7 @@ void AddMServCommands(void) COM_AddCommand("listserv", Command_Listserv_f); COM_AddCommand("masterserver_update", Update_parameters); // allows people to updates manually in case you were delisted by accident #endif +#endif } #ifdef MASTERSERVER @@ -186,6 +189,7 @@ void GetMODVersion_Console(void) } #endif +#ifndef NONET /** Gets a list of game servers. Called from console. */ static void Command_Listserv_f(void) @@ -196,6 +200,7 @@ static void Command_Listserv_f(void) HMS_list_servers(); } } +#endif static void Finish_registration (void) diff --git a/src/netcode/mserv.h b/src/mserv.h similarity index 99% rename from src/netcode/mserv.h rename to src/mserv.h index 7fdf3ed1b..23b26fbc5 100644 --- a/src/netcode/mserv.h +++ b/src/mserv.h @@ -14,7 +14,7 @@ #ifndef _MSERV_H_ #define _MSERV_H_ -#include "../i_threads.h" +#include "i_threads.h" // lowered from 32 due to menu changes #define NUM_LIST_ROOMS 16 diff --git a/src/netcode/Sourcefile b/src/netcode/Sourcefile deleted file mode 100644 index 7c0354714..000000000 --- a/src/netcode/Sourcefile +++ /dev/null @@ -1,13 +0,0 @@ -d_clisrv.c -server_connection.c -client_connection.c -tic_command.c -net_command.c -gamestate.c -commands.c -d_net.c -d_netcmd.c -d_netfil.c -http-mserv.c -i_tcp.c -mserv.c diff --git a/src/netcode/client_connection.c b/src/netcode/client_connection.c deleted file mode 100644 index d363d7d5a..000000000 --- a/src/netcode/client_connection.c +++ /dev/null @@ -1,1161 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file client_connection.h -/// \brief Client connection handling - -#include "client_connection.h" -#include "gamestate.h" -#include "d_clisrv.h" -#include "d_netfil.h" -#include "../d_main.h" -#include "../f_finale.h" -#include "../g_game.h" -#include "../i_gamepad.h" -#include "i_net.h" -#include "../i_system.h" -#include "../i_time.h" -#include "../i_video.h" -#include "../m_menu.h" -#include "../m_misc.h" -#include "../snake.h" -#include "../s_sound.h" -#include "../v_video.h" -#include "../y_inter.h" -#include "../z_zone.h" -#include "../doomtype.h" -#include "../doomstat.h" - -cl_mode_t cl_mode = CL_SEARCHING; -static UINT16 cl_lastcheckedfilecount = 0; // used for full file list -boolean serverisfull = false; // lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not -tic_t firstconnectattempttime = 0; -UINT8 mynode; -static void *snake = NULL; - -static void CL_DrawConnectionStatusBox(void) -{ - M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1); - if (cl_mode != CL_CONFIRMCONNECT) - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); -} - -// -// CL_DrawConnectionStatus -// -// Keep the local client informed of our status. -// -static inline void CL_DrawConnectionStatus(void) -{ - INT32 ccstime = I_GetTime(); - - // Draw background fade - V_DrawFadeScreen(0xFF00, 16); // force default - - if (cl_mode != CL_DOWNLOADFILES && cl_mode != CL_LOADFILES) - { - INT32 animtime = ((ccstime / 4) & 15) + 16; - UINT8 palstart; - const char *cltext; - - // Draw the bottom box. - CL_DrawConnectionStatusBox(); - - if (cl_mode == CL_SEARCHING) - palstart = 32; // Red - else if (cl_mode == CL_CONFIRMCONNECT) - palstart = 48; // Orange - else - palstart = 96; // Green - - if (!(cl_mode == CL_DOWNLOADSAVEGAME && lastfilenum != -1)) - for (INT32 i = 0; i < 16; ++i) // 15 pal entries total. - V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-16, 16, 8, palstart + ((animtime - i) & 15)); - - switch (cl_mode) - { - case CL_DOWNLOADSAVEGAME: - if (fileneeded && lastfilenum != -1) - { - UINT32 currentsize = fileneeded[lastfilenum].currentsize; - UINT32 totalsize = fileneeded[lastfilenum].totalsize; - INT32 dldlength; - - cltext = M_GetText("Downloading game state..."); - Net_GetNetStat(); - - dldlength = (INT32)((currentsize/(double)totalsize) * 256); - if (dldlength > 256) - dldlength = 256; - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, dldlength, 8, 96); - - V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, - va(" %4uK/%4uK",currentsize>>10,totalsize>>10)); - - V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, - va("%3.1fK/s ", ((double)getbps)/1024)); - } - else - cltext = M_GetText("Waiting to download game state..."); - break; - case CL_ASKFULLFILELIST: - case CL_CHECKFILES: - cltext = M_GetText("Checking server addon list..."); - break; - case CL_CONFIRMCONNECT: - cltext = ""; - break; - case CL_LOADFILES: - cltext = M_GetText("Loading server addons..."); - break; - case CL_ASKJOIN: - case CL_WAITJOINRESPONSE: - if (serverisfull) - cltext = M_GetText("Server full, waiting for a slot..."); - else - cltext = M_GetText("Requesting to join..."); - break; - default: - cltext = M_GetText("Connecting to server..."); - break; - } - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, cltext); - } - else - { - if (cl_mode == CL_LOADFILES) - { - INT32 totalfileslength; - INT32 loadcompletednum = 0; - - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); - - // ima just count files here - if (fileneeded) - { - for (INT32 i = 0; i < fileneedednum; i++) - if (fileneeded[i].status == FS_OPEN) - loadcompletednum++; - } - - // Loading progress - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, "Loading server addons..."); - totalfileslength = (INT32)((loadcompletednum/(double)(fileneedednum)) * 256); - M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, totalfileslength, 8, 96); - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, - va(" %2u/%2u Files",loadcompletednum,fileneedednum)); - } - else if (lastfilenum != -1) - { - INT32 dldlength; - static char tempname[28]; - fileneeded_t *file; - char *filename; - - if (snake) - Snake_Draw(snake); - - // Draw the bottom box. - CL_DrawConnectionStatusBox(); - - if (fileneeded) - { - file = &fileneeded[lastfilenum]; - filename = file->filename; - } - else - return; - - Net_GetNetStat(); - dldlength = (INT32)((file->currentsize/(double)file->totalsize) * 256); - if (dldlength > 256) - dldlength = 256; - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, dldlength, 8, 96); - - memset(tempname, 0, sizeof(tempname)); - // offset filename to just the name only part - filename += strlen(filename) - nameonlylength(filename); - - if (strlen(filename) > sizeof(tempname)-1) // too long to display fully - { - size_t endhalfpos = strlen(filename)-10; - // display as first 14 chars + ... + last 10 chars - // which should add up to 27 if our math(s) is correct - snprintf(tempname, sizeof(tempname), "%.14s...%.10s", filename, filename+endhalfpos); - } - else // we can copy the whole thing in safely - { - strncpy(tempname, filename, sizeof(tempname)-1); - } - - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, - va(M_GetText("Downloading \"%s\""), tempname)); - V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, - va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,file->totalsize>>10)); - V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, - va("%3.1fK/s ", ((double)getbps)/1024)); - } - else - { - if (snake) - Snake_Draw(snake); - - CL_DrawConnectionStatusBox(); - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, - M_GetText("Waiting to download files...")); - } - } -} - -static boolean CL_AskFileList(INT32 firstfile) -{ - netbuffer->packettype = PT_TELLFILESNEEDED; - netbuffer->u.filesneedednum = firstfile; - - return HSendPacket(servernode, false, 0, sizeof (INT32)); -} - -/** Sends a PT_CLIENTJOIN packet to the server - * - * \return True if the packet was successfully sent - * - */ -boolean CL_SendJoin(void) -{ - UINT8 localplayers = 1; - if (netgame) - CONS_Printf(M_GetText("Sending join request...\n")); - netbuffer->packettype = PT_CLIENTJOIN; - - netbuffer->u.clientcfg.modversion = MODVERSION; - strncpy(netbuffer->u.clientcfg.application, - SRB2APPLICATION, - sizeof netbuffer->u.clientcfg.application); - - if (splitscreen || botingame) - localplayers++; - netbuffer->u.clientcfg.localplayers = localplayers; - - CleanupPlayerName(consoleplayer, cv_playername.zstring); - if (splitscreen) - CleanupPlayerName(1, cv_playername2.zstring); // 1 is a HACK? oh no - - strncpy(netbuffer->u.clientcfg.names[0], cv_playername.zstring, MAXPLAYERNAME); - strncpy(netbuffer->u.clientcfg.names[1], cv_playername2.zstring, MAXPLAYERNAME); - - return HSendPacket(servernode, true, 0, sizeof (clientconfig_pak)); -} - -static void SendAskInfo(INT32 node) -{ - const tic_t asktime = I_GetTime(); - netbuffer->packettype = PT_ASKINFO; - netbuffer->u.askinfo.version = VERSION; - netbuffer->u.askinfo.time = (tic_t)LONG(asktime); - - // Even if this never arrives due to the host being firewalled, we've - // now allowed traffic from the host to us in, so once the MS relays - // our address to the host, it'll be able to speak to us. - HSendPacket(node, false, 0, sizeof (askinfo_pak)); -} - -serverelem_t serverlist[MAXSERVERLIST]; -UINT32 serverlistcount = 0; - -#define FORCECLOSE 0x8000 - -static void SL_ClearServerList(INT32 connectedserver) -{ - for (UINT32 i = 0; i < serverlistcount; i++) - if (connectedserver != serverlist[i].node) - { - Net_CloseConnection(serverlist[i].node|FORCECLOSE); - serverlist[i].node = 0; - } - serverlistcount = 0; -} - -static UINT32 SL_SearchServer(INT32 node) -{ - for (UINT32 i = 0; i < serverlistcount; i++) - if (serverlist[i].node == node) - return i; - - return UINT32_MAX; -} - -static void SL_InsertServer(serverinfo_pak* info, SINT8 node) -{ - UINT32 i; - - // search if not already on it - i = SL_SearchServer(node); - if (i == UINT32_MAX) - { - // not found add it - if (serverlistcount >= MAXSERVERLIST) - return; // list full - - // check it later if connecting to this one - if (node != servernode) - { - if (info->_255 != 255) - return; // Old packet format - - if (info->packetversion != PACKETVERSION) - return; // Old new packet format - - if (info->version != VERSION) - return; // Not same version. - - if (info->subversion != SUBVERSION) - return; // Close, but no cigar. - - if (strcmp(info->application, SRB2APPLICATION)) - return; // That's a different mod - } - - i = serverlistcount++; - } - - serverlist[i].info = *info; - serverlist[i].node = node; - - // resort server list - M_SortServerList(); -} - -#if defined (MASTERSERVER) && defined (HAVE_THREADS) -struct Fetch_servers_ctx -{ - int room; - int id; -}; - -static void -Fetch_servers_thread (struct Fetch_servers_ctx *ctx) -{ - msg_server_t *server_list; - - server_list = GetShortServersList(ctx->room, ctx->id); - - if (server_list) - { - I_lock_mutex(&ms_QueryId_mutex); - { - if (ctx->id != ms_QueryId) - { - free(server_list); - server_list = NULL; - } - } - I_unlock_mutex(ms_QueryId_mutex); - - if (server_list) - { - I_lock_mutex(&m_menu_mutex); - { - if (m_waiting_mode == M_WAITING_SERVERS) - m_waiting_mode = M_NOT_WAITING; - } - I_unlock_mutex(m_menu_mutex); - - I_lock_mutex(&ms_ServerList_mutex); - { - ms_ServerList = server_list; - } - I_unlock_mutex(ms_ServerList_mutex); - } - } - - free(ctx); -} -#endif // defined (MASTERSERVER) && defined (HAVE_THREADS) - -void CL_QueryServerList (msg_server_t *server_list) -{ - for (INT32 i = 0; server_list[i].header.buffer[0]; i++) - { - // Make sure MS version matches our own, to - // thwart nefarious servers who lie to the MS. - - // lol bruh, that version COMES from the servers - //if (strcmp(version, server_list[i].version) == 0) - { - INT32 node = I_NetMakeNodewPort(server_list[i].ip, server_list[i].port); - if (node == -1) - break; // no more node free - SendAskInfo(node); - // Force close the connection so that servers can't eat - // up nodes forever if we never get a reply back from them - // (usually when they've not forwarded their ports). - // - // Don't worry, we'll get in contact with the working - // servers again when they send SERVERINFO to us later! - // - // (Note: as a side effect this probably means every - // server in the list will probably be using the same node (e.g. node 1), - // not that it matters which nodes they use when - // the connections are closed afterwards anyway) - // -- Monster Iestyn 12/11/18 - Net_CloseConnection(node|FORCECLOSE); - } - } -} - -void CL_UpdateServerList(boolean internetsearch, INT32 room) -{ - (void)internetsearch; - (void)room; - - SL_ClearServerList(0); - - if (!netgame && I_NetOpenSocket) - { - if (I_NetOpenSocket()) - { - netgame = true; - multiplayer = true; - } - } - - // search for local servers - if (netgame) - SendAskInfo(BROADCASTADDR); - -#ifdef MASTERSERVER - if (internetsearch) - { -#ifdef HAVE_THREADS - struct Fetch_servers_ctx *ctx; - - ctx = malloc(sizeof *ctx); - - // This called from M_Refresh so I don't use a mutex - m_waiting_mode = M_WAITING_SERVERS; - - I_lock_mutex(&ms_QueryId_mutex); - { - ctx->id = ms_QueryId; - } - I_unlock_mutex(ms_QueryId_mutex); - - ctx->room = room; - - I_spawn_thread("fetch-servers", (I_thread_fn)Fetch_servers_thread, ctx); -#else - msg_server_t *server_list; - - server_list = GetShortServersList(room, 0); - - if (server_list) - { - CL_QueryServerList(server_list); - free(server_list); - } -#endif - } -#endif // MASTERSERVER -} - -static void M_ConfirmConnect(event_t *ev) -{ - if (ev->type == ev_keydown || ev->type == ev_gamepad_down) - { - if ((ev->type == ev_keydown && (ev->key == ' ' || ev->key == 'y' || ev->key == KEY_ENTER)) || (ev->type == ev_gamepad_down && ev->which == 0 && ev->key == GAMEPAD_BUTTON_A)) - { - if (totalfilesrequestednum > 0) - { - if (CL_SendFileRequest()) - { - cl_mode = CL_DOWNLOADFILES; - Snake_Allocate(&snake); - } - } - else - cl_mode = CL_LOADFILES; - - M_ClearMenus(true); - } - else if ((ev->type == ev_keydown && (ev->key == 'n' || ev->key == KEY_ESCAPE)) || (ev->type == ev_gamepad_down && ev->which == 0 && ev->key == GAMEPAD_BUTTON_B)) - { - cl_mode = CL_ABORTED; - M_ClearMenus(true); - } - } -} - -static boolean CL_FinishedFileList(void) -{ - INT32 i; - char *downloadsize = NULL; - - //CONS_Printf(M_GetText("Checking files...\n")); - i = CL_CheckFiles(); - if (i == 4) // still checking ... - { - return true; - } - else if (i == 3) // too many files - { - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText( - "You have too many WAD files loaded\n" - "to add ones the server is using.\n" - "Please restart SRB2 before connecting.\n\n" - "Press ESC\n" - ), NULL, MM_NOTHING); - return false; - } - else if (i == 2) // cannot join for some reason - { - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText( - "You have the wrong addons loaded.\n\n" - "To play on this server, restart\n" - "the game and don't load any addons.\n" - "SRB2 will automatically add\n" - "everything you need when you join.\n\n" - "Press ESC\n" - ), NULL, MM_NOTHING); - return false; - } - else if (i == 1) - { - if (serverisfull) - { - M_StartMessage(M_GetText( - "This server is full!\n" - "\n" - "You may load server addons (if any), and wait for a slot.\n" - "\n" - "Press ENTER to continue\nor ESC to cancel.\n\n" - ), M_ConfirmConnect, MM_EVENTHANDLER); - cl_mode = CL_CONFIRMCONNECT; - curfadevalue = 0; - } - else - cl_mode = CL_LOADFILES; - } - else - { - // must download something - // can we, though? - if (!CL_CheckDownloadable()) // nope! - { - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText( - "An error occured when trying to\n" - "download missing addons.\n" - "(This is almost always a problem\n" - "with the server, not your game.)\n\n" - "See the console or log file\n" - "for additional details.\n\n" - "Press ESC\n" - ), NULL, MM_NOTHING); - return false; - } - - downloadcompletednum = 0; - downloadcompletedsize = 0; - totalfilesrequestednum = 0; - totalfilesrequestedsize = 0; - - if (fileneeded == NULL) - I_Error("CL_FinishedFileList: fileneeded == NULL"); - - for (i = 0; i < fileneedednum; i++) - if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD) - { - totalfilesrequestednum++; - totalfilesrequestedsize += fileneeded[i].totalsize; - } - - if (totalfilesrequestedsize>>20 >= 100) - downloadsize = Z_StrDup(va("%uM",totalfilesrequestedsize>>20)); - else - downloadsize = Z_StrDup(va("%uK",totalfilesrequestedsize>>10)); - - if (serverisfull) - M_StartMessage(va(M_GetText( - "This server is full!\n" - "Download of %s additional content\nis required to join.\n" - "\n" - "You may download, load server addons,\nand wait for a slot.\n" - "\n" - "Press ENTER to continue\nor ESC to cancel.\n" - ), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER); - else - M_StartMessage(va(M_GetText( - "Download of %s additional content\nis required to join.\n" - "\n" - "Press ENTER to continue\nor ESC to cancel.\n" - ), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER); - - Z_Free(downloadsize); - cl_mode = CL_CONFIRMCONNECT; - curfadevalue = 0; - } - return true; -} - -static const char * InvalidServerReason (serverinfo_pak *info) -{ -#define EOT "\nPress ESC\n" - - // Magic number for new packet format - if (info->_255 != 255) - { - return - "Outdated server (version unknown).\n" EOT; - } - - if (strncmp(info->application, SRB2APPLICATION, sizeof - info->application)) - { - return va( - "%s cannot connect\n" - "to %s servers.\n" EOT, - SRB2APPLICATION, - info->application); - } - - if ( - info->packetversion != PACKETVERSION || - info->version != VERSION || - info->subversion != SUBVERSION - ){ - return va( - "Incompatible %s versions.\n" - "(server version %d.%d.%d)\n" EOT, - SRB2APPLICATION, - info->version / 100, - info->version % 100, - info->subversion); - } - - switch (info->refusereason) - { - case REFUSE_BANNED: - return - "You have been banned\n" - "from the server.\n" EOT; - case REFUSE_JOINS_DISABLED: - return - "The server is not accepting\n" - "joins for the moment.\n" EOT; - case REFUSE_SLOTS_FULL: - return va( - "Maximum players reached: %d\n" EOT, - info->maxplayer); - default: - if (info->refusereason) - { - return - "You can't join.\n" - "I don't know why,\n" - "but you can't join.\n" EOT; - } - } - - return NULL; - -#undef EOT -} - -/** Called by CL_ServerConnectionTicker - * - * \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit. - * \return False if the connection was aborted - * \sa CL_ServerConnectionTicker - * \sa CL_ConnectToServer - * - */ -static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) -{ - INT32 i; - - // serverlist is updated by GetPackets - if (serverlistcount > 0) - { - // This can be a response to our broadcast request - if (servernode == -1 || servernode >= MAXNETNODES) - { - i = 0; - servernode = serverlist[i].node; - CONS_Printf(M_GetText("Found, ")); - } - else - { - i = SL_SearchServer(servernode); - if (i < 0) - return true; - } - - if (client) - { - serverinfo_pak *info = &serverlist[i].info; - - if (info->refusereason == REFUSE_SLOTS_FULL) - serverisfull = true; - else - { - const char *reason = InvalidServerReason(info); - - // Quit here rather than downloading files - // and being refused later. - if (reason) - { - char *message = Z_StrDup(reason); - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(message, NULL, MM_NOTHING); - Z_Free(message); - return false; - } - } - - D_ParseFileneeded(info->fileneedednum, info->fileneeded, 0); - - if (info->flags & SV_LOTSOFADDONS) - { - cl_mode = CL_ASKFULLFILELIST; - cl_lastcheckedfilecount = 0; - return true; - } - - cl_mode = CL_CHECKFILES; - } - else - { - cl_mode = CL_ASKJOIN; // files need not be checked for the server. - *asksent = 0; - } - - return true; - } - - // Ask the info to the server (askinfo packet) - if (*asksent + NEWTICRATE < I_GetTime()) - { - SendAskInfo(servernode); - *asksent = I_GetTime(); - } - - return true; -} - -/** Called by CL_ConnectToServer - * - * \param tmpsave The name of the gamestate file??? - * \param oldtic Used for knowing when to poll events and redraw - * \param asksent ??? - * \return False if the connection was aborted - * \sa CL_ServerConnectionSearchTicker - * \sa CL_ConnectToServer - * - */ -static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic_t *asksent) -{ - boolean waitmore; - - switch (cl_mode) - { - case CL_SEARCHING: - if (!CL_ServerConnectionSearchTicker(asksent)) - return false; - break; - - case CL_ASKFULLFILELIST: - if (cl_lastcheckedfilecount == UINT16_MAX) // All files retrieved - cl_mode = CL_CHECKFILES; - else if (fileneedednum != cl_lastcheckedfilecount || I_GetTime() >= *asksent) - { - if (CL_AskFileList(fileneedednum)) - { - cl_lastcheckedfilecount = fileneedednum; - *asksent = I_GetTime() + NEWTICRATE; - } - } - break; - case CL_CHECKFILES: - if (!CL_FinishedFileList()) - return false; - break; - case CL_DOWNLOADFILES: - waitmore = false; - for (INT32 i = 0; i < fileneedednum; i++) - if (fileneeded[i].status == FS_DOWNLOADING - || fileneeded[i].status == FS_REQUESTED) - { - waitmore = true; - break; - } - if (waitmore) - break; // exit the case - - Snake_Free(&snake); - - cl_mode = CL_LOADFILES; - break; - case CL_LOADFILES: - if (CL_LoadServerFiles()) - { - FreeFileNeeded(); - *asksent = 0; // This ensures the first join request is right away - firstconnectattempttime = I_GetTime(); - cl_mode = CL_ASKJOIN; - } - break; - case CL_ASKJOIN: - if (firstconnectattempttime + NEWTICRATE*300 < I_GetTime() && !server) - { - CONS_Printf(M_GetText("5 minute wait time exceeded.\n")); - CONS_Printf(M_GetText("Network game synchronization aborted.\n")); - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText( - "5 minute wait time exceeded.\n" - "You may retry connection.\n" - "\n" - "Press ESC\n" - ), NULL, MM_NOTHING); - return false; - } - - // Prepare structures to save the file - CL_PrepareDownloadSaveGame(tmpsave); - - if (I_GetTime() >= *asksent && CL_SendJoin()) - { - *asksent = I_GetTime() + NEWTICRATE*3; - cl_mode = CL_WAITJOINRESPONSE; - } - break; - case CL_WAITJOINRESPONSE: - if (I_GetTime() >= *asksent) - { - cl_mode = CL_ASKJOIN; - } - break; - case CL_DOWNLOADSAVEGAME: - // At this state, the first (and only) needed file is the gamestate - if (fileneeded[0].status == FS_FOUND) - { - // Gamestate is now handled within CL_LoadReceivedSavegame() - CL_LoadReceivedSavegame(false); - cl_mode = CL_CONNECTED; - } // don't break case continue to CL_CONNECTED - else - break; - - case CL_CONNECTED: - case CL_CONFIRMCONNECT: //logic is handled by M_ConfirmConnect - default: - break; - - // Connection closed by cancel, timeout or refusal. - case CL_ABORTED: - cl_mode = CL_SEARCHING; - return false; - } - - GetPackets(); - Net_AckTicker(); - - // Call it only once by tic - if (*oldtic != I_GetTime()) - { - I_OsPolling(); - - if (cl_mode == CL_CONFIRMCONNECT) - D_ProcessEvents(); //needed for menu system to receive inputs - else - { - // my hand has been forced and I am dearly sorry for this awful hack :vomit: - for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) - { - G_MapEventsToControls(&events[eventtail]); - } - } - - if (gamekeydown[KEY_ESCAPE] || gamepads[0].buttons[GAMEPAD_BUTTON_B] || cl_mode == CL_ABORTED) - { - CONS_Printf(M_GetText("Network game synchronization aborted.\n")); - M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); - - Snake_Free(&snake); - - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - memset(gamekeydown, 0, NUMKEYS); - return false; - } - else if (cl_mode == CL_DOWNLOADFILES && snake) - Snake_Update(snake); - - if (client && (cl_mode == CL_DOWNLOADFILES || cl_mode == CL_DOWNLOADSAVEGAME)) - FileReceiveTicker(); - - *oldtic = I_GetTime(); - - if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED) - { - if (!snake) - { - F_MenuPresTicker(true); // title sky - F_TitleScreenTicker(true); - F_TitleScreenDrawer(); - } - CL_DrawConnectionStatus(); -#ifdef HAVE_THREADS - I_lock_mutex(&m_menu_mutex); -#endif - M_Drawer(); //Needed for drawing messageboxes on the connection screen -#ifdef HAVE_THREADS - I_unlock_mutex(m_menu_mutex); -#endif - I_UpdateNoVsync(); // page flip or blit buffer - if (moviemode) - M_SaveFrame(); - S_UpdateSounds(); - S_UpdateClosedCaptions(); - } - } - else - { - I_Sleep(cv_sleep.value); - I_UpdateTime(cv_timescale.value); - } - - return true; -} - -#define TMPSAVENAME "$$$.sav" - -void CL_ConnectToServer(void) -{ - INT32 pnumnodes, nodewaited = doomcom->numnodes, i; - tic_t oldtic; - tic_t asksent; - char tmpsave[256]; - - sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); - - lastfilenum = -1; - - cl_mode = CL_SEARCHING; - - // Don't get a corrupt savegame error because tmpsave already exists - if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1) - I_Error("Can't delete %s\n", tmpsave); - - if (netgame) - { - if (servernode < 0 || servernode >= MAXNETNODES) - CONS_Printf(M_GetText("Searching for a server...\n")); - else - CONS_Printf(M_GetText("Contacting the server...\n")); - } - - if (gamestate == GS_INTERMISSION) - Y_EndIntermission(); // clean up intermission graphics etc - - DEBFILE(va("waiting %d nodes\n", doomcom->numnodes)); - G_SetGamestate(GS_WAITINGPLAYERS); - wipegamestate = GS_WAITINGPLAYERS; - - ClearAdminPlayers(); - pnumnodes = 1; - oldtic = I_GetTime() - 1; - - asksent = (tic_t) - TICRATE; - firstconnectattempttime = I_GetTime(); - - i = SL_SearchServer(servernode); - - if (i != -1) - { - char *gametypestr = serverlist[i].info.gametypename; - CONS_Printf(M_GetText("Connecting to: %s\n"), serverlist[i].info.servername); - gametypestr[sizeof serverlist[i].info.gametypename - 1] = '\0'; - CONS_Printf(M_GetText("Gametype: %s\n"), gametypestr); - CONS_Printf(M_GetText("Version: %d.%d.%u\n"), serverlist[i].info.version/100, - serverlist[i].info.version%100, serverlist[i].info.subversion); - } - SL_ClearServerList(servernode); - - do - { - // If the connection was aborted for some reason, leave - if (!CL_ServerConnectionTicker(tmpsave, &oldtic, &asksent)) - return; - - if (server) - { - pnumnodes = 0; - for (i = 0; i < MAXNETNODES; i++) - if (netnodes[i].ingame) - pnumnodes++; - } - } - while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes)))); - - DEBFILE(va("Synchronisation Finished\n")); - - displayplayer = consoleplayer; -} - -/** Called when a PT_SERVERINFO packet is received - * - * \param node The packet sender - * \note What happens if the packet comes from a client or something like that? - * - */ -void PT_ServerInfo(SINT8 node) -{ - // compute ping in ms - const tic_t ticnow = I_GetTime(); - const tic_t ticthen = (tic_t)LONG(netbuffer->u.serverinfo.time); - const tic_t ticdiff = (ticnow - ticthen)*1000/NEWTICRATE; - netbuffer->u.serverinfo.time = (tic_t)LONG(ticdiff); - netbuffer->u.serverinfo.servername[MAXSERVERNAME-1] = 0; - netbuffer->u.serverinfo.application - [sizeof netbuffer->u.serverinfo.application - 1] = '\0'; - netbuffer->u.serverinfo.gametypename - [sizeof netbuffer->u.serverinfo.gametypename - 1] = '\0'; - - SL_InsertServer(&netbuffer->u.serverinfo, node); -} - -// Helper function for packets that should only be sent by the server -// If it is NOT from the server, bail out and close the connection! -static boolean ServerOnly(SINT8 node) -{ - if (node == servernode) - return false; - - Net_CloseConnection(node); - return true; -} - -void PT_MoreFilesNeeded(SINT8 node) -{ - if (server && serverrunning) - { // But wait I thought I'm the server? - Net_CloseConnection(node); - return; - } - if (ServerOnly(node)) - return; - if (cl_mode == CL_ASKFULLFILELIST && netbuffer->u.filesneededcfg.first == fileneedednum) - { - D_ParseFileneeded(netbuffer->u.filesneededcfg.num, netbuffer->u.filesneededcfg.files, netbuffer->u.filesneededcfg.first); - if (!netbuffer->u.filesneededcfg.more) - cl_lastcheckedfilecount = UINT16_MAX; // Got the whole file list - } -} - -// Negative response of client join request -void PT_ServerRefuse(SINT8 node) -{ - if (server && serverrunning) - { // But wait I thought I'm the server? - Net_CloseConnection(node); - return; - } - if (ServerOnly(node)) - return; - if (cl_mode == CL_WAITJOINRESPONSE) - { - // Save the reason so it can be displayed after quitting the netgame - char *reason = strdup(netbuffer->u.serverrefuse.reason); - if (!reason) - I_Error("Out of memory!\n"); - - if (strstr(reason, "Maximum players reached")) - { - serverisfull = true; - //Special timeout for when refusing due to player cap. The client will wait 3 seconds between join requests when waiting for a slot, so we need this to be much longer - //We set it back to the value of cv_nettimeout.value in CL_Reset - connectiontimeout = NEWTICRATE*7; - cl_mode = CL_ASKJOIN; - free(reason); - return; - } - - M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"), - reason), NULL, MM_NOTHING); - - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - - free(reason); - - // Will be reset by caller. Signals refusal. - cl_mode = CL_ABORTED; - } -} - -// Positive response of client join request -void PT_ServerCFG(SINT8 node) -{ - if (server && serverrunning && node != servernode) - { // but wait I thought I'm the server? - Net_CloseConnection(node); - return; - } - if (ServerOnly(node)) - return; - /// \note how would this happen? and is it doing the right thing if it does? - if (cl_mode != CL_WAITJOINRESPONSE) - return; - - if (client) - { - maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); - G_SetGametype(netbuffer->u.servercfg.gametype); - modifiedgame = netbuffer->u.servercfg.modifiedgame; - memcpy(server_context, netbuffer->u.servercfg.server_context, 8); - } - - netnodes[(UINT8)servernode].ingame = true; - serverplayer = netbuffer->u.servercfg.serverplayer; - doomcom->numslots = SHORT(netbuffer->u.servercfg.totalslotnum); - mynode = netbuffer->u.servercfg.clientnode; - if (serverplayer >= 0) - playernode[(UINT8)serverplayer] = servernode; - - if (netgame) - CONS_Printf(M_GetText("Join accepted, waiting for complete game state...\n")); - DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode)); - - /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? - /// Shouldn't they be downloaded even at intermission time? - /// Also, according to PT_ClientJoin, the server will send the savegame even during intermission... - if (netbuffer->u.servercfg.gamestate == GS_LEVEL/* || - netbuffer->u.servercfg.gamestate == GS_INTERMISSION*/) - cl_mode = CL_DOWNLOADSAVEGAME; - else - cl_mode = CL_CONNECTED; -} diff --git a/src/netcode/client_connection.h b/src/netcode/client_connection.h deleted file mode 100644 index 74cff61ff..000000000 --- a/src/netcode/client_connection.h +++ /dev/null @@ -1,61 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file client_connection.h -/// \brief Client connection handling - -#ifndef __D_CLIENT_CONNECTION__ -#define __D_CLIENT_CONNECTION__ - -#include "../doomtype.h" -#include "d_clisrv.h" - -#define MAXSERVERLIST (MAXNETNODES-1) - -typedef struct -{ - SINT8 node; - serverinfo_pak info; -} serverelem_t; - -typedef enum -{ - CL_SEARCHING, - CL_CHECKFILES, - CL_DOWNLOADFILES, - CL_ASKJOIN, - CL_LOADFILES, - CL_WAITJOINRESPONSE, - CL_DOWNLOADSAVEGAME, - CL_CONNECTED, - CL_ABORTED, - CL_ASKFULLFILELIST, - CL_CONFIRMCONNECT -} cl_mode_t; - -extern serverelem_t serverlist[MAXSERVERLIST]; -extern UINT32 serverlistcount; - -extern cl_mode_t cl_mode; -extern boolean serverisfull; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not -extern tic_t firstconnectattempttime; -extern UINT8 mynode; // my address pointofview server - -void CL_QueryServerList(msg_server_t *list); -void CL_UpdateServerList(boolean internetsearch, INT32 room); - -void CL_ConnectToServer(void); -boolean CL_SendJoin(void); - -void PT_ServerInfo(SINT8 node); -void PT_MoreFilesNeeded(SINT8 node); -void PT_ServerRefuse(SINT8 node); -void PT_ServerCFG(SINT8 node); - -#endif diff --git a/src/netcode/commands.c b/src/netcode/commands.c deleted file mode 100644 index 4d9a48b6b..000000000 --- a/src/netcode/commands.c +++ /dev/null @@ -1,484 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file commands.c -/// \brief Various netgame commands, such as kick and ban - -#include "commands.h" -#include "d_clisrv.h" -#include "client_connection.h" -#include "net_command.h" -#include "d_netcmd.h" -#include "d_net.h" -#include "i_net.h" -#include "protocol.h" -#include "../byteptr.h" -#include "../d_main.h" -#include "../g_game.h" -#include "../w_wad.h" -#include "../z_zone.h" -#include "../doomstat.h" -#include "../doomdef.h" -#include "../r_local.h" -#include -#include -#include -#include - -typedef struct banreason_s -{ - char *reason; - struct banreason_s *prev; //-1 - struct banreason_s *next; //+1 -} banreason_t; - -static banreason_t *reasontail = NULL; //last entry, use prev -static banreason_t *reasonhead = NULL; //1st entry, use next - -void Ban_Add(const char *reason) -{ - banreason_t *reasonlist = malloc(sizeof(*reasonlist)); - - if (!reasonlist) - return; - if (!reason) - reason = "NA"; - - reasonlist->next = NULL; - reasonlist->reason = Z_StrDup(reason); - if ((reasonlist->prev = reasontail) == NULL) - reasonhead = reasonlist; - else - reasontail->next = reasonlist; - reasontail = reasonlist; -} - -static void Ban_Clear(void) -{ - banreason_t *temp; - - I_ClearBans(); - - reasontail = NULL; - - while (reasonhead) - { - temp = reasonhead->next; - Z_Free(reasonhead->reason); - free(reasonhead); - reasonhead = temp; - } -} - -void Ban_Load_File(boolean warning) -{ - FILE *f; - const char *address, *mask; - char buffer[MAX_WADPATH]; - - if (!I_ClearBans) - return; - - f = fopen(va("%s"PATHSEP"%s", srb2home, "ban.txt"), "r"); - - if (!f) - { - if (warning) - CONS_Alert(CONS_WARNING, M_GetText("Could not open ban.txt for ban list\n")); - return; - } - - Ban_Clear(); - - for (size_t i=0; fgets(buffer, (int)sizeof(buffer), f); i++) - { - address = strtok(buffer, " \t\r\n"); - mask = strtok(NULL, " \t\r\n"); - - I_SetBanAddress(address, mask); - - Ban_Add(strtok(NULL, "\r\n")); - } - - fclose(f); -} - -void D_SaveBan(void) -{ - FILE *f; - banreason_t *reasonlist = reasonhead; - const char *address, *mask; - const char *path = va("%s"PATHSEP"%s", srb2home, "ban.txt"); - - if (!reasonhead) - { - remove(path); - return; - } - - f = fopen(path, "w"); - - if (!f) - { - CONS_Alert(CONS_WARNING, M_GetText("Could not save ban list into ban.txt\n")); - return; - } - - for (size_t i = 0;(address = I_GetBanAddress(i)) != NULL;i++) - { - if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL) - fprintf(f, "%s 0", address); - else - fprintf(f, "%s %s", address, mask); - - if (reasonlist && reasonlist->reason) - fprintf(f, " %s\n", reasonlist->reason); - else - fprintf(f, " %s\n", "NA"); - - if (reasonlist) reasonlist = reasonlist->next; - } - - fclose(f); -} - -void Command_ShowBan(void) //Print out ban list -{ - size_t i; - const char *address, *mask; - banreason_t *reasonlist = reasonhead; - - if (I_GetBanAddress) - CONS_Printf(M_GetText("Ban List:\n")); - else - return; - - for (i = 0;(address = I_GetBanAddress(i)) != NULL;i++) - { - if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL) - CONS_Printf("%s: %s ", sizeu1(i+1), address); - else - CONS_Printf("%s: %s/%s ", sizeu1(i+1), address, mask); - - if (reasonlist && reasonlist->reason) - CONS_Printf("(%s)\n", reasonlist->reason); - else - CONS_Printf("\n"); - - if (reasonlist) reasonlist = reasonlist->next; - } - - if (i == 0 && !address) - CONS_Printf(M_GetText("(empty)\n")); -} - -void Command_ClearBans(void) -{ - if (!I_ClearBans) - return; - - Ban_Clear(); - D_SaveBan(); -} - -void Command_Ban(void) -{ - if (COM_Argc() < 2) - { - CONS_Printf(M_GetText("Ban : ban and kick a player\n")); - return; - } - - if (!netgame) // Don't kick Tails in splitscreen! - { - CONS_Printf(M_GetText("This only works in a netgame.\n")); - return; - } - - if (server || IsPlayerAdmin(consoleplayer)) - { - UINT8 buf[3 + MAX_REASONLENGTH]; - UINT8 *p = buf; - const SINT8 pn = nametonum(COM_Argv(1)); - const INT32 node = playernode[(INT32)pn]; - - if (pn == -1 || pn == 0) - return; - - WRITEUINT8(p, pn); - - if (server && I_Ban && !I_Ban(node)) // only the server is allowed to do this right now - { - CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n")); - WRITEUINT8(p, KICK_MSG_GO_AWAY); - SendNetXCmd(XD_KICK, &buf, 2); - } - else - { - if (server) // only the server is allowed to do this right now - { - Ban_Add(COM_Argv(2)); - D_SaveBan(); // save the ban list - } - - if (COM_Argc() == 2) - { - WRITEUINT8(p, KICK_MSG_BANNED); - SendNetXCmd(XD_KICK, &buf, 2); - } - else - { - size_t j = COM_Argc(); - char message[MAX_REASONLENGTH]; - - //Steal from the motd code so you don't have to put the reason in quotes. - strlcpy(message, COM_Argv(2), sizeof message); - for (size_t i = 3; i < j; i++) - { - strlcat(message, " ", sizeof message); - strlcat(message, COM_Argv(i), sizeof message); - } - - WRITEUINT8(p, KICK_MSG_CUSTOM_BAN); - WRITESTRINGN(p, message, MAX_REASONLENGTH); - SendNetXCmd(XD_KICK, &buf, p - buf); - } - } - } - else - CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); - -} - -void Command_BanIP(void) -{ - if (COM_Argc() < 2) - { - CONS_Printf(M_GetText("banip : ban an ip address\n")); - return; - } - - if (server) // Only the server can use this, otherwise does nothing. - { - const char *address = (COM_Argv(1)); - const char *reason; - - if (COM_Argc() == 2) - reason = NULL; - else - reason = COM_Argv(2); - - - if (I_SetBanAddress && I_SetBanAddress(address, NULL)) - { - if (reason) - CONS_Printf("Banned IP address %s for: %s\n", address, reason); - else - CONS_Printf("Banned IP address %s\n", address); - - Ban_Add(reason); - D_SaveBan(); - } - else - { - return; - } - } -} - -void Command_ReloadBan(void) //recheck ban.txt -{ - Ban_Load_File(true); -} - -void Command_Kick(void) -{ - if (COM_Argc() < 2) - { - CONS_Printf(M_GetText("kick : kick a player\n")); - return; - } - - if (!netgame) // Don't kick Tails in splitscreen! - { - CONS_Printf(M_GetText("This only works in a netgame.\n")); - return; - } - - if (server || IsPlayerAdmin(consoleplayer)) - { - UINT8 buf[3 + MAX_REASONLENGTH]; - UINT8 *p = buf; - const SINT8 pn = nametonum(COM_Argv(1)); - - if (pn == -1 || pn == 0) - return; - - // Special case if we are trying to kick a player who is downloading the game state: - // trigger a timeout instead of kicking them, because a kick would only - // take effect after they have finished downloading - if (server && playernode[pn] != UINT8_MAX && netnodes[playernode[pn]].sendingsavegame) - { - Net_ConnectionTimeout(playernode[pn]); - return; - } - - WRITESINT8(p, pn); - - if (COM_Argc() == 2) - { - WRITEUINT8(p, KICK_MSG_GO_AWAY); - SendNetXCmd(XD_KICK, &buf, 2); - } - else - { - size_t j = COM_Argc(); - char message[MAX_REASONLENGTH]; - - //Steal from the motd code so you don't have to put the reason in quotes. - strlcpy(message, COM_Argv(2), sizeof message); - for (size_t i = 3; i < j; i++) - { - strlcat(message, " ", sizeof message); - strlcat(message, COM_Argv(i), sizeof message); - } - - WRITEUINT8(p, KICK_MSG_CUSTOM_KICK); - WRITESTRINGN(p, message, MAX_REASONLENGTH); - SendNetXCmd(XD_KICK, &buf, p - buf); - } - } - else - CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); -} - -void Command_connect(void) -{ - if (COM_Argc() < 2 || *COM_Argv(1) == 0) - { - CONS_Printf(M_GetText( - "Connect (port): connect to a server\n" - "Connect ANY: connect to the first lan server found\n" - //"Connect SELF: connect to your own server.\n" - )); - return; - } - - if (Playing() || titledemo) - { - CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n")); - return; - } - - server = false; -/* - if (!stricmp(COM_Argv(1), "self")) - { - servernode = 0; - server = true; - /// \bug should be but... - //SV_SpawnServer(); - } - else -*/ - { - // used in menu to connect to a server in the list - if (netgame && !stricmp(COM_Argv(1), "node")) - { - servernode = (SINT8)atoi(COM_Argv(2)); - } - else if (netgame) - { - CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n")); - return; - } - else if (I_NetOpenSocket) - { - I_NetOpenSocket(); - netgame = true; - multiplayer = true; - - if (!stricmp(COM_Argv(1), "any")) - servernode = BROADCASTADDR; - else if (I_NetMakeNodewPort) - { - if (COM_Argc() >= 3) // address AND port - servernode = I_NetMakeNodewPort(COM_Argv(1), COM_Argv(2)); - else // address only, or address:port - servernode = I_NetMakeNode(COM_Argv(1)); - } - else - { - CONS_Alert(CONS_ERROR, M_GetText("There is no server identification with this network driver\n")); - D_CloseConnection(); - return; - } - } - else - CONS_Alert(CONS_ERROR, M_GetText("There is no network driver\n")); - } - - splitscreen = false; - SplitScreen_OnChange(); - botingame = false; - botskin = 0; - CL_ConnectToServer(); -} - -void Command_GetPlayerNum(void) -{ - for (INT32 i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - { - if (serverplayer == i) - CONS_Printf(M_GetText("num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]); - else - CONS_Printf(M_GetText("\x82num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]); - } -} - -/** Lists all players and their player numbers. - * - * \sa Command_GetPlayerNum - */ -void Command_Nodes(void) -{ - size_t maxlen = 0; - const char *address; - - for (INT32 i = 0; i < MAXPLAYERS; i++) - { - const size_t plen = strlen(player_names[i]); - if (playeringame[i] && plen > maxlen) - maxlen = plen; - } - - for (INT32 i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i]) - { - CONS_Printf("%.2u: %*s", i, (int)maxlen, player_names[i]); - - if (playernode[i] != UINT8_MAX) - { - CONS_Printf(" - node %.2d", playernode[i]); - if (I_GetNodeAddress && (address = I_GetNodeAddress(playernode[i])) != NULL) - CONS_Printf(" - %s", address); - } - - if (IsPlayerAdmin(i)) - CONS_Printf(M_GetText(" (verified admin)")); - - if (players[i].spectator) - CONS_Printf(M_GetText(" (spectator)")); - - CONS_Printf("\n"); - } - } -} diff --git a/src/netcode/commands.h b/src/netcode/commands.h deleted file mode 100644 index 5ff4d1cae..000000000 --- a/src/netcode/commands.h +++ /dev/null @@ -1,33 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file commands.h -/// \brief Various netgame commands, such as kick and ban - -#ifndef __COMMANDS__ -#define __COMMANDS__ - -#include "../doomdef.h" - -#define MAX_REASONLENGTH 30 - -void Ban_Add(const char *reason); -void D_SaveBan(void); -void Ban_Load_File(boolean warning); -void Command_ShowBan(void); -void Command_ClearBans(void); -void Command_Ban(void); -void Command_BanIP(void); -void Command_ReloadBan(void); -void Command_Kick(void); -void Command_connect(void); -void Command_GetPlayerNum(void); -void Command_Nodes(void); - -#endif diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c deleted file mode 100644 index 18eae580c..000000000 --- a/src/netcode/d_clisrv.c +++ /dev/null @@ -1,1564 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file d_clisrv.c -/// \brief SRB2 Network game communication and protocol, all OS independent parts. - -#include -#ifdef __GNUC__ -#include //for unlink -#endif - -#include "../i_time.h" -#include "i_net.h" -#include "../i_system.h" -#include "../i_video.h" -#include "d_net.h" -#include "../d_main.h" -#include "../g_game.h" -#include "../st_stuff.h" -#include "../hu_stuff.h" -#include "../keys.h" -#include "../g_input.h" -#include "../i_gamepad.h" -#include "../m_menu.h" -#include "../console.h" -#include "d_netfil.h" -#include "../byteptr.h" -#include "../p_saveg.h" -#include "../z_zone.h" -#include "../p_local.h" -#include "../p_haptic.h" -#include "../m_misc.h" -#include "../am_map.h" -#include "../m_random.h" -#include "mserv.h" -#include "../y_inter.h" -#include "../r_local.h" -#include "../m_argv.h" -#include "../p_setup.h" -#include "../lzf.h" -#include "../lua_script.h" -#include "../lua_hook.h" -#include "../lua_libs.h" -#include "../md5.h" -#include "../m_perfstats.h" -#include "server_connection.h" -#include "client_connection.h" -#include "tic_command.h" -#include "net_command.h" -#include "gamestate.h" -#include "commands.h" -#include "protocol.h" - -// -// NETWORKING -// -// gametic is the tic about to (or currently being) run -// Server: -// maketic is the tic that hasn't had control made for it yet -// nettics is the tic for each node -// firstticstosend is the lowest value of nettics -// Client: -// neededtic is the tic needed by the client to run the game -// firstticstosend is used to optimize a condition -// Normally maketic >= gametic > 0 - -boolean server = true; // true or false but !server == client -boolean serverrunning = false; -INT32 serverplayer = 0; -char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support) - -netnode_t netnodes[MAXNETNODES]; - -// Server specific vars -UINT8 playernode[MAXPLAYERS]; - -UINT16 pingmeasurecount = 1; -UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone. -UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values. -static INT32 pingtimeout[MAXPLAYERS]; -tic_t servermaxping = 800; // server's max ping. Defaults to 800 - -tic_t maketic; - -INT16 consistancy[BACKUPTICS]; - -// true when a player is connecting or disconnecting so that the gameplay has stopped in its tracks -boolean hu_stopped = false; - -UINT8 adminpassmd5[16]; -boolean adminpasswordset = false; - -tic_t neededtic; -SINT8 servernode = 0; // the number of the server node - -boolean acceptnewnode = true; - -UINT16 software_MAXPACKETLENGTH; - -static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; -consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL); - -static CV_PossibleValue_t resynchattempts_cons_t[] = {{1, "MIN"}, {20, "MAX"}, {0, "No"}, {0, NULL}}; -consvar_t cv_resynchattempts = CVAR_INIT ("resynchattempts", "10", CV_SAVE|CV_NETVAR, resynchattempts_cons_t, NULL); - -consvar_t cv_blamecfail = CVAR_INIT ("blamecfail", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); - -static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}}; -consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_cons_t, NULL); - -void ResetNode(INT32 node) -{ - memset(&netnodes[node], 0, sizeof(*netnodes)); - netnodes[node].player = -1; - netnodes[node].player2 = -1; -} - -void CL_Reset(void) -{ - if (metalrecording) - G_StopMetalRecording(false); - if (metalplayback) - G_StopMetalDemo(); - if (demorecording) - G_CheckDemoStatus(); - - // reset client/server code - DEBFILE(va("\n-=-=-=-=-=-=-= Client reset =-=-=-=-=-=-=-\n\n")); - - if (servernode > 0 && servernode < MAXNETNODES) - { - netnodes[(UINT8)servernode].ingame = false; - Net_CloseConnection(servernode); - } - D_CloseConnection(); // netgame = false - multiplayer = false; - servernode = 0; - server = true; - doomcom->numnodes = 1; - doomcom->numslots = 1; - SV_StopServer(); - SV_ResetServer(); - - // make sure we don't leave any fileneeded gunk over from a failed join - FreeFileNeeded(); - fileneedednum = 0; - - totalfilesrequestednum = 0; - totalfilesrequestedsize = 0; - firstconnectattempttime = 0; - serverisfull = false; - connectiontimeout = (tic_t)cv_nettimeout.value; //reset this temporary hack - - // D_StartTitle should get done now, but the calling function will handle it -} - -// -// CL_ClearPlayer -// -// Clears the player data so that a future client can use this slot -// -void CL_ClearPlayer(INT32 playernum) -{ - if (players[playernum].mo) - P_RemoveMobj(players[playernum].mo); - memset(&players[playernum], 0, sizeof (player_t)); - memset(playeraddress[playernum], 0, sizeof(*playeraddress)); -} - -// Xcmd XD_ADDPLAYER -static void Got_AddPlayer(UINT8 **p, INT32 playernum) -{ - INT16 node, newplayernum; - boolean splitscreenplayer; - boolean rejoined; - player_t *newplayer; - - if (playernum != serverplayer && !IsPlayerAdmin(playernum)) - { - // protect against hacked/buggy client - CONS_Alert(CONS_WARNING, M_GetText("Illegal add player command received from %s\n"), player_names[playernum]); - if (server) - SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - return; - } - - node = READUINT8(*p); - newplayernum = READUINT8(*p); - splitscreenplayer = newplayernum & 0x80; - newplayernum &= ~0x80; - - rejoined = playeringame[newplayernum]; - - if (!rejoined) - { - // Clear player before joining, lest some things get set incorrectly - // HACK: don't do this for splitscreen, it relies on preset values - if (!splitscreen && !botingame) - CL_ClearPlayer(newplayernum); - playeringame[newplayernum] = true; - G_AddPlayer(newplayernum); - if (newplayernum+1 > doomcom->numslots) - doomcom->numslots = (INT16)(newplayernum+1); - - if (server && I_GetNodeAddress) - { - const char *address = I_GetNodeAddress(node); - char *port = NULL; - if (address) // MI: fix msvcrt.dll!_mbscat crash? - { - strcpy(playeraddress[newplayernum], address); - port = strchr(playeraddress[newplayernum], ':'); - if (port) - *port = '\0'; - } - } - } - - newplayer = &players[newplayernum]; - - newplayer->jointime = 0; - newplayer->quittime = 0; - - READSTRINGN(*p, player_names[newplayernum], MAXPLAYERNAME); - - // the server is creating my player - if (node == mynode) - { - playernode[newplayernum] = 0; // for information only - if (!splitscreenplayer) - { - consoleplayer = newplayernum; - displayplayer = newplayernum; - secondarydisplayplayer = newplayernum; - DEBFILE("spawning me\n"); - ticcmd_oldangleturn[0] = newplayer->oldrelangleturn; - } - else - { - secondarydisplayplayer = newplayernum; - DEBFILE("spawning my brother\n"); - if (botingame) - newplayer->bot = 1; - ticcmd_oldangleturn[1] = newplayer->oldrelangleturn; - } - P_ForceLocalAngle(newplayer, (angle_t)(newplayer->angleturn << 16)); - D_SendPlayerConfig(); - addedtogame = true; - - if (rejoined) - { - if (newplayer->mo) - { - newplayer->viewheight = 41*newplayer->height/48; - - if (newplayer->mo->eflags & MFE_VERTICALFLIP) - newplayer->viewz = newplayer->mo->z + newplayer->mo->height - newplayer->viewheight; - else - newplayer->viewz = newplayer->mo->z + newplayer->viewheight; - } - - // wake up the status bar - ST_Start(); - // wake up the heads up text - HU_Start(); - - if (camera.chase && !splitscreenplayer) - P_ResetCamera(newplayer, &camera); - if (camera2.chase && splitscreenplayer) - P_ResetCamera(newplayer, &camera2); - } - } - - if (netgame) - { - char joinmsg[256]; - - if (rejoined) - strcpy(joinmsg, M_GetText("\x82*%s has rejoined the game (player %d)")); - else - strcpy(joinmsg, M_GetText("\x82*%s has joined the game (player %d)")); - strcpy(joinmsg, va(joinmsg, player_names[newplayernum], newplayernum)); - - // Merge join notification + IP to avoid clogging console/chat - if (server && cv_showjoinaddress.value && I_GetNodeAddress) - { - const char *address = I_GetNodeAddress(node); - if (address) - strcat(joinmsg, va(" (%s)", address)); - } - - HU_AddChatText(joinmsg, false); - } - - if (server && multiplayer && motd[0] != '\0') - COM_BufAddText(va("sayto %d %s\n", newplayernum, motd)); - - if (!rejoined) - LUA_HookInt(newplayernum, HOOK(PlayerJoin)); -} - -static void UnlinkPlayerFromNode(INT32 playernum) -{ - INT32 node = playernode[playernum]; - - if (node == UINT8_MAX) - return; - - playernode[playernum] = UINT8_MAX; - - netnodes[node].numplayers--; - if (netnodes[node].numplayers <= 0) - { - netnodes[node].ingame = false; - Net_CloseConnection(node); - ResetNode(node); - } -} - -static void PT_ClientQuit(SINT8 node, INT32 netconsole) -{ - if (client) - return; - - if (netnodes[node].ingame && netconsole != -1 && playeringame[netconsole]) - SendKicksForNode(node, KICK_MSG_PLAYER_QUIT | KICK_MSG_KEEP_BODY); - - Net_CloseConnection(node); - netnodes[node].ingame = false; - netnodes[node].player = -1; - netnodes[node].player2 = -1; -} - -static void Got_KickCmd(UINT8 **p, INT32 playernum) -{ - INT32 pnum, msg; - char buf[3 + MAX_REASONLENGTH]; - char *reason = buf; - kickreason_t kickreason = KR_KICK; - boolean keepbody; - - pnum = READUINT8(*p); - msg = READUINT8(*p); - keepbody = (msg & KICK_MSG_KEEP_BODY) != 0; - msg &= ~KICK_MSG_KEEP_BODY; - - if (pnum == serverplayer && IsPlayerAdmin(playernum)) - { - CONS_Printf(M_GetText("Server is being shut down remotely. Goodbye!\n")); - - if (server) - COM_BufAddText("quit\n"); - - return; - } - - // Is playernum authorized to make this kick? - if (playernum != serverplayer && !IsPlayerAdmin(playernum) - && !(playernode[playernum] != UINT8_MAX && netnodes[playernode[playernum]].numplayers == 2 - && netnodes[playernode[playernum]].player2 == pnum)) - { - // We received a kick command from someone who isn't the - // server or admin, and who isn't in splitscreen removing - // player 2. Thus, it must be someone with a modified - // binary, trying to kick someone but without having - // authorization. - - // We deal with this by changing the kick reason to - // "consistency failure" and kicking the offending user - // instead. - - // Note: Splitscreen in netgames is broken because of - // this. Only the server has any idea of which players - // are using splitscreen on the same computer, so - // clients cannot always determine if a kick is - // legitimate. - - CONS_Alert(CONS_WARNING, M_GetText("Illegal kick command received from %s for player %d\n"), player_names[playernum], pnum); - - // In debug, print a longer message with more details. - // TODO Callum: Should we translate this? -/* - CONS_Debug(DBG_NETPLAY, - "So, you must be asking, why is this an illegal kick?\n" - "Well, let's take a look at the facts, shall we?\n" - "\n" - "playernum (this is the guy who did it), he's %d.\n" - "pnum (the guy he's trying to kick) is %d.\n" - "playernum's node is %d.\n" - "That node has %d players.\n" - "Player 2 on that node is %d.\n" - "pnum's node is %d.\n" - "That node has %d players.\n" - "Player 2 on that node is %d.\n" - "\n" - "If you think this is a bug, please report it, including all of the details above.\n", - playernum, pnum, - playernode[playernum], netnodes[playernode[playernum]].numplayers, - netnodes[playernode[playernum]].player2, - playernode[pnum], netnodes[playernode[pnum]].numplayers, - netnodes[playernode[pnum]].player2); -*/ - pnum = playernum; - msg = KICK_MSG_CON_FAIL; - keepbody = true; - } - - //CONS_Printf("\x82%s ", player_names[pnum]); - - // If a verified admin banned someone, the server needs to know about it. - // If the playernum isn't zero (the server) then the server needs to record the ban. - if (server && playernum && (msg == KICK_MSG_BANNED || msg == KICK_MSG_CUSTOM_BAN)) - { - if (I_Ban && !I_Ban(playernode[(INT32)pnum])) - CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n")); - else - Ban_Add(reason); - } - - switch (msg) - { - case KICK_MSG_GO_AWAY: - if (!players[pnum].quittime) - HU_AddChatText(va("\x82*%s has been kicked (No reason given)", player_names[pnum]), false); - kickreason = KR_KICK; - break; - case KICK_MSG_PING_HIGH: - HU_AddChatText(va("\x82*%s left the game (Broke ping limit)", player_names[pnum]), false); - kickreason = KR_PINGLIMIT; - break; - case KICK_MSG_CON_FAIL: - HU_AddChatText(va("\x82*%s left the game (Synch failure)", player_names[pnum]), false); - kickreason = KR_SYNCH; - - if (M_CheckParm("-consisdump")) // Helps debugging some problems - { - CONS_Printf(M_GetText("Player kicked is #%d, dumping consistency...\n"), pnum); - - for (INT32 i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - CONS_Printf("-------------------------------------\n"); - CONS_Printf("Player %d: %s\n", i, player_names[i]); - CONS_Printf("Skin: %d\n", players[i].skin); - CONS_Printf("Color: %d\n", players[i].skincolor); - CONS_Printf("Speed: %d\n",players[i].speed>>FRACBITS); - if (players[i].mo) - { - if (!players[i].mo->skin) - CONS_Printf("Mobj skin: NULL!\n"); - else - CONS_Printf("Mobj skin: %s\n", ((skin_t *)players[i].mo->skin)->name); - CONS_Printf("Position: %d, %d, %d\n", players[i].mo->x, players[i].mo->y, players[i].mo->z); - if (!players[i].mo->state) - CONS_Printf("State: S_NULL\n"); - else - CONS_Printf("State: %d\n", (statenum_t)(players[i].mo->state-states)); - } - else - CONS_Printf("Mobj: NULL\n"); - CONS_Printf("-------------------------------------\n"); - } - } - break; - case KICK_MSG_TIMEOUT: - HU_AddChatText(va("\x82*%s left the game (Connection timeout)", player_names[pnum]), false); - kickreason = KR_TIMEOUT; - break; - case KICK_MSG_PLAYER_QUIT: - if (netgame && !players[pnum].quittime) // not splitscreen/bots or soulless body - HU_AddChatText(va("\x82*%s left the game", player_names[pnum]), false); - kickreason = KR_LEAVE; - break; - case KICK_MSG_BANNED: - HU_AddChatText(va("\x82*%s has been banned (No reason given)", player_names[pnum]), false); - kickreason = KR_BAN; - break; - case KICK_MSG_CUSTOM_KICK: - READSTRINGN(*p, reason, MAX_REASONLENGTH+1); - HU_AddChatText(va("\x82*%s has been kicked (%s)", player_names[pnum], reason), false); - kickreason = KR_KICK; - break; - case KICK_MSG_CUSTOM_BAN: - READSTRINGN(*p, reason, MAX_REASONLENGTH+1); - HU_AddChatText(va("\x82*%s has been banned (%s)", player_names[pnum], reason), false); - kickreason = KR_BAN; - break; - } - - if (pnum == consoleplayer) - { - LUA_HookBool(false, HOOK(GameQuit)); -#ifdef DUMPCONSISTENCY - if (msg == KICK_MSG_CON_FAIL) SV_SavedGame(); -#endif - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - if (msg == KICK_MSG_CON_FAIL) - M_StartMessage(M_GetText("Server closed connection\n(synch failure)\nPress ESC\n"), NULL, MM_NOTHING); - else if (msg == KICK_MSG_PING_HIGH) - M_StartMessage(M_GetText("Server closed connection\n(Broke ping limit)\nPress ESC\n"), NULL, MM_NOTHING); - else if (msg == KICK_MSG_BANNED) - M_StartMessage(M_GetText("You have been banned by the server\n\nPress ESC\n"), NULL, MM_NOTHING); - else if (msg == KICK_MSG_CUSTOM_KICK) - M_StartMessage(va(M_GetText("You have been kicked\n(%s)\nPress ESC\n"), reason), NULL, MM_NOTHING); - else if (msg == KICK_MSG_CUSTOM_BAN) - M_StartMessage(va(M_GetText("You have been banned\n(%s)\nPress ESC\n"), reason), NULL, MM_NOTHING); - else - M_StartMessage(M_GetText("You have been kicked by the server\n\nPress ESC\n"), NULL, MM_NOTHING); - } - else if (keepbody) - { - if (server) - UnlinkPlayerFromNode(pnum); - players[pnum].quittime = 1; - } - else - CL_RemovePlayer(pnum, kickreason); -} - -// If in a special stage, redistribute the player's -// spheres across the remaining players. -// I feel like this shouldn't even be in this file at all, but well. -static void RedistributeSpecialStageSpheres(INT32 playernum) -{ - if (!G_IsSpecialStage(gamemap) || D_NumPlayers() <= 1) - return; - - INT32 count = D_NumPlayers() - 1; - INT32 spheres = players[playernum].spheres; - INT32 rings = players[playernum].rings; - - while (spheres || rings) - { - INT32 sincrement = max(spheres / count, 1); - INT32 rincrement = max(rings / count, 1); - - INT32 n; - for (INT32 i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || i == playernum) - continue; - - n = min(spheres, sincrement); - P_GivePlayerSpheres(&players[i], n); - spheres -= n; - - n = min(rings, rincrement); - P_GivePlayerRings(&players[i], n); - rings -= n; - } - } -} - -// -// CL_RemovePlayer -// -// Removes a player from the current game -// -void CL_RemovePlayer(INT32 playernum, kickreason_t reason) -{ - // Sanity check: exceptional cases (i.e. c-fails) can cause multiple - // kick commands to be issued for the same player. - if (!playeringame[playernum]) - return; - - if (server) - UnlinkPlayerFromNode(playernum); - - if (gametyperules & GTR_TEAMFLAGS) - P_PlayerFlagBurst(&players[playernum], false); // Don't take the flag with you! - - RedistributeSpecialStageSpheres(playernum); - - LUA_HookPlayerQuit(&players[playernum], reason); // Lua hook for player quitting - - // don't look through someone's view who isn't there - if (playernum == displayplayer) - { - // Call ViewpointSwitch hooks here. - // The viewpoint was forcibly changed. - LUA_HookViewpointSwitch(&players[consoleplayer], &players[consoleplayer], true); - displayplayer = consoleplayer; - } - - // Reset player data - CL_ClearPlayer(playernum); - - // remove avatar of player - playeringame[playernum] = false; - while (!playeringame[doomcom->numslots-1] && doomcom->numslots > 1) - doomcom->numslots--; - - // Reset the name - sprintf(player_names[playernum], "Player %d", playernum+1); - - player_name_changes[playernum] = 0; - - if (IsPlayerAdmin(playernum)) - { - RemoveAdminPlayer(playernum); // don't stay admin after you're gone - } - - LUA_InvalidatePlayer(&players[playernum]); - - if (G_TagGametype()) //Check if you still have a game. Location flexible. =P - P_CheckSurvivors(); - else if (gametyperules & GTR_RACE) - P_CheckRacers(); -} - -// -// D_QuitNetGame -// Called before quitting to leave a net game -// without hanging the other players -// -void D_QuitNetGame(void) -{ - mousegrabbedbylua = true; - I_UpdateMouseGrab(); - - if (!netgame || !netbuffer) - return; - - DEBFILE("===========================================================================\n" - " Quitting Game, closing connection\n" - "===========================================================================\n"); - - // abort send/receive of files - CloseNetFile(); - RemoveAllLuaFileTransfers(); - waitingforluafiletransfer = false; - waitingforluafilecommand = false; - - if (server) - { - netbuffer->packettype = PT_SERVERSHUTDOWN; - for (INT32 i = 0; i < MAXNETNODES; i++) - if (netnodes[i].ingame) - HSendPacket(i, true, 0, 0); -#ifdef MASTERSERVER - if (serverrunning && ms_RoomId > 0) - UnregisterServer(); -#endif - } - else if (servernode > 0 && servernode < MAXNETNODES && netnodes[(UINT8)servernode].ingame) - { - netbuffer->packettype = PT_CLIENTQUIT; - HSendPacket(servernode, true, 0, 0); - } - - D_CloseConnection(); - ClearAdminPlayers(); - - DEBFILE("===========================================================================\n" - " Log finish\n" - "===========================================================================\n"); -#ifdef DEBUGFILE - if (debugfile) - { - fclose(debugfile); - debugfile = NULL; - } -#endif -} - -void CL_HandleTimeout(void) -{ - LUA_HookBool(false, HOOK(GameQuit)); - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText("Server Timeout\n\nPress Esc\n"), NULL, MM_NOTHING); -} - -void CL_AddSplitscreenPlayer(void) -{ - if (cl_mode == CL_CONNECTED) - CL_SendJoin(); -} - -void CL_RemoveSplitscreenPlayer(void) -{ - if (cl_mode != CL_CONNECTED) - return; - - SendKick(secondarydisplayplayer, KICK_MSG_PLAYER_QUIT); -} - -void SV_ResetServer(void) -{ - // +1 because this command will be executed in com_executebuffer in - // tryruntic so gametic will be incremented, anyway maketic > gametic - // is not an issue - - maketic = gametic + 1; - neededtic = maketic; - tictoclear = maketic; - - joindelay = 0; - - for (INT32 i = 0; i < MAXNETNODES; i++) - ResetNode(i); - - for (INT32 i = 0; i < MAXPLAYERS; i++) - { - LUA_InvalidatePlayer(&players[i]); - playeringame[i] = false; - playernode[i] = UINT8_MAX; - memset(playeraddress[i], 0, sizeof(*playeraddress)); - sprintf(player_names[i], "Player %d", i + 1); - adminplayers[i] = -1; // Populate the entire adminplayers array with -1. - } - - memset(player_name_changes, 0, sizeof player_name_changes); - - mynode = 0; - cl_packetmissed = false; - cl_redownloadinggamestate = false; - - if (dedicated) - { - netnodes[0].ingame = true; - serverplayer = 0; - } - else - serverplayer = consoleplayer; - - if (server) - servernode = 0; - - doomcom->numslots = 0; - - // clear server_context - memset(server_context, '-', 8); - - CV_RevertNetVars(); - - DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n"); -} - -static inline void SV_GenContext(void) -{ - // generate server_context, as exactly 8 bytes of randomly mixed A-Z and a-z - // (hopefully M_Random is initialized!! if not this will be awfully silly!) - for (UINT8 i = 0; i < 8; i++) - { - const char a = M_RandomKey(26*2); - if (a < 26) // uppercase - server_context[i] = 'A'+a; - else // lowercase - server_context[i] = 'a'+(a-26); - } -} - -void SV_SpawnServer(void) -{ - if (demoplayback) - G_StopDemo(); // reset engine parameter - if (metalplayback) - G_StopMetalDemo(); - - if (!serverrunning) - { - CONS_Printf(M_GetText("Starting Server....\n")); - serverrunning = true; - SV_ResetServer(); - SV_GenContext(); - if (netgame && I_NetOpenSocket) - { - I_NetOpenSocket(); -#ifdef MASTERSERVER - if (ms_RoomId > 0) - RegisterServer(); -#endif - } - - // non dedicated server just connect to itself - if (!dedicated) - CL_ConnectToServer(); - else doomcom->numslots = 1; - } -} - -// called at singleplayer start and stopdemo -void SV_StartSinglePlayerServer(void) -{ - server = true; - netgame = false; - multiplayer = false; - G_SetGametype(GT_COOP); - - // no more tic the game with this settings! - SV_StopServer(); - - if (splitscreen) - multiplayer = true; -} - -void SV_StopServer(void) -{ - if (gamestate == GS_INTERMISSION) - Y_EndIntermission(); - gamestate = wipegamestate = GS_NULL; - - localtextcmd[0] = 0; - localtextcmd2[0] = 0; - - for (tic_t i = firstticstosend; i < firstticstosend + BACKUPTICS; i++) - D_Clearticcmd(i); - - consoleplayer = 0; - cl_mode = CL_SEARCHING; - maketic = gametic+1; - neededtic = maketic; - serverrunning = false; -} - -/** Called when a PT_SERVERSHUTDOWN packet is received - * - * \param node The packet sender (should be the server) - * - */ -static void PT_ServerShutdown(SINT8 node) -{ - if (node != servernode || server || cl_mode == CL_SEARCHING) - return; - - (void)node; - LUA_HookBool(false, HOOK(GameQuit)); - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText("Server has shutdown\n\nPress Esc\n"), NULL, MM_NOTHING); -} - -static void PT_Login(SINT8 node, INT32 netconsole) -{ - (void)node; - - if (client) - return; - -#ifndef NOMD5 - UINT8 finalmd5[16];/* Well, it's the cool thing to do? */ - - if (doomcom->datalength < 16)/* ignore partial sends */ - return; - - if (!adminpasswordset) - { - CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[netconsole]); - return; - } - - // Do the final pass to compare with the sent md5 - D_MD5PasswordPass(adminpassmd5, 16, va("PNUM%02d", netconsole), &finalmd5); - - if (!memcmp(netbuffer->u.md5sum, finalmd5, 16)) - { - CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[netconsole]); - COM_BufInsertText(va("promote %d\n", netconsole)); // do this immediately - } - else - CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[netconsole]); -#else - (void)netconsole; -#endif -} - -static void PT_AskLuaFile(SINT8 node) -{ - if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_ASKED) - AddLuaFileToSendQueue(node, luafiletransfers->realfilename); -} - -static void PT_HasLuaFile(SINT8 node) -{ - if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_SENDING) - SV_HandleLuaFileSent(node); -} - -static void PT_SendingLuaFile(SINT8 node) -{ - (void)node; - - if (client) - CL_PrepareDownloadLuaFile(); -} - -/* -Ping Update except better: -We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out. -If they're not lagging, decrement the timer by 1. Of course, reset all of this if they leave. -*/ - -static inline void PingUpdate(void) -{ - boolean laggers[MAXPLAYERS]; - UINT8 numlaggers = 0; - memset(laggers, 0, sizeof(boolean) * MAXPLAYERS); - - netbuffer->packettype = PT_PING; - - //check for ping limit breakage. - if (cv_maxping.value) - { - for (INT32 i = 1; i < MAXPLAYERS; i++) - { - if (playeringame[i] && !players[i].quittime - && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value)) - { - if (players[i].jointime > 30 * TICRATE) - laggers[i] = true; - numlaggers++; - } - else - pingtimeout[i] = 0; - } - - //kick lagging players... unless everyone but the server's ping sucks. - //in that case, it is probably the server's fault. - if (numlaggers < D_NumPlayers() - 1) - { - for (INT32 i = 1; i < MAXPLAYERS; i++) - { - if (playeringame[i] && laggers[i]) - { - pingtimeout[i]++; - // ok your net has been bad for too long, you deserve to die. - if (pingtimeout[i] > cv_pingtimeout.value) - { - pingtimeout[i] = 0; - SendKick(i, KICK_MSG_PING_HIGH | KICK_MSG_KEEP_BODY); - } - } - /* - you aren't lagging, - but you aren't free yet. - In case you'll keep spiking, - we just make the timer go back down. (Very unstable net must still get kicked). - */ - else - pingtimeout[i] = (pingtimeout[i] == 0 ? 0 : pingtimeout[i]-1); - } - } - } - - //make the ping packet and clear server data for next one - for (INT32 i = 0; i < MAXPLAYERS; i++) - { - netbuffer->u.pingtable[i] = realpingtable[i] / pingmeasurecount; - //server takes a snapshot of the real ping for display. - //otherwise, pings fluctuate a lot and would be odd to look at. - playerpingtable[i] = realpingtable[i] / pingmeasurecount; - realpingtable[i] = 0; //Reset each as we go. - } - - // send the server's maxping as last element of our ping table. This is useful to let us know when we're about to get kicked. - netbuffer->u.pingtable[MAXPLAYERS] = cv_maxping.value; - - //send out our ping packets - for (INT32 i = 0; i < MAXNETNODES; i++) - if (netnodes[i].ingame) - HSendPacket(i, true, 0, sizeof(INT32) * (MAXPLAYERS+1)); - - pingmeasurecount = 1; //Reset count -} - -static void PT_Ping(SINT8 node, INT32 netconsole) -{ - // Only accept PT_PING from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_PING", node); - if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - return; - } - - //Update client ping table from the server. - if (client) - { - for (INT32 i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i]; - - servermaxping = (tic_t)netbuffer->u.pingtable[MAXPLAYERS]; - } -} - -/** Handles a packet received from a node that isn't in game - * - * \param node The packet sender - * \todo Choose a better name, as the packet can also come from the server apparently? - * \sa HandlePacketFromPlayer - * \sa GetPackets - * - */ -static void HandlePacketFromAwayNode(SINT8 node) -{ - if (node != servernode) - DEBFILE(va("Received packet from unknown host %d\n", node)); - - switch (netbuffer->packettype) - { - case PT_ASKINFOVIAMS : PT_AskInfoViaMS (node ); break; - case PT_SERVERINFO : PT_ServerInfo (node ); break; - case PT_TELLFILESNEEDED: PT_TellFilesNeeded(node ); break; - case PT_MOREFILESNEEDED: PT_MoreFilesNeeded(node ); break; - case PT_ASKINFO : PT_AskInfo (node ); break; - case PT_SERVERREFUSE : PT_ServerRefuse (node ); break; - case PT_SERVERCFG : PT_ServerCFG (node ); break; - case PT_FILEFRAGMENT : PT_FileFragment (node, -1); break; - case PT_FILEACK : PT_FileAck (node ); break; - case PT_FILERECEIVED : PT_FileReceived (node ); break; - case PT_REQUESTFILE : PT_RequestFile (node ); break; - case PT_CLIENTQUIT : PT_ClientQuit (node, -1); break; - case PT_SERVERTICS : PT_ServerTics (node, -1); break; - case PT_CLIENTJOIN : PT_ClientJoin (node ); break; - case PT_SERVERSHUTDOWN : PT_ServerShutdown (node ); break; - case PT_CLIENTCMD : break; // This is not an "unknown packet" - case PT_PLAYERINFO : break; // This is not an "unknown packet" - - default: - DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype)); - Net_CloseConnection(node); - } -} - -/** Handles a packet received from a node that is in game - * - * \param node The packet sender - * \todo Choose a better name - * \sa HandlePacketFromAwayNode - * \sa GetPackets - * - */ -static void HandlePacketFromPlayer(SINT8 node) -{ - INT32 netconsole; - - if (dedicated && node == 0) - netconsole = 0; - else - netconsole = netnodes[node].player; -#ifdef PARANOIA - if (netconsole >= MAXPLAYERS) - I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole); -#endif - - switch (netbuffer->packettype) - { - // SERVER RECEIVE - case PT_CLIENTCMD: - case PT_CLIENT2CMD: - case PT_CLIENTMIS: - case PT_CLIENT2MIS: - case PT_NODEKEEPALIVE: - case PT_NODEKEEPALIVEMIS: - PT_ClientCmd(node, netconsole); - break; - case PT_TEXTCMD : PT_TextCmd (node, netconsole); break; - case PT_TEXTCMD2 : PT_TextCmd (node, netconsole); break; - case PT_LOGIN : PT_Login (node, netconsole); break; - case PT_CLIENTQUIT : PT_ClientQuit (node, netconsole); break; - case PT_CANRECEIVEGAMESTATE: PT_CanReceiveGamestate(node ); break; - case PT_ASKLUAFILE : PT_AskLuaFile (node ); break; - case PT_HASLUAFILE : PT_HasLuaFile (node ); break; - case PT_RECEIVEDGAMESTATE : PT_ReceivedGamestate (node ); break; - case PT_SERVERINFO : PT_ServerInfo (node ); break; - - // CLIENT RECEIVE - case PT_SERVERTICS : PT_ServerTics (node, netconsole); break; - case PT_PING : PT_Ping (node, netconsole); break; - case PT_FILEFRAGMENT : PT_FileFragment (node, netconsole); break; - case PT_FILEACK : PT_FileAck (node ); break; - case PT_FILERECEIVED : PT_FileReceived (node ); break; - case PT_WILLRESENDGAMESTATE: PT_WillResendGamestate(node ); break; - case PT_SENDINGLUAFILE : PT_SendingLuaFile (node ); break; - case PT_SERVERSHUTDOWN : PT_ServerShutdown (node ); break; - case PT_SERVERCFG : break; - case PT_CLIENTJOIN : break; - - default: - DEBFILE(va("UNKNOWN PACKET TYPE RECEIVED %d from host %d\n", - netbuffer->packettype, node)); - } -} - -/** Handles all received packets, if any - * - * \todo Add details to this description (lol) - * - */ -void GetPackets(void) -{ - while (HGetPacket()) - { - SINT8 node = doomcom->remotenode; - - // Packet received from someone already playing - if (netnodes[node].ingame) - HandlePacketFromPlayer(node); - // Packet received from someone not playing - else - HandlePacketFromAwayNode(node); - } -} - -boolean TryRunTics(tic_t realtics) -{ - // the machine has lagged but it is not so bad - if (realtics > TICRATE/7) - { - if (server) - realtics = 1; - else - realtics = TICRATE/7; - } - - if (singletics) - realtics = 1; - - if (realtics >= 1) - { - COM_BufTicker(); - if (mapchangepending) - D_MapChange(-1, 0, ultimatemode, false, 2, false, fromlevelselect); // finish the map change - } - - NetUpdate(); - - if (demoplayback) - { - neededtic = gametic + realtics; - // start a game after a demo - maketic += realtics; - firstticstosend = maketic; - tictoclear = firstticstosend; - } - - GetPackets(); - -#ifdef DEBUGFILE - if (debugfile && (realtics || neededtic > gametic)) - { - fprintf(debugfile, "------------ Tryruntic: REAL:%d NEED:%d GAME:%d LOAD: %d\n", - realtics, neededtic, gametic, debugload); - debugload = 100000; - } -#endif - - if (neededtic > gametic) - { - if (realtics) - hu_stopped = false; - - if (advancedemo) - { - if (timedemo_quit) - COM_ImmedExecute("quit"); - else - D_StartTitle(); - } - else - // run the count * tics - while (neededtic > gametic) - { - boolean update_stats = !(paused || P_AutoPause()); - - DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic)); - - if (update_stats) - PS_START_TIMING(ps_tictime); - - G_Ticker((gametic % NEWTICRATERATIO) == 0); - ExtraDataTicker(); - gametic++; - consistancy[gametic%BACKUPTICS] = Consistancy(); - - if (update_stats) - { - PS_STOP_TIMING(ps_tictime); - PS_UpdateTickStats(); - } - - // Leave a certain amount of tics present in the net buffer as long as we've ran at least one tic this frame. - if (client && gamestate == GS_LEVEL && leveltime > 3 && neededtic <= gametic + cv_netticbuffer.value) - break; - } - - return true; - } - else - { - if (realtics) - hu_stopped = true; - - return false; - } -} - -void NetUpdate(void) -{ - static tic_t gametime = 0; - static tic_t resptime = 0; - tic_t nowtime; - INT32 realtics; - - nowtime = I_GetTime(); - realtics = nowtime - gametime; - - if (realtics <= 0) // nothing new to update - return; - if (realtics > 5) - { - if (server) - realtics = 1; - else - realtics = 5; - } - - gametime = nowtime; - - if (server) - { - if (netgame && !(gametime % 35)) // update once per second. - PingUpdate(); - // update node latency values so we can take an average later. - for (INT32 i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && playernode[i] != UINT8_MAX) - realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i])); - pingmeasurecount++; - } - - if (client) - maketic = neededtic; - - Local_Maketic(realtics); - - if (server) - CL_SendClientCmd(); // send it - - GetPackets(); // get packet from client or from server - - // The client sends the command after receiving from the server - // The server sends it before because this is better in single player - -#ifdef MASTERSERVER - MasterClient_Ticker(); // Acking the Master Server -#endif - - if (client) - { - // If the client just finished redownloading the game state, load it - if (cl_redownloadinggamestate && fileneeded[0].status == FS_FOUND) - CL_ReloadReceivedSavegame(); - - CL_SendClientCmd(); // Send tic cmd - hu_redownloadinggamestate = cl_redownloadinggamestate; - } - else - { - if (!demoplayback) - { - hu_redownloadinggamestate = false; - - firstticstosend = gametic; - for (INT32 i = 0; i < MAXNETNODES; i++) - if (netnodes[i].ingame && netnodes[i].tic < firstticstosend) - { - firstticstosend = netnodes[i].tic; - - if (maketic + 1 >= netnodes[i].tic + BACKUPTICS) - Net_ConnectionTimeout(i); - } - - // Don't erase tics not acknowledged - INT32 counts = realtics; - if (maketic + counts >= firstticstosend + BACKUPTICS) - counts = firstticstosend+BACKUPTICS-maketic-1; - - for (INT32 i = 0; i < counts; i++) - SV_Maketic(); // Create missed tics and increment maketic - - for (; tictoclear < firstticstosend; tictoclear++) // Clear only when acknowledged - D_Clearticcmd(tictoclear); // Clear the maketic the new tic - - SV_SendTics(); - - neededtic = maketic; // The server is a client too - } - } - - Net_AckTicker(); - - // Handle timeouts to prevent definitive freezes from happenning - if (server) - { - for (INT32 i = 1; i < MAXNETNODES; i++) - if (netnodes[i].ingame && netnodes[i].freezetimeout < I_GetTime()) - Net_ConnectionTimeout(i); - - // In case the cvar value was lowered - if (joindelay) - joindelay = min(joindelay - 1, 3 * (tic_t)cv_joindelay.value * TICRATE); - } - - nowtime /= NEWTICRATERATIO; - if (nowtime > resptime) - { - resptime = nowtime; -#ifdef HAVE_THREADS - I_lock_mutex(&m_menu_mutex); -#endif - M_Ticker(); -#ifdef HAVE_THREADS - I_unlock_mutex(m_menu_mutex); -#endif - CON_Ticker(); - } - - FileSendTicker(); -} - -// called one time at init -void D_ClientServerInit(void) -{ - DEBFILE(va("- - -== SRB2 v%d.%.2d.%d "VERSIONSTRING" debugfile ==- - -\n", - VERSION/100, VERSION%100, SUBVERSION)); - - COM_AddCommand("getplayernum", Command_GetPlayerNum); - COM_AddCommand("kick", Command_Kick); - COM_AddCommand("ban", Command_Ban); - COM_AddCommand("banip", Command_BanIP); - COM_AddCommand("clearbans", Command_ClearBans); - COM_AddCommand("showbanlist", Command_ShowBan); - COM_AddCommand("reloadbans", Command_ReloadBan); - COM_AddCommand("connect", Command_connect); - COM_AddCommand("nodes", Command_Nodes); - COM_AddCommand("resendgamestate", Command_ResendGamestate); -#ifdef PACKETDROP - COM_AddCommand("drop", Command_Drop); - COM_AddCommand("droprate", Command_Droprate); -#endif -#ifdef _DEBUG - COM_AddCommand("numnodes", Command_Numnodes); -#endif - - RegisterNetXCmd(XD_KICK, Got_KickCmd); - RegisterNetXCmd(XD_ADDPLAYER, Got_AddPlayer); -#ifdef DUMPCONSISTENCY - CV_RegisterVar(&cv_dumpconsistency); -#endif - Ban_Load_File(false); - - gametic = 0; - localgametic = 0; - - // do not send anything before the real begin - SV_StopServer(); - SV_ResetServer(); - if (dedicated) - SV_SpawnServer(); -} - -SINT8 nametonum(const char *name) -{ - INT32 playernum; - - if (!strcmp(name, "0")) - return 0; - - playernum = (SINT8)atoi(name); - - if (playernum < 0 || playernum >= MAXPLAYERS) - return -1; - - if (playernum) - { - if (playeringame[playernum]) - return (SINT8)playernum; - else - return -1; - } - - for (INT32 i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && !stricmp(player_names[i], name)) - return (SINT8)i; - - CONS_Printf(M_GetText("There is no player named \"%s\"\n"), name); - - return -1; -} - -// Is there a game running? -boolean Playing(void) -{ - return (server && serverrunning) || (client && cl_mode == CL_CONNECTED); -} - -/** Returns the number of players playing. - * \return Number of players. Can be zero if we're running a ::dedicated - * server. - * \author Graue - */ -INT32 D_NumPlayers(void) -{ - INT32 num = 0; - for (INT32 ix = 0; ix < MAXPLAYERS; ix++) - if (playeringame[ix]) - num++; - return num; -} - -// -// Consistancy -// -// Note: It is called consistAncy on purpose. -// -INT16 Consistancy(void) -{ - UINT32 ret = 0; -#ifdef MOBJCONSISTANCY - thinker_t *th; - mobj_t *mo; -#endif - - DEBFILE(va("TIC %u ", gametic)); - - for (INT32 i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - ret ^= 0xCCCC; - else if (!players[i].mo); - else - { - ret += players[i].mo->x; - ret -= players[i].mo->y; - ret += players[i].powers[pw_shield]; - ret *= i+1; - } - } - // I give up - // Coop desynching enemies is painful - if (!G_PlatformGametype()) - ret += P_GetRandSeed(); - -#ifdef MOBJCONSISTANCY - if (gamestate == GS_LEVEL) - { - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo = (mobj_t *)th; - - if (mo->flags & (MF_SPECIAL | MF_SOLID | MF_PUSHABLE | MF_BOSS | MF_MISSILE | MF_SPRING | MF_MONITOR | MF_FIRE | MF_ENEMY | MF_PAIN | MF_STICKY)) - { - ret -= mo->type; - ret += mo->x; - ret -= mo->y; - ret += mo->z; - ret -= mo->momx; - ret += mo->momy; - ret -= mo->momz; - ret += mo->angle; - ret -= mo->flags; - ret += mo->flags2; - ret -= mo->eflags; - if (mo->target) - { - ret += mo->target->type; - ret -= mo->target->x; - ret += mo->target->y; - ret -= mo->target->z; - ret += mo->target->momx; - ret -= mo->target->momy; - ret += mo->target->momz; - ret -= mo->target->angle; - ret += mo->target->flags; - ret -= mo->target->flags2; - ret += mo->target->eflags; - ret -= mo->target->state - states; - ret += mo->target->tics; - ret -= mo->target->sprite; - ret += mo->target->frame; - } - else - ret ^= 0x3333; - if (mo->tracer && mo->tracer->type != MT_OVERLAY) - { - ret += mo->tracer->type; - ret -= mo->tracer->x; - ret += mo->tracer->y; - ret -= mo->tracer->z; - ret += mo->tracer->momx; - ret -= mo->tracer->momy; - ret += mo->tracer->momz; - ret -= mo->tracer->angle; - ret += mo->tracer->flags; - ret -= mo->tracer->flags2; - ret += mo->tracer->eflags; - ret -= mo->tracer->state - states; - ret += mo->tracer->tics; - ret -= mo->tracer->sprite; - ret += mo->tracer->frame; - } - else - ret ^= 0xAAAA; - ret -= mo->state - states; - ret += mo->tics; - ret -= mo->sprite; - ret += mo->frame; - } - } - } -#endif - - DEBFILE(va("Consistancy = %u\n", (ret & 0xFFFF))); - - return (INT16)(ret & 0xFFFF); -} - -tic_t GetLag(INT32 node) -{ - return gametic - netnodes[node].tic; -} - -void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest) -{ -#ifdef NOMD5 - (void)buffer; - (void)len; - (void)salt; - memset(dest, 0, 16); -#else - char tmpbuf[256]; - const size_t sl = strlen(salt); - - if (len > 256-sl) - len = 256-sl; - - memcpy(tmpbuf, buffer, len); - memmove(&tmpbuf[len], salt, sl); - //strcpy(&tmpbuf[len], salt); - len += strlen(salt); - if (len < 256) - memset(&tmpbuf[len],0,256-len); - - // Yes, we intentionally md5 the ENTIRE buffer regardless of size... - md5_buffer(tmpbuf, 256, dest); -#endif -} diff --git a/src/netcode/d_clisrv.h b/src/netcode/d_clisrv.h deleted file mode 100644 index 0abd638ce..000000000 --- a/src/netcode/d_clisrv.h +++ /dev/null @@ -1,131 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file d_clisrv.h -/// \brief high level networking stuff - -#ifndef __D_CLISRV__ -#define __D_CLISRV__ - -#include "protocol.h" -#include "../d_ticcmd.h" -#include "d_net.h" -#include "d_netcmd.h" -#include "d_net.h" -#include "../tables.h" -#include "../d_player.h" -#include "mserv.h" - -#define CLIENTBACKUPTICS 32 - -#ifdef PACKETDROP -void Command_Drop(void); -void Command_Droprate(void); -#endif -#ifdef _DEBUG -void Command_Numnodes(void); -#endif - -extern INT32 mapchangepending; - -// Points inside doomcom -extern doomdata_t *netbuffer; - -#define BASEPACKETSIZE offsetof(doomdata_t, u) -#define BASESERVERTICSSIZE offsetof(doomdata_t, u.serverpak.cmds[0]) - -typedef enum -{ - KR_KICK = 1, //Kicked by server - KR_PINGLIMIT = 2, //Broke Ping Limit - KR_SYNCH = 3, //Synch Failure - KR_TIMEOUT = 4, //Connection Timeout - KR_BAN = 5, //Banned by server - KR_LEAVE = 6, //Quit the game - -} kickreason_t; - -/* the max number of name changes in some time period */ -#define MAXNAMECHANGES (5) -#define NAMECHANGERATE (60*TICRATE) - -extern boolean server; -extern boolean serverrunning; -#define client (!server) -extern boolean dedicated; // For dedicated server -extern UINT16 software_MAXPACKETLENGTH; -extern boolean acceptnewnode; -extern SINT8 servernode; -extern tic_t maketic; -extern tic_t neededtic; -extern INT16 consistancy[BACKUPTICS]; - -void Command_Ping_f(void); -extern tic_t connectiontimeout; -extern UINT16 pingmeasurecount; -extern UINT32 realpingtable[MAXPLAYERS]; -extern UINT32 playerpingtable[MAXPLAYERS]; -extern tic_t servermaxping; - -extern consvar_t cv_netticbuffer, cv_resynchattempts, cv_blamecfail, cv_playbackspeed; - -// Used in d_net, the only dependence -void D_ClientServerInit(void); - -// Create any new ticcmds and broadcast to other players. -void NetUpdate(void); - -void GetPackets(void); -void ResetNode(INT32 node); -INT16 Consistancy(void); - -void SV_StartSinglePlayerServer(void); -void SV_SpawnServer(void); -void SV_StopServer(void); -void SV_ResetServer(void); -void CL_AddSplitscreenPlayer(void); -void CL_RemoveSplitscreenPlayer(void); -void CL_Reset(void); -void CL_ClearPlayer(INT32 playernum); -void CL_RemovePlayer(INT32 playernum, kickreason_t reason); -void CL_HandleTimeout(void); -// Is there a game running -boolean Playing(void); - -// Broadcasts special packets to other players -// to notify of game exit -void D_QuitNetGame(void); - -//? How many ticks to run? -boolean TryRunTics(tic_t realtic); - -// extra data for lmps -// these functions scare me. they contain magic. -/*boolean AddLmpExtradata(UINT8 **demo_p, INT32 playernum); -void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum);*/ - -// translate a playername in a player number return -1 if not found and -// print a error message in the console -SINT8 nametonum(const char *name); - -extern char motd[254], server_context[8]; -extern UINT8 playernode[MAXPLAYERS]; - -INT32 D_NumPlayers(void); - -tic_t GetLag(INT32 node); - -void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest); - -extern UINT8 adminpassmd5[16]; -extern boolean adminpasswordset; - -extern boolean hu_stopped; - -#endif diff --git a/src/netcode/gamestate.c b/src/netcode/gamestate.c deleted file mode 100644 index c1ceb95b5..000000000 --- a/src/netcode/gamestate.c +++ /dev/null @@ -1,336 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file gamestate.c -/// \brief Gamestate (re)sending - -#include "d_clisrv.h" -#include "d_netfil.h" -#include "gamestate.h" -#include "i_net.h" -#include "protocol.h" -#include "server_connection.h" -#include "../am_map.h" -#include "../byteptr.h" -#include "../console.h" -#include "../d_main.h" -#include "../doomstat.h" -#include "../doomtype.h" -#include "../f_finale.h" -#include "../g_demo.h" -#include "../g_game.h" -#include "../i_time.h" -#include "../lua_script.h" -#include "../lzf.h" -#include "../m_misc.h" -#include "../p_haptic.h" -#include "../p_local.h" -#include "../p_saveg.h" -#include "../r_main.h" -#include "../tables.h" -#include "../z_zone.h" - -#define SAVEGAMESIZE (768*1024) - -UINT8 hu_redownloadinggamestate = 0; -boolean cl_redownloadinggamestate = false; - -boolean SV_ResendingSavegameToAnyone(void) -{ - for (INT32 i = 0; i < MAXNETNODES; i++) - if (netnodes[i].resendingsavegame) - return true; - return false; -} - -void SV_SendSaveGame(INT32 node, boolean resending) -{ - size_t length, compressedlen; - UINT8 *savebuffer; - UINT8 *compressedsave; - UINT8 *buffertosend; - - // first save it in a malloced buffer - savebuffer = (UINT8 *)malloc(SAVEGAMESIZE); - if (!savebuffer) - { - CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); - return; - } - - // Leave room for the uncompressed length. - save_p = savebuffer + sizeof(UINT32); - - P_SaveNetGame(resending); - - length = save_p - savebuffer; - if (length > SAVEGAMESIZE) - { - free(savebuffer); - save_p = NULL; - I_Error("Savegame buffer overrun"); - } - - // Allocate space for compressed save: one byte fewer than for the - // uncompressed data to ensure that the compression is worthwhile. - compressedsave = malloc(length - 1); - if (!compressedsave) - { - CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); - return; - } - - // Attempt to compress it. - if((compressedlen = lzf_compress(savebuffer + sizeof(UINT32), length - sizeof(UINT32), compressedsave + sizeof(UINT32), length - sizeof(UINT32) - 1))) - { - // Compressing succeeded; send compressed data - - free(savebuffer); - - // State that we're compressed. - buffertosend = compressedsave; - WRITEUINT32(compressedsave, length - sizeof(UINT32)); - length = compressedlen + sizeof(UINT32); - } - else - { - // Compression failed to make it smaller; send original - - free(compressedsave); - - // State that we're not compressed - buffertosend = savebuffer; - WRITEUINT32(savebuffer, 0); - } - - AddRamToSendQueue(node, buffertosend, length, SF_RAM, 0); - save_p = NULL; - - // Remember when we started sending the savegame so we can handle timeouts - netnodes[node].sendingsavegame = true; - netnodes[node].freezetimeout = I_GetTime() + jointimeout + length / 1024; // 1 extra tic for each kilobyte -} - -#ifdef DUMPCONSISTENCY -#define TMPSAVENAME "badmath.sav" -static consvar_t cv_dumpconsistency = CVAR_INIT ("dumpconsistency", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); - -void SV_SavedGame(void) -{ - size_t length; - UINT8 *savebuffer; - char tmpsave[256]; - - if (!cv_dumpconsistency.value) - return; - - sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); - - // first save it in a malloced buffer - save_p = savebuffer = (UINT8 *)malloc(SAVEGAMESIZE); - if (!save_p) - { - CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); - return; - } - - P_SaveNetGame(false); - - length = save_p - savebuffer; - if (length > SAVEGAMESIZE) - { - free(savebuffer); - save_p = NULL; - I_Error("Savegame buffer overrun"); - } - - // then save it! - if (!FIL_WriteFile(tmpsave, savebuffer, length)) - CONS_Printf(M_GetText("Didn't save %s for netgame"), tmpsave); - - free(savebuffer); - save_p = NULL; -} - -#undef TMPSAVENAME -#endif -#define TMPSAVENAME "$$$.sav" - - -void CL_LoadReceivedSavegame(boolean reloading) -{ - UINT8 *savebuffer = NULL; - size_t length, decompressedlen; - char tmpsave[256]; - - FreeFileNeeded(); - - sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); - - length = FIL_ReadFile(tmpsave, &savebuffer); - - CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(length)); - if (!length) - { - I_Error("Can't read savegame sent"); - return; - } - - save_p = savebuffer; - - // Decompress saved game if necessary. - decompressedlen = READUINT32(save_p); - if(decompressedlen > 0) - { - UINT8 *decompressedbuffer = Z_Malloc(decompressedlen, PU_STATIC, NULL); - lzf_decompress(save_p, length - sizeof(UINT32), decompressedbuffer, decompressedlen); - Z_Free(savebuffer); - save_p = savebuffer = decompressedbuffer; - } - - paused = false; - demoplayback = false; - titlemapinaction = TITLEMAP_OFF; - titledemo = false; - automapactive = false; - - P_StopRumble(NULL); - - // load a base level - if (P_LoadNetGame(reloading)) - { - const UINT8 actnum = mapheaderinfo[gamemap-1]->actnum; - CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap)); - if (strcmp(mapheaderinfo[gamemap-1]->lvlttl, "")) - { - CONS_Printf(": %s", mapheaderinfo[gamemap-1]->lvlttl); - if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) - CONS_Printf(M_GetText(" Zone")); - if (actnum > 0) - CONS_Printf(" %2d", actnum); - } - CONS_Printf("\"\n"); - } - - // done - Z_Free(savebuffer); - save_p = NULL; - if (unlink(tmpsave) == -1) - CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave); - consistancy[gametic%BACKUPTICS] = Consistancy(); - CON_ToggleOff(); - - // Tell the server we have received and reloaded the gamestate - // so they know they can resume the game - netbuffer->packettype = PT_RECEIVEDGAMESTATE; - HSendPacket(servernode, true, 0, 0); -} - -void CL_ReloadReceivedSavegame(void) -{ - for (INT32 i = 0; i < MAXPLAYERS; i++) - { - LUA_InvalidatePlayer(&players[i]); - sprintf(player_names[i], "Player %d", i + 1); - } - - CL_LoadReceivedSavegame(true); - - neededtic = max(neededtic, gametic); - maketic = neededtic; - - ticcmd_oldangleturn[0] = players[consoleplayer].oldrelangleturn; - P_ForceLocalAngle(&players[consoleplayer], (angle_t)(players[consoleplayer].angleturn << 16)); - if (splitscreen) - { - ticcmd_oldangleturn[1] = players[secondarydisplayplayer].oldrelangleturn; - P_ForceLocalAngle(&players[secondarydisplayplayer], (angle_t)(players[secondarydisplayplayer].angleturn << 16)); - } - - camera.subsector = R_PointInSubsector(camera.x, camera.y); - camera2.subsector = R_PointInSubsector(camera2.x, camera2.y); - - cl_redownloadinggamestate = false; - - CONS_Printf(M_GetText("Game state reloaded\n")); -} - -void Command_ResendGamestate(void) -{ - SINT8 playernum; - - if (COM_Argc() == 1) - { - CONS_Printf(M_GetText("resendgamestate : resend the game state to a player\n")); - return; - } - else if (client) - { - CONS_Printf(M_GetText("Only the server can use this.\n")); - return; - } - - playernum = nametonum(COM_Argv(1)); - if (playernum == -1 || playernum == 0) - return; - - // Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on - netbuffer->packettype = PT_WILLRESENDGAMESTATE; - if (!HSendPacket(playernode[playernum], true, 0, 0)) - { - CONS_Alert(CONS_ERROR, M_GetText("A problem occured, please try again.\n")); - return; - } -} - -void PT_CanReceiveGamestate(SINT8 node) -{ - if (client || netnodes[node].sendingsavegame) - return; - - CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[netnodes[node].player]); - - SV_SendSaveGame(node, true); // Resend a complete game state - netnodes[node].resendingsavegame = true; -} - -void PT_ReceivedGamestate(SINT8 node) -{ - netnodes[node].sendingsavegame = false; - netnodes[node].resendingsavegame = false; - netnodes[node].savegameresendcooldown = I_GetTime() + 5 * TICRATE; -} - -void PT_WillResendGamestate(SINT8 node) -{ - (void)node; - - char tmpsave[256]; - - if (server || cl_redownloadinggamestate) - return; - - // Send back a PT_CANRECEIVEGAMESTATE packet to the server - // so they know they can start sending the game state - netbuffer->packettype = PT_CANRECEIVEGAMESTATE; - if (!HSendPacket(servernode, true, 0, 0)) - return; - - CONS_Printf(M_GetText("Reloading game state...\n")); - - sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); - - // Don't get a corrupt savegame error because tmpsave already exists - if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1) - I_Error("Can't delete %s\n", tmpsave); - - CL_PrepareDownloadSaveGame(tmpsave); - - cl_redownloadinggamestate = true; -} diff --git a/src/netcode/gamestate.h b/src/netcode/gamestate.h deleted file mode 100644 index 9d2779772..000000000 --- a/src/netcode/gamestate.h +++ /dev/null @@ -1,31 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file gamestate.h -/// \brief Gamestate (re)sending - -#ifndef __GAMESTATE__ -#define __GAMESTATE__ - -#include "../doomtype.h" - -extern UINT8 hu_redownloadinggamestate; -extern boolean cl_redownloadinggamestate; - -boolean SV_ResendingSavegameToAnyone(void); -void SV_SendSaveGame(INT32 node, boolean resending); -void SV_SavedGame(void); -void CL_LoadReceivedSavegame(boolean reloading); -void CL_ReloadReceivedSavegame(void); -void Command_ResendGamestate(void); -void PT_CanReceiveGamestate(SINT8 node); -void PT_ReceivedGamestate(SINT8 node); -void PT_WillResendGamestate(SINT8 node); - -#endif diff --git a/src/netcode/net_command.c b/src/netcode/net_command.c deleted file mode 100644 index efc8bd0ef..000000000 --- a/src/netcode/net_command.c +++ /dev/null @@ -1,386 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file net_command.c -/// \brief Net command handling - -#include "net_command.h" -#include "tic_command.h" -#include "gamestate.h" -#include "server_connection.h" -#include "d_clisrv.h" -#include "i_net.h" -#include "../byteptr.h" -#include "../g_game.h" -#include "../z_zone.h" -#include "../doomtype.h" - -textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL}; -UINT8 localtextcmd[MAXTEXTCMD]; -UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen -static void (*listnetxcmd[MAXNETXCMD])(UINT8 **p, INT32 playernum); - -void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)) -{ -#ifdef PARANOIA - if (id >= MAXNETXCMD) - I_Error("Command id %d too big", id); - if (listnetxcmd[id] != 0) - I_Error("Command id %d already used", id); -#endif - listnetxcmd[id] = cmd_f; -} - -void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam) -{ - if (localtextcmd[0]+2+nparam > MAXTEXTCMD) - { - // for future reference: if (cv_debug) != debug disabled. - CONS_Alert(CONS_ERROR, M_GetText("NetXCmd buffer full, cannot add netcmd %d! (size: %d, needed: %s)\n"), id, localtextcmd[0], sizeu1(nparam)); - return; - } - localtextcmd[0]++; - localtextcmd[localtextcmd[0]] = (UINT8)id; - if (param && nparam) - { - M_Memcpy(&localtextcmd[localtextcmd[0]+1], param, nparam); - localtextcmd[0] = (UINT8)(localtextcmd[0] + (UINT8)nparam); - } -} - -// splitscreen player -void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam) -{ - if (localtextcmd2[0]+2+nparam > MAXTEXTCMD) - { - I_Error("No more place in the buffer for netcmd %d\n",id); - return; - } - localtextcmd2[0]++; - localtextcmd2[localtextcmd2[0]] = (UINT8)id; - if (param && nparam) - { - M_Memcpy(&localtextcmd2[localtextcmd2[0]+1], param, nparam); - localtextcmd2[0] = (UINT8)(localtextcmd2[0] + (UINT8)nparam); - } -} - -UINT8 GetFreeXCmdSize(void) -{ - // -1 for the size and another -1 for the ID. - return (UINT8)(localtextcmd[0] - 2); -} - -// Frees all textcmd memory for the specified tic -void D_FreeTextcmd(tic_t tic) -{ - textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; - textcmdtic_t *textcmdtic = *tctprev; - - while (textcmdtic && textcmdtic->tic != tic) - { - tctprev = &textcmdtic->next; - textcmdtic = textcmdtic->next; - } - - if (textcmdtic) - { - // Remove this tic from the list. - *tctprev = textcmdtic->next; - - // Free all players. - for (INT32 i = 0; i < TEXTCMD_HASH_SIZE; i++) - { - textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[i]; - - while (textcmdplayer) - { - textcmdplayer_t *tcpnext = textcmdplayer->next; - Z_Free(textcmdplayer); - textcmdplayer = tcpnext; - } - } - - // Free this tic's own memory. - Z_Free(textcmdtic); - } -} - -// Gets the buffer for the specified ticcmd, or NULL if there isn't one -UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum) -{ - textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; - while (textcmdtic && textcmdtic->tic != tic) textcmdtic = textcmdtic->next; - - // Do we have an entry for the tic? If so, look for player. - if (textcmdtic) - { - textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)]; - while (textcmdplayer && textcmdplayer->playernum != playernum) textcmdplayer = textcmdplayer->next; - - if (textcmdplayer) return textcmdplayer->cmd; - } - - return NULL; -} - -// Gets the buffer for the specified ticcmd, creating one if necessary -UINT8* D_GetTextcmd(tic_t tic, INT32 playernum) -{ - textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; - textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; - textcmdplayer_t *textcmdplayer, **tcpprev; - - // Look for the tic. - while (textcmdtic && textcmdtic->tic != tic) - { - tctprev = &textcmdtic->next; - textcmdtic = textcmdtic->next; - } - - // If we don't have an entry for the tic, make it. - if (!textcmdtic) - { - textcmdtic = *tctprev = Z_Calloc(sizeof (textcmdtic_t), PU_STATIC, NULL); - textcmdtic->tic = tic; - } - - tcpprev = &textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)]; - textcmdplayer = *tcpprev; - - // Look for the player. - while (textcmdplayer && textcmdplayer->playernum != playernum) - { - tcpprev = &textcmdplayer->next; - textcmdplayer = textcmdplayer->next; - } - - // If we don't have an entry for the player, make it. - if (!textcmdplayer) - { - textcmdplayer = *tcpprev = Z_Calloc(sizeof (textcmdplayer_t), PU_STATIC, NULL); - textcmdplayer->playernum = playernum; - } - - return textcmdplayer->cmd; -} - -void ExtraDataTicker(void) -{ - for (INT32 i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] || i == 0) - { - UINT8 *bufferstart = D_GetExistingTextcmd(gametic, i); - - if (bufferstart) - { - UINT8 *curpos = bufferstart; - UINT8 *bufferend = &curpos[curpos[0]+1]; - - curpos++; - while (curpos < bufferend) - { - if (*curpos < MAXNETXCMD && listnetxcmd[*curpos]) - { - const UINT8 id = *curpos; - curpos++; - DEBFILE(va("executing x_cmd %s ply %u ", netxcmdnames[id - 1], i)); - (listnetxcmd[id])(&curpos, i); - DEBFILE("done\n"); - } - else - { - if (server) - { - SendKick(i, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - DEBFILE(va("player %d kicked [gametic=%u] reason as follows:\n", i, gametic)); - } - CONS_Alert(CONS_WARNING, M_GetText("Got unknown net command [%s]=%d (max %d)\n"), sizeu1(curpos - bufferstart), *curpos, bufferstart[0]); - break; - } - } - } - } - - // If you are a client, you can safely forget the net commands for this tic - // If you are the server, you need to remember them until every client has been acknowledged, - // because if you need to resend a PT_SERVERTICS packet, you will need to put the commands in it - if (client) - D_FreeTextcmd(gametic); -} - -// used at txtcmds received to check packetsize bound -size_t TotalTextCmdPerTic(tic_t tic) -{ - size_t total = 1; // num of textcmds in the tic (ntextcmd byte) - - for (INT32 i = 0; i < MAXPLAYERS; i++) - { - UINT8 *textcmd = D_GetExistingTextcmd(tic, i); - if ((!i || playeringame[i]) && textcmd) - total += 2 + textcmd[0]; // "+2" for size and playernum - } - - return total; -} - -void PT_TextCmd(SINT8 node, INT32 netconsole) -{ - if (client) - return; - - // splitscreen special - if (netbuffer->packettype == PT_TEXTCMD2) - netconsole = netnodes[node].player2; - - if (netconsole < 0 || netconsole >= MAXPLAYERS) - Net_UnAcknowledgePacket(node); - else - { - size_t j; - tic_t tic = maketic; - UINT8 *textcmd; - - // ignore if the textcmd has a reported size of zero - // this shouldn't be sent at all - if (!netbuffer->u.textcmd[0]) - { - DEBFILE(va("GetPacket: Textcmd with size 0 detected! (node %u, player %d)\n", - node, netconsole)); - Net_UnAcknowledgePacket(node); - return; - } - - // ignore if the textcmd size var is actually larger than it should be - // BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength - if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1) - { - DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n", - netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1), - node, netconsole)); - Net_UnAcknowledgePacket(node); - return; - } - - // check if tic that we are making isn't too large else we cannot send it :( - // doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time - j = software_MAXPACKETLENGTH - - (netbuffer->u.textcmd[0]+2+BASESERVERTICSSIZE - + (doomcom->numslots+1)*sizeof(ticcmd_t)); - - // search a tic that have enougth space in the ticcmd - while ((textcmd = D_GetExistingTextcmd(tic, netconsole)), - (TotalTextCmdPerTic(tic) > j || netbuffer->u.textcmd[0] + (textcmd ? textcmd[0] : 0) > MAXTEXTCMD) - && tic < firstticstosend + BACKUPTICS) - tic++; - - if (tic >= firstticstosend + BACKUPTICS) - { - DEBFILE(va("GetPacket: Textcmd too long (max %s, used %s, mak %d, " - "tosend %u, node %u, player %d)\n", sizeu1(j), sizeu2(TotalTextCmdPerTic(maketic)), - maketic, firstticstosend, node, netconsole)); - Net_UnAcknowledgePacket(node); - return; - } - - // Make sure we have a buffer - if (!textcmd) textcmd = D_GetTextcmd(tic, netconsole); - - DEBFILE(va("textcmd put in tic %u at position %d (player %d) ftts %u mk %u\n", - tic, textcmd[0]+1, netconsole, firstticstosend, maketic)); - - M_Memcpy(&textcmd[textcmd[0]+1], netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]); - textcmd[0] += (UINT8)netbuffer->u.textcmd[0]; - } -} - -void SV_WriteNetCommandsForTic(tic_t tic, UINT8 **buf) -{ - UINT8 *numcmds; - - numcmds = (*buf)++; - *numcmds = 0; - for (INT32 i = 0; i < MAXPLAYERS; i++) - { - UINT8 *cmd = D_GetExistingTextcmd(tic, i); - INT32 size = cmd ? cmd[0] : 0; - - if ((!i || playeringame[i]) && size) - { - (*numcmds)++; - WRITEUINT8(*buf, i); - M_Memcpy(*buf, cmd, size + 1); - *buf += size + 1; - } - } -} - -void CL_CopyNetCommandsFromServerPacket(tic_t tic) -{ - servertics_pak *packet = &netbuffer->u.serverpak; - UINT8 *cmds = (UINT8*)&packet->cmds[packet->numslots * packet->numtics]; - UINT8 numcmds; - - numcmds = *cmds++; - - for (UINT32 i = 0; i < numcmds; i++) - { - INT32 playernum = *cmds++; // playernum - size_t size = cmds[0]+1; - - if (tic >= gametic) // Don't copy old net commands - M_Memcpy(D_GetTextcmd(tic, playernum), cmds, size); - cmds += size; - } -} - -void CL_SendNetCommands(void) -{ - // Send extra data if needed - if (localtextcmd[0]) - { - netbuffer->packettype = PT_TEXTCMD; - M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1); - // All extra data have been sent - if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail... - localtextcmd[0] = 0; - } - - // Send extra data if needed for player 2 (splitscreen) - if (localtextcmd2[0]) - { - netbuffer->packettype = PT_TEXTCMD2; - M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1); - // All extra data have been sent - if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail... - localtextcmd2[0] = 0; - } -} - -void SendKick(UINT8 playernum, UINT8 msg) -{ - UINT8 buf[2]; - - if (!(server && cv_rejointimeout.value)) - msg &= ~KICK_MSG_KEEP_BODY; - - buf[0] = playernum; - buf[1] = msg; - SendNetXCmd(XD_KICK, &buf, 2); -} - -void SendKicksForNode(SINT8 node, UINT8 msg) -{ - if (!netnodes[node].ingame) - return; - - for (INT32 playernum = netnodes[node].player; playernum != -1; playernum = netnodes[node].player2) - if (playernum != -1 && playeringame[playernum]) - SendKick(playernum, msg); -} diff --git a/src/netcode/net_command.h b/src/netcode/net_command.h deleted file mode 100644 index cc26aeb0e..000000000 --- a/src/netcode/net_command.h +++ /dev/null @@ -1,66 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file net_command.h -/// \brief Net command handling - -#ifndef __D_NET_COMMAND__ -#define __D_NET_COMMAND__ - -#include "d_clisrv.h" -#include "../doomtype.h" - -// Must be a power of two -#define TEXTCMD_HASH_SIZE 4 - -typedef struct textcmdplayer_s -{ - INT32 playernum; - UINT8 cmd[MAXTEXTCMD]; - struct textcmdplayer_s *next; -} textcmdplayer_t; - -typedef struct textcmdtic_s -{ - tic_t tic; - textcmdplayer_t *playercmds[TEXTCMD_HASH_SIZE]; - struct textcmdtic_s *next; -} textcmdtic_t; - -extern textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE]; - -extern UINT8 localtextcmd[MAXTEXTCMD]; -extern UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen - -void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)); -void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam); -void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player - -UINT8 GetFreeXCmdSize(void); -void D_FreeTextcmd(tic_t tic); - -// Gets the buffer for the specified ticcmd, or NULL if there isn't one -UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum); - -// Gets the buffer for the specified ticcmd, creating one if necessary -UINT8* D_GetTextcmd(tic_t tic, INT32 playernum); - -void ExtraDataTicker(void); - -// used at txtcmds received to check packetsize bound -size_t TotalTextCmdPerTic(tic_t tic); - -void PT_TextCmd(SINT8 node, INT32 netconsole); -void SV_WriteNetCommandsForTic(tic_t tic, UINT8 **buf); -void CL_CopyNetCommandsFromServerPacket(tic_t tic); -void CL_SendNetCommands(void); -void SendKick(UINT8 playernum, UINT8 msg); -void SendKicksForNode(SINT8 node, UINT8 msg); - -#endif diff --git a/src/netcode/server_connection.c b/src/netcode/server_connection.c deleted file mode 100644 index f8ec3c7bd..000000000 --- a/src/netcode/server_connection.c +++ /dev/null @@ -1,507 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file server_connection.c -/// \brief Server-side part of connection handling - -#include "server_connection.h" -#include "i_net.h" -#include "d_clisrv.h" -#include "d_netfil.h" -#include "mserv.h" -#include "net_command.h" -#include "gamestate.h" -#include "../byteptr.h" -#include "../g_game.h" -#include "../g_state.h" -#include "../p_setup.h" -#include "../p_tick.h" -#include "../command.h" -#include "../doomstat.h" - -// Minimum timeout for sending the savegame -// The actual timeout will be longer depending on the savegame length -tic_t jointimeout = (10*TICRATE); - -// Incremented by cv_joindelay when a client joins, decremented each tic. -// If higher than cv_joindelay * 2 (3 joins in a short timespan), joins are temporarily disabled. -tic_t joindelay = 0; - -// Minimum timeout for sending the savegame -// The actual timeout will be longer depending on the savegame length -char playeraddress[MAXPLAYERS][64]; - -consvar_t cv_showjoinaddress = CVAR_INIT ("showjoinaddress", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); - -consvar_t cv_allownewplayer = CVAR_INIT ("allowjoin", "On", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); - -static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}}; -consvar_t cv_maxplayers = CVAR_INIT ("maxplayers", "8", CV_SAVE|CV_NETVAR, maxplayers_cons_t, NULL); - -static CV_PossibleValue_t joindelay_cons_t[] = {{1, "MIN"}, {3600, "MAX"}, {0, "Off"}, {0, NULL}}; -consvar_t cv_joindelay = CVAR_INIT ("joindelay", "10", CV_SAVE|CV_NETVAR, joindelay_cons_t, NULL); - -static CV_PossibleValue_t rejointimeout_cons_t[] = {{1, "MIN"}, {60 * FRACUNIT, "MAX"}, {0, "Off"}, {0, NULL}}; -consvar_t cv_rejointimeout = CVAR_INIT ("rejointimeout", "2", CV_SAVE|CV_NETVAR|CV_FLOAT, rejointimeout_cons_t, NULL); - -static INT32 FindRejoinerNum(SINT8 node) -{ - char strippednodeaddress[64]; - const char *nodeaddress; - char *port; - - // Make sure there is no dead dress before proceeding to the stripping - if (!I_GetNodeAddress) - return -1; - nodeaddress = I_GetNodeAddress(node); - if (!nodeaddress) - return -1; - - // Strip the address of its port - strcpy(strippednodeaddress, nodeaddress); - port = strchr(strippednodeaddress, ':'); - if (port) - *port = '\0'; - - // Check if any player matches the stripped address - for (INT32 i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && playeraddress[i][0] && playernode[i] == UINT8_MAX - && !strcmp(playeraddress[i], strippednodeaddress)) - return i; - } - - return -1; -} - -static UINT8 -GetRefuseReason (INT32 node) -{ - if (!node || FindRejoinerNum(node) != -1) - return 0; - else if (bannednode && bannednode[node]) - return REFUSE_BANNED; - else if (!cv_allownewplayer.value) - return REFUSE_JOINS_DISABLED; - else if (D_NumPlayers() >= cv_maxplayers.value) - return REFUSE_SLOTS_FULL; - else - return 0; -} - -static void SV_SendServerInfo(INT32 node, tic_t servertime) -{ - UINT8 *p; - - netbuffer->packettype = PT_SERVERINFO; - netbuffer->u.serverinfo._255 = 255; - netbuffer->u.serverinfo.packetversion = PACKETVERSION; - netbuffer->u.serverinfo.version = VERSION; - netbuffer->u.serverinfo.subversion = SUBVERSION; - strncpy(netbuffer->u.serverinfo.application, SRB2APPLICATION, - sizeof netbuffer->u.serverinfo.application); - // return back the time value so client can compute their ping - netbuffer->u.serverinfo.time = (tic_t)LONG(servertime); - netbuffer->u.serverinfo.leveltime = (tic_t)LONG(leveltime); - - netbuffer->u.serverinfo.numberofplayer = (UINT8)D_NumPlayers(); - netbuffer->u.serverinfo.maxplayer = (UINT8)cv_maxplayers.value; - - netbuffer->u.serverinfo.refusereason = GetRefuseReason(node); - - strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype], - sizeof netbuffer->u.serverinfo.gametypename); - netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame; - netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled(); - netbuffer->u.serverinfo.flags = (dedicated ? SV_DEDICATED : 0); - strncpy(netbuffer->u.serverinfo.servername, cv_servername.string, - MAXSERVERNAME); - strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7); - - M_Memcpy(netbuffer->u.serverinfo.mapmd5, mapmd5, 16); - - memset(netbuffer->u.serverinfo.maptitle, 0, sizeof netbuffer->u.serverinfo.maptitle); - - if (mapheaderinfo[gamemap-1] && *mapheaderinfo[gamemap-1]->lvlttl) - { - char *read = mapheaderinfo[gamemap-1]->lvlttl, *writ = netbuffer->u.serverinfo.maptitle; - while (writ < (netbuffer->u.serverinfo.maptitle+32) && *read != '\0') - { - if (!(*read & 0x80)) - { - *writ = toupper(*read); - writ++; - } - read++; - } - *writ = '\0'; - //strncpy(netbuffer->u.serverinfo.maptitle, (char *)mapheaderinfo[gamemap-1]->lvlttl, 33); - } - else - strncpy(netbuffer->u.serverinfo.maptitle, "UNKNOWN", 32); - - if (mapheaderinfo[gamemap-1] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) - netbuffer->u.serverinfo.iszone = 1; - else - netbuffer->u.serverinfo.iszone = 0; - - if (mapheaderinfo[gamemap-1]) - netbuffer->u.serverinfo.actnum = mapheaderinfo[gamemap-1]->actnum; - - p = PutFileNeeded(0); - - HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); -} - -static void SV_SendPlayerInfo(INT32 node) -{ - netbuffer->packettype = PT_PLAYERINFO; - - for (UINT8 i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - { - netbuffer->u.playerinfo[i].num = 255; // This slot is empty. - continue; - } - - netbuffer->u.playerinfo[i].num = i; - strncpy(netbuffer->u.playerinfo[i].name, (const char *)&player_names[i], MAXPLAYERNAME+1); - netbuffer->u.playerinfo[i].name[MAXPLAYERNAME] = '\0'; - - //fetch IP address - //No, don't do that, you fuckface. - memset(netbuffer->u.playerinfo[i].address, 0, 4); - - if (G_GametypeHasTeams()) - { - if (!players[i].ctfteam) - netbuffer->u.playerinfo[i].team = 255; - else - netbuffer->u.playerinfo[i].team = (UINT8)players[i].ctfteam; - } - else - { - if (players[i].spectator) - netbuffer->u.playerinfo[i].team = 255; - else - netbuffer->u.playerinfo[i].team = 0; - } - - netbuffer->u.playerinfo[i].score = LONG(players[i].score); - netbuffer->u.playerinfo[i].timeinserver = SHORT((UINT16)(players[i].jointime / TICRATE)); - netbuffer->u.playerinfo[i].skin = (UINT8)(players[i].skin -#ifdef DEVELOP // it's safe to do this only because PLAYERINFO isn't read by the game itself - % 3 -#endif - ); - - // Extra data - netbuffer->u.playerinfo[i].data = 0; //players[i].skincolor; - - if (players[i].pflags & PF_TAGIT) - netbuffer->u.playerinfo[i].data |= 0x20; - - if (players[i].gotflag) - netbuffer->u.playerinfo[i].data |= 0x40; - - if (players[i].powers[pw_super]) - netbuffer->u.playerinfo[i].data |= 0x80; - } - - HSendPacket(node, false, 0, sizeof(plrinfo_pak) * MAXPLAYERS); -} - -/** Sends a PT_SERVERCFG packet - * - * \param node The destination - * \return True if the packet was successfully sent - * - */ -static boolean SV_SendServerConfig(INT32 node) -{ - boolean waspacketsent; - - netbuffer->packettype = PT_SERVERCFG; - - netbuffer->u.servercfg.serverplayer = (UINT8)serverplayer; - netbuffer->u.servercfg.totalslotnum = (UINT8)(doomcom->numslots); - netbuffer->u.servercfg.gametic = (tic_t)LONG(gametic); - netbuffer->u.servercfg.clientnode = (UINT8)node; - netbuffer->u.servercfg.gamestate = (UINT8)gamestate; - netbuffer->u.servercfg.gametype = (UINT8)gametype; - netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame; - - memcpy(netbuffer->u.servercfg.server_context, server_context, 8); - - { - const size_t len = sizeof (serverconfig_pak); - -#ifdef DEBUGFILE - if (debugfile) - { - fprintf(debugfile, "ServerConfig Packet about to be sent, size of packet:%s to node:%d\n", - sizeu1(len), node); - } -#endif - - waspacketsent = HSendPacket(node, true, 0, len); - } - -#ifdef DEBUGFILE - if (debugfile) - { - if (waspacketsent) - { - fprintf(debugfile, "ServerConfig Packet was sent\n"); - } - else - { - fprintf(debugfile, "ServerConfig Packet could not be sent right now\n"); - } - } -#endif - - return waspacketsent; -} - -// Adds a node to the game (player will follow at map change or at savegame....) -static inline void SV_AddNode(INT32 node) -{ - netnodes[node].tic = gametic; - netnodes[node].supposedtic = gametic; - // little hack because the server connects to itself and puts - // nodeingame when connected not here - if (node) - netnodes[node].ingame = true; -} - -static void SV_AddPlayer(SINT8 node, const char *name) -{ - INT32 n; - UINT8 buf[2 + MAXPLAYERNAME]; - UINT8 *p; - INT32 newplayernum; - - newplayernum = FindRejoinerNum(node); - if (newplayernum == -1) - { - // search for a free playernum - // we can't use playeringame since it is not updated here - for (newplayernum = dedicated ? 1 : 0; newplayernum < MAXPLAYERS; newplayernum++) - { - if (playeringame[newplayernum]) - continue; - for (n = 0; n < MAXNETNODES; n++) - if (netnodes[n].player == newplayernum || netnodes[n].player2 == newplayernum) - break; - if (n == MAXNETNODES) - break; - } - } - - // should never happen since we check the playernum - // before accepting the join - I_Assert(newplayernum < MAXPLAYERS); - - playernode[newplayernum] = (UINT8)node; - - p = buf + 2; - buf[0] = (UINT8)node; - buf[1] = newplayernum; - if (netnodes[node].numplayers < 1) - { - netnodes[node].player = newplayernum; - } - else - { - netnodes[node].player2 = newplayernum; - buf[1] |= 0x80; - } - WRITESTRINGN(p, name, MAXPLAYERNAME); - netnodes[node].numplayers++; - - SendNetXCmd(XD_ADDPLAYER, &buf, p - buf); - - DEBFILE(va("Server added player %d node %d\n", newplayernum, node)); -} - -static void SV_SendRefuse(INT32 node, const char *reason) -{ - strcpy(netbuffer->u.serverrefuse.reason, reason); - - netbuffer->packettype = PT_SERVERREFUSE; - HSendPacket(node, true, 0, strlen(netbuffer->u.serverrefuse.reason) + 1); - Net_CloseConnection(node); -} - -static const char * -GetRefuseMessage (SINT8 node, INT32 rejoinernum) -{ - clientconfig_pak *cc = &netbuffer->u.clientcfg; - - boolean rejoining = (rejoinernum != -1); - - if (!node)/* server connecting to itself */ - return NULL; - - if ( - cc->modversion != MODVERSION || - strncmp(cc->application, SRB2APPLICATION, - sizeof cc->application) - ){ - return/* this is probably client's fault */ - "Incompatible."; - } - else if (bannednode && bannednode[node]) - { - return - "You have been banned\n" - "from the server."; - } - else if (cc->localplayers != 1) - { - return - "Wrong player count."; - } - - if (!rejoining) - { - if (!cv_allownewplayer.value) - { - return - "The server is not accepting\n" - "joins for the moment."; - } - else if (D_NumPlayers() >= cv_maxplayers.value) - { - return va( - "Maximum players reached: %d", - cv_maxplayers.value); - } - } - - if (luafiletransfers) - { - return - "The serveris broadcasting a file\n" - "requested by a Lua script.\n" - "Please wait a bit and then\n" - "try rejoining."; - } - - if (netgame) - { - const tic_t th = 2 * cv_joindelay.value * TICRATE; - - if (joindelay > th) - { - return va( - "Too many people are connecting.\n" - "Please wait %d seconds and then\n" - "try rejoining.", - (joindelay - th) / TICRATE); - } - } - - return NULL; -} - -/** Called when a PT_CLIENTJOIN packet is received - * - * \param node The packet sender - * - */ -void PT_ClientJoin(SINT8 node) -{ - char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1]; - INT32 numplayers = netbuffer->u.clientcfg.localplayers; - INT32 rejoinernum; - - // Ignore duplicate packets - if (client || netnodes[node].ingame) - return; - - rejoinernum = FindRejoinerNum(node); - - const char *refuse = GetRefuseMessage(node, rejoinernum); - if (refuse) - { - SV_SendRefuse(node, refuse); - return; - } - - for (INT32 i = 0; i < numplayers; i++) - { - strlcpy(names[i], netbuffer->u.clientcfg.names[i], MAXPLAYERNAME + 1); - if (!EnsurePlayerNameIsGood(names[i], rejoinernum)) - { - SV_SendRefuse(node, "Bad player name"); - return; - } - } - - SV_AddNode(node); - - if (!SV_SendServerConfig(node)) - { - /// \note Shouldn't SV_SendRefuse be called before ResetNode? - ResetNode(node); - SV_SendRefuse(node, M_GetText("Server couldn't send info, please try again")); - /// \todo fix this !!! - return; - } - DEBFILE("new node joined\n"); - - if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) - { - SV_SendSaveGame(node, false); // send a complete game state - DEBFILE("send savegame\n"); - } - - // Splitscreen can allow 2 players in one node - for (INT32 i = 0; i < numplayers; i++) - SV_AddPlayer(node, names[i]); - - joindelay += cv_joindelay.value * TICRATE; -} - -void PT_AskInfoViaMS(SINT8 node) -{ - Net_CloseConnection(node); -} - -void PT_TellFilesNeeded(SINT8 node) -{ - if (server && serverrunning) - { - UINT8 *p; - INT32 firstfile = netbuffer->u.filesneedednum; - - netbuffer->packettype = PT_MOREFILESNEEDED; - netbuffer->u.filesneededcfg.first = firstfile; - netbuffer->u.filesneededcfg.more = 0; - - p = PutFileNeeded(firstfile); - - HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); - } - else // Shouldn't get this if you aren't the server...? - Net_CloseConnection(node); -} - -void PT_AskInfo(SINT8 node) -{ - if (server && serverrunning) - { - SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time)); - SV_SendPlayerInfo(node); // Send extra info - } - Net_CloseConnection(node); -} diff --git a/src/netcode/server_connection.h b/src/netcode/server_connection.h deleted file mode 100644 index 7481d0eb5..000000000 --- a/src/netcode/server_connection.h +++ /dev/null @@ -1,30 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file server_connection.h -/// \brief Server-side part of connection handling - -#ifndef __D_SERVER_CONNECTION__ -#define __D_SERVER_CONNECTION__ - -#include "../command.h" -#include "../doomdef.h" -#include "../doomtype.h" - -void PT_ClientJoin(SINT8 node); -void PT_AskInfoViaMS(SINT8 node); -void PT_TellFilesNeeded(SINT8 node); -void PT_AskInfo(SINT8 node); - -extern tic_t jointimeout; -extern tic_t joindelay; -extern char playeraddress[MAXPLAYERS][64]; -extern consvar_t cv_showjoinaddress, cv_allownewplayer, cv_maxplayers, cv_joindelay, cv_rejointimeout; - -#endif diff --git a/src/netcode/tic_command.c b/src/netcode/tic_command.c deleted file mode 100644 index 620a10f7a..000000000 --- a/src/netcode/tic_command.c +++ /dev/null @@ -1,454 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file tic_command.c -/// \brief Tic command handling - -#include "tic_command.h" -#include "d_clisrv.h" -#include "net_command.h" -#include "client_connection.h" -#include "gamestate.h" -#include "i_net.h" -#include "../d_main.h" -#include "../g_game.h" -#include "../i_system.h" -#include "../i_time.h" -#include "../byteptr.h" -#include "../doomstat.h" -#include "../doomtype.h" - -tic_t firstticstosend; // Smallest netnode.tic -tic_t tictoclear = 0; // Optimize D_ClearTiccmd -ticcmd_t localcmds; -ticcmd_t localcmds2; -boolean cl_packetmissed; -ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; - -static inline void *G_DcpyTiccmd(void* dest, const ticcmd_t* src, const size_t n) -{ - const size_t d = n / sizeof(ticcmd_t); - const size_t r = n % sizeof(ticcmd_t); - UINT8 *ret = dest; - - if (r) - M_Memcpy(dest, src, n); - else if (d) - G_MoveTiccmd(dest, src, d); - return ret+n; -} - -static inline void *G_ScpyTiccmd(ticcmd_t* dest, void* src, const size_t n) -{ - const size_t d = n / sizeof(ticcmd_t); - const size_t r = n % sizeof(ticcmd_t); - UINT8 *ret = src; - - if (r) - M_Memcpy(dest, src, n); - else if (d) - G_MoveTiccmd(dest, src, d); - return ret+n; -} - -/** Guesses the full value of a tic from its lowest byte, for a specific node - * - * \param low The lowest byte of the tic value - * \param node The node to deduce the tic for - * \return The full tic value - * - */ -tic_t ExpandTics(INT32 low, INT32 node) -{ - INT32 delta; - - delta = low - (netnodes[node].tic & UINT8_MAX); - - if (delta >= -64 && delta <= 64) - return (netnodes[node].tic & ~UINT8_MAX) + low; - else if (delta > 64) - return (netnodes[node].tic & ~UINT8_MAX) - 256 + low; - else //if (delta < -64) - return (netnodes[node].tic & ~UINT8_MAX) + 256 + low; -} - -void D_Clearticcmd(tic_t tic) -{ - D_FreeTextcmd(tic); - - for (INT32 i = 0; i < MAXPLAYERS; i++) - netcmds[tic%BACKUPTICS][i].angleturn = 0; - - DEBFILE(va("clear tic %5u (%2u)\n", tic, tic%BACKUPTICS)); -} - -void D_ResetTiccmds(void) -{ - memset(&localcmds, 0, sizeof(ticcmd_t)); - memset(&localcmds2, 0, sizeof(ticcmd_t)); - - // Reset the net command list - for (INT32 i = 0; i < TEXTCMD_HASH_SIZE; i++) - while (textcmds[i]) - D_Clearticcmd(textcmds[i]->tic); -} - -// Check ticcmd for "speed hacks" -static void CheckTiccmdHacks(INT32 playernum) -{ - ticcmd_t *cmd = &netcmds[maketic%BACKUPTICS][playernum]; - if (cmd->forwardmove > MAXPLMOVE || cmd->forwardmove < -MAXPLMOVE - || cmd->sidemove > MAXPLMOVE || cmd->sidemove < -MAXPLMOVE) - { - CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), playernum); - SendKick(playernum, KICK_MSG_CON_FAIL); - } -} - -// Check player consistancy during the level -static void CheckConsistancy(SINT8 nodenum, tic_t tic) -{ - netnode_t *node = &netnodes[nodenum]; - INT16 neededconsistancy = consistancy[tic%BACKUPTICS]; - INT16 clientconsistancy = SHORT(netbuffer->u.clientpak.consistancy); - - if (tic > gametic || tic + BACKUPTICS - 1 <= gametic || gamestate != GS_LEVEL - || neededconsistancy == clientconsistancy || SV_ResendingSavegameToAnyone() - || node->resendingsavegame || node->savegameresendcooldown > I_GetTime()) - return; - - if (cv_resynchattempts.value) - { - // Tell the client we are about to resend them the gamestate - netbuffer->packettype = PT_WILLRESENDGAMESTATE; - HSendPacket(nodenum, true, 0, 0); - - node->resendingsavegame = true; - - if (cv_blamecfail.value) - CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), - node->player+1, player_names[node->player], - neededconsistancy, clientconsistancy); - - DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", - node->player, tic, neededconsistancy, clientconsistancy)); - } - else - { - SendKick(node->player, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - - DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", - node->player, tic, neededconsistancy, clientconsistancy)); - } -} - -void PT_ClientCmd(SINT8 nodenum, INT32 netconsole) -{ - netnode_t *node = &netnodes[nodenum]; - tic_t realend, realstart; - - if (client) - return; - - // To save bytes, only the low byte of tic numbers are sent - // Use ExpandTics to figure out what the rest of the bytes are - realstart = ExpandTics(netbuffer->u.clientpak.client_tic, nodenum); - realend = ExpandTics(netbuffer->u.clientpak.resendfrom, nodenum); - - if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS - || netbuffer->packettype == PT_NODEKEEPALIVEMIS - || node->supposedtic < realend) - { - node->supposedtic = realend; - } - // Discard out of order packet - if (node->tic > realend) - { - DEBFILE(va("out of order ticcmd discarded nettics = %u\n", node->tic)); - return; - } - - // Update the nettics - node->tic = realend; - - // Don't do anything for packets of type NODEKEEPALIVE? - if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE - || netbuffer->packettype == PT_NODEKEEPALIVEMIS) - return; - - // As long as clients send valid ticcmds, the server can keep running, so reset the timeout - /// \todo Use a separate cvar for that kind of timeout? - node->freezetimeout = I_GetTime() + connectiontimeout; - - // Copy ticcmd - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); - - // Splitscreen cmd - if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) - && node->player2 >= 0) - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)node->player2], - &netbuffer->u.client2pak.cmd2, 1); - - CheckTiccmdHacks(netconsole); - CheckConsistancy(nodenum, realstart); -} - -void PT_ServerTics(SINT8 node, INT32 netconsole) -{ - tic_t realend, realstart; - - if (!netnodes[node].ingame) - { - // Do not remove my own server (we have just get a out of order packet) - if (node != servernode) - { - DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype)); - Net_CloseConnection(node); - } - return; - } - - // Only accept PT_SERVERTICS from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_SERVERTICS", node); - if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - return; - } - - realstart = netbuffer->u.serverpak.starttic; - realend = realstart + netbuffer->u.serverpak.numtics; - - realend = min(realend, gametic + CLIENTBACKUPTICS); - cl_packetmissed = realstart > neededtic; - - if (realstart <= neededtic && realend > neededtic) - { - UINT8 *pak = (UINT8 *)&netbuffer->u.serverpak.cmds; - - for (tic_t i = realstart; i < realend; i++) - { - // clear first - D_Clearticcmd(i); - - // copy the tics - pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak, - netbuffer->u.serverpak.numslots*sizeof (ticcmd_t)); - - CL_CopyNetCommandsFromServerPacket(i); - } - - neededtic = realend; - } - else - { - DEBFILE(va("frame not in bound: %u\n", neededtic)); - } -} - -// send the client packet to the server -void CL_SendClientCmd(void) -{ - size_t packetsize = 0; - - netbuffer->packettype = PT_CLIENTCMD; - - if (cl_packetmissed) - netbuffer->packettype++; - netbuffer->u.clientpak.resendfrom = (UINT8)(neededtic & UINT8_MAX); - netbuffer->u.clientpak.client_tic = (UINT8)(gametic & UINT8_MAX); - - if (gamestate == GS_WAITINGPLAYERS) - { - // Send PT_NODEKEEPALIVE packet - netbuffer->packettype += 4; - packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16); - HSendPacket(servernode, false, 0, packetsize); - } - else if (gamestate != GS_NULL && (addedtogame || dedicated)) - { - G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1); - netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]); - - // Send a special packet with 2 cmd for splitscreen - if (splitscreen || botingame) - { - netbuffer->packettype += 2; - G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1); - packetsize = sizeof (client2cmd_pak); - } - else - packetsize = sizeof (clientcmd_pak); - - HSendPacket(servernode, false, 0, packetsize); - } - - if (cl_mode == CL_CONNECTED || dedicated) - CL_SendNetCommands(); -} - -// PT_SERVERTICS packets can grow too large for a single UDP packet, -// So this checks how many tics worth of data can be sent in one packet. -// The rest can be sent later, usually the next tic. -static tic_t SV_CalculateNumTicsForPacket(SINT8 nodenum, tic_t firsttic, tic_t lasttic) -{ - size_t size = BASESERVERTICSSIZE; - - for (tic_t tic = firsttic; tic < lasttic; tic++) - { - size += sizeof (ticcmd_t) * doomcom->numslots; - size += TotalTextCmdPerTic(tic); - - if (size > software_MAXPACKETLENGTH) - { - DEBFILE(va("packet too large (%s) at tic %d (should be from %d to %d)\n", - sizeu1(size), tic, firsttic, lasttic)); - lasttic = tic; - - // Too bad: too many players have sent extra data - // and there is too much data for a single tic. - // To avoid that, keep the data for the next tic (see PT_TEXTCMD). - if (lasttic == firsttic) - { - if (size > MAXPACKETLENGTH) - I_Error("Too many players: can't send %s data for %d players to node %d\n" - "Well sorry nobody is perfect....\n", - sizeu1(size), doomcom->numslots, nodenum); - else - { - lasttic++; // send it anyway! - DEBFILE("sending it anyway\n"); - } - } - break; - } - } - - return lasttic - firsttic; -} - -// Sends the server packet -// Sends tic/net commands from firstticstosend to maketic-1 -void SV_SendTics(void) -{ - tic_t realfirsttic, lasttictosend; - - // Send to all clients except yourself - // For each node, create a packet with x tics and send it - // x is computed using node.supposedtic, max packet size and maketic - for (INT32 n = 1; n < MAXNETNODES; n++) - if (netnodes[n].ingame) - { - netnode_t *node = netnodes[n]; - - // assert node->supposedtic>=node->tic - realfirsttic = node->supposedtic; - lasttictosend = min(maketic, node->tic + CLIENTBACKUPTICS); - - if (realfirsttic >= lasttictosend) - { - // Well, we have sent all the tics, so we will use extra bandwidth - // to resend packets that are supposed lost. - // This is necessary since lost packet detection - // works when we receive a packet with firsttic > neededtic (PT_SERVERTICS) - DEBFILE(va("Nothing to send node %u mak=%u sup=%u net=%u \n", - n, maketic, node->supposedtic, node->tic)); - - realfirsttic = node->tic; - - if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3) - // All tics are Ok - continue; - - DEBFILE(va("Sent %d anyway\n", realfirsttic)); - } - realfirsttic = max(realfirsttic, firstticstosend); - - lasttictosend = realfirsttic + SV_CalculateNumTicsForPacket(n, realfirsttic, lasttictosend); - - // Prepare the packet header - netbuffer->packettype = PT_SERVERTICS; - netbuffer->u.serverpak.starttic = realfirsttic; - netbuffer->u.serverpak.numtics = (UINT8)(lasttictosend - realfirsttic); - netbuffer->u.serverpak.numslots = (UINT8)SHORT(doomcom->numslots); - - // Fill and send the packet - UINT8 *bufpos = (UINT8 *)&netbuffer->u.serverpak.cmds; - for (tic_t i = realfirsttic; i < lasttictosend; i++) - bufpos = G_DcpyTiccmd(bufpos, netcmds[i%BACKUPTICS], doomcom->numslots * sizeof (ticcmd_t)); - for (tic_t i = realfirsttic; i < lasttictosend; i++) - SV_WriteNetCommandsForTic(i, &bufpos); - size_t packsize = bufpos - (UINT8 *)&(netbuffer->u); - HSendPacket(n, false, 0, packsize); - - // When tics are too large, only one tic is sent so don't go backwards! - if (lasttictosend-doomcom->extratics > realfirsttic) - node->supposedtic = lasttictosend-doomcom->extratics; - else - node->supposedtic = lasttictosend; - node->supposedtic = max(node->supposedtic, node->tic); - } - - // node 0 is me! - netnodes[0].supposedtic = maketic; -} - -void Local_Maketic(INT32 realtics) -{ - I_OsPolling(); // I_Getevent - D_ProcessEvents(); // menu responder, cons responder, - // game responder calls HU_Responder, AM_Responder, - // and G_MapEventsToControls - if (!dedicated) - rendergametic = gametic; - // translate inputs (keyboard/mouse/gamepad) into game controls - G_BuildTiccmd(&localcmds, realtics, 1); - if (splitscreen || botingame) - G_BuildTiccmd(&localcmds2, realtics, 2); - - localcmds.angleturn |= TICCMD_RECEIVED; - localcmds2.angleturn |= TICCMD_RECEIVED; -} - -// create missed tic -void SV_Maketic(void) -{ - for (INT32 i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - - // We didn't receive this tic - if ((netcmds[maketic % BACKUPTICS][i].angleturn & TICCMD_RECEIVED) == 0) - { - ticcmd_t * ticcmd = &netcmds[(maketic ) % BACKUPTICS][i]; - ticcmd_t *prevticcmd = &netcmds[(maketic - 1) % BACKUPTICS][i]; - - if (players[i].quittime) - { - // Copy the angle/aiming from the previous tic - // and empty the other inputs - memset(ticcmd, 0, sizeof(netcmds[0][0])); - ticcmd->angleturn = prevticcmd->angleturn | TICCMD_RECEIVED; - ticcmd->aiming = prevticcmd->aiming; - } - else - { - DEBFILE(va("MISS tic%4d for player %d\n", maketic, i)); - // Copy the input from the previous tic - *ticcmd = *prevticcmd; - ticcmd->angleturn &= ~TICCMD_RECEIVED; - } - } - } - - // All tics have been processed, make the next - maketic++; -} diff --git a/src/netcode/tic_command.h b/src/netcode/tic_command.h deleted file mode 100644 index 289750fb3..000000000 --- a/src/netcode/tic_command.h +++ /dev/null @@ -1,44 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file tic_command.h -/// \brief Tic command handling - -#ifndef __D_TIC_COMMAND__ -#define __D_TIC_COMMAND__ - -#include "d_clisrv.h" -#include "../d_ticcmd.h" -#include "../doomdef.h" -#include "../doomtype.h" - -extern tic_t firstticstosend; // min of the nettics -extern tic_t tictoclear; // optimize d_clearticcmd - -extern ticcmd_t localcmds; -extern ticcmd_t localcmds2; -extern boolean cl_packetmissed; - -extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; - -tic_t ExpandTics(INT32 low, INT32 node); -void D_Clearticcmd(tic_t tic); -void D_ResetTiccmds(void); - -void PT_ClientCmd(SINT8 nodenum, INT32 netconsole); -void PT_ServerTics(SINT8 node, INT32 netconsole); - -// send the client packet to the server -void CL_SendClientCmd(void); - -void SV_SendTics(void); -void Local_Maketic(INT32 realtics); -void SV_Maketic(void); - -#endif diff --git a/src/p_ceilng.c b/src/p_ceilng.c index 949eeddf2..66f2dd58e 100644 --- a/src/p_ceilng.c +++ b/src/p_ceilng.c @@ -17,7 +17,7 @@ #include "r_main.h" #include "s_sound.h" #include "z_zone.h" -#include "netcode/d_netcmd.h" +#include "d_netcmd.h" // ========================================================================== // CEILINGS diff --git a/src/p_haptic.c b/src/p_haptic.c index 4d22fbd77..dbfa58737 100644 --- a/src/p_haptic.c +++ b/src/p_haptic.c @@ -11,7 +11,7 @@ #include "p_haptic.h" #include "g_game.h" -#include "netcode/d_netcmd.h" +#include "d_netcmd.h" #include "i_gamepad.h" #include "doomstat.h" diff --git a/src/p_inter.c b/src/p_inter.c index f33494d1f..f3c13e315 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -30,7 +30,6 @@ #include "m_misc.h" #include "v_video.h" // video flags for CEchos #include "f_finale.h" -#include "netcode/net_command.h" // CTF player names #define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : "" diff --git a/src/p_lights.c b/src/p_lights.c index a1f4de853..4c783f884 100644 --- a/src/p_lights.c +++ b/src/p_lights.c @@ -17,7 +17,7 @@ #include "r_state.h" #include "z_zone.h" #include "m_random.h" -#include "netcode/d_netcmd.h" +#include "d_netcmd.h" /** Removes any active lighting effects in a sector. * diff --git a/src/p_mobj.c b/src/p_mobj.c index daf8e0262..c14ffb251 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -36,7 +36,6 @@ #include "p_slopes.h" #include "f_finale.h" #include "m_cond.h" -#include "netcode/net_command.h" static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}}; consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL); diff --git a/src/p_setup.c b/src/p_setup.c index 916fb7524..d7b532282 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -87,8 +87,6 @@ #include "taglist.h" -#include "netcode/net_command.h" - // // Map MD5, calculated on level load. // Sent to clients in PT_SERVERINFO. diff --git a/src/p_tick.c b/src/p_tick.c index e92dfe8e4..fe6a4d33f 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -26,8 +26,6 @@ #include "r_main.h" #include "r_fps.h" #include "i_video.h" // rendermode -#include "netcode/net_command.h" -#include "netcode/server_connection.h" // Object place #include "m_cheat.h" diff --git a/src/p_user.c b/src/p_user.c index de3bd0af2..4ca4e6c8a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -18,8 +18,7 @@ #include "doomdef.h" #include "i_system.h" #include "d_event.h" -#include "netcode/d_net.h" -#include "netcode/net_command.h" +#include "d_net.h" #include "g_game.h" #include "p_local.h" #include "r_fps.h" diff --git a/src/r_segs.c b/src/r_segs.c index 704f33334..43a7f945f 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -20,7 +20,7 @@ #include "w_wad.h" #include "z_zone.h" -#include "netcode/d_netcmd.h" +#include "d_netcmd.h" #include "m_misc.h" #include "p_local.h" // Camera... #include "p_slopes.h" diff --git a/src/r_things.c b/src/r_things.c index 5e444d0b9..461761977 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -34,7 +34,7 @@ #include "p_tick.h" #include "p_local.h" #include "p_slopes.h" -#include "netcode/d_netfil.h" // blargh. for nameonly(). +#include "d_netfil.h" // blargh. for nameonly(). #include "m_cheat.h" // objectplace #ifdef HWRENDER #include "hardware/hw_md2.h" diff --git a/src/screen.c b/src/screen.c index ad9c91462..d4785f941 100644 --- a/src/screen.c +++ b/src/screen.c @@ -27,7 +27,7 @@ #include "hu_stuff.h" #include "z_zone.h" #include "d_main.h" -#include "netcode/d_clisrv.h" +#include "d_clisrv.h" #include "f_finale.h" #include "y_inter.h" // usebuffer #include "i_sound.h" // closed captions diff --git a/src/sdl/i_gamepad.c b/src/sdl/i_gamepad.c index f27504f76..ecde251fb 100644 --- a/src/sdl/i_gamepad.c +++ b/src/sdl/i_gamepad.c @@ -15,7 +15,7 @@ #include "../i_system.h" #include "../doomdef.h" #include "../d_main.h" -#include "../netcode/d_netcmd.h" +#include "../d_netcmd.h" #include "../g_game.h" #include "../m_argv.h" #include "../m_menu.h" diff --git a/src/sdl/i_net.c b/src/sdl/i_net.c index 515a85568..ee4a34c13 100644 --- a/src/sdl/i_net.c +++ b/src/sdl/i_net.c @@ -21,16 +21,16 @@ #include "../i_system.h" #include "../d_event.h" -#include "../netcode/d_net.h" +#include "../d_net.h" #include "../m_argv.h" #include "../doomstat.h" -#include "../netcode/i_net.h" +#include "../i_net.h" #include "../z_zone.h" -#include "../netcode/i_tcp.h" +#include "../i_tcp.h" #ifdef HAVE_SDL diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 47402e549..ee082fd5d 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -188,8 +188,7 @@ static char returnWadPath[256]; #include "../i_gamepad.h" #include "../i_threads.h" #include "../screen.h" //vid.WndParent -#include "../netcode/d_net.h" -#include "../netcode/commands.h" +#include "../d_net.h" #include "../g_game.h" #include "../filesrch.h" #include "endtxt.h" @@ -208,7 +207,7 @@ static char returnWadPath[256]; #if !defined(NOMUMBLE) && defined(HAVE_MUMBLE) // Mumble context string -#include "../netcode/d_clisrv.h" +#include "../d_clisrv.h" #include "../byteptr.h" #endif @@ -1593,7 +1592,9 @@ void I_Quit(void) SDLforceUngrabMouse(); quiting = SDL_FALSE; M_SaveConfig(NULL); //save game config, cvars.. +#ifndef NONET D_SaveBan(); // save the ban list +#endif G_SaveGameData(); // Tails 12-08-2002 //added:16-02-98: when recording a demo, should exit using 'q' key, // but sometimes we forget and use 'F10'.. so save here too. @@ -1708,7 +1709,9 @@ void I_Error(const char *error, ...) // --- M_SaveConfig(NULL); // save game config, cvars.. +#ifndef NONET D_SaveBan(); // save the ban list +#endif G_SaveGameData(); // Tails 12-08-2002 // Shutdown. Here might be other errors. diff --git a/src/sdl/i_ttf.c b/src/sdl/i_ttf.c index 1f838e9b4..f2cd497ee 100644 --- a/src/sdl/i_ttf.c +++ b/src/sdl/i_ttf.c @@ -21,7 +21,7 @@ #include "SDL_ttf.h" #include "../doomdef.h" #include "../doomstat.h" -#include "../netcode/d_netfil.h" +#include "../d_netfil.h" #include "../filesrch.h" #include "i_ttf.h" diff --git a/src/snake.c b/src/snake.c deleted file mode 100644 index 21e79401d..000000000 --- a/src/snake.c +++ /dev/null @@ -1,535 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 2023-2023 by Louis-Antoine de Moulins de Rochefort. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file snake.c -/// \brief Snake minigame for the download screen. - -#include "snake.h" -#include "g_input.h" -#include "m_random.h" -#include "s_sound.h" -#include "screen.h" -#include "v_video.h" -#include "w_wad.h" -#include "z_zone.h" - -#define SPEED 5 - -#define NUM_BLOCKS_X 20 -#define NUM_BLOCKS_Y 10 -#define BLOCK_SIZE 12 -#define BORDER_SIZE 12 - -#define MAP_WIDTH (NUM_BLOCKS_X * BLOCK_SIZE) -#define MAP_HEIGHT (NUM_BLOCKS_Y * BLOCK_SIZE) - -#define LEFT_X ((BASEVIDWIDTH - MAP_WIDTH) / 2 - BORDER_SIZE) -#define RIGHT_X (LEFT_X + MAP_WIDTH + BORDER_SIZE * 2 - 1) -#define BOTTOM_Y (BASEVIDHEIGHT - 48) -#define TOP_Y (BOTTOM_Y - MAP_HEIGHT - BORDER_SIZE * 2 + 1) - -enum bonustype_s { - BONUS_NONE = 0, - BONUS_SLOW, - BONUS_FAST, - BONUS_GHOST, - BONUS_NUKE, - BONUS_SCISSORS, - BONUS_REVERSE, - BONUS_EGGMAN, - NUM_BONUSES, -}; - -typedef struct snake_s -{ - boolean paused; - boolean pausepressed; - tic_t time; - tic_t nextupdate; - boolean gameover; - UINT8 background; - - UINT16 snakelength; - enum bonustype_s snakebonus; - tic_t snakebonustime; - UINT8 snakex[NUM_BLOCKS_X * NUM_BLOCKS_Y]; - UINT8 snakey[NUM_BLOCKS_X * NUM_BLOCKS_Y]; - UINT8 snakedir[NUM_BLOCKS_X * NUM_BLOCKS_Y]; - - UINT8 applex; - UINT8 appley; - - enum bonustype_s bonustype; - UINT8 bonusx; - UINT8 bonusy; -} snake_t; - -static const char *bonuspatches[] = { - NULL, - "DL_SLOW", - "TVSSC0", - "TVIVC0", - "TVARC0", - "DL_SCISSORS", - "TVRCC0", - "TVEGC0", -}; - -static const char *backgrounds[] = { - "RVPUMICF", - "FRSTRCKF", - "TAR", - "MMFLRB4", - "RVDARKF1", - "RVZWALF1", - "RVZWALF4", - "RVZWALF5", - "RVZGRS02", - "RVZGRS04", -}; - -static void Initialise(snake_t *snake) -{ - snake->paused = false; - snake->pausepressed = false; - snake->time = 0; - snake->nextupdate = SPEED; - snake->gameover = false; - snake->background = M_RandomKey(sizeof(backgrounds) / sizeof(*backgrounds)); - - snake->snakelength = 1; - snake->snakebonus = BONUS_NONE; - snake->snakex[0] = M_RandomKey(NUM_BLOCKS_X); - snake->snakey[0] = M_RandomKey(NUM_BLOCKS_Y); - snake->snakedir[0] = 0; - snake->snakedir[1] = 0; - - snake->applex = M_RandomKey(NUM_BLOCKS_X); - snake->appley = M_RandomKey(NUM_BLOCKS_Y); - - snake->bonustype = BONUS_NONE; -} - -static UINT8 GetOppositeDir(UINT8 dir) -{ - if (dir == 1 || dir == 3) - return dir + 1; - else if (dir == 2 || dir == 4) - return dir - 1; - else - return 12 + 5 - dir; -} - -static void FindFreeSlot(snake_t *snake, UINT8 *freex, UINT8 *freey, UINT8 headx, UINT8 heady) -{ - UINT8 x, y; - UINT16 i; - - do - { - x = M_RandomKey(NUM_BLOCKS_X); - y = M_RandomKey(NUM_BLOCKS_Y); - - for (i = 0; i < snake->snakelength; i++) - if (x == snake->snakex[i] && y == snake->snakey[i]) - break; - } while (i < snake->snakelength || (x == headx && y == heady) - || (x == snake->applex && y == snake->appley) - || (snake->bonustype != BONUS_NONE && x == snake->bonusx && y == snake->bonusy)); - - *freex = x; - *freey = y; -} - -void Snake_Allocate(void **opaque) -{ - if (*opaque) - Snake_Free(opaque); - *opaque = malloc(sizeof(snake_t)); - Initialise(*opaque); -} - -void Snake_Update(void *opaque) -{ - UINT8 x, y; - UINT8 oldx, oldy; - UINT16 i; - UINT16 joystate = 0; - - snake_t *snake = opaque; - - // Handle retry - if (snake->gameover && (G_PlayerInputDown(0, GC_JUMP) || gamekeydown[KEY_ENTER])) - { - Initialise(snake); - snake->pausepressed = true; // Avoid accidental pause on respawn - } - - // Handle pause - if (G_PlayerInputDown(0, GC_PAUSE) || gamekeydown[KEY_ENTER]) - { - if (!snake->pausepressed) - snake->paused = !snake->paused; - snake->pausepressed = true; - } - else - snake->pausepressed = false; - - if (snake->paused) - return; - - snake->time++; - - x = snake->snakex[0]; - y = snake->snakey[0]; - oldx = snake->snakex[1]; - oldy = snake->snakey[1]; - - // Update direction - if (G_PlayerInputDown(0, GC_STRAFELEFT) || gamekeydown[KEY_LEFTARROW] || joystate == 3) - { - if (snake->snakelength < 2 || x <= oldx) - snake->snakedir[0] = 1; - } - else if (G_PlayerInputDown(0, GC_STRAFERIGHT) || gamekeydown[KEY_RIGHTARROW] || joystate == 4) - { - if (snake->snakelength < 2 || x >= oldx) - snake->snakedir[0] = 2; - } - else if (G_PlayerInputDown(0, GC_FORWARD) || gamekeydown[KEY_UPARROW] || joystate == 1) - { - if (snake->snakelength < 2 || y <= oldy) - snake->snakedir[0] = 3; - } - else if (G_PlayerInputDown(0, GC_BACKWARD) || gamekeydown[KEY_DOWNARROW] || joystate == 2) - { - if (snake->snakelength < 2 || y >= oldy) - snake->snakedir[0] = 4; - } - - if (snake->snakebonustime) - { - snake->snakebonustime--; - if (!snake->snakebonustime) - snake->snakebonus = BONUS_NONE; - } - - snake->nextupdate--; - if (snake->nextupdate) - return; - if (snake->snakebonus == BONUS_SLOW) - snake->nextupdate = SPEED * 2; - else if (snake->snakebonus == BONUS_FAST) - snake->nextupdate = SPEED * 2 / 3; - else - snake->nextupdate = SPEED; - - if (snake->gameover) - return; - - // Find new position - switch (snake->snakedir[0]) - { - case 1: - if (x > 0) - x--; - else - snake->gameover = true; - break; - case 2: - if (x < NUM_BLOCKS_X - 1) - x++; - else - snake->gameover = true; - break; - case 3: - if (y > 0) - y--; - else - snake->gameover = true; - break; - case 4: - if (y < NUM_BLOCKS_Y - 1) - y++; - else - snake->gameover = true; - break; - } - - // Check collision with snake - if (snake->snakebonus != BONUS_GHOST) - for (i = 1; i < snake->snakelength - 1; i++) - if (x == snake->snakex[i] && y == snake->snakey[i]) - { - if (snake->snakebonus == BONUS_SCISSORS) - { - snake->snakebonus = BONUS_NONE; - snake->snakelength = i; - S_StartSound(NULL, sfx_adderr); - } - else - snake->gameover = true; - } - - if (snake->gameover) - { - S_StartSound(NULL, sfx_lose); - return; - } - - // Check collision with apple - if (x == snake->applex && y == snake->appley) - { - if (snake->snakelength + 3 < NUM_BLOCKS_X * NUM_BLOCKS_Y) - { - snake->snakelength++; - snake->snakex [snake->snakelength - 1] = snake->snakex [snake->snakelength - 2]; - snake->snakey [snake->snakelength - 1] = snake->snakey [snake->snakelength - 2]; - snake->snakedir[snake->snakelength - 1] = snake->snakedir[snake->snakelength - 2]; - } - - // Spawn new apple - FindFreeSlot(snake, &snake->applex, &snake->appley, x, y); - - // Spawn new bonus - if (!(snake->snakelength % 5)) - { - do - { - snake->bonustype = M_RandomKey(NUM_BONUSES - 1) + 1; - } while (snake->snakelength > NUM_BLOCKS_X * NUM_BLOCKS_Y * 3 / 4 - && (snake->bonustype == BONUS_EGGMAN || snake->bonustype == BONUS_FAST || snake->bonustype == BONUS_REVERSE)); - - FindFreeSlot(snake, &snake->bonusx, &snake->bonusy, x, y); - } - - S_StartSound(NULL, sfx_s3k6b); - } - - if (snake->snakelength > 1 && snake->snakedir[0]) - { - UINT8 dir = snake->snakedir[0]; - - oldx = snake->snakex[1]; - oldy = snake->snakey[1]; - - // Move - for (i = snake->snakelength - 1; i > 0; i--) - { - snake->snakex[i] = snake->snakex[i - 1]; - snake->snakey[i] = snake->snakey[i - 1]; - snake->snakedir[i] = snake->snakedir[i - 1]; - } - - // Handle corners - if (x < oldx && dir == 3) - dir = 5; - else if (x > oldx && dir == 3) - dir = 6; - else if (x < oldx && dir == 4) - dir = 7; - else if (x > oldx && dir == 4) - dir = 8; - else if (y < oldy && dir == 1) - dir = 9; - else if (y < oldy && dir == 2) - dir = 10; - else if (y > oldy && dir == 1) - dir = 11; - else if (y > oldy && dir == 2) - dir = 12; - snake->snakedir[1] = dir; - } - - snake->snakex[0] = x; - snake->snakey[0] = y; - - // Check collision with bonus - if (snake->bonustype != BONUS_NONE && x == snake->bonusx && y == snake->bonusy) - { - S_StartSound(NULL, sfx_ncchip); - - switch (snake->bonustype) - { - case BONUS_SLOW: - snake->snakebonus = BONUS_SLOW; - snake->snakebonustime = 20 * TICRATE; - break; - case BONUS_FAST: - snake->snakebonus = BONUS_FAST; - snake->snakebonustime = 20 * TICRATE; - break; - case BONUS_GHOST: - snake->snakebonus = BONUS_GHOST; - snake->snakebonustime = 10 * TICRATE; - break; - case BONUS_NUKE: - for (i = 0; i < snake->snakelength; i++) - { - snake->snakex [i] = snake->snakex [0]; - snake->snakey [i] = snake->snakey [0]; - snake->snakedir[i] = snake->snakedir[0]; - } - - S_StartSound(NULL, sfx_bkpoof); - break; - case BONUS_SCISSORS: - snake->snakebonus = BONUS_SCISSORS; - snake->snakebonustime = 60 * TICRATE; - break; - case BONUS_REVERSE: - for (i = 0; i < (snake->snakelength + 1) / 2; i++) - { - UINT16 i2 = snake->snakelength - 1 - i; - UINT8 tmpx = snake->snakex [i]; - UINT8 tmpy = snake->snakey [i]; - UINT8 tmpdir = snake->snakedir[i]; - - // Swap first segment with last segment - snake->snakex [i] = snake->snakex [i2]; - snake->snakey [i] = snake->snakey [i2]; - snake->snakedir[i] = GetOppositeDir(snake->snakedir[i2]); - snake->snakex [i2] = tmpx; - snake->snakey [i2] = tmpy; - snake->snakedir[i2] = GetOppositeDir(tmpdir); - } - - snake->snakedir[0] = 0; - - S_StartSound(NULL, sfx_gravch); - break; - default: - if (snake->snakebonus != BONUS_GHOST) - { - snake->gameover = true; - S_StartSound(NULL, sfx_lose); - } - } - - snake->bonustype = BONUS_NONE; - } -} - -void Snake_Draw(void *opaque) -{ - INT16 i; - - snake_t *snake = opaque; - - // Background - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); - - V_DrawFlatFill( - LEFT_X + BORDER_SIZE, - TOP_Y + BORDER_SIZE, - MAP_WIDTH, - MAP_HEIGHT, - W_GetNumForName(backgrounds[snake->background]) - ); - - // Borders - V_DrawFill(LEFT_X, TOP_Y, BORDER_SIZE + MAP_WIDTH, BORDER_SIZE, 242); // Top - V_DrawFill(LEFT_X + BORDER_SIZE + MAP_WIDTH, TOP_Y, BORDER_SIZE, BORDER_SIZE + MAP_HEIGHT, 242); // Right - V_DrawFill(LEFT_X + BORDER_SIZE, TOP_Y + BORDER_SIZE + MAP_HEIGHT, BORDER_SIZE + MAP_WIDTH, BORDER_SIZE, 242); // Bottom - V_DrawFill(LEFT_X, TOP_Y + BORDER_SIZE, BORDER_SIZE, BORDER_SIZE + MAP_HEIGHT, 242); // Left - - // Apple - V_DrawFixedPatch( - (LEFT_X + BORDER_SIZE + snake->applex * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT, - (TOP_Y + BORDER_SIZE + snake->appley * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT, - FRACUNIT / 4, - 0, - W_CachePatchLongName("DL_APPLE", PU_HUDGFX), - NULL - ); - - // Bonus - if (snake->bonustype != BONUS_NONE) - V_DrawFixedPatch( - (LEFT_X + BORDER_SIZE + snake->bonusx * BLOCK_SIZE + BLOCK_SIZE / 2 ) * FRACUNIT, - (TOP_Y + BORDER_SIZE + snake->bonusy * BLOCK_SIZE + BLOCK_SIZE / 2 + 4) * FRACUNIT, - FRACUNIT / 2, - 0, - W_CachePatchLongName(bonuspatches[snake->bonustype], PU_HUDGFX), - NULL - ); - - // Snake - if (!snake->gameover || snake->time % 8 < 8 / 2) // Blink if game over - { - for (i = snake->snakelength - 1; i >= 0; i--) - { - const char *patchname; - UINT8 dir = snake->snakedir[i]; - - if (i == 0) // Head - { - switch (dir) - { - case 1: patchname = "DL_SNAKEHEAD_L"; break; - case 2: patchname = "DL_SNAKEHEAD_R"; break; - case 3: patchname = "DL_SNAKEHEAD_T"; break; - case 4: patchname = "DL_SNAKEHEAD_B"; break; - default: patchname = "DL_SNAKEHEAD_M"; - } - } - else // Body - { - switch (dir) - { - case 1: patchname = "DL_SNAKEBODY_L"; break; - case 2: patchname = "DL_SNAKEBODY_R"; break; - case 3: patchname = "DL_SNAKEBODY_T"; break; - case 4: patchname = "DL_SNAKEBODY_B"; break; - case 5: patchname = "DL_SNAKEBODY_LT"; break; - case 6: patchname = "DL_SNAKEBODY_RT"; break; - case 7: patchname = "DL_SNAKEBODY_LB"; break; - case 8: patchname = "DL_SNAKEBODY_RB"; break; - case 9: patchname = "DL_SNAKEBODY_TL"; break; - case 10: patchname = "DL_SNAKEBODY_TR"; break; - case 11: patchname = "DL_SNAKEBODY_BL"; break; - case 12: patchname = "DL_SNAKEBODY_BR"; break; - default: patchname = "DL_SNAKEBODY_B"; - } - } - - V_DrawFixedPatch( - (LEFT_X + BORDER_SIZE + snake->snakex[i] * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT, - (TOP_Y + BORDER_SIZE + snake->snakey[i] * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT, - i == 0 && dir == 0 ? FRACUNIT / 5 : FRACUNIT / 2, - snake->snakebonus == BONUS_GHOST ? V_TRANSLUCENT : 0, - W_CachePatchLongName(patchname, PU_HUDGFX), - NULL - ); - } - } - - // Length - V_DrawString(RIGHT_X + 4, TOP_Y, V_MONOSPACE, va("%u", snake->snakelength)); - - // Bonus - if (snake->snakebonus != BONUS_NONE - && (snake->snakebonustime >= 3 * TICRATE || snake->time % 4 < 4 / 2)) - V_DrawFixedPatch( - (RIGHT_X + 10) * FRACUNIT, - (TOP_Y + 24) * FRACUNIT, - FRACUNIT / 2, - 0, - W_CachePatchLongName(bonuspatches[snake->snakebonus], PU_HUDGFX), - NULL - ); -} - -void Snake_Free(void **opaque) -{ - if (*opaque) - { - free(opaque); - *opaque = NULL; - } -} diff --git a/src/snake.h b/src/snake.h deleted file mode 100644 index a3106bb0f..000000000 --- a/src/snake.h +++ /dev/null @@ -1,20 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 2023-2023 by Louis-Antoine de Moulins de Rochefort. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file snake.h -/// \brief Snake minigame for the download screen. - -#ifndef __SNAKE__ -#define __SNAKE__ - -void Snake_Allocate(void **opaque); -void Snake_Update(void *opaque); -void Snake_Draw(void *opaque); -void Snake_Free(void **opaque); - -#endif diff --git a/src/w_wad.c b/src/w_wad.c index 1e64cf093..42c6bf83b 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -51,8 +51,8 @@ #include "filesrch.h" #include "d_main.h" -#include "netcode/d_netfil.h" -#include "netcode/d_clisrv.h" +#include "d_netfil.h" +#include "d_clisrv.h" #include "dehacked.h" #include "r_defs.h" #include "r_data.h" diff --git a/src/y_inter.c b/src/y_inter.c index de757ec70..7faceff50 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -15,7 +15,7 @@ #include "f_finale.h" #include "g_game.h" #include "hu_stuff.h" -#include "netcode/i_net.h" +#include "i_net.h" #include "i_video.h" #include "p_tick.h" #include "r_defs.h" From 43eb7526c0bc51f805517d8f1944f636fa884b5e Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Fri, 20 Jan 2023 19:00:50 +0000 Subject: [PATCH 81/96] Update http-mserv.c --- src/http-mserv.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/http-mserv.c b/src/http-mserv.c index 7b418c99a..6e3de4535 100644 --- a/src/http-mserv.c +++ b/src/http-mserv.c @@ -86,13 +86,8 @@ Contact_error (void) static void get_user_agent(char *buf, size_t len) { -#if defined(__STDC__) && __STDC_VERSION__ >= 201112L - if (sprintf_s(buf, len, "%s/%s (%s; %s; %i; %i) SRB2BASE/%i", SRB2APPLICATION, VERSIONSTRING, compbranch, comprevision, MODID, MODVERSION, CODEBASE) < 1) + if (snprintf(buf, len, "%s/%s (%s; %s; %i; %i) SRB2BASE/%i", SRB2APPLICATION, VERSIONSTRING, compbranch, comprevision, MODID, MODVERSION, CODEBASE) < 0) I_Error("http-mserv: get_user_agent failed"); -#else - if (sprintf(buf, "%s/%s (%s; %s; %i; %i) SRB2BASE/%i", SRB2APPLICATION, VERSIONSTRING, compbranch, comprevision, MODID, MODVERSION, CODEBASE) < 0) - I_Error("http-mserv: get_user_agent failed"); -#endif } static void From 6c54af377481a42f639da2db6cefe33d02918bce Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 25 Jan 2023 19:44:39 -0600 Subject: [PATCH 82/96] Fix precip interpolation Fixes STJr/SRB2#916 --- src/p_mobj.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index c14ffb251..635d4f42b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3989,12 +3989,11 @@ void P_NullPrecipThinker(precipmobj_t *mobj) { //(void)mobj; mobj->precipflags &= ~PCF_THUNK; + R_ResetPrecipitationMobjInterpolationState(mobj); } void P_SnowThinker(precipmobj_t *mobj) { - R_ResetPrecipitationMobjInterpolationState(mobj); - P_CycleStateAnimation((mobj_t *)mobj); // adjust height @@ -4007,8 +4006,6 @@ void P_SnowThinker(precipmobj_t *mobj) void P_RainThinker(precipmobj_t *mobj) { - R_ResetPrecipitationMobjInterpolationState(mobj); - P_CycleStateAnimation((mobj_t *)mobj); if (mobj->state != &states[S_RAIN1]) From add018cb8333e7f7846a93ce41aefac7380e0b2e Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 25 Jan 2023 20:37:04 -0600 Subject: [PATCH 83/96] Interpolate minecart marks Fixes STJr/SRB2#906 Uses the old displacement of the minecart to position the mark relative to its destination. It's not completely correct, but it works. --- src/p_user.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/p_user.c b/src/p_user.c index 4ca4e6c8a..ba43a422f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -11038,6 +11038,21 @@ static void P_MinecartThink(player_t *player) S_StartSound(minecart, minecart->info->activesound); } } + + // Mark interpolation; the old positions need to be relative to the displacement from the minecart _after_ it's moved. + // This isn't quite correct (it captures the landing wobble) but it works well enough + if (detleft) + { + detleft->old_x = detleft->x - (minecart->old_x - minecart->old_x2); + detleft->old_y = detleft->y - (minecart->old_y - minecart->old_y2); + detleft->old_z = detleft->z - (minecart->old_z - minecart->old_z2); + } + if (detright) + { + detright->old_x = detright->x - (minecart->old_x - minecart->old_x2); + detright->old_y = detright->y - (minecart->old_y - minecart->old_y2); + detright->old_z = detright->z - (minecart->old_z - minecart->old_z2); + } } else { From b02707a4ee4966e7768cc6923fe3ab98c212ee5d Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 25 Jan 2023 20:44:04 -0600 Subject: [PATCH 84/96] Adjust caption pop-in by tics instead of frames Fixes STJr/SRB2#900 pop-in animation being affected by framerate --- src/screen.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/screen.c b/src/screen.c index d4785f941..3842a365d 100644 --- a/src/screen.c +++ b/src/screen.c @@ -621,7 +621,13 @@ void SCR_ClosedCaptions(void) y = basey-((i + 2)*10); if (closedcaptions[i].b) - y -= (closedcaptions[i].b--)*vid.dupy; + { + y -= closedcaptions[i].b * vid.dupy; + if (renderisnewtic) + { + closedcaptions[i].b--; + } + } if (closedcaptions[i].t < CAPTIONFADETICS) flags |= (((CAPTIONFADETICS-closedcaptions[i].t)/2)*V_10TRANS); From 42fa7f4723f25fc24c03e64a03a51aa9e02fa70c Mon Sep 17 00:00:00 2001 From: Lach Date: Thu, 26 Jan 2023 15:29:35 +1100 Subject: [PATCH 85/96] Invert OpenGL rollangle for papersprites to match software renderer behaviour --- src/hardware/hw_main.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 3a6baab71..05d1be28f 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5180,7 +5180,15 @@ static void HWR_ProjectSprite(mobj_t *thing) if (thing->rollangle && !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE))) { - rollangle = R_GetRollAngle(thing->rollangle); + if (papersprite) + { + // a positive rollangle should should pitch papersprites upwards relative to their facing angle + rollangle = R_GetRollAngle(InvAngle(thing->rollangle)); + } + else + { + rollangle = R_GetRollAngle(thing->rollangle); + } rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle); if (rotsprite != NULL) @@ -5234,7 +5242,7 @@ static void HWR_ProjectSprite(mobj_t *thing) { interpmobjstate_t casterinterp = { 0 }; fixed_t groundz; - fixed_t floordiff; + fixed_t floordiff; if (R_UsingFrameInterpolation() && !paused) { @@ -5244,7 +5252,7 @@ static void HWR_ProjectSprite(mobj_t *thing) { R_InterpolateMobjState(caster, FRACUNIT, &casterinterp); } - + groundz = R_GetShadowZ(thing, NULL); floordiff = abs(((thing->eflags & MFE_VERTICALFLIP) ? caster->height : 0) + casterinterp.z - groundz); From f1a7494a31a08f5b829cb95d2511fb7d531af012 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 26 Jan 2023 08:59:51 -0600 Subject: [PATCH 86/96] Handle splitscreen lua hud lists separately Fixes STJr/SRB2#935 by ensuring each drawlist is drawn separately while stplyr is set correctly. --- src/st_stuff.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index ed130c912..3e75750a8 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -164,7 +164,7 @@ hudinfo_t hudinfo[NUMHUDITEMS] = { 288, 176, V_SNAPTORIGHT|V_SNAPTOBOTTOM}, // HUD_POWERUPS }; -static huddrawlist_h luahuddrawlist_game; +static huddrawlist_h luahuddrawlist_game[2]; static huddrawlist_h luahuddrawlist_titlecard; // @@ -427,7 +427,8 @@ void ST_Init(void) ST_LoadGraphics(); - luahuddrawlist_game = LUA_HUD_CreateDrawList(); + luahuddrawlist_game[0] = LUA_HUD_CreateDrawList(); + luahuddrawlist_game[1] = LUA_HUD_CreateDrawList(); luahuddrawlist_titlecard = LUA_HUD_CreateDrawList(); } @@ -2757,10 +2758,13 @@ static void ST_overlayDrawer(void) if (!(netgame || multiplayer) || !hu_showscores) { + INT32 hooklistindex = splitscreen && stplyr == &players[secondarydisplayplayer] ? 1 : 0; if (renderisnewtic) { - LUA_HUDHOOK(game, luahuddrawlist_game); + LUA_HUD_ClearDrawList(luahuddrawlist_game[hooklistindex]); + LUA_HUDHOOK(game, luahuddrawlist_game[hooklistindex]); } + LUA_HUD_DrawList(luahuddrawlist_game[hooklistindex]); } // draw level title Tails @@ -2839,10 +2843,6 @@ void ST_Drawer(void) if (st_overlay) { - if (renderisnewtic) - { - LUA_HUD_ClearDrawList(luahuddrawlist_game); - } // No deadview! stplyr = &players[displayplayer]; ST_overlayDrawer(); @@ -2852,7 +2852,5 @@ void ST_Drawer(void) stplyr = &players[secondarydisplayplayer]; ST_overlayDrawer(); } - - LUA_HUD_DrawList(luahuddrawlist_game); } } From bbd4cff75cb92cafe5f21a2cb83c1a8830184b94 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 26 Jan 2023 19:24:21 -0600 Subject: [PATCH 87/96] Revert "Merge branch 'gamepadtweaks' into 'next'" This reverts commit 96bfd8cea7c4ed75357a25603ecdf3ab98fd625b, reversing changes made to 24f9ec4ec4039155ee2cfee7ef1eefcb46d1398a. --- src/command.c | 160 +++++++++++++++++++++++++++++++ src/d_netcmd.c | 9 ++ src/deh_tables.c | 5 + src/g_game.c | 61 ++++++++++-- src/g_game.h | 8 ++ src/g_input.c | 240 ++++++++++++++++++++++++++++------------------- src/g_input.h | 4 +- src/m_menu.c | 55 +++++------ 8 files changed, 404 insertions(+), 138 deletions(-) diff --git a/src/command.c b/src/command.c index d1db9f9c9..201cceeee 100644 --- a/src/command.c +++ b/src/command.c @@ -2181,6 +2181,132 @@ static void CV_EnforceExecVersion(void) CV_StealthSetValue(&cv_execversion, EXECVERSION); } +static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr) +{ + // If ALL axis settings are previous defaults, set them to the new defaults + // EXECVERSION < 26 (2.1.21) + + if (joyaxis_default) + { + if (!stricmp(v->name, "joyaxis_turn")) + { + if (joyaxis_count > 6) return false; + // we're currently setting the new defaults, don't interfere + else if (joyaxis_count == 6) return true; + + if (!stricmp(valstr, "X-Axis")) joyaxis_count++; + else joyaxis_default = false; + } + if (!stricmp(v->name, "joyaxis_move")) + { + if (joyaxis_count > 6) return false; + else if (joyaxis_count == 6) return true; + + if (!stricmp(valstr, "Y-Axis")) joyaxis_count++; + else joyaxis_default = false; + } + if (!stricmp(v->name, "joyaxis_side")) + { + if (joyaxis_count > 6) return false; + else if (joyaxis_count == 6) return true; + + if (!stricmp(valstr, "Z-Axis")) joyaxis_count++; + else joyaxis_default = false; + } + if (!stricmp(v->name, "joyaxis_look")) + { + if (joyaxis_count > 6) return false; + else if (joyaxis_count == 6) return true; + + if (!stricmp(valstr, "None")) joyaxis_count++; + else joyaxis_default = false; + } + if (!stricmp(v->name, "joyaxis_fire") + || !stricmp(v->name, "joyaxis_firenormal")) + { + if (joyaxis_count > 6) return false; + else if (joyaxis_count == 6) return true; + + if (!stricmp(valstr, "None")) joyaxis_count++; + else joyaxis_default = false; + } + // reset all axis settings to defaults + if (joyaxis_count == 6) + { + COM_BufInsertText(va("%s \"%s\"\n", cv_turnaxis[0].name, cv_turnaxis[0].defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_moveaxis[0].name, cv_moveaxis[0].defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_sideaxis[0].name, cv_sideaxis[0].defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_lookaxis[0].name, cv_lookaxis[0].defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_fireaxis[0].name, cv_fireaxis[0].defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_firenaxis[0].name, cv_firenaxis[0].defaultvalue)); + joyaxis_count++; + return false; + } + } + + if (joyaxis2_default) + { + if (!stricmp(v->name, "joyaxis2_turn")) + { + if (joyaxis2_count > 6) return false; + // we're currently setting the new defaults, don't interfere + else if (joyaxis2_count == 6) return true; + + if (!stricmp(valstr, "X-Axis")) joyaxis2_count++; + else joyaxis2_default = false; + } + if (!stricmp(v->name, "joyaxis2_move")) + { + if (joyaxis2_count > 6) return false; + else if (joyaxis2_count == 6) return true; + + if (!stricmp(valstr, "Y-Axis")) joyaxis2_count++; + else joyaxis2_default = false; + } + if (!stricmp(v->name, "joyaxis2_side")) + { + if (joyaxis2_count > 6) return false; + else if (joyaxis2_count == 6) return true; + + if (!stricmp(valstr, "Z-Axis")) joyaxis2_count++; + else joyaxis2_default = false; + } + if (!stricmp(v->name, "joyaxis2_look")) + { + if (joyaxis2_count > 6) return false; + else if (joyaxis2_count == 6) return true; + + if (!stricmp(valstr, "None")) joyaxis2_count++; + else joyaxis2_default = false; + } + if (!stricmp(v->name, "joyaxis2_fire") + || !stricmp(v->name, "joyaxis2_firenormal")) + { + if (joyaxis2_count > 6) return false; + else if (joyaxis2_count == 6) return true; + + if (!stricmp(valstr, "None")) joyaxis2_count++; + else joyaxis2_default = false; + } + + // reset all axis settings to defaults + if (joyaxis2_count == 6) + { + COM_BufInsertText(va("%s \"%s\"\n", cv_turnaxis[1].name, cv_turnaxis[1].defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_moveaxis[1].name, cv_moveaxis[1].defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_sideaxis[1].name, cv_sideaxis[1].defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_lookaxis[1].name, cv_lookaxis[1].defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_fireaxis[1].name, cv_fireaxis[1].defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_firenaxis[1].name, cv_firenaxis[1].defaultvalue)); + joyaxis2_count++; + return false; + } + } + + // we haven't reached our counts yet, or we're not default + return true; +} + #ifndef OLD_GAMEPAD_AXES static boolean CV_ConvertOldJoyAxisVars(consvar_t *v, const char *valstr) { @@ -2233,6 +2359,40 @@ static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr) if (!(v->flags & CV_SAVE)) return true; + if (GETMAJOREXECVERSION(cv_execversion.value) < 26) // 26 = 2.1.21 + { + // MOUSE SETTINGS + // alwaysfreelook split between first and third person (chasefreelook) + // mousemove was on by default, which invalidates the current approach + if (!stricmp(v->name, "alwaysmlook") + || !stricmp(v->name, "alwaysmlook2") + || !stricmp(v->name, "mousemove") + || !stricmp(v->name, "mousemove2")) + return false; + + // mousesens was changed from 35 to 20 due to oversensitivity + if ((!stricmp(v->name, "mousesens") + || !stricmp(v->name, "mousesens2") + || !stricmp(v->name, "mouseysens") + || !stricmp(v->name, "mouseysens2")) + && atoi(valstr) == 35) + return false; + + // GAMEPAD DEFAULTS + // use_gamepad was changed from 0 to 1 to automatically use a gamepad if available +#if defined(HAVE_SDL) || defined(_WINDOWS) + if ((!stricmp(v->name, "use_joystick") + || !stricmp(v->name, "use_joystick2")) + && atoi(valstr) == 0) + return false; +#endif + + // axis defaults were changed to be friendly to 360 controllers + // if ALL axis settings are defaults, then change them to new values + if (!CV_FilterJoyAxisVars(v, valstr)) + return false; + } + #ifndef OLD_GAMEPAD_AXES if (GETMAJOREXECVERSION(cv_execversion.value) <= 51 && GETMINOREXECVERSION(cv_execversion.value) < 1) { diff --git a/src/d_netcmd.c b/src/d_netcmd.c index f721aa75a..07dba1777 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -815,6 +815,14 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_moveaxis[1]); CV_RegisterVar(&cv_lookaxis[0]); CV_RegisterVar(&cv_lookaxis[1]); + CV_RegisterVar(&cv_jumpaxis[0]); + CV_RegisterVar(&cv_jumpaxis[1]); + CV_RegisterVar(&cv_spinaxis[0]); + CV_RegisterVar(&cv_spinaxis[1]); + CV_RegisterVar(&cv_fireaxis[0]); + CV_RegisterVar(&cv_fireaxis[1]); + CV_RegisterVar(&cv_firenaxis[0]); + CV_RegisterVar(&cv_firenaxis[1]); CV_RegisterVar(&cv_deadzone[0]); CV_RegisterVar(&cv_deadzone[1]); CV_RegisterVar(&cv_digitaldeadzone[0]); @@ -834,6 +842,7 @@ void D_RegisterClientCommands(void) #if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON) CV_RegisterVar(&cv_mouse2opt); #endif + CV_RegisterVar(&cv_controlperkey); CV_RegisterVar(&cv_usemouse); CV_RegisterVar(&cv_usemouse2); diff --git a/src/deh_tables.c b/src/deh_tables.c index 90c3047a8..a2cc9732d 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5648,6 +5648,11 @@ struct int_const_s const INT_CONST[] = { {"JA_MOVE",JA_MOVE}, {"JA_LOOK",JA_LOOK}, {"JA_STRAFE",JA_STRAFE}, + {"JA_DIGITAL",JA_DIGITAL}, + {"JA_JUMP",JA_JUMP}, + {"JA_SPIN",JA_SPIN}, + {"JA_FIRE",JA_FIRE}, + {"JA_FIRENORMAL",JA_FIRENORMAL}, {"JOYAXISRANGE",OLDJOYAXISRANGE}, // Game controls diff --git a/src/g_game.c b/src/g_game.c index dc12c2bab..b4a127a73 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -297,13 +297,17 @@ CV_PossibleValue_t joyaxis_cons_t[] = {{0, "None"}, #ifndef OLD_GAMEPAD_AXES #define MOVEAXIS_DEFAULT "Left Stick Y" #define SIDEAXIS_DEFAULT "Left Stick X" -#define LOOKAXIS_DEFAULT "Right Stick Y" +#define LOOKAXIS_DEFAULT "Right Stick Y-" #define TURNAXIS_DEFAULT "Right Stick X" +#define FIREAXIS_DEFAULT "Right Trigger" +#define FIRENAXIS_DEFAULT "Left Trigger" #else #define MOVEAXIS_DEFAULT "Y-Axis" #define SIDEAXIS_DEFAULT "X-Axis" #define LOOKAXIS_DEFAULT "Y-Rudder-" #define TURNAXIS_DEFAULT "X-Rudder" +#define FIREAXIS_DEFAULT "Z-Rudder" +#define FIRENAXIS_DEFAULT "Z-Axis" #endif // don't mind me putting these here, I was lazy to figure out where else I could put those without blowing up the compiler. @@ -435,6 +439,22 @@ consvar_t cv_turnaxis[2] = { CVAR_INIT ("joyaxis_turn", TURNAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL), CVAR_INIT ("joyaxis2_turn", TURNAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL) }; +consvar_t cv_jumpaxis[2] = { + CVAR_INIT ("joyaxis_jump", "None", CV_SAVE, joyaxis_cons_t, NULL), + CVAR_INIT ("joyaxis2_jump", "None", CV_SAVE, joyaxis_cons_t, NULL) +}; +consvar_t cv_spinaxis[2] = { + CVAR_INIT ("joyaxis_spin", "None", CV_SAVE, joyaxis_cons_t, NULL), + CVAR_INIT ("joyaxis2_spin", "None", CV_SAVE, joyaxis_cons_t, NULL) +}; +consvar_t cv_fireaxis[2] = { + CVAR_INIT ("joyaxis_fire", FIREAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL), + CVAR_INIT ("joyaxis2_fire", FIREAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL) +}; +consvar_t cv_firenaxis[2] = { + CVAR_INIT ("joyaxis_firenormal", FIRENAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL), + CVAR_INIT ("joyaxis2_firenormal", FIRENAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL) +}; consvar_t cv_deadzone[2] = { CVAR_INIT ("joy_deadzone", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), CVAR_INIT ("joy_deadzone2", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL) @@ -870,7 +890,7 @@ static gamepad_axis_e ConvertXboxControllerAxes(int type) } #endif -static INT16 GetJoystickAxisValue(INT32 axisval) +static INT16 GetJoystickAxisValue(UINT8 which, joyaxis_e axissel, INT32 axisval) { boolean flp = false; @@ -905,7 +925,14 @@ static INT16 GetJoystickAxisValue(INT32 axisval) } INT16 retaxis = G_GetGamepadAxisValue(0, gp_axis); - + + if (gamepads[which].digital && axissel >= JA_DIGITAL) + { + const UINT16 jdeadzone = G_GetGamepadDigitalDeadZone(which) / 2; + if (-jdeadzone < retaxis && retaxis < jdeadzone) + return 0; + } + // flip it around if (flp) { @@ -938,11 +965,23 @@ INT16 G_JoyAxis(UINT8 which, joyaxis_e axissel) case JA_STRAFE: axisval = cv_sideaxis[which].value; break; + case JA_JUMP: + axisval = cv_jumpaxis[which].value; + break; + case JA_SPIN: + axisval = cv_spinaxis[which].value; + break; + case JA_FIRE: + axisval = cv_fireaxis[which].value; + break; + case JA_FIRENORMAL: + axisval = cv_firenaxis[which].value; + break; default: return 0; } - value = GetJoystickAxisValue(axisval); + value = GetJoystickAxisValue(which, axissel, axisval); if (axissel == JA_LOOK) { // Look is inverted because +Y goes _down_ in gamepads. @@ -1053,7 +1092,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) boolean forcestrafe = false; boolean forcefullinput = false; - INT32 tspeed, forward, side, strafeaxis, moveaxis, turnaxis, lookaxis, i; + INT32 tspeed, forward, side, axis, strafeaxis, moveaxis, turnaxis, lookaxis, i; joystickvector2_t movejoystickvector, lookjoystickvector; @@ -1339,11 +1378,13 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) } // fire with any button/key - if (G_PlayerInputDown(forplayer, GC_FIRE)) + axis = G_JoyAxis(forplayer, JA_FIRE); + if (G_PlayerInputDown(forplayer, GC_FIRE) || (usegamepad && axis > 0)) cmd->buttons |= BT_ATTACK; // fire normal with any button/key - if (G_PlayerInputDown(forplayer, GC_FIRENORMAL)) + axis = G_JoyAxis(forplayer, JA_FIRENORMAL); + if (G_PlayerInputDown(forplayer, GC_FIRENORMAL) || (usegamepad && axis > 0)) cmd->buttons |= BT_FIRENORMAL; if (G_PlayerInputDown(forplayer, GC_TOSSFLAG)) @@ -1358,7 +1399,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) cmd->buttons |= BT_CUSTOM3; // spin with any button/key - if (G_PlayerInputDown(forplayer, GC_SPIN)) + axis = G_JoyAxis(forplayer, JA_SPIN); + if (G_PlayerInputDown(forplayer, GC_SPIN) || (usegamepad && axis > 0)) cmd->buttons |= BT_SPIN; // Centerview can be a toggle in simple mode! @@ -1474,7 +1516,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) resetdown[forplayer] = false; // jump button - if (G_PlayerInputDown(forplayer, GC_JUMP)) + axis = G_JoyAxis(forplayer, JA_JUMP); + if (G_PlayerInputDown(forplayer, GC_JUMP) || (usegamepad && axis > 0)) cmd->buttons |= BT_JUMP; // player aiming shit, ahhhh... diff --git a/src/g_game.h b/src/g_game.h index 8d6e84b12..e798176af 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -71,6 +71,7 @@ extern consvar_t cv_autobrake, cv_autobrake2; extern consvar_t cv_ghost_bestscore, cv_ghost_besttime, cv_ghost_bestrings, cv_ghost_last, cv_ghost_guest; extern consvar_t cv_sideaxis[2], cv_turnaxis[2], cv_moveaxis[2], cv_lookaxis[2], + cv_jumpaxis[2], cv_spinaxis[2], cv_fireaxis[2], cv_firenaxis[2], cv_deadzone[2], cv_digitaldeadzone[2]; extern CV_PossibleValue_t joyaxis_cons_t[]; @@ -97,6 +98,13 @@ typedef enum JA_MOVE, JA_LOOK, JA_STRAFE, + + JA_DIGITAL, // axes henceforth use digital deadzone + + JA_JUMP = JA_DIGITAL, + JA_SPIN, + JA_FIRE, + JA_FIRENORMAL, } joyaxis_e; INT16 G_JoyAxis(UINT8 which, joyaxis_e axissel); diff --git a/src/g_input.c b/src/g_input.c index 87f4d5173..6b0da7e41 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -24,12 +24,14 @@ #define MAXMOUSESENSITIVITY 100 // sensitivity steps static CV_PossibleValue_t mousesens_cons_t[] = {{1, "MIN"}, {MAXMOUSESENSITIVITY, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t onecontrolperkey_cons_t[] = {{1, "One"}, {2, "Several"}, {0, NULL}}; // mouse values are used once consvar_t cv_mousesens = CVAR_INIT ("mousesens", "20", CV_SAVE, mousesens_cons_t, NULL); consvar_t cv_mousesens2 = CVAR_INIT ("mousesens2", "20", CV_SAVE, mousesens_cons_t, NULL); consvar_t cv_mouseysens = CVAR_INIT ("mouseysens", "20", CV_SAVE, mousesens_cons_t, NULL); consvar_t cv_mouseysens2 = CVAR_INIT ("mouseysens2", "20", CV_SAVE, mousesens_cons_t, NULL); +consvar_t cv_controlperkey = CVAR_INIT ("controlperkey", "One", CV_SAVE, onecontrolperkey_cons_t, NULL); mouse_t mouse; mouse_t mouse2; @@ -960,6 +962,9 @@ static keyname_t keynames[] = DEF_GAMEPAD_AXIS(TRIGGERLEFT, "left trigger"), DEF_GAMEPAD_AXIS(TRIGGERRIGHT, "right trigger"), +#undef DEF_GAMEPAD_NAME +#undef DEF_GAMEPAD_AXIS + {KEY_DBLMOUSE1+0, "dblmouse1"}, {KEY_DBLMOUSE1+1, "dblmouse2"}, {KEY_DBLMOUSE1+2, "dblmouse3"}, @@ -978,50 +983,7 @@ static keyname_t keynames[] = {KEY_DBL2MOUSE1+7, "dblsec_mouse8"} }; -static keyname_t oldjoynames[] = -{ - DEF_GAMEPAD_NAME(A, "joy1"), - DEF_GAMEPAD_NAME(B, "joy2"), - DEF_GAMEPAD_NAME(X, "joy3"), - DEF_GAMEPAD_NAME(Y, "joy4"), - - DEF_GAMEPAD_NAME(BACK, "joy7"), - DEF_GAMEPAD_NAME(START, "joy8"), - DEF_GAMEPAD_NAME(LEFTSTICK, "joy9"), - DEF_GAMEPAD_NAME(RIGHTSTICK, "joy10"), - - DEF_GAMEPAD_NAME(LEFTSHOULDER, "joy5"), - DEF_GAMEPAD_NAME(RIGHTSHOULDER, "joy6"), - - DEF_GAMEPAD_NAME(DPAD_UP, "hatup"), - DEF_GAMEPAD_NAME(DPAD_DOWN, "hatdown"), - DEF_GAMEPAD_NAME(DPAD_LEFT, "hatleft"), - DEF_GAMEPAD_NAME(DPAD_RIGHT, "hatright"), - - DEF_GAMEPAD_NAME(A, "sec_joy1"), - DEF_GAMEPAD_NAME(B, "sec_joy2"), - DEF_GAMEPAD_NAME(X, "sec_joy3"), - DEF_GAMEPAD_NAME(Y, "sec_joy4"), - - DEF_GAMEPAD_NAME(BACK, "sec_joy7"), - DEF_GAMEPAD_NAME(START, "sec_joy8"), - DEF_GAMEPAD_NAME(LEFTSTICK, "sec_joy9"), - DEF_GAMEPAD_NAME(RIGHTSTICK, "sec_joy10"), - - DEF_GAMEPAD_NAME(LEFTSHOULDER, "sec_joy5"), - DEF_GAMEPAD_NAME(RIGHTSHOULDER, "sec_joy6"), - - DEF_GAMEPAD_NAME(DPAD_UP, "sec_hatup"), - DEF_GAMEPAD_NAME(DPAD_DOWN, "sec_hatdown"), - DEF_GAMEPAD_NAME(DPAD_LEFT, "sec_hatleft"), - DEF_GAMEPAD_NAME(DPAD_RIGHT, "sec_hatright"), -}; - -#undef DEF_GAMEPAD_NAME -#undef DEF_GAMEPAD_AXIS - #define NUMKEYNAMES (sizeof(keynames) / sizeof(keyname_t)) -#define NUMOLDJOYNAMES (sizeof(oldjoynames) / sizeof(keyname_t)) static keyname_t displaykeynames[] = { @@ -1310,10 +1272,6 @@ INT32 G_KeyNameToNum(const char *keystr) if (!stricmp(keynames[j].name, keystr)) return keynames[j].keynum; - for (j = 0; j < NUMOLDJOYNAMES; j++) - if (!stricmp(oldjoynames[j].name, keystr)) - return oldjoynames[j].keynum; - return 0; } @@ -1419,17 +1377,15 @@ void G_DefineDefaultControls(void) gamecontroldefault[i][GC_CUSTOM1 ][1] = GAMEPAD_KEY(B); // B gamecontroldefault[i][GC_CUSTOM2 ][1] = GAMEPAD_KEY(Y); // Y gamecontroldefault[i][GC_CUSTOM3 ][1] = GAMEPAD_KEY(LEFTSTICK); // Left Stick - gamecontroldefault[i][GC_CENTERVIEW ][1] = GAMEPAD_KEY(RIGHTSHOULDER); // R1 - gamecontroldefault[i][GC_CAMTOGGLE ][1] = GAMEPAD_KEY(LEFTSHOULDER); // L1 + gamecontroldefault[i][GC_CENTERVIEW ][1] = GAMEPAD_KEY(RIGHTSTICK); // Right Stick + gamecontroldefault[i][GC_WEAPONPREV ][1] = GAMEPAD_KEY(LEFTSHOULDER); // LB + gamecontroldefault[i][GC_WEAPONNEXT ][1] = GAMEPAD_KEY(RIGHTSHOULDER); // RB gamecontroldefault[i][GC_SCREENSHOT ][1] = GAMEPAD_KEY(BACK); // Back gamecontroldefault[i][GC_SYSTEMMENU ][0] = GAMEPAD_KEY(START); // Start - gamecontroldefault[i][GC_TOSSFLAG ][1] = GAMEPAD_KEY(DPAD_UP); // D-Pad Up - gamecontroldefault[i][GC_WEAPONPREV ][1] = GAMEPAD_KEY(DPAD_LEFT); // D-Pad Left - gamecontroldefault[i][GC_WEAPONNEXT ][1] = GAMEPAD_KEY(DPAD_RIGHT); // D-Pad Right - gamecontroldefault[i][GC_SCORES ][1] = GAMEPAD_KEY(DPAD_DOWN); // D-Pad Down - gamecontroldefault[i][GC_VIEWPOINTNEXT][1] = GAMEPAD_KEY(RIGHTSTICK); // Right Stick - gamecontroldefault[i][GC_FIRE ][1] = GAMEPAD_AXIS(TRIGGERRIGHT); // R2 - gamecontroldefault[i][GC_FIRENORMAL ][1] = GAMEPAD_AXIS(TRIGGERLEFT); // L2 + gamecontroldefault[i][GC_CAMTOGGLE ][1] = GAMEPAD_KEY(DPAD_UP); // D-Pad Up + gamecontroldefault[i][GC_VIEWPOINTNEXT][1] = GAMEPAD_KEY(DPAD_DOWN); // D-Pad Down + gamecontroldefault[i][GC_TOSSFLAG ][1] = GAMEPAD_KEY(DPAD_LEFT); // D-Pad Left + gamecontroldefault[i][GC_SCORES ][1] = GAMEPAD_KEY(DPAD_RIGHT); // D-Pad Right // Second player only has gamepad defaults gamecontrolbisdefault[i][GC_JUMP ][1] = GAMEPAD_KEY(A); // A @@ -1437,17 +1393,15 @@ void G_DefineDefaultControls(void) gamecontrolbisdefault[i][GC_CUSTOM1 ][1] = GAMEPAD_KEY(B); // B gamecontrolbisdefault[i][GC_CUSTOM2 ][1] = GAMEPAD_KEY(Y); // Y gamecontrolbisdefault[i][GC_CUSTOM3 ][1] = GAMEPAD_KEY(LEFTSTICK); // Left Stick - gamecontrolbisdefault[i][GC_CENTERVIEW ][1] = GAMEPAD_KEY(RIGHTSHOULDER); // R1 - gamecontrolbisdefault[i][GC_CAMTOGGLE ][1] = GAMEPAD_KEY(LEFTSHOULDER); // L1 + gamecontrolbisdefault[i][GC_CENTERVIEW ][1] = GAMEPAD_KEY(RIGHTSTICK); // Right Stick + gamecontrolbisdefault[i][GC_WEAPONPREV ][1] = GAMEPAD_KEY(LEFTSHOULDER); // LB + gamecontrolbisdefault[i][GC_WEAPONNEXT ][1] = GAMEPAD_KEY(RIGHTSHOULDER); // RB gamecontrolbisdefault[i][GC_SCREENSHOT ][1] = GAMEPAD_KEY(BACK); // Back //gamecontrolbisdefault[i][GC_SYSTEMMENU ][0] = GAMEPAD_KEY(START); // Start - gamecontrolbisdefault[i][GC_TOSSFLAG ][1] = GAMEPAD_KEY(DPAD_UP); // D-Pad Up - gamecontrolbisdefault[i][GC_WEAPONPREV ][1] = GAMEPAD_KEY(DPAD_LEFT); // D-Pad Left - gamecontrolbisdefault[i][GC_WEAPONNEXT ][1] = GAMEPAD_KEY(DPAD_RIGHT); // D-Pad Right - //gamecontrolbisdefault[i][GC_SCORES ][1] = GAMEPAD_KEY(DPAD_DOWN); // D-Pad Down - gamecontrolbisdefault[i][GC_VIEWPOINTNEXT][1] = GAMEPAD_KEY(RIGHTSTICK); // Right Stick - gamecontrolbisdefault[i][GC_FIRE ][1] = GAMEPAD_AXIS(TRIGGERRIGHT); // R2 - gamecontrolbisdefault[i][GC_FIRENORMAL ][1] = GAMEPAD_AXIS(TRIGGERLEFT); // L2 + gamecontrolbisdefault[i][GC_CAMTOGGLE ][1] = GAMEPAD_KEY(DPAD_UP); // D-Pad Up + gamecontrolbisdefault[i][GC_VIEWPOINTNEXT][1] = GAMEPAD_KEY(DPAD_DOWN); // D-Pad Down + gamecontrolbisdefault[i][GC_TOSSFLAG ][1] = GAMEPAD_KEY(DPAD_LEFT); // D-Pad Left + //gamecontrolbisdefault[i][GC_SCORES ][1] = GAMEPAD_KEY(DPAD_RIGHT); // D-Pad Right } } @@ -1517,40 +1471,42 @@ void G_SaveKeySetting(FILE *f, INT32 (*fromcontrols)[2], INT32 (*fromcontrolsbis } } -INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify, UINT8 player) +INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify) { INT32 result = GC_NULL; - INT32 i; - for (i = 0; i < NUM_GAMECONTROLS; i++) + if (cv_controlperkey.value == 1) { - if (gamecontrol[i][0] == keynum && player != 2) + INT32 i; + for (i = 0; i < NUM_GAMECONTROLS; i++) { - result = i; - if (modify) gamecontrol[i][0] = KEY_NULL; + if (gamecontrol[i][0] == keynum) + { + result = i; + if (modify) gamecontrol[i][0] = KEY_NULL; + } + if (gamecontrol[i][1] == keynum) + { + result = i; + if (modify) gamecontrol[i][1] = KEY_NULL; + } + if (gamecontrolbis[i][0] == keynum) + { + result = i; + if (modify) gamecontrolbis[i][0] = KEY_NULL; + } + if (gamecontrolbis[i][1] == keynum) + { + result = i; + if (modify) gamecontrolbis[i][1] = KEY_NULL; + } + if (result && !modify) + return result; } - if (gamecontrol[i][1] == keynum && player != 2) - { - result = i; - if (modify) gamecontrol[i][1] = KEY_NULL; - } - if (gamecontrolbis[i][0] == keynum && player != 1) - { - result = i; - if (modify) gamecontrolbis[i][0] = KEY_NULL; - } - if (gamecontrolbis[i][1] == keynum && player != 1) - { - result = i; - if (modify) gamecontrolbis[i][1] = KEY_NULL; - } - if (result && !modify) - return result; } - return result; } -static INT32 G_FilterSpecialKeys(INT32 keyidx, INT32 *keynum1, INT32 *keynum2) +static INT32 G_FilterKeyByVersion(INT32 numctrl, INT32 keyidx, INT32 player, INT32 *keynum1, INT32 *keynum2, boolean *nestedoverride) { // Special case: ignore KEY_PAUSE because it's hardcoded if (keyidx == 0 && *keynum1 == KEY_PAUSE) @@ -1566,6 +1522,99 @@ static INT32 G_FilterSpecialKeys(INT32 keyidx, INT32 *keynum1, INT32 *keynum2) else if (keyidx == 1 && *keynum2 == KEY_PAUSE) return -1; // skip setting control + if (GETMAJOREXECVERSION(cv_execversion.value) < 27 && ( // v2.1.22 + numctrl == GC_WEAPONNEXT || numctrl == GC_WEAPONPREV || numctrl == GC_TOSSFLAG || + numctrl == GC_SPIN || numctrl == GC_CAMRESET || numctrl == GC_JUMP || + numctrl == GC_PAUSE || numctrl == GC_SYSTEMMENU || numctrl == GC_CAMTOGGLE || + numctrl == GC_SCREENSHOT || numctrl == GC_TALKKEY || numctrl == GC_SCORES || + numctrl == GC_CENTERVIEW + )) + { + INT32 keynum = 0, existingctrl = 0; + INT32 defaultkey; + boolean defaultoverride = false; + + // get the default gamecontrol + if (player == 0 && numctrl == GC_SYSTEMMENU) + defaultkey = gamecontrol[numctrl][0]; + else + defaultkey = (player == 1 ? gamecontrolbis[numctrl][0] : gamecontrol[numctrl][1]); + + // Assign joypad button defaults if there is an open slot. + // At this point, gamecontrol/bis should have the default controls + // (unless LOADCONFIG is being run) + // + // If the player runs SETCONTROL in-game, this block should not be reached + // because EXECVERSION is locked onto the latest version. + if (keyidx == 0 && !*keynum1) + { + if (*keynum2) // push keynum2 down; this is an edge case + { + *keynum1 = *keynum2; + *keynum2 = 0; + keynum = *keynum1; + } + else + { + keynum = defaultkey; + defaultoverride = true; + } + } + else if (keyidx == 1 && (!*keynum2 || (!*keynum1 && *keynum2))) // last one is the same edge case as above + { + keynum = defaultkey; + defaultoverride = true; + } + else // default to the specified keynum + keynum = (keyidx == 1 ? *keynum2 : *keynum1); + + // Did our last call override keynum2? + if (*nestedoverride) + { + defaultoverride = true; + *nestedoverride = false; + } + + // Fill keynum2 with the default control + if (keyidx == 0 && !*keynum2) + { + *keynum2 = defaultkey; + // Tell the next call that this is an override + *nestedoverride = true; + + // if keynum2 already matches keynum1, we probably recursed + // so unset it + if (*keynum1 == *keynum2) + { + *keynum2 = 0; + *nestedoverride = false; + } + } + + // check if the key is being used somewhere else before passing it + // pass it through if it's the same numctrl. This is an edge case -- when using + // LOADCONFIG, gamecontrol is not reset with default. + // + // Also, only check if we're actually overriding, to preserve behavior where + // config'd keys overwrite default keys. + if (defaultoverride) + existingctrl = G_CheckDoubleUsage(keynum, false); + + if (keynum && (!existingctrl || existingctrl == numctrl)) + return keynum; + else if (keyidx == 0 && *keynum2) + { + // try it again and push down keynum2 + *keynum1 = *keynum2; + *keynum2 = 0; + return G_FilterKeyByVersion(numctrl, keyidx, player, keynum1, keynum2, nestedoverride); + // recursion *should* be safe because we only assign keynum2 to a joy default + // and then clear it if we find that keynum1 already has the joy default. + } + else + return 0; + } + // All's good, so pass the keynum as-is if (keyidx == 1) return *keynum2; @@ -1579,6 +1628,7 @@ static void setcontrol(INT32 (*gc)[2]) const char *namectrl; INT32 keynum, keynum1, keynum2; INT32 player = ((void*)gc == (void*)&gamecontrolbis ? 1 : 0); + boolean nestedoverride = false; // Update me for 2.3 namectrl = (stricmp(COM_Argv(1), "use")) ? COM_Argv(1) : "spin"; @@ -1593,20 +1643,20 @@ static void setcontrol(INT32 (*gc)[2]) } keynum1 = G_KeyNameToNum(COM_Argv(2)); keynum2 = G_KeyNameToNum(COM_Argv(3)); - keynum = G_FilterSpecialKeys(0, &keynum1, &keynum2); + keynum = G_FilterKeyByVersion(numctrl, 0, player, &keynum1, &keynum2, &nestedoverride); if (keynum >= 0) { - (void)G_CheckDoubleUsage(keynum, true, player+1); + (void)G_CheckDoubleUsage(keynum, true); // if keynum was rejected, try it again with keynum2 if (!keynum && keynum2) { keynum1 = keynum2; // push down keynum2 keynum2 = 0; - keynum = G_FilterSpecialKeys(0, &keynum1, &keynum2); + keynum = G_FilterKeyByVersion(numctrl, 0, player, &keynum1, &keynum2, &nestedoverride); if (keynum >= 0) - (void)G_CheckDoubleUsage(keynum, true, player+1); + (void)G_CheckDoubleUsage(keynum, true); } } @@ -1615,7 +1665,7 @@ static void setcontrol(INT32 (*gc)[2]) if (keynum2) { - keynum = G_FilterSpecialKeys(1, &keynum1, &keynum2); + keynum = G_FilterKeyByVersion(numctrl, 1, player, &keynum1, &keynum2, &nestedoverride); if (keynum >= 0) { if (keynum != gc[numctrl][0]) diff --git a/src/g_input.h b/src/g_input.h index bb50d3516..fe623034a 100644 --- a/src/g_input.h +++ b/src/g_input.h @@ -188,7 +188,6 @@ typedef enum } key_input_e; #define GAMEPAD_KEY(key) (KEY_GAMEPAD + GAMEPAD_BUTTON_##key) -#define GAMEPAD_AXIS(key) (KEY_AXES + GAMEPAD_AXIS_##key) typedef enum { @@ -249,6 +248,7 @@ typedef enum // mouse values are used once extern consvar_t cv_mousesens, cv_mouseysens; extern consvar_t cv_mousesens2, cv_mouseysens2; +extern consvar_t cv_controlperkey; typedef struct { @@ -354,7 +354,7 @@ void G_DefineDefaultControls(void); INT32 G_GetControlScheme(INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gclen); void G_CopyControls(INT32 (*setupcontrols)[2], INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gclen); void G_SaveKeySetting(FILE *f, INT32 (*fromcontrols)[2], INT32 (*fromcontrolsbis)[2]); -INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify, UINT8 player); +INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify); // sets the members of a mouse_t given position deltas void G_SetMouseDeltas(INT32 dx, INT32 dy, UINT8 ssplayer); diff --git a/src/m_menu.c b/src/m_menu.c index 1e7e1a761..1d5bd65f3 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1070,9 +1070,9 @@ static menuitem_t OP_MainMenu[] = { {IT_SUBMENU | IT_STRING, NULL, "Player 1 Controls...", &OP_P1ControlsDef, 10}, {IT_SUBMENU | IT_STRING, NULL, "Player 2 Controls...", &OP_P2ControlsDef, 20}, + {IT_CVAR | IT_STRING, NULL, "Controls per key", &cv_controlperkey, 30}, - {IT_CALL | IT_STRING, NULL, "Video Options...", M_VideoOptions, 40}, - + {IT_CALL | IT_STRING, NULL, "Video Options...", M_VideoOptions, 50}, {IT_SUBMENU | IT_STRING, NULL, "Sound Options...", &OP_SoundOptionsDef, 60}, {IT_CALL | IT_STRING, NULL, "Server Options...", M_ServerOptions, 80}, @@ -1080,16 +1080,6 @@ static menuitem_t OP_MainMenu[] = {IT_SUBMENU | IT_STRING, NULL, "Data Options...", &OP_DataOptionsDef, 100}, }; -enum -{ - opplayer1, - opplayer2, - opvideo, - opsound, - opserver, - opdata -}; - static menuitem_t OP_P1ControlsMenu[] = { {IT_CALL | IT_STRING, NULL, "Control Configuration...", M_Setup1PControlsMenu, 10}, @@ -1177,11 +1167,15 @@ static menuitem_t OP_Gamepad1Menu[] = {IT_STRING | IT_CVAR, NULL, "Move \x18 Axis" , &cv_sideaxis[0] , 40}, {IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis[0] , 50}, {IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis[0] , 60}, + {IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis[0] , 70}, + {IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis[0] , 80}, + {IT_STRING | IT_CVAR, NULL, "Fire Axis" , &cv_fireaxis[0] , 90}, + {IT_STRING | IT_CVAR, NULL, "Fire Normal Axis" , &cv_firenaxis[0] ,100}, - {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook, 80}, - {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook, 90}, - {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Analog Deadzone", &cv_deadzone[0], 100}, - {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Digital Deadzone", &cv_digitaldeadzone[0], 110}, + {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook, 120}, + {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook, 130}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Analog Deadzone", &cv_deadzone[0], 140}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Digital Deadzone", &cv_digitaldeadzone[0], 150}, }; static menuitem_t OP_Gamepad2Menu[] = @@ -1191,11 +1185,15 @@ static menuitem_t OP_Gamepad2Menu[] = {IT_STRING | IT_CVAR, NULL, "Move \x18 Axis" , &cv_sideaxis[1] , 40}, {IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis[1] , 50}, {IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis[1] , 60}, + {IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis[1] , 70}, + {IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis[1] , 80}, + {IT_STRING | IT_CVAR, NULL, "Fire Axis" , &cv_fireaxis[1] , 90}, + {IT_STRING | IT_CVAR, NULL, "Fire Normal Axis" , &cv_firenaxis[1] ,100}, - {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook2,80}, - {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook2, 90}, - {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Analog Deadzone", &cv_deadzone[1],100}, - {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Digital Deadzone", &cv_digitaldeadzone[1],110}, + {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook2,120}, + {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook2, 130}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Analog Deadzone", &cv_deadzone[1],140}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Digital Deadzone", &cv_digitaldeadzone[1],150}, }; static menuitem_t OP_GamepadSetMenu[MAX_CONNECTED_GAMEPADS + 1]; @@ -1543,13 +1541,6 @@ static menuitem_t OP_DataOptionsMenu[] = {IT_STRING | IT_SUBMENU, NULL, "\x85" "Erase Data...", &OP_EraseDataDef, 40}, }; -enum -{ - opdataaddon, - opdatascreenshot, - opdataerase -}; - static menuitem_t OP_ScreenshotOptionsMenu[] = { {IT_HEADER, NULL, "General", NULL, 0}, @@ -3475,7 +3466,7 @@ boolean M_Responder(event_t *ev) if (!useEventHandler) { UINT16 type = currentMenu->menuitems[itemOn].alphaKey; - if (type == MM_YESNO && !(ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE || ch == KEY_ENTER || ch == KEY_DEL || ch == KEY_BACKSPACE)) + if (type == MM_YESNO && !(ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE || ch == KEY_ENTER || ch == KEY_DEL)) return true; if (routine) routine(ch); @@ -7046,10 +7037,10 @@ static void M_Options(INT32 choice) (void)choice; // if the player is not admin or server, disable server options - OP_MainMenu[opserver].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); + OP_MainMenu[5].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); // if the player is playing _at all_, disable the erase data options - OP_DataOptionsMenu[opdataerase].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); + OP_DataOptionsMenu[2].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); OP_MainDef.prevMenu = currentMenu; M_SetupNextMenu(&OP_MainDef); @@ -9124,7 +9115,7 @@ static void M_LoadGame(INT32 choice) if (tutorialmap && cv_tutorialprompt.value) { - M_StartMessage("Do you want to \x82play a brief Tutorial\x80?\n\nWe highly recommend this because \nthe controls are slightly different \nfrom other games.\n\nPress the\x82 Y\x80 key or the\x83 A button\x80 to go\nPress the\x82 N\x80 key or the\x83 X button\x80 to skip\n", + M_StartMessage("Do you want to \x82play a brief Tutorial\x80?\n\nWe highly recommend this because \nthe controls are slightly different \nfrom other games.\n\nPress the\x82 Y\x80 key or the\x83 A button\x80 to go\nPress the\x82 N\x80 key or the\x83 Y button\x80 to skip\n", M_FirstTimeResponse, MM_YESNO); return; } @@ -13032,7 +13023,7 @@ static void M_ChangeControlResponse(event_t *ev) setupcontrols[control][1] = KEY_NULL; //replace key 1,clear key2 } - G_CheckDoubleUsage(ch, true, setupcontrols_secondaryplayer ? 2 : 1); + G_CheckDoubleUsage(ch, true); setupcontrols[control][found] = ch; } From 5827a19b89dd6a7bfd264faa90924c7348eb3cf0 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 26 Jan 2023 19:24:52 -0600 Subject: [PATCH 88/96] Revert "Merge branch 'controller-fixes' into 'next'" This reverts commit 71736f358f6b08962bb1e6af40c6886b905e2eb1, reversing changes made to 4e3f78784a99c50d31e18f7b7947e3a435cebbea. --- src/g_input.c | 4 ++-- src/m_menu.c | 14 +++----------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/g_input.c b/src/g_input.c index 6b0da7e41..465db0316 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -543,9 +543,9 @@ INT32 G_RemapGamepadEvent(event_t *event, INT32 *type) const INT16 value = G_GetGamepadAxisValue(event->which, event->key); if (value < -jdeadzone || value > jdeadzone) - *type = ev_keydown; - else *type = ev_keyup; + else + *type = ev_keydown; if (value < -jdeadzone) return KEY_INV_AXES + event->key; diff --git a/src/m_menu.c b/src/m_menu.c index 1d5bd65f3..51d13df98 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -3224,7 +3224,6 @@ boolean M_Responder(event_t *ev) static INT32 pjoyx = 0, pjoyy = 0; static INT32 pmousex = 0, pmousey = 0; static INT32 lastx = 0, lasty = 0; - boolean shouldswallowevent = false; void (*routine)(INT32 choice); // for some casting problem if (dedicated || (demoplayback && titledemo) @@ -3240,18 +3239,11 @@ boolean M_Responder(event_t *ev) boolean useEventHandler = false; - if (menuactive && ev->type == ev_gamepad_axis && ev->which == 0) - { - // ALWAYS swallow gamepad axis events, to prevent trickling down to game input - // this applies even if the axis event does not get remapped - shouldswallowevent = true; - } - if (noFurtherInput) { // Ignore input after enter/escape/other buttons // (but still allow shift keyup so caps doesn't get stuck) - return shouldswallowevent; + return false; } else if (menuactive) { @@ -3376,7 +3368,7 @@ boolean M_Responder(event_t *ev) } if (!useEventHandler && ch == -1) - return shouldswallowevent; + return false; else if (ch == gamecontrol[GC_SYSTEMMENU][0] || ch == gamecontrol[GC_SYSTEMMENU][1]) // allow remappable ESC key ch = KEY_ESCAPE; @@ -3609,7 +3601,7 @@ boolean M_Responder(event_t *ev) //currentMenu->lastOn = itemOn; //if (currentMenu->prevMenu) // M_SetupNextMenu(currentMenu->prevMenu); - return shouldswallowevent; + return false; default: CON_Responder(ev); From f9c9e0829a665071bcf5e8b0e98e6d98041dfa2f Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 26 Jan 2023 19:25:53 -0600 Subject: [PATCH 89/96] Revert "sdl: I can't believe it's more version-guards" This reverts commit fdb6f2aff93e91cfc1dac24804c912d8b0dc31e6. --- src/sdl/i_gamepad.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/sdl/i_gamepad.c b/src/sdl/i_gamepad.c index ecde251fb..b2b50e43d 100644 --- a/src/sdl/i_gamepad.c +++ b/src/sdl/i_gamepad.c @@ -103,7 +103,6 @@ INT32 I_NumGamepads(void) #define USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO2 0x4001 #define USB_PRODUCT_XBOX_SERIES_X_POWERA_SPECTRA 0x4002 -#if SDL_VERSION_ATLEAST(2,0,6) static boolean IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id) { if (vendor_id == USB_VENDOR_MICROSOFT) { @@ -142,7 +141,6 @@ static boolean IsJoystickXboxSeriesXS(Uint16 vendor_id, Uint16 product_id) return false; } -#endif // Opens a controller device static boolean Controller_OpenDevice(UINT8 which, INT32 devindex) @@ -887,7 +885,6 @@ boolean I_SetGamepadSmallMotorFreq(UINT8 which, fixed_t freq) void I_SetGamepadRumblePaused(UINT8 which, boolean pause) { -#if SDL_VERSION_ATLEAST(2,0,9) if (!I_RumbleSupported() || which >= NUM_GAMEPADS) return; @@ -918,11 +915,6 @@ void I_SetGamepadRumblePaused(UINT8 which, boolean pause) } controller->info->rumble.paused = pause; -#else - (void)which; - (void)pause; - return; -#endif } boolean I_GetGamepadRumbleSupported(UINT8 which) From 40a5580e653a32df51f0d8744bce2b367eebf5ea Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 26 Jan 2023 19:25:56 -0600 Subject: [PATCH 90/96] Revert "sdl: Yet more SDL rumble version-guards" This reverts commit df28ffd72eb168bf392db7cf88a4c58218fe2923. --- src/sdl/i_gamepad.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/sdl/i_gamepad.c b/src/sdl/i_gamepad.c index b2b50e43d..109d37d4a 100644 --- a/src/sdl/i_gamepad.c +++ b/src/sdl/i_gamepad.c @@ -66,11 +66,7 @@ void I_InitGamepads(void) if (!InitGamepadSubsystems()) return; -#if SDL_VERSION_ATLEAST(2,0,9) rumble_supported = !M_CheckParm("-norumble"); -#else - rumble_supported = false; -#endif for (UINT8 i = 0; i < NUM_GAMEPADS; i++) controllers[i].info = &gamepads[i]; @@ -731,20 +727,14 @@ boolean I_RumbleSupported(void) static boolean Controller_Rumble(ControllerInfo *c) { -#if SDL_VERSION_ATLEAST(2,0,9) if (SDL_GameControllerRumble(c->dev, c->rumble.large_magnitude, c->rumble.small_magnitude, 0) == -1) return false; return true; -#else - (void)c; - return false; -#endif } void I_ToggleControllerRumble(boolean unpause) { -#if SDL_VERSION_ATLEAST(2,0,9) if (!I_RumbleSupported() || rumble_paused == !unpause) return; @@ -764,10 +754,6 @@ void I_ToggleControllerRumble(boolean unpause) controller->rumble.expiration = controller->rumble.time_left = 0; } } -#else - (void)unpause; - return; -#endif } void I_UpdateControllers(void) From 2810a46095ec6568a5ff4c38f70d6e36b4feb7b1 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 26 Jan 2023 19:25:59 -0600 Subject: [PATCH 91/96] Revert "sdl: Version-guard rumble and extended buttons" This reverts commit f5f224136ba6d8db1319eb091c9b9877173d8e55. --- src/sdl/i_gamepad.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/sdl/i_gamepad.c b/src/sdl/i_gamepad.c index 109d37d4a..28f9681be 100644 --- a/src/sdl/i_gamepad.c +++ b/src/sdl/i_gamepad.c @@ -231,7 +231,6 @@ static boolean Controller_OpenDevice(UINT8 which, INT32 devindex) controller->info->type = GAMEPAD_TYPE_UNKNOWN; #endif // SDL_VERSION_ATLEAST(2,0,12) -#if SDL_VERSION_ATLEAST(2,0,6) // Check the device vendor and product to find out what controller this actually is Uint16 vendor = SDL_JoystickGetDeviceVendor(devindex); Uint16 product = SDL_JoystickGetDeviceProduct(devindex); @@ -240,17 +239,13 @@ static boolean Controller_OpenDevice(UINT8 which, INT32 devindex) controller->info->type = GAMEPAD_TYPE_XBOX_SERIES_XS; else if (IsJoystickXboxOneElite(vendor, product)) controller->info->type = GAMEPAD_TYPE_XBOX_ELITE; -#endif CONS_Debug(DBG_GAMELOGIC, M_GetText(" Type: %s\n"), G_GamepadTypeToString(controller->info->type)); -#if SDL_VERSION_ATLEAST(2,0,12) // Change the ring LEDs on Xbox 360 controllers // FIXME: Doesn't seem to work? SDL_GameControllerSetPlayerIndex(controller->dev, which); -#endif -#if SDL_VERSION_ATLEAST(2,0,18) // Check if rumble is supported if (SDL_GameControllerHasRumble(controller->dev) == SDL_TRUE) { @@ -260,12 +255,8 @@ static boolean Controller_OpenDevice(UINT8 which, INT32 devindex) else { controller->info->rumble.supported = false; - CONS_Debug(DBG_GAMELOGIC, M_GetText(" Rumble supported: No\n")); + CONS_Debug(DBG_GAMELOGIC, M_GetText(" Rumble supported: No\n"));; } -#else - controller->info->rumble.supported = true; - CONS_Debug(DBG_GAMELOGIC, M_GetText(" Rumble supported: Maybe\n")); -#endif // SDL_VERSION_ATLEAST(2,0,18) if (!controller->info->connected) { @@ -609,14 +600,12 @@ void I_HandleControllerButtonEvent(SDL_ControllerButtonEvent evt, Uint32 type) GAMEPAD_BUTTON_CASE(DPAD_DOWN); GAMEPAD_BUTTON_CASE(DPAD_LEFT); GAMEPAD_BUTTON_CASE(DPAD_RIGHT); -#if SDL_VERSION_ATLEAST(2,0,14) GAMEPAD_BUTTON_CASE(MISC1); GAMEPAD_BUTTON_CASE(PADDLE1); GAMEPAD_BUTTON_CASE(PADDLE2); GAMEPAD_BUTTON_CASE(PADDLE3); GAMEPAD_BUTTON_CASE(PADDLE4); GAMEPAD_BUTTON_CASE(TOUCHPAD); -#endif default: return; } @@ -674,10 +663,8 @@ static void Controller_StopRumble(UINT8 num) gamepad->rumble.data.small_magnitude = 0; gamepad->rumble.data.duration = 0; -#if SDL_VERSION_ATLEAST(2,0,9) if (gamepad->rumble.supported) SDL_GameControllerRumble(controller->dev, 0, 0, 0); -#endif } static void Controller_Close(UINT8 num) From bbf6e8ccce0bde7698363594f1941f78049bac4a Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 26 Jan 2023 19:26:02 -0600 Subject: [PATCH 92/96] Revert "sdl: SDL version-guard controller type and hidapi" This reverts commit ec58b1504d28513ae4a972b4d2a32bfed01dec4a. --- src/sdl/i_gamepad.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/sdl/i_gamepad.c b/src/sdl/i_gamepad.c index 28f9681be..dbafc1f63 100644 --- a/src/sdl/i_gamepad.c +++ b/src/sdl/i_gamepad.c @@ -39,10 +39,8 @@ static boolean InitGamepadSubsystems(void) { if (M_CheckParm("-noxinput")) SDL_SetHintWithPriority(SDL_HINT_XINPUT_ENABLED, "0", SDL_HINT_OVERRIDE); -#if SDL_VERSION_ATLEAST(2,0,9) if (M_CheckParm("-nohidapi")) SDL_SetHintWithPriority(SDL_HINT_JOYSTICK_HIDAPI, "0", SDL_HINT_OVERRIDE); -#endif if (SDL_WasInit(GAMEPAD_INIT_FLAGS) == 0) { @@ -201,7 +199,6 @@ static boolean Controller_OpenDevice(UINT8 which, INT32 devindex) CONS_Debug(DBG_GAMELOGIC, M_GetText("Controller %d: %s\n"), which, SDL_GameControllerName(controller->dev)); -#if SDL_VERSION_ATLEAST(2,0,12) #define GAMEPAD_TYPE_CASE(ctrl) \ case SDL_CONTROLLER_TYPE_##ctrl: \ controller->info->type = GAMEPAD_TYPE_##ctrl; \ @@ -214,22 +211,15 @@ static boolean Controller_OpenDevice(UINT8 which, INT32 devindex) GAMEPAD_TYPE_CASE(XBOXONE); GAMEPAD_TYPE_CASE(PS3); GAMEPAD_TYPE_CASE(PS4); -#if SDL_VERSION_ATLEAST(2,0,14) GAMEPAD_TYPE_CASE(PS5); -#endif GAMEPAD_TYPE_CASE(NINTENDO_SWITCH_PRO); -#if SDL_VERSION_ATLEAST(2,0,16) GAMEPAD_TYPE_CASE(GOOGLE_STADIA); GAMEPAD_TYPE_CASE(AMAZON_LUNA); -#endif GAMEPAD_TYPE_CASE(VIRTUAL); default: break; } + #undef GAMEPAD_BUTTON_CASE -#else - // Under older versions of SDL, we aren't provided controller type information. - controller->info->type = GAMEPAD_TYPE_UNKNOWN; -#endif // SDL_VERSION_ATLEAST(2,0,12) // Check the device vendor and product to find out what controller this actually is Uint16 vendor = SDL_JoystickGetDeviceVendor(devindex); From 7ad54af89fca8a62faa8edd1aba00e64a0df7ee1 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 26 Jan 2023 19:26:17 -0600 Subject: [PATCH 93/96] Revert "Fix axis inversion and camera look inversion" This reverts commit 6428d6fc612e31753d424e2efcfcc6afc6d2e93a. --- src/g_game.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index b4a127a73..b406b8f94 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -935,12 +935,7 @@ static INT16 GetJoystickAxisValue(UINT8 which, joyaxis_e axissel, INT32 axisval) // flip it around if (flp) - { - if (retaxis == -32768) - retaxis = 32767; - else - retaxis = -retaxis; - } + retaxis = -retaxis; return retaxis; } @@ -948,7 +943,6 @@ static INT16 GetJoystickAxisValue(UINT8 which, joyaxis_e axissel, INT32 axisval) INT16 G_JoyAxis(UINT8 which, joyaxis_e axissel) { INT32 axisval; - INT32 value; // find what axis to get switch (axissel) @@ -981,16 +975,7 @@ INT16 G_JoyAxis(UINT8 which, joyaxis_e axissel) return 0; } - value = GetJoystickAxisValue(which, axissel, axisval); - if (axissel == JA_LOOK) - { - // Look is inverted because +Y goes _down_ in gamepads. - if (value == -32768) - value = 32767; - else - value = -value; - } - return value; + return GetJoystickAxisValue(which, axissel, axisval); } static INT16 GetAnalogInput(UINT8 which, gamecontrols_e gc) From 6cc48a6e893999f3b35a2305d2539b081fe07aa2 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 26 Jan 2023 19:26:21 -0600 Subject: [PATCH 94/96] Revert "Merge branch 'gamepad-refactor-lua-rumble' into 'next'" This reverts commit 7d8e8e20b7c1b40231ac47c812225cd63358b12a, reversing changes made to 7f1cafcd3d0a0738bf106b8edcaf9a23f9cefa19. --- src/lua_baselib.c | 82 +---------------------------------------------- src/lua_script.h | 1 - 2 files changed, 1 insertion(+), 82 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index c94e9e91e..6212a77f0 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -15,7 +15,6 @@ #include "p_local.h" #include "p_setup.h" // So we can have P_SetupLevelSky #include "p_slopes.h" // P_GetSlopeZAt -#include "p_haptic.h" #include "z_zone.h" #include "r_main.h" #include "r_draw.h" @@ -1734,78 +1733,6 @@ static int lib_pPlayerShouldUseSpinHeight(lua_State *L) return 1; } -// P_HAPTIC -/////////// -#define GET_OPTIONAL_PLAYER(arg) \ - player_t *player = NULL; \ - if (!lua_isnoneornil(L, arg)) { \ - player = *((player_t **)luaL_checkudata(L, arg, META_PLAYER)); \ - if (!player) \ - return LUA_ErrInvalid(L, "player_t"); \ - } - -static int lib_pDoRumble(lua_State *L) -{ - GET_OPTIONAL_PLAYER(1); - fixed_t large_magnitude = luaL_checkfixed(L, 2); - fixed_t small_magnitude = luaL_optfixed(L, 3, large_magnitude); - tic_t duration = luaL_optinteger(L, 4, 0); - -#define CHECK_MAGNITUDE(which) \ - if (which##_magnitude < 0 || which##_magnitude > FRACUNIT) \ - return luaL_error(L, va(#which " motor frequency %f out of range (minimum is 0.0, maximum is 1.0)", \ - FixedToFloat(which##_magnitude))) - - CHECK_MAGNITUDE(large); - CHECK_MAGNITUDE(small); - -#undef CHECK_MAGNITUDE - - lua_pushboolean(L, P_DoRumble(player, large_magnitude, small_magnitude, duration)); - return 1; -} - -static int lib_pPauseRumble(lua_State *L) -{ - GET_OPTIONAL_PLAYER(1); - P_PauseRumble(player); - return 0; -} - -static int lib_pUnpauseRumble(lua_State *L) -{ - GET_OPTIONAL_PLAYER(1); - P_UnpauseRumble(player); - return 0; -} - -static int lib_pIsRumbleEnabled(lua_State *L) -{ - GET_OPTIONAL_PLAYER(1); - if (player && P_IsLocalPlayer(player)) - lua_pushboolean(L, P_IsRumbleEnabled(player)); - else - lua_pushnil(L); - return 1; -} - -static int lib_pIsRumblePaused(lua_State *L) -{ - GET_OPTIONAL_PLAYER(1); - if (player && P_IsLocalPlayer(player)) - lua_pushboolean(L, P_IsRumblePaused(player)); - else - lua_pushnil(L); - return 1; -} - -static int lib_pStopRumble(lua_State *L) -{ - GET_OPTIONAL_PLAYER(1); - P_StopRumble(player); - return 0; -} - // P_MAP /////////// @@ -3442,6 +3369,7 @@ static int lib_sResumeMusic(lua_State *L) // G_GAME //////////// +// Copypasted from lib_cvRegisterVar :] static int lib_gAddGametype(lua_State *L) { const char *k; @@ -4163,14 +4091,6 @@ static luaL_Reg lib[] = { {"P_PlayerCanEnterSpinGaps",lib_pPlayerCanEnterSpinGaps}, {"P_PlayerShouldUseSpinHeight",lib_pPlayerShouldUseSpinHeight}, - // p_haptic - {"P_DoRumble",lib_pDoRumble}, - {"P_PauseRumble",lib_pPauseRumble}, - {"P_UnpauseRumble",lib_pUnpauseRumble}, - {"P_IsRumbleEnabled",lib_pIsRumbleEnabled}, - {"P_IsRumblePaused",lib_pIsRumblePaused}, - {"P_StopRumble",lib_pStopRumble}, - // p_map {"P_CheckPosition",lib_pCheckPosition}, {"P_TryMove",lib_pTryMove}, diff --git a/src/lua_script.h b/src/lua_script.h index 1c98a32f3..080427039 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -36,7 +36,6 @@ // angle_t casting // TODO deal with signedness #define luaL_checkangle(L, i) ((angle_t)luaL_checkinteger(L, i)) -#define luaL_optangle(L, i, o) ((angle_t)luaL_optinteger(L, i, o)) #define lua_pushangle(L, a) lua_pushinteger(L, a) #ifdef _DEBUG From 366ee4ad92db728602917ce851106f8feee1d860 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 26 Jan 2023 19:26:24 -0600 Subject: [PATCH 95/96] Revert "Merge branch 'gamepad-refactor-lua-features' into 'next'" This reverts commit 7f1cafcd3d0a0738bf106b8edcaf9a23f9cefa19, reversing changes made to 696e2ab9097a674716e579eb848024b0b8539205. --- src/g_game.c | 11 -- src/g_game.h | 3 - src/lua_baselib.c | 1 - src/lua_hook.h | 6 - src/lua_hooklib.c | 23 --- src/lua_inputlib.c | 372 -------------------------------------------- src/lua_libs.h | 1 - src/lua_script.c | 18 --- src/lua_script.h | 1 - src/sdl/i_gamepad.c | 8 +- 10 files changed, 2 insertions(+), 442 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index b406b8f94..ce41ccaf6 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1808,15 +1808,8 @@ INT32 G_GetGamepadDeviceIndex(INT32 player) return cv_usegamepad[player].value; } -void G_OnGamepadConnect(UINT8 which) -{ - LUA_HookGamepadEvent(which, HOOK(GamepadAdded)); -} - void G_OnGamepadDisconnect(UINT8 which) { - LUA_HookGamepadEvent(which, HOOK(GamepadRemoved)); - if (!cv_gamepad_autopause.value) return; @@ -2340,10 +2333,6 @@ boolean G_LuaResponder(event_t *ev) cancelled = LUA_HookKey(ev, HOOK(KeyUp)); LUA_InvalidateUserdata(ev); } - else if (ev->type == ev_gamepad_down) - cancelled = LUA_HookGamepadButton(ev, HOOK(GamepadButtonDown)); - else if (ev->type == ev_gamepad_up) - cancelled = LUA_HookGamepadButton(ev, HOOK(GamepadButtonUp)); return cancelled; } diff --git a/src/g_game.h b/src/g_game.h index e798176af..6c24054a0 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -133,9 +133,6 @@ INT32 G_GetGamepadDeviceIndex(INT32 player); // returns a player's gamepad index INT16 G_GetGamepadForPlayer(player_t *player); -// called when a player's gamepad is connected -void G_OnGamepadConnect(UINT8 which); - // called when a player's gamepad is disconnected void G_OnGamepadDisconnect(UINT8 which); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 6212a77f0..29adb478a 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -220,7 +220,6 @@ static const struct { {META_LUABANKS, "luabanks[]"}, {META_KEYEVENT, "keyevent_t"}, - {META_GAMEPAD, "gamepad_t"}, {META_MOUSE, "mouse_t"}, {NULL, NULL} }; diff --git a/src/lua_hook.h b/src/lua_hook.h index ff6470d76..4fa3a1a17 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -74,10 +74,6 @@ automatically. X (PlayerCanEnterSpinGaps),\ X (KeyDown),\ X (KeyUp),\ - X (GamepadButtonDown),\ - X (GamepadButtonUp),\ - X (GamepadAdded),\ - X (GamepadRemoved),\ #define STRING_HOOK_LIST(X) \ X (BotAI),/* B_BuildTailsTiccmd by skin name */\ @@ -129,8 +125,6 @@ void LUA_HookBool(boolean value, int hook); int LUA_HookPlayer(player_t *, int hook); int LUA_HookTiccmd(player_t *, ticcmd_t *, int hook); int LUA_HookKey(event_t *event, int hook); // Hooks for key events -int LUA_HookGamepadButton(event_t *event, int hook); -void LUA_HookGamepadEvent(UINT8 which, int hook); void LUA_HookThinkFrame(void); int LUA_HookMobjLineCollide(mobj_t *, line_t *); diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index ef8426d7a..c4083c9ad 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -14,7 +14,6 @@ #include "doomstat.h" #include "p_mobj.h" #include "g_game.h" -#include "g_input.h" #include "r_skins.h" #include "b_bot.h" #include "z_zone.h" @@ -647,28 +646,6 @@ int LUA_HookKey(event_t *event, int hook_type) return hook.status; } -int LUA_HookGamepadButton(event_t *event, int hook_type) -{ - Hook_State hook; - if (prepare_hook(&hook, false, hook_type)) - { - LUA_PushUserdata(gL, &gamepads[event->which], META_GAMEPAD); - lua_pushstring(gL, gamepad_button_names[event->key]); - call_hooks(&hook, 1, res_true); - } - return hook.status; -} - -void LUA_HookGamepadEvent(UINT8 which, int hook_type) -{ - Hook_State hook; - if (prepare_hook(&hook, 0, hook_type)) - { - LUA_PushUserdata(gL, &gamepads[which], META_GAMEPAD); - call_hooks(&hook, 0, res_none); - } -} - void LUA_HookHUD(int hook_type, huddrawlist_h list) { const hook_t * map = &hudHookIds[hook_type]; diff --git a/src/lua_inputlib.c b/src/lua_inputlib.c index e4962a0fb..88efc3490 100644 --- a/src/lua_inputlib.c +++ b/src/lua_inputlib.c @@ -129,21 +129,6 @@ static int lib_getCursorPosition(lua_State *L) return 2; } -static int lib_getPlayerGamepad(lua_State *L) -{ - player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); - if (!player) - return LUA_ErrInvalid(L, "player_t"); - - INT16 which = G_GetGamepadForPlayer(player); - if (which >= 0) - LUA_PushUserdata(L, &gamepads[which], META_GAMEPAD); - else - lua_pushnil(L); - - return 1; -} - static luaL_Reg lib[] = { {"gameControlDown", lib_gameControlDown}, {"gameControl2Down", lib_gameControl2Down}, @@ -158,7 +143,6 @@ static luaL_Reg lib[] = { {"getMouseGrab", lib_getMouseGrab}, {"setMouseGrab", lib_setMouseGrab}, {"getCursorPosition", lib_getCursorPosition}, - {"getPlayerGamepad", lib_getPlayerGamepad}, {NULL, NULL} }; @@ -214,341 +198,6 @@ static int keyevent_get(lua_State *L) return 1; } -///////////// -// GAMEPAD // -///////////// - -enum gamepad_leftright_e { - gamepad_opt_left, - gamepad_opt_right -}; - -static const char *const gamepad_leftright_opt[] = { - "left", - "right", - NULL}; - -// Buttons -static int gamepad_isButtonDown(lua_State *L) -{ - gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD)); - gamepad_button_e button = luaL_checkoption(L, 2, NULL, gamepad_button_names); - lua_pushboolean(L, gamepad->buttons[button] == 1); - return 1; -} - -// Axes -static int gamepad_getAxis(lua_State *L) -{ - gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD)); - gamepad_axis_e axis = luaL_checkoption(L, 2, NULL, gamepad_axis_names); - boolean applyDeadzone = luaL_opt(L, luaL_checkboolean, 3, true); - lua_pushfixed(L, G_GetAdjustedGamepadAxis(gamepad->num, axis, applyDeadzone)); - return 1; -} - -// Sticks -static int gamepad_getStick(lua_State *L) -{ - gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD)); - enum gamepad_leftright_e stick = luaL_checkoption(L, 2, NULL, gamepad_leftright_opt); - boolean applyDeadzone = luaL_opt(L, luaL_checkboolean, 3, true); - - switch (stick) - { - case gamepad_opt_left: - lua_pushfixed(L, G_GetAdjustedGamepadAxis(gamepad->num, GAMEPAD_AXIS_LEFTX, applyDeadzone)); - lua_pushfixed(L, G_GetAdjustedGamepadAxis(gamepad->num, GAMEPAD_AXIS_LEFTY, applyDeadzone)); - break; - case gamepad_opt_right: - lua_pushfixed(L, G_GetAdjustedGamepadAxis(gamepad->num, GAMEPAD_AXIS_RIGHTX, applyDeadzone)); - lua_pushfixed(L, G_GetAdjustedGamepadAxis(gamepad->num, GAMEPAD_AXIS_RIGHTY, applyDeadzone)); - break; - } - - return 2; -} - -// Triggers -static int gamepad_getTrigger(lua_State *L) -{ - gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD)); - enum gamepad_leftright_e stick = luaL_checkoption(L, 2, NULL, gamepad_leftright_opt); - boolean applyDeadzone = luaL_opt(L, luaL_checkboolean, 3, true); - gamepad_axis_e axis = 0; - - switch (stick) - { - case gamepad_opt_left: - axis = GAMEPAD_AXIS_TRIGGERLEFT; - break; - case gamepad_opt_right: - axis = GAMEPAD_AXIS_TRIGGERRIGHT; - break; - } - - lua_pushfixed(L, G_GetAdjustedGamepadAxis(gamepad->num, axis, applyDeadzone)); - return 1; -} - -// Button and axis names -static int gamepad_getButtonName(lua_State *L) -{ - gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD)); - gamepad_button_e button = luaL_checkoption(L, 2, NULL, gamepad_button_names); - lua_pushstring(L, G_GetGamepadButtonString(gamepad->type, button, GAMEPAD_STRING_DEFAULT)); - return 1; -} - -static int gamepad_getAxisName(lua_State *L) -{ - gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD)); - gamepad_axis_e axis = luaL_checkoption(L, 2, NULL, gamepad_axis_names); - lua_pushstring(L, G_GetGamepadAxisString(gamepad->type, axis, GAMEPAD_STRING_DEFAULT, false)); - return 1; -} - -static int gamepad_getTriggerName(lua_State *L) -{ - gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD)); - enum gamepad_leftright_e stick = luaL_checkoption(L, 2, NULL, gamepad_leftright_opt); - gamepad_axis_e axis = 0; - - switch (stick) - { - case gamepad_opt_left: - axis = GAMEPAD_AXIS_TRIGGERLEFT; - break; - case gamepad_opt_right: - axis = GAMEPAD_AXIS_TRIGGERRIGHT; - break; - } - - lua_pushstring(L, G_GetGamepadAxisString(gamepad->type, axis, GAMEPAD_STRING_DEFAULT, false)); - return 1; -} - -// Rumble -static int gamepad_doRumble(lua_State *L) -{ - gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD)); - fixed_t large_magnitude = luaL_checkfixed(L, 2); - fixed_t small_magnitude = luaL_optfixed(L, 3, large_magnitude); - tic_t duration = luaL_optinteger(L, 4, 0); - -#define CHECK_MAGNITUDE(which) \ - if (which##_magnitude < 0 || which##_magnitude > FRACUNIT) \ - return luaL_error(L, va(#which " motor frequency %f out of range (minimum is 0.0, maximum is 1.0)", \ - FixedToFloat(which##_magnitude))) - - CHECK_MAGNITUDE(large); - CHECK_MAGNITUDE(small); - -#undef CHECK_MAGNITUDE - - lua_pushboolean(L, G_RumbleGamepad(gamepad->num, large_magnitude, small_magnitude, duration)); - return 1; -} - -static int gamepad_stopRumble(lua_State *L) -{ - gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD)); - G_StopGamepadRumble(gamepad->num); - return 0; -} - -// Accessing gamepad userdata -enum gamepad_opt_e { - gamepad_opt_connected, - gamepad_opt_type, - gamepad_opt_isXbox, - gamepad_opt_isPlayStation, - gamepad_opt_isNintendoSwitch, - gamepad_opt_isJoyCon, - gamepad_opt_hasRumble, - gamepad_opt_isRumbling, - gamepad_opt_isRumblePaused, - gamepad_opt_largeMotorFrequency, - gamepad_opt_smallMotorFrequency, - gamepad_opt_isButtonDown, - gamepad_opt_getAxis, - gamepad_opt_getStick, - gamepad_opt_getTrigger, - gamepad_opt_getButtonName, - gamepad_opt_getAxisName, - gamepad_opt_getTriggerName, - gamepad_opt_rumble, - gamepad_opt_stopRumble -}; - -static const char *const gamepad_opt[] = { - "connected", - "type", - "isXbox", - "isPlayStation", - "isNintendoSwitch", - "isJoyCon", - "hasRumble", - "isRumbling", - "isRumblePaused", - "largeMotorFrequency", - "smallMotorFrequency", - "isButtonDown", - "getAxis", - "getStick", - "getTrigger", - "getButtonName", - "getAxisName", - "getTriggerName", - "rumble", - "stopRumble", - NULL}; - -static int (*gamepad_fn_list[9])(lua_State *L) = { - gamepad_isButtonDown, - gamepad_getAxis, - gamepad_getStick, - gamepad_getTrigger, - gamepad_getButtonName, - gamepad_getAxisName, - gamepad_getTriggerName, - gamepad_doRumble, - gamepad_stopRumble -}; - -static int gamepad_get(lua_State *L) -{ - gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD)); - enum gamepad_opt_e field = luaL_checkoption(L, 2, NULL, gamepad_opt); - - switch (field) - { - case gamepad_opt_connected: - lua_pushboolean(L, gamepad->connected); - break; - case gamepad_opt_type: - lua_pushstring(L, G_GamepadTypeToString(gamepad->type)); - break; - case gamepad_opt_isXbox: - lua_pushboolean(L, G_GamepadTypeIsXbox(gamepad->type)); - break; - case gamepad_opt_isPlayStation: - lua_pushboolean(L, G_GamepadTypeIsPlayStation(gamepad->type)); - break; - case gamepad_opt_isNintendoSwitch: - lua_pushboolean(L, G_GamepadTypeIsNintendoSwitch(gamepad->type)); - break; - case gamepad_opt_isJoyCon: - // No, this does not include the grip. - lua_pushboolean(L, G_GamepadTypeIsJoyCon(gamepad->type)); - break; - case gamepad_opt_hasRumble: - lua_pushboolean(L, G_RumbleSupported(gamepad->num)); - break; - case gamepad_opt_isRumbling: - lua_pushboolean(L, gamepad->rumble.active); - break; - case gamepad_opt_isRumblePaused: - lua_pushboolean(L, G_GetGamepadRumblePaused(gamepad->num)); - break; - case gamepad_opt_largeMotorFrequency: - lua_pushfixed(L, G_GetLargeMotorFreq(gamepad->num)); - break; - case gamepad_opt_smallMotorFrequency: - lua_pushfixed(L, G_GetSmallMotorFreq(gamepad->num)); - break; - case gamepad_opt_isButtonDown: - case gamepad_opt_getAxis: - case gamepad_opt_getStick: - case gamepad_opt_getTrigger: - case gamepad_opt_getButtonName: - case gamepad_opt_getAxisName: - case gamepad_opt_getTriggerName: - case gamepad_opt_rumble: - case gamepad_opt_stopRumble: - lua_pushcfunction(L, gamepad_fn_list[field - gamepad_opt_isButtonDown]); - break; - } - return 1; -} - -static int gamepad_set(lua_State *L) -{ - gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD)); - enum gamepad_opt_e field = luaL_checkoption(L, 2, NULL, gamepad_opt); - - switch (field) - { - case gamepad_opt_isRumblePaused: - G_SetGamepadRumblePaused(gamepad->num, luaL_checkboolean(L, 3)); - break; - case gamepad_opt_largeMotorFrequency: - G_SetLargeMotorFreq(gamepad->num, luaL_checkfixed(L, 3)); - break; - case gamepad_opt_smallMotorFrequency: - G_SetSmallMotorFreq(gamepad->num, luaL_checkfixed(L, 3)); - break; - default: - return luaL_error(L, LUA_QL("gamepad") " field " LUA_QS " should not be set directly.", gamepad_opt[field]); - } - return 1; -} - -static int gamepad_num(lua_State *L) -{ - gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD)); - lua_pushinteger(L, gamepad->num + 1); - return 1; -} - -static int lib_iterateGamepads(lua_State *L) -{ - INT32 i = -1; - if (lua_gettop(L) < 2) - { - lua_pushcfunction(L, lib_iterateGamepads); - return 1; - } - lua_settop(L, 2); - lua_remove(L, 1); // State is unused - if (!lua_isnil(L, 1)) - i = (INT32)(*((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD)) - gamepads); - for (i++; i < NUM_GAMEPADS; i++) - { - if (!gamepads[i].connected) - continue; - LUA_PushUserdata(L, &gamepads[i], META_GAMEPAD); - return 1; - } - return 0; -} - -static int lib_getGamepad(lua_State *L) -{ - if (lua_type(L, 2) == LUA_TNUMBER) - { - lua_Integer i = luaL_checkinteger(L, 2); - if (i < 1 || i > NUM_GAMEPADS) - return luaL_error(L, "gamepads[] index %d out of range (1 - %d)", i, NUM_GAMEPADS); - LUA_PushUserdata(L, &gamepads[i - 1], META_GAMEPAD); - return 1; - } - - if (fastcmp(luaL_checkstring(L, 2), "iterate")) - { - lua_pushcfunction(L, lib_iterateGamepads); - return 1; - } - - return 0; -} - -static int lib_lenGamepad(lua_State *L) -{ - lua_pushinteger(L, NUM_GAMEPADS); - return 1; -} - /////////// // MOUSE // /////////// @@ -609,27 +258,6 @@ int LUA_InputLib(lua_State *L) lua_setfield(L, -2, "__index"); lua_pop(L, 1); - luaL_newmetatable(L, META_GAMEPAD); - lua_pushcfunction(L, gamepad_get); - lua_setfield(L, -2, "__index"); - - lua_pushcfunction(L, gamepad_set); - lua_setfield(L, -2, "__newindex"); - - lua_pushcfunction(L, gamepad_num); - lua_setfield(L, -2, "__len"); - lua_pop(L, 1); - - lua_newuserdata(L, 0); - lua_createtable(L, 0, 2); - lua_pushcfunction(L, lib_getGamepad); - lua_setfield(L, -2, "__index"); - - lua_pushcfunction(L, lib_lenGamepad); - lua_setfield(L, -2, "__len"); - lua_setmetatable(L, -2); - lua_setglobal(L, "gamepads"); - luaL_newmetatable(L, META_MOUSE); lua_pushcfunction(L, mouse_get); lua_setfield(L, -2, "__index"); diff --git a/src/lua_libs.h b/src/lua_libs.h index 68e976234..b4a891edb 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -91,7 +91,6 @@ extern boolean mousegrabbedbylua; #define META_LUABANKS "LUABANKS[]*" #define META_KEYEVENT "KEYEVENT_T*" -#define META_GAMEPAD "GAMEPAD_T*" #define META_MOUSE "MOUSE_T*" boolean luaL_checkboolean(lua_State *L, int narg); diff --git a/src/lua_script.c b/src/lua_script.c index 8d8fb295c..f166fb4e6 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -949,7 +949,6 @@ enum ARCH_MAPHEADER, ARCH_SKINCOLOR, ARCH_MOUSE, - ARCH_GAMEPAD, ARCH_TEND=0xFF, }; @@ -977,7 +976,6 @@ static const struct { {META_SLOPE, ARCH_SLOPE}, {META_MAPHEADER, ARCH_MAPHEADER}, {META_SKINCOLOR, ARCH_SKINCOLOR}, - {META_GAMEPAD, ARCH_GAMEPAD}, {META_MOUSE, ARCH_MOUSE}, {NULL, ARCH_NULL} }; @@ -1293,13 +1291,6 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) WRITEUINT16(save_p, info - skincolors); break; } - case ARCH_GAMEPAD: - { - gamepad_t *gamepad = *((gamepad_t **)lua_touserdata(gL, myindex)); - WRITEUINT8(save_p, ARCH_GAMEPAD); - WRITEUINT8(save_p, gamepad->num); - break; - } case ARCH_MOUSE: { mouse_t *m = *((mouse_t **)lua_touserdata(gL, myindex)); @@ -1550,15 +1541,6 @@ static UINT8 UnArchiveValue(int TABLESINDEX) case ARCH_SKINCOLOR: LUA_PushUserdata(gL, &skincolors[READUINT16(save_p)], META_SKINCOLOR); break; - case ARCH_GAMEPAD: - { - UINT8 which = READUINT8(save_p); - if (which < NUM_GAMEPADS) - LUA_PushUserdata(gL, &gamepads[which], META_GAMEPAD); - else // Wait, what? - lua_pushnil(gL); - break; - } case ARCH_MOUSE: LUA_PushUserdata(gL, READUINT16(save_p) == 1 ? &mouse : &mouse2, META_MOUSE); break; diff --git a/src/lua_script.h b/src/lua_script.h index 080427039..e586b04a8 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -30,7 +30,6 @@ // TODO add some distinction between fixed numbers and integer numbers // for at least the purpose of printing and maybe math. #define luaL_checkfixed(L, i) luaL_checkinteger(L, i) -#define luaL_optfixed(L, i, o) luaL_optinteger(L, i, o) #define lua_pushfixed(L, f) lua_pushinteger(L, f) // angle_t casting diff --git a/src/sdl/i_gamepad.c b/src/sdl/i_gamepad.c index dbafc1f63..69f03d662 100644 --- a/src/sdl/i_gamepad.c +++ b/src/sdl/i_gamepad.c @@ -233,7 +233,7 @@ static boolean Controller_OpenDevice(UINT8 which, INT32 devindex) CONS_Debug(DBG_GAMELOGIC, M_GetText(" Type: %s\n"), G_GamepadTypeToString(controller->info->type)); // Change the ring LEDs on Xbox 360 controllers - // FIXME: Doesn't seem to work? + // TODO: Doesn't seem to work? SDL_GameControllerSetPlayerIndex(controller->dev, which); // Check if rumble is supported @@ -248,11 +248,7 @@ static boolean Controller_OpenDevice(UINT8 which, INT32 devindex) CONS_Debug(DBG_GAMELOGIC, M_GetText(" Rumble supported: No\n"));; } - if (!controller->info->connected) - { - controller->info->connected = true; - G_OnGamepadConnect(which); - } + controller->info->connected = true; } return controller->started; From e5dea805fa6c66b151b9510703795bc0070a1ff1 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 26 Jan 2023 19:26:28 -0600 Subject: [PATCH 96/96] Revert "Merge branch 'gamepad-refactor' into next" This reverts commit 696e2ab9097a674716e579eb848024b0b8539205, reversing changes made to d98d59494f493307b3cae8d741e9a3969c2af2eb. --- src/Sourcefile | 1 - src/command.c | 81 +-- src/console.c | 9 +- src/d_clisrv.c | 89 ++- src/d_event.h | 14 +- src/d_main.c | 8 - src/d_netcmd.c | 140 ++--- src/d_netcmd.h | 12 +- src/deh_tables.c | 10 +- src/doomdef.h | 5 +- src/f_finale.c | 76 ++- src/g_demo.c | 6 +- src/g_game.c | 705 ++++++++++------------- src/g_game.h | 24 +- src/g_input.c | 1331 ++++++++++++------------------------------- src/g_input.h | 216 +------ src/hu_stuff.c | 22 +- src/i_gamepad.h | 58 -- src/i_joy.h | 58 ++ src/i_system.h | 94 ++- src/lua_inputlib.c | 9 +- src/m_cheat.c | 32 +- src/m_menu.c | 756 ++++++++++-------------- src/m_menu.h | 28 +- src/p_haptic.c | 115 ---- src/p_haptic.h | 27 - src/p_inter.c | 70 ++- src/p_local.h | 15 + src/p_user.c | 6 +- src/sdl/Sourcefile | 1 - src/sdl/i_gamepad.c | 914 ----------------------------- src/sdl/i_system.c | 767 ++++++++++++++++++++++++- src/sdl/i_video.c | 448 +++++++++++++-- src/sdl/sdlmain.h | 72 ++- 34 files changed, 2663 insertions(+), 3556 deletions(-) delete mode 100644 src/i_gamepad.h create mode 100644 src/i_joy.h delete mode 100644 src/p_haptic.c delete mode 100644 src/p_haptic.h delete mode 100644 src/sdl/i_gamepad.c diff --git a/src/Sourcefile b/src/Sourcefile index 9de90eee4..de90bb609 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -51,7 +51,6 @@ p_spec.c p_telept.c p_tick.c p_user.c -p_haptic.c p_slopes.c tables.c r_bsp.c diff --git a/src/command.c b/src/command.c index 201cceeee..b22f03d1a 100644 --- a/src/command.c +++ b/src/command.c @@ -77,6 +77,7 @@ CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}}; // Filter consvars by EXECVERSION // First implementation is 26 (2.1.21), so earlier configs default at 25 (2.1.20) +// Also set CV_HIDEN during runtime, after config is loaded static boolean execversion_enabled = false; consvar_t cv_execversion = CVAR_INIT ("execversion","25",CV_CALL,CV_Unsigned, CV_EnforceExecVersion); @@ -2233,12 +2234,12 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr) // reset all axis settings to defaults if (joyaxis_count == 6) { - COM_BufInsertText(va("%s \"%s\"\n", cv_turnaxis[0].name, cv_turnaxis[0].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_moveaxis[0].name, cv_moveaxis[0].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_sideaxis[0].name, cv_sideaxis[0].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_lookaxis[0].name, cv_lookaxis[0].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_fireaxis[0].name, cv_fireaxis[0].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_firenaxis[0].name, cv_firenaxis[0].defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_turnaxis.name, cv_turnaxis.defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_moveaxis.name, cv_moveaxis.defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_sideaxis.name, cv_sideaxis.defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_lookaxis.name, cv_lookaxis.defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_fireaxis.name, cv_fireaxis.defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_firenaxis.name, cv_firenaxis.defaultvalue)); joyaxis_count++; return false; } @@ -2292,12 +2293,12 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr) // reset all axis settings to defaults if (joyaxis2_count == 6) { - COM_BufInsertText(va("%s \"%s\"\n", cv_turnaxis[1].name, cv_turnaxis[1].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_moveaxis[1].name, cv_moveaxis[1].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_sideaxis[1].name, cv_sideaxis[1].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_lookaxis[1].name, cv_lookaxis[1].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_fireaxis[1].name, cv_fireaxis[1].defaultvalue)); - COM_BufInsertText(va("%s \"%s\"\n", cv_firenaxis[1].name, cv_firenaxis[1].defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_turnaxis2.name, cv_turnaxis2.defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_moveaxis2.name, cv_moveaxis2.defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_sideaxis2.name, cv_sideaxis2.defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_lookaxis2.name, cv_lookaxis2.defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_fireaxis2.name, cv_fireaxis2.defaultvalue)); + COM_BufInsertText(va("%s \"%s\"\n", cv_firenaxis2.name, cv_firenaxis2.defaultvalue)); joyaxis2_count++; return false; } @@ -2307,49 +2308,6 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr) return true; } -#ifndef OLD_GAMEPAD_AXES -static boolean CV_ConvertOldJoyAxisVars(consvar_t *v, const char *valstr) -{ - static struct { - const char *old; - const char *new; - } axis_names[] = { - {"X-Axis", "Left Stick X"}, - {"Y-Axis", "Left Stick Y"}, - {"X-Axis-", "Left Stick X-"}, - {"Y-Axis-", "Left Stick Y-"}, - {"X-Rudder", "Right Stick X"}, - {"Y-Rudder", "Right Stick Y"}, - {"X-Rudder-", "Right Stick X-"}, - {"Y-Rudder-", "Right Stick Y-"}, - {"Z-Axis", "Left Trigger"}, - {"Z-Rudder", "Right Trigger"}, - {"Z-Axis-", "Left Trigger"}, - {"Z-Rudder-", "Right Trigger"}, - {NULL, NULL} - }; - - if (v->PossibleValue != joyaxis_cons_t) - return true; - - for (unsigned i = 0;; i++) - { - if (axis_names[i].old == NULL) - { - CV_SetCVar(v, "None", false); - return false; - } - else if (!stricmp(valstr, axis_names[i].old)) - { - CV_SetCVar(v, axis_names[i].new, false); - return false; - } - } - - return true; -} -#endif - static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr) { // True means allow the CV change, False means block it @@ -2378,8 +2336,8 @@ static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr) && atoi(valstr) == 35) return false; - // GAMEPAD DEFAULTS - // use_gamepad was changed from 0 to 1 to automatically use a gamepad if available + // JOYSTICK DEFAULTS + // use_joystick was changed from 0 to 1 to automatically use a joystick if available #if defined(HAVE_SDL) || defined(_WINDOWS) if ((!stricmp(v->name, "use_joystick") || !stricmp(v->name, "use_joystick2")) @@ -2392,15 +2350,6 @@ static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr) if (!CV_FilterJoyAxisVars(v, valstr)) return false; } - -#ifndef OLD_GAMEPAD_AXES - if (GETMAJOREXECVERSION(cv_execversion.value) <= 51 && GETMINOREXECVERSION(cv_execversion.value) < 1) - { - if (!CV_ConvertOldJoyAxisVars(v, valstr)) - return false; - } -#endif - return true; } diff --git a/src/console.c b/src/console.c index 7cad4aee5..40fb43121 100644 --- a/src/console.c +++ b/src/console.c @@ -918,8 +918,7 @@ boolean CON_Responder(event_t *ev) static INT32 alias_skips; const char *cmd = NULL; - INT32 key = ev->key; - boolean key_is_console = (key == gamecontrol[GC_CONSOLE][0] || key == gamecontrol[GC_CONSOLE][1]); + INT32 key; if (chat_on) return false; @@ -927,18 +926,20 @@ boolean CON_Responder(event_t *ev) // let go keyup events, don't eat them if (ev->type != ev_keydown && ev->type != ev_console) { - if (key_is_console) + if (ev->key == gamecontrol[GC_CONSOLE][0] || ev->key == gamecontrol[GC_CONSOLE][1]) consdown = false; return false; } + key = ev->key; + // check for console toggle key if (ev->type != ev_console) { if (modeattacking || metalrecording || marathonmode) return false; - if (key_is_console) + if (key == gamecontrol[GC_CONSOLE][0] || key == gamecontrol[GC_CONSOLE][1]) { if (consdown) // ignore repeat return true; diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 3091f3344..1ff053e5c 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -25,8 +25,7 @@ #include "st_stuff.h" #include "hu_stuff.h" #include "keys.h" -#include "g_input.h" -#include "i_gamepad.h" +#include "g_input.h" // JOY1 #include "m_menu.h" #include "console.h" #include "d_netfil.h" @@ -34,7 +33,6 @@ #include "p_saveg.h" #include "z_zone.h" #include "p_local.h" -#include "p_haptic.h" #include "m_misc.h" #include "am_map.h" #include "m_random.h" @@ -51,7 +49,7 @@ #include "m_perfstats.h" // aaaaaa -#include "i_gamepad.h" +#include "i_joy.h" #ifndef NONET // cl loading screen @@ -655,6 +653,22 @@ static UINT8 Snake_GetOppositeDir(UINT8 dir) return 12 + 5 - dir; } +event_t *snakejoyevents[MAXEVENTS]; +UINT16 joyeventcount = 0; + +// I'm screaming the hack is clean - ashi +static boolean Snake_Joy_Grabber(event_t *ev) +{ + if (ev->type == ev_joystick && ev->key == 0) + { + snakejoyevents[joyeventcount] = ev; + joyeventcount++; + return true; + } + else + return false; +} + static void Snake_FindFreeSlot(UINT8 *freex, UINT8 *freey, UINT8 headx, UINT8 heady) { UINT8 x, y; @@ -681,17 +695,19 @@ static void Snake_Handle(void) UINT8 x, y; UINT8 oldx, oldy; UINT16 i; + UINT16 j; UINT16 joystate = 0; + static INT32 pjoyx = 0, pjoyy = 0; // Handle retry - if (snake->gameover && (G_PlayerInputDown(0, GC_JUMP) || gamekeydown[KEY_ENTER])) + if (snake->gameover && (PLAYER1INPUTDOWN(GC_JUMP) || gamekeydown[KEY_ENTER])) { Snake_Initialise(); snake->pausepressed = true; // Avoid accidental pause on respawn } // Handle pause - if (G_PlayerInputDown(0, GC_PAUSE) || gamekeydown[KEY_ENTER]) + if (PLAYER1INPUTDOWN(GC_PAUSE) || gamekeydown[KEY_ENTER]) { if (!snake->pausepressed) snake->paused = !snake->paused; @@ -710,23 +726,58 @@ static void Snake_Handle(void) oldx = snake->snakex[1]; oldy = snake->snakey[1]; + // process the input events in here dear lord + for (j = 0; j < joyeventcount; j++) + { + event_t *ev = snakejoyevents[j]; + const INT32 jdeadzone = (JOYAXISRANGE * cv_digitaldeadzone.value) / FRACUNIT; + if (ev->y != INT32_MAX) + { + if (Joystick.bGamepadStyle || abs(ev->y) > jdeadzone) + { + if (ev->y < 0 && pjoyy >= 0) + joystate = 1; + else if (ev->y > 0 && pjoyy <= 0) + joystate = 2; + pjoyy = ev->y; + } + else + pjoyy = 0; + } + + if (ev->x != INT32_MAX) + { + if (Joystick.bGamepadStyle || abs(ev->x) > jdeadzone) + { + if (ev->x < 0 && pjoyx >= 0) + joystate = 3; + else if (ev->x > 0 && pjoyx <= 0) + joystate = 4; + pjoyx = ev->x; + } + else + pjoyx = 0; + } + } + joyeventcount = 0; + // Update direction - if (G_PlayerInputDown(0, GC_STRAFELEFT) || gamekeydown[KEY_LEFTARROW] || joystate == 3) + if (PLAYER1INPUTDOWN(GC_STRAFELEFT) || gamekeydown[KEY_LEFTARROW] || joystate == 3) { if (snake->snakelength < 2 || x <= oldx) snake->snakedir[0] = 1; } - else if (G_PlayerInputDown(0, GC_STRAFERIGHT) || gamekeydown[KEY_RIGHTARROW] || joystate == 4) + else if (PLAYER1INPUTDOWN(GC_STRAFERIGHT) || gamekeydown[KEY_RIGHTARROW] || joystate == 4) { if (snake->snakelength < 2 || x >= oldx) snake->snakedir[0] = 2; } - else if (G_PlayerInputDown(0, GC_FORWARD) || gamekeydown[KEY_UPARROW] || joystate == 1) + else if (PLAYER1INPUTDOWN(GC_FORWARD) || gamekeydown[KEY_UPARROW] || joystate == 1) { if (snake->snakelength < 2 || y <= oldy) snake->snakedir[0] = 3; } - else if (G_PlayerInputDown(0, GC_BACKWARD) || gamekeydown[KEY_DOWNARROW] || joystate == 2) + else if (PLAYER1INPUTDOWN(GC_BACKWARD) || gamekeydown[KEY_DOWNARROW] || joystate == 2) { if (snake->snakelength < 2 || y >= oldy) snake->snakedir[0] = 4; @@ -1652,8 +1703,6 @@ static void CL_LoadReceivedSavegame(boolean reloading) titledemo = false; automapactive = false; - P_StopRumble(NULL); - // load a base level if (P_LoadNetGame(reloading)) { @@ -1940,10 +1989,9 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room) static void M_ConfirmConnect(event_t *ev) { #ifndef NONET - - if (ev->type == ev_keydown || ev->type == ev_gamepad_down) + if (ev->type == ev_keydown) { - if ((ev->type == ev_keydown && (ev->key == ' ' || ev->key == 'y' || ev->key == KEY_ENTER)) || (ev->type == ev_gamepad_down && ev->which == 0 && ev->key == GAMEPAD_BUTTON_A)) + if (ev->key == ' ' || ev->key == 'y' || ev->key == KEY_ENTER || ev->key == KEY_JOY1) { if (totalfilesrequestednum > 0) { @@ -1958,7 +2006,7 @@ static void M_ConfirmConnect(event_t *ev) M_ClearMenus(true); } - else if ((ev->type == ev_keydown && (ev->key == 'n' || ev->key == KEY_ESCAPE)) || (ev->type == ev_gamepad_down && ev->which == 0 && ev->key == GAMEPAD_BUTTON_B)) + else if (ev->key == 'n' || ev->key == KEY_ESCAPE || ev->key == KEY_JOY1 + 3) { cl_mode = CL_ABORTED; M_ClearMenus(true); @@ -2392,11 +2440,14 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic // my hand has been forced and I am dearly sorry for this awful hack :vomit: for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) { - G_MapEventsToControls(&events[eventtail]); +#ifndef NONET + if (!Snake_Joy_Grabber(&events[eventtail])) +#endif + G_MapEventsToControls(&events[eventtail]); } } - if (gamekeydown[KEY_ESCAPE] || gamepads[0].buttons[GAMEPAD_BUTTON_B] || cl_mode == CL_ABORTED) + if (gamekeydown[KEY_ESCAPE] || gamekeydown[KEY_JOY1+1] || cl_mode == CL_ABORTED) { CONS_Printf(M_GetText("Network game synchronization aborted.\n")); M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); @@ -5179,7 +5230,7 @@ static void Local_Maketic(INT32 realtics) // game responder calls HU_Responder, AM_Responder, // and G_MapEventsToControls if (!dedicated) rendergametic = gametic; - // translate inputs (keyboard/mouse/gamepad) into game controls + // translate inputs (keyboard/mouse/joystick) into game controls G_BuildTiccmd(&localcmds, realtics, 1); if (splitscreen || botingame) G_BuildTiccmd(&localcmds2, realtics, 2); diff --git a/src/d_event.h b/src/d_event.h index 9448b9c5a..c0b9cef77 100644 --- a/src/d_event.h +++ b/src/d_event.h @@ -24,21 +24,19 @@ typedef enum ev_keyup, ev_console, ev_mouse, + ev_joystick, ev_mouse2, - ev_gamepad_up, - ev_gamepad_down, - ev_gamepad_axis + ev_joystick2, } evtype_t; // Event structure. typedef struct { evtype_t type; - INT32 key; // key, mouse button, or gamepad button/axis type - INT32 x; // mouse x move, or gamepad axis value - INT32 y; // mouse y move - UINT8 which; // which gamepad or mouse ID - boolean repeated; // is the event repeated? + INT32 key; // keys/mouse/joystick buttons + INT32 x; // mouse/joystick x move + INT32 y; // mouse/joystick y move + boolean repeated; // key repeat } event_t; // diff --git a/src/d_main.c b/src/d_main.c index 1af8d090c..3566e7f3d 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -43,7 +43,6 @@ #include "i_time.h" #include "i_threads.h" #include "i_video.h" -#include "i_gamepad.h" #include "m_argv.h" #include "m_menu.h" #include "m_misc.h" @@ -987,7 +986,6 @@ void D_StartTitle(void) G_SetGametype(GT_COOP); paused = false; advancedemo = false; - P_StopRumble(NULL); F_InitMenuPresValues(); F_StartTitleScreen(); @@ -1398,9 +1396,6 @@ void D_SRB2Main(void) CONS_Printf("I_InitializeTime()...\n"); I_InitializeTime(); - // Initializes the game logic side of gamepads - G_InitGamepads(); - // Make backups of some SOCcable tables. P_BackupTables(); @@ -1456,9 +1451,6 @@ void D_SRB2Main(void) D_RegisterServerCommands(); D_RegisterClientCommands(); // be sure that this is called before D_CheckNetGame - - I_InitGamepads(); - R_RegisterEngineStuff(); S_RegisterSoundStuff(); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 07dba1777..f63f38a74 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -21,7 +21,6 @@ #include "g_game.h" #include "hu_stuff.h" #include "g_input.h" -#include "i_gamepad.h" #include "m_menu.h" #include "r_local.h" #include "r_skins.h" @@ -183,6 +182,14 @@ static CV_PossibleValue_t mouse2port_cons_t[] = {{1, "COM1"}, {2, "COM2"}, {3, " {0, NULL}}; #endif +#ifdef LJOYSTICK +static CV_PossibleValue_t joyport_cons_t[] = {{1, "/dev/js0"}, {2, "/dev/js1"}, {3, "/dev/js2"}, + {4, "/dev/js3"}, {0, NULL}}; +#else +// accept whatever value - it is in fact the joystick device number +#define usejoystick_cons_t NULL +#endif + static CV_PossibleValue_t teamscramble_cons_t[] = {{0, "Off"}, {1, "Random"}, {2, "Points"}, {0, NULL}}; static CV_PossibleValue_t startingliveslimit_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, NULL}}; @@ -241,61 +248,19 @@ INT32 cv_debug; consvar_t cv_usemouse = CVAR_INIT ("use_mouse", "On", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse); consvar_t cv_usemouse2 = CVAR_INIT ("use_mouse2", "Off", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse2); -// We use cv_usegamepad.string as the USER-SET var -// and cv_usegamepad.value as the INTERNAL var -// -// In practice, if cv_usegamepad.string == 0, this overrides -// cv_usegamepad.value and always disables - -static void UseGamepad_OnChange(void) -{ - I_ChangeGamepad(0); -} - -static void UseGamepad2_OnChange(void) -{ - I_ChangeGamepad(1); -} - -consvar_t cv_usegamepad[2] = { - CVAR_INIT ("use_gamepad", "1", CV_SAVE|CV_CALL, NULL, UseGamepad_OnChange), - CVAR_INIT ("use_gamepad2", "2", CV_SAVE|CV_CALL, NULL, UseGamepad2_OnChange) -}; - -static void PadScale_OnChange(void) -{ - I_SetGamepadDigital(0, cv_gamepad_scale[0].value == 0); -} - -static void PadScale2_OnChange(void) -{ - I_SetGamepadDigital(1, cv_gamepad_scale[1].value == 0); -} - -consvar_t cv_gamepad_scale[2] = { - CVAR_INIT ("padscale", "1", CV_SAVE|CV_CALL, NULL, PadScale_OnChange), - CVAR_INIT ("padscale2", "1", CV_SAVE|CV_CALL, NULL, PadScale2_OnChange) -}; - -static void PadRumble_OnChange(void) -{ - if (!cv_gamepad_rumble[0].value) - I_StopGamepadRumble(0); -} - -static void PadRumble2_OnChange(void) -{ - if (!cv_gamepad_rumble[1].value) - I_StopGamepadRumble(1); -} - -consvar_t cv_gamepad_rumble[2] = { - CVAR_INIT ("padrumble", "Off", CV_SAVE|CV_CALL, CV_OnOff, PadRumble_OnChange), - CVAR_INIT ("padrumble2", "Off", CV_SAVE|CV_CALL, CV_OnOff, PadRumble2_OnChange) -}; - -consvar_t cv_gamepad_autopause = CVAR_INIT ("pauseongamepaddisconnect", "On", CV_SAVE, CV_OnOff, NULL); - +consvar_t cv_usejoystick = CVAR_INIT ("use_gamepad", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick); +consvar_t cv_usejoystick2 = CVAR_INIT ("use_gamepad2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick2); +#if (defined (LJOYSTICK) || defined (HAVE_SDL)) +#ifdef LJOYSTICK +consvar_t cv_joyport = CVAR_INIT ("padport", "/dev/js0", CV_SAVE, joyport_cons_t, NULL); +consvar_t cv_joyport2 = CVAR_INIT ("padport2", "/dev/js0", CV_SAVE, joyport_cons_t, NULL); //Alam: for later +#endif +consvar_t cv_joyscale = CVAR_INIT ("padscale", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale); +consvar_t cv_joyscale2 = CVAR_INIT ("padscale2", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale2); +#else +consvar_t cv_joyscale = CVAR_INIT ("padscale", "1", CV_SAVE|CV_HIDEN, NULL, NULL); //Alam: Dummy for save +consvar_t cv_joyscale2 = CVAR_INIT ("padscale2", "1", CV_SAVE|CV_HIDEN, NULL, NULL); //Alam: Dummy for save +#endif #if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON) consvar_t cv_mouse2port = CVAR_INIT ("mouse2port", "/dev/gpmdata", CV_SAVE, mouse2port_cons_t, NULL); consvar_t cv_mouse2opt = CVAR_INIT ("mouse2opt", "0", CV_SAVE, NULL, NULL); @@ -807,26 +772,26 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_pauseifunfocused); // g_input.c - CV_RegisterVar(&cv_sideaxis[0]); - CV_RegisterVar(&cv_sideaxis[1]); - CV_RegisterVar(&cv_turnaxis[0]); - CV_RegisterVar(&cv_turnaxis[1]); - CV_RegisterVar(&cv_moveaxis[0]); - CV_RegisterVar(&cv_moveaxis[1]); - CV_RegisterVar(&cv_lookaxis[0]); - CV_RegisterVar(&cv_lookaxis[1]); - CV_RegisterVar(&cv_jumpaxis[0]); - CV_RegisterVar(&cv_jumpaxis[1]); - CV_RegisterVar(&cv_spinaxis[0]); - CV_RegisterVar(&cv_spinaxis[1]); - CV_RegisterVar(&cv_fireaxis[0]); - CV_RegisterVar(&cv_fireaxis[1]); - CV_RegisterVar(&cv_firenaxis[0]); - CV_RegisterVar(&cv_firenaxis[1]); - CV_RegisterVar(&cv_deadzone[0]); - CV_RegisterVar(&cv_deadzone[1]); - CV_RegisterVar(&cv_digitaldeadzone[0]); - CV_RegisterVar(&cv_digitaldeadzone[1]); + CV_RegisterVar(&cv_sideaxis); + CV_RegisterVar(&cv_sideaxis2); + CV_RegisterVar(&cv_turnaxis); + CV_RegisterVar(&cv_turnaxis2); + CV_RegisterVar(&cv_moveaxis); + CV_RegisterVar(&cv_moveaxis2); + CV_RegisterVar(&cv_lookaxis); + CV_RegisterVar(&cv_lookaxis2); + CV_RegisterVar(&cv_jumpaxis); + CV_RegisterVar(&cv_jumpaxis2); + CV_RegisterVar(&cv_spinaxis); + CV_RegisterVar(&cv_spinaxis2); + CV_RegisterVar(&cv_fireaxis); + CV_RegisterVar(&cv_fireaxis2); + CV_RegisterVar(&cv_firenaxis); + CV_RegisterVar(&cv_firenaxis2); + CV_RegisterVar(&cv_deadzone); + CV_RegisterVar(&cv_deadzone2); + CV_RegisterVar(&cv_digitaldeadzone); + CV_RegisterVar(&cv_digitaldeadzone2); // filesrch.c CV_RegisterVar(&cv_addons_option); @@ -855,14 +820,14 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_mousemove); CV_RegisterVar(&cv_mousemove2); - for (i = 0; i < 2; i++) - { - CV_RegisterVar(&cv_usegamepad[i]); - CV_RegisterVar(&cv_gamepad_scale[i]); - CV_RegisterVar(&cv_gamepad_rumble[i]); - } - - CV_RegisterVar(&cv_gamepad_autopause); + CV_RegisterVar(&cv_usejoystick); + CV_RegisterVar(&cv_usejoystick2); +#ifdef LJOYSTICK + CV_RegisterVar(&cv_joyport); + CV_RegisterVar(&cv_joyport2); +#endif + CV_RegisterVar(&cv_joyscale); + CV_RegisterVar(&cv_joyscale2); // Analog Control CV_RegisterVar(&cv_analog[0]); @@ -2251,14 +2216,9 @@ static void Got_Pause(UINT8 **cp, INT32 playernum) { if (!menuactive || netgame) S_PauseAudio(); - - P_PauseRumble(NULL); } else - { S_ResumeAudio(); - P_UnpauseRumble(NULL); - } } I_UpdateMouseGrab(); @@ -4653,8 +4613,6 @@ void Command_ExitGame_f(void) emeralds = 0; memset(&luabanks, 0, sizeof(luabanks)); - P_StopRumble(NULL); - if (dirmenu) closefilemenu(true); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 47f68a17e..0beeae154 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -33,10 +33,14 @@ extern consvar_t cv_defaultskin2; extern consvar_t cv_seenames, cv_allowseenames; extern consvar_t cv_usemouse; -extern consvar_t cv_usegamepad[2]; -extern consvar_t cv_gamepad_scale[2]; -extern consvar_t cv_gamepad_rumble[2]; -extern consvar_t cv_gamepad_autopause; +extern consvar_t cv_usejoystick; +extern consvar_t cv_usejoystick2; +#ifdef LJOYSTICK +extern consvar_t cv_joyport; +extern consvar_t cv_joyport2; +#endif +extern consvar_t cv_joyscale; +extern consvar_t cv_joyscale2; // splitscreen with second mouse extern consvar_t cv_mouse2port; diff --git a/src/deh_tables.c b/src/deh_tables.c index a2cc9732d..4a3467f78 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -22,9 +22,9 @@ #include "v_video.h" // video flags (for lua) #include "i_sound.h" // musictype_t (for lua) #include "g_state.h" // gamestate_t (for lua) -#include "g_game.h" // Gamepad axes (for lua) +#include "g_game.h" // Joystick axes (for lua) +#include "i_joy.h" #include "g_input.h" // Game controls (for lua) -#include "i_gamepad.h" #include "deh_tables.h" @@ -4841,7 +4841,7 @@ const char *const MENUTYPES_LIST[] = { "OP_CHANGECONTROLS", // OP_ChangeControlsDef shared with P2 "OP_P1MOUSE", "OP_P1JOYSTICK", - "OP_JOYSTICKSET", // OP_GamepadSetDef shared with P2 + "OP_JOYSTICKSET", // OP_JoystickSetDef shared with P2 "OP_P1CAMERA", "OP_P2CONTROLS", @@ -5642,7 +5642,7 @@ struct int_const_s const INT_CONST[] = { {"GS_DEDICATEDSERVER",GS_DEDICATEDSERVER}, {"GS_WAITINGPLAYERS",GS_WAITINGPLAYERS}, - // Gamepad axes + // Joystick axes {"JA_NONE",JA_NONE}, {"JA_TURN",JA_TURN}, {"JA_MOVE",JA_MOVE}, @@ -5653,7 +5653,7 @@ struct int_const_s const INT_CONST[] = { {"JA_SPIN",JA_SPIN}, {"JA_FIRE",JA_FIRE}, {"JA_FIRENORMAL",JA_FIRENORMAL}, - {"JOYAXISRANGE",OLDJOYAXISRANGE}, + {"JOYAXISRANGE",JOYAXISRANGE}, // Game controls {"GC_NULL",GC_NULL}, diff --git a/src/doomdef.h b/src/doomdef.h index 24b4fa980..2b62bcd6e 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -209,7 +209,7 @@ extern char logfilename[1024]; // to an increment in MODVERSION. This might never happen in practice. // If MODVERSION increases, set MINOREXECVERSION to 0. #define MAJOREXECVERSION MODVERSION -#define MINOREXECVERSION 1 +#define MINOREXECVERSION 0 // (It would have been nice to use VERSION and SUBVERSION but those are zero'd out for DEVELOP builds) // Macros @@ -556,6 +556,9 @@ UINT32 quickncasehash (const char *p, size_t n) #define max(x, y) (((x) > (y)) ? (x) : (y)) #endif +// Max gamepad/joysticks that can be detected/used. +#define MAX_JOYSTICKS 4 + #ifndef M_PIl #define M_PIl 3.1415926535897932384626433832795029L #endif diff --git a/src/f_finale.c b/src/f_finale.c index 307e00aaa..bca8e3ba6 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -37,7 +37,6 @@ #include "m_cond.h" #include "p_local.h" #include "p_setup.h" -#include "p_haptic.h" #include "st_stuff.h" // hud hiding #include "fastcmp.h" #include "console.h" @@ -511,7 +510,6 @@ void F_StartIntro(void) gameaction = ga_nothing; paused = false; CON_ToggleOff(); - P_StopRumble(NULL); F_NewCutscene(introtext[0]); intro_scenenum = 0; @@ -993,10 +991,9 @@ void F_IntroTicker(void) // boolean F_IntroResponder(event_t *event) { - INT32 type = event->type; - INT32 key = G_RemapGamepadEvent(event, &type); + INT32 key = event->key; - // remap virtual keys (mouse & gamepad buttons) + // remap virtual keys (mouse & joystick buttons) switch (key) { case KEY_MOUSE1: @@ -1005,30 +1002,34 @@ boolean F_IntroResponder(event_t *event) case KEY_MOUSE1 + 1: key = KEY_BACKSPACE; break; - case GAMEPAD_KEY(START): - case GAMEPAD_KEY(A): - case GAMEPAD_KEY(X): - case GAMEPAD_KEY(B): + case KEY_JOY1: + case KEY_JOY1 + 2: key = KEY_ENTER; break; - case GAMEPAD_KEY(DPAD_UP): + case KEY_JOY1 + 3: + key = 'n'; + break; + case KEY_JOY1 + 1: + key = KEY_BACKSPACE; + break; + case KEY_HAT1: key = KEY_UPARROW; break; - case GAMEPAD_KEY(DPAD_DOWN): + case KEY_HAT1 + 1: key = KEY_DOWNARROW; break; - case GAMEPAD_KEY(DPAD_LEFT): + case KEY_HAT1 + 2: key = KEY_LEFTARROW; break; - case GAMEPAD_KEY(DPAD_RIGHT): + case KEY_HAT1 + 3: key = KEY_RIGHTARROW; break; } - if (type != ev_keydown) + if (event->type != ev_keydown && key != 301) return false; - if (key != KEY_ESCAPE && key != KEY_ENTER && key != KEY_SPACE && key != KEY_BACKSPACE) + if (key != 27 && key != KEY_ENTER && key != KEY_SPACE && key != KEY_BACKSPACE) return false; if (keypressed) @@ -1263,7 +1264,6 @@ void F_StartCredits(void) gameaction = ga_nothing; paused = false; CON_ToggleOff(); - P_StopRumble(NULL); S_StopMusic(); S_StopSounds(); @@ -1376,10 +1376,9 @@ void F_CreditTicker(void) boolean F_CreditResponder(event_t *event) { - INT32 type = event->type; - INT32 key = G_RemapGamepadEvent(event, &type); + INT32 key = event->key; - // remap virtual keys (mouse & gamepad buttons) + // remap virtual keys (mouse & joystick buttons) switch (key) { case KEY_MOUSE1: @@ -1388,22 +1387,26 @@ boolean F_CreditResponder(event_t *event) case KEY_MOUSE1 + 1: key = KEY_BACKSPACE; break; - case GAMEPAD_KEY(START): - case GAMEPAD_KEY(A): - case GAMEPAD_KEY(X): - case GAMEPAD_KEY(B): + case KEY_JOY1: + case KEY_JOY1 + 2: key = KEY_ENTER; break; - case GAMEPAD_KEY(DPAD_UP): + case KEY_JOY1 + 3: + key = 'n'; + break; + case KEY_JOY1 + 1: + key = KEY_BACKSPACE; + break; + case KEY_HAT1: key = KEY_UPARROW; break; - case GAMEPAD_KEY(DPAD_DOWN): + case KEY_HAT1 + 1: key = KEY_DOWNARROW; break; - case GAMEPAD_KEY(DPAD_LEFT): + case KEY_HAT1 + 2: key = KEY_LEFTARROW; break; - case GAMEPAD_KEY(DPAD_RIGHT): + case KEY_HAT1 + 3: key = KEY_RIGHTARROW; break; } @@ -1411,7 +1414,7 @@ boolean F_CreditResponder(event_t *event) if (!(timesBeaten) && !(netgame || multiplayer) && !cv_debug) return false; - if (type != ev_keydown) + if (event->type != ev_keydown) return false; if (key != KEY_ESCAPE && key != KEY_ENTER && key != KEY_SPACE && key != KEY_BACKSPACE) @@ -1452,7 +1455,6 @@ void F_StartGameEvaluation(void) gameaction = ga_nothing; paused = false; CON_ToggleOff(); - P_StopRumble(NULL); finalecount = -1; sparklloop = 0; @@ -1778,7 +1780,6 @@ void F_StartEnding(void) gameaction = ga_nothing; paused = false; CON_ToggleOff(); - P_StopRumble(NULL); S_StopMusic(); // todo: placeholder S_StopSounds(); @@ -2224,7 +2225,6 @@ void F_StartGameEnd(void) paused = false; CON_ToggleOff(); S_StopSounds(); - P_StopRumble(NULL); // In case menus are still up?!! M_ClearMenus(true); @@ -3567,7 +3567,6 @@ void F_StartContinue(void) keypressed = false; paused = false; CON_ToggleOff(); - P_StopRumble(NULL); // In case menus are still up?!! M_ClearMenus(true); @@ -3820,26 +3819,24 @@ void F_ContinueTicker(void) boolean F_ContinueResponder(event_t *event) { + INT32 key = event->key; + if (keypressed) return true; - INT32 type = event->type; - INT32 key = G_RemapGamepadEvent(event, &type); - if (timetonext >= 21*TICRATE/2) return false; if (event->type != ev_keydown) return false; - // remap virtual keys (mouse & gamepad buttons) + // remap virtual keys (mouse & joystick buttons) switch (key) { case KEY_ENTER: case KEY_SPACE: case KEY_MOUSE1: - case GAMEPAD_KEY(START): - case GAMEPAD_KEY(A): - case GAMEPAD_KEY(X): + case KEY_JOY1: + case KEY_JOY1 + 2: break; default: return false; @@ -3957,7 +3954,6 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset gameaction = ga_nothing; paused = false; CON_ToggleOff(); - P_StopRumble(NULL); F_NewCutscene(cutscenes[cutscenenum]->scene[0].text); diff --git a/src/g_demo.c b/src/g_demo.c index 9099adc71..2da5a76ab 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -32,7 +32,7 @@ #include "z_zone.h" #include "i_video.h" #include "byteptr.h" -#include "i_gamepad.h" +#include "i_joy.h" #include "r_local.h" #include "r_skins.h" #include "y_inter.h" @@ -1527,9 +1527,9 @@ void G_BeginRecording(void) buf |= 0x08; pflags |= PF_AUTOBRAKE; } - if (cv_usegamepad[0].value) + if (cv_usejoystick.value) buf |= 0x10; - CV_SetValue(&cv_showinputjoy, !!(cv_usegamepad[0].value)); + CV_SetValue(&cv_showinputjoy, !!(cv_usejoystick.value)); WRITEUINT8(demo_p,buf); player->pflags = pflags; diff --git a/src/g_game.c b/src/g_game.c index ce41ccaf6..74bc42711 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -24,7 +24,6 @@ #include "am_map.h" #include "m_random.h" #include "p_local.h" -#include "p_haptic.h" #include "r_draw.h" #include "r_main.h" #include "s_sound.h" @@ -39,7 +38,7 @@ #include "z_zone.h" #include "i_video.h" #include "byteptr.h" -#include "i_gamepad.h" +#include "i_joy.h" #include "r_local.h" #include "r_skins.h" #include "y_inter.h" @@ -60,6 +59,9 @@ boolean botingame; UINT8 botskin; UINT16 botcolor; +JoyType_t Joystick; +JoyType_t Joystick2; + // 1024 bytes is plenty for a savegame #define SAVEGAMESIZE (1024) @@ -254,6 +256,12 @@ UINT32 timesBeaten; UINT32 timesBeatenWithEmeralds; UINT32 timesBeatenUltimate; +typedef struct joystickvector2_s +{ + INT32 xaxis; + INT32 yaxis; +} joystickvector2_t; + boolean precache = true; // if true, load all graphics at start INT16 prevmap, nextmap; @@ -272,42 +280,21 @@ static void AutoBrake2_OnChange(void); void SendWeaponPref(void); void SendWeaponPref2(void); -CV_PossibleValue_t joyaxis_cons_t[] = {{0, "None"}, -#ifndef OLD_GAMEPAD_AXES - {1, "Left Stick X"}, {2, "Left Stick Y"}, - {3, "Right Stick X"},{4, "Right Stick Y"}, - {-1, "Left Stick X-"}, {-2, "Left Stick Y-"}, - {-3, "Right Stick X-"}, {-4, "Right Stick Y-"}, - {5, "Left Trigger"}, {6, "Right Trigger"}, -#else - {1, "X-Axis"}, {2, "Y-Axis"}, {-1, "X-Axis-"}, {-2, "Y-Axis-"}, - #if JOYAXISSET > 1 - {3, "Z-Axis"}, {4, "X-Rudder"}, {-3, "Z-Axis-"}, {-4, "X-Rudder-"}, - #endif - #if JOYAXISSET > 2 - {5, "Y-Rudder"}, {6, "Z-Rudder"}, {-5, "Y-Rudder-"}, {-6, "Z-Rudder-"}, - #endif - #if JOYAXISSET > 3 - {7, "U-Axis"}, {8, "V-Axis"}, {-7, "U-Axis-"}, {-8, "V-Axis-"}, - #endif +static CV_PossibleValue_t crosshair_cons_t[] = {{0, "Off"}, {1, "Cross"}, {2, "Angle"}, {3, "Point"}, {0, NULL}}; +static CV_PossibleValue_t joyaxis_cons_t[] = {{0, "None"}, +{1, "X-Axis"}, {2, "Y-Axis"}, {-1, "X-Axis-"}, {-2, "Y-Axis-"}, +#if JOYAXISSET > 1 +{3, "Z-Axis"}, {4, "X-Rudder"}, {-3, "Z-Axis-"}, {-4, "X-Rudder-"}, #endif - {0, NULL} -}; - -#ifndef OLD_GAMEPAD_AXES -#define MOVEAXIS_DEFAULT "Left Stick Y" -#define SIDEAXIS_DEFAULT "Left Stick X" -#define LOOKAXIS_DEFAULT "Right Stick Y-" -#define TURNAXIS_DEFAULT "Right Stick X" -#define FIREAXIS_DEFAULT "Right Trigger" -#define FIRENAXIS_DEFAULT "Left Trigger" -#else -#define MOVEAXIS_DEFAULT "Y-Axis" -#define SIDEAXIS_DEFAULT "X-Axis" -#define LOOKAXIS_DEFAULT "Y-Rudder-" -#define TURNAXIS_DEFAULT "X-Rudder" -#define FIREAXIS_DEFAULT "Z-Rudder" -#define FIRENAXIS_DEFAULT "Z-Axis" +#if JOYAXISSET > 2 +{5, "Y-Rudder"}, {6, "Z-Rudder"}, {-5, "Y-Rudder-"}, {-6, "Z-Rudder-"}, +#endif +#if JOYAXISSET > 3 +{7, "U-Axis"}, {8, "V-Axis"}, {-7, "U-Axis-"}, {-8, "V-Axis-"}, +#endif + {0, NULL}}; +#if JOYAXISSET > 4 +"More Axis Sets" #endif // don't mind me putting these here, I was lazy to figure out where else I could put those without blowing up the compiler. @@ -343,7 +330,6 @@ consvar_t cv_consolechat = CVAR_INIT ("chatmode", "Window", CV_SAVE, consolechat // Pause game upon window losing focus consvar_t cv_pauseifunfocused = CVAR_INIT ("pauseifunfocused", "Yes", CV_SAVE, CV_YesNo, NULL); -static CV_PossibleValue_t crosshair_cons_t[] = {{0, "Off"}, {1, "Cross"}, {2, "Angle"}, {3, "Point"}, {0, NULL}}; consvar_t cv_crosshair = CVAR_INIT ("crosshair", "Cross", CV_SAVE, crosshair_cons_t, NULL); consvar_t cv_crosshair2 = CVAR_INIT ("crosshair2", "Cross", CV_SAVE, crosshair_cons_t, NULL); consvar_t cv_invertmouse = CVAR_INIT ("invertmouse", "Off", CV_SAVE, CV_OnOff, NULL); @@ -423,46 +409,27 @@ consvar_t cv_cam_lockonboss[2] = { CVAR_INIT ("cam2_lockaimassist", "Full", CV_SAVE, lockedassist_cons_t, NULL), }; -consvar_t cv_moveaxis[2] = { - CVAR_INIT ("joyaxis_move", MOVEAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL), - CVAR_INIT ("joyaxis2_move", MOVEAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL) -}; -consvar_t cv_sideaxis[2] = { - CVAR_INIT ("joyaxis_side", SIDEAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL), - CVAR_INIT ("joyaxis2_side", SIDEAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL) -}; -consvar_t cv_lookaxis[2] = { - CVAR_INIT ("joyaxis_look", LOOKAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL), - CVAR_INIT ("joyaxis2_look", LOOKAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL) -}; -consvar_t cv_turnaxis[2] = { - CVAR_INIT ("joyaxis_turn", TURNAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL), - CVAR_INIT ("joyaxis2_turn", TURNAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL) -}; -consvar_t cv_jumpaxis[2] = { - CVAR_INIT ("joyaxis_jump", "None", CV_SAVE, joyaxis_cons_t, NULL), - CVAR_INIT ("joyaxis2_jump", "None", CV_SAVE, joyaxis_cons_t, NULL) -}; -consvar_t cv_spinaxis[2] = { - CVAR_INIT ("joyaxis_spin", "None", CV_SAVE, joyaxis_cons_t, NULL), - CVAR_INIT ("joyaxis2_spin", "None", CV_SAVE, joyaxis_cons_t, NULL) -}; -consvar_t cv_fireaxis[2] = { - CVAR_INIT ("joyaxis_fire", FIREAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL), - CVAR_INIT ("joyaxis2_fire", FIREAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL) -}; -consvar_t cv_firenaxis[2] = { - CVAR_INIT ("joyaxis_firenormal", FIRENAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL), - CVAR_INIT ("joyaxis2_firenormal", FIRENAXIS_DEFAULT, CV_SAVE, joyaxis_cons_t, NULL) -}; -consvar_t cv_deadzone[2] = { - CVAR_INIT ("joy_deadzone", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), - CVAR_INIT ("joy_deadzone2", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL) -}; -consvar_t cv_digitaldeadzone[2] = { - CVAR_INIT ("joy_digdeadzone", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), - CVAR_INIT ("joy_digdeadzone2", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL) -}; +consvar_t cv_moveaxis = CVAR_INIT ("joyaxis_move", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_sideaxis = CVAR_INIT ("joyaxis_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_lookaxis = CVAR_INIT ("joyaxis_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_turnaxis = CVAR_INIT ("joyaxis_turn", "X-Rudder", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_jumpaxis = CVAR_INIT ("joyaxis_jump", "None", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_spinaxis = CVAR_INIT ("joyaxis_spin", "None", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_fireaxis = CVAR_INIT ("joyaxis_fire", "Z-Rudder", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_firenaxis = CVAR_INIT ("joyaxis_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_deadzone = CVAR_INIT ("joy_deadzone", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL); +consvar_t cv_digitaldeadzone = CVAR_INIT ("joy_digdeadzone", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL); + +consvar_t cv_moveaxis2 = CVAR_INIT ("joyaxis2_move", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_sideaxis2 = CVAR_INIT ("joyaxis2_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_lookaxis2 = CVAR_INIT ("joyaxis2_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_turnaxis2 = CVAR_INIT ("joyaxis2_turn", "X-Rudder", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_jumpaxis2 = CVAR_INIT ("joyaxis2_jump", "None", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_spinaxis2 = CVAR_INIT ("joyaxis2_spin", "None", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_fireaxis2 = CVAR_INIT ("joyaxis2_fire", "Z-Rudder", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_firenaxis2 = CVAR_INIT ("joyaxis2_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_deadzone2 = CVAR_INIT ("joy_deadzone2", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL); +consvar_t cv_digitaldeadzone2 = CVAR_INIT ("joy_digdeadzone2", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL); player_t *seenplayer; // player we're aiming at right now @@ -861,171 +828,194 @@ INT16 G_SoftwareClipAimingPitch(INT32 *aiming) return (INT16)((*aiming)>>16); } -#ifdef OLD_GAMEPAD_AXES -static gamepad_axis_e ConvertXboxControllerAxes(int type) -{ - switch (type) - { - // Left stick - case 1: // X-Axis - return GAMEPAD_AXIS_LEFTX; - case 2: // Y-Axis - return GAMEPAD_AXIS_LEFTY; - - // Right stick - case 4: // X-Rudder - return GAMEPAD_AXIS_RIGHTX; - case 5: // Y-Rudder - return GAMEPAD_AXIS_RIGHTY; - - // Triggers - case 3: // Z-Axis - return GAMEPAD_AXIS_TRIGGERLEFT; - case 6: // Z-Rudder - return GAMEPAD_AXIS_TRIGGERRIGHT; - - default: // All the other ones - return NUM_GAMEPAD_AXES; - } -} -#endif - -static INT16 GetJoystickAxisValue(UINT8 which, joyaxis_e axissel, INT32 axisval) +INT32 JoyAxis(joyaxis_e axissel) { + INT32 retaxis; + INT32 axisval; boolean flp = false; - if (axisval < 0) // odd -axes - { - axisval = -axisval; - flp = true; - } - else if (axisval == 0) - return 0; - - if (axisval > JOYAXISSET*2) - return 0; - - gamepad_axis_e gp_axis; - -#ifdef OLD_GAMEPAD_AXES - gp_axis = ConvertXboxControllerAxes(axisval); -#else - gp_axis = axisval - 1; -#endif - - if (gp_axis >= NUM_GAMEPAD_AXES) - return 0; - - if (axisval % 2) - axisval /= 2; - else - { - axisval--; - axisval /= 2; - } - - INT16 retaxis = G_GetGamepadAxisValue(0, gp_axis); - - if (gamepads[which].digital && axissel >= JA_DIGITAL) - { - const UINT16 jdeadzone = G_GetGamepadDigitalDeadZone(which) / 2; - if (-jdeadzone < retaxis && retaxis < jdeadzone) - return 0; - } - - // flip it around - if (flp) - retaxis = -retaxis; - - return retaxis; -} - -INT16 G_JoyAxis(UINT8 which, joyaxis_e axissel) -{ - INT32 axisval; - - // find what axis to get + //find what axis to get switch (axissel) { case JA_TURN: - axisval = cv_turnaxis[which].value; + axisval = cv_turnaxis.value; break; case JA_MOVE: - axisval = cv_moveaxis[which].value; + axisval = cv_moveaxis.value; break; case JA_LOOK: - axisval = cv_lookaxis[which].value; + axisval = cv_lookaxis.value; break; case JA_STRAFE: - axisval = cv_sideaxis[which].value; + axisval = cv_sideaxis.value; break; case JA_JUMP: - axisval = cv_jumpaxis[which].value; + axisval = cv_jumpaxis.value; break; case JA_SPIN: - axisval = cv_spinaxis[which].value; + axisval = cv_spinaxis.value; break; case JA_FIRE: - axisval = cv_fireaxis[which].value; + axisval = cv_fireaxis.value; break; case JA_FIRENORMAL: - axisval = cv_firenaxis[which].value; + axisval = cv_firenaxis.value; break; default: return 0; } - return GetJoystickAxisValue(which, axissel, axisval); -} - -static INT16 GetAnalogInput(UINT8 which, gamecontrols_e gc) -{ - for (UINT8 i = 0; i < 2; i++) + if (axisval < 0) //odd -axises { - SINT8 isAnalog = G_PlayerInputIsAnalog(which, gc, i); - if (!isAnalog) - continue; + axisval = -axisval; + flp = true; + } + if (axisval > JOYAXISSET*2 || axisval == 0) //not there in array or None + return 0; - INT16 value = G_GetAnalogPlayerInput(which, gc, i); - if (value > 0 && isAnalog == 1) - return value; - else if (value < 0 && isAnalog == -1) - return max(min(-value, INT16_MAX), INT16_MIN); + if (axisval%2) + { + axisval /= 2; + retaxis = joyxmove[axisval]; + } + else + { + axisval--; + axisval /= 2; + retaxis = joyymove[axisval]; } - return 0; + if (retaxis < (-JOYAXISRANGE)) + retaxis = -JOYAXISRANGE; + if (retaxis > (+JOYAXISRANGE)) + retaxis = +JOYAXISRANGE; + + if (!Joystick.bGamepadStyle && axissel >= JA_DIGITAL) + { + const INT32 jdeadzone = ((JOYAXISRANGE-1) * cv_digitaldeadzone.value) >> FRACBITS; + if (-jdeadzone < retaxis && retaxis < jdeadzone) + return 0; + } + + if (flp) retaxis = -retaxis; //flip it around + return retaxis; } -static boolean CheckAxesUsable(UINT8 which, gamecontrols_e gc1, gamecontrols_e gc2) +INT32 Joy2Axis(joyaxis_e axissel) { - INT32 (*controls)[2] = which == 0 ? gamecontrol : gamecontrolbis; + INT32 retaxis; + INT32 axisval; + boolean flp = false; -#define CHECK_RANGE(x, y, z) \ - (controls[x][y] >= KEY_AXES && controls[x][y] < KEY_AXES + NUM_GAMEPAD_AXES \ - && controls[x][z] >= KEY_INV_AXES && controls[x][z] < KEY_INV_AXES + NUM_GAMEPAD_AXES) + //find what axis to get + switch (axissel) + { + case JA_TURN: + axisval = cv_turnaxis2.value; + break; + case JA_MOVE: + axisval = cv_moveaxis2.value; + break; + case JA_LOOK: + axisval = cv_lookaxis2.value; + break; + case JA_STRAFE: + axisval = cv_sideaxis2.value; + break; + case JA_JUMP: + axisval = cv_jumpaxis2.value; + break; + case JA_SPIN: + axisval = cv_spinaxis2.value; + break; + case JA_FIRE: + axisval = cv_fireaxis2.value; + break; + case JA_FIRENORMAL: + axisval = cv_firenaxis2.value; + break; + default: + return 0; + } - if (CHECK_RANGE(gc1, 0, 1) || CHECK_RANGE(gc2, 0, 1)) - return false; - if (CHECK_RANGE(gc1, 1, 0) || CHECK_RANGE(gc2, 1, 0)) - return false; -#undef CHECK_RANGE + if (axisval < 0) //odd -axises + { + axisval = -axisval; + flp = true; + } - return true; + if (axisval > JOYAXISSET*2 || axisval == 0) //not there in array or None + return 0; + + if (axisval%2) + { + axisval /= 2; + retaxis = joy2xmove[axisval]; + } + else + { + axisval--; + axisval /= 2; + retaxis = joy2ymove[axisval]; + } + + if (retaxis < (-JOYAXISRANGE)) + retaxis = -JOYAXISRANGE; + if (retaxis > (+JOYAXISRANGE)) + retaxis = +JOYAXISRANGE; + + if (!Joystick2.bGamepadStyle && axissel >= JA_DIGITAL) + { + const INT32 jdeadzone = ((JOYAXISRANGE-1) * cv_digitaldeadzone2.value) >> FRACBITS; + if (-jdeadzone < retaxis && retaxis < jdeadzone) + return 0; + } + + if (flp) retaxis = -retaxis; //flip it around + return retaxis; } -typedef struct + +#define PlayerJoyAxis(p, ax) ((p) == 1 ? JoyAxis(ax) : Joy2Axis(ax)) + +// Take a magnitude of two axes, and adjust it to take out the deadzone +// Will return a value between 0 and JOYAXISRANGE +static INT32 G_BasicDeadZoneCalculation(INT32 magnitude, fixed_t deadZone) { - INT32 xaxis, yaxis; -} joystickvector2_t; + const INT32 jdeadzone = (JOYAXISRANGE * deadZone) / FRACUNIT; + INT32 deadzoneAppliedValue = 0; + INT32 adjustedMagnitude = abs(magnitude); + + if (jdeadzone >= JOYAXISRANGE && adjustedMagnitude >= JOYAXISRANGE) // If the deadzone and magnitude are both 100%... + return JOYAXISRANGE; // ...return 100% input directly, to avoid dividing by 0 + else if (adjustedMagnitude > jdeadzone) // Otherwise, calculate how much the magnitude exceeds the deadzone + { + adjustedMagnitude = min(adjustedMagnitude, JOYAXISRANGE); + + adjustedMagnitude -= jdeadzone; + + deadzoneAppliedValue = (adjustedMagnitude * JOYAXISRANGE) / (JOYAXISRANGE - jdeadzone); + } + + return deadzoneAppliedValue; +} // Get the actual sensible radial value for a joystick axis when accounting for a deadzone -static void G_HandleAxisDeadZone(UINT8 playernum, joystickvector2_t *joystickvector) +static void G_HandleAxisDeadZone(UINT8 splitnum, joystickvector2_t *joystickvector) { - if (!gamepads[playernum].digital) - { - const UINT16 deadZone = G_GetGamepadDeadZone(playernum); + INT32 gamepadStyle = Joystick.bGamepadStyle; + fixed_t deadZone = cv_deadzone.value; + if (splitnum == 1) + { + gamepadStyle = Joystick2.bGamepadStyle; + deadZone = cv_deadzone2.value; + } + + // When gamepadstyle is "true" the values are just -1, 0, or 1. This is done in the interface code. + if (!gamepadStyle) + { // Get the total magnitude of the 2 axes INT32 magnitude = (joystickvector->xaxis * joystickvector->xaxis) + (joystickvector->yaxis * joystickvector->yaxis); INT32 normalisedXAxis; @@ -1039,18 +1029,18 @@ static void G_HandleAxisDeadZone(UINT8 playernum, joystickvector2_t *joystickvec normalisedYAxis = (joystickvector->yaxis * magnitude) / JOYAXISRANGE; // Apply the deadzone to the magnitude to give a correct value between 0 and JOYAXISRANGE - normalisedMagnitude = G_BasicDeadZoneCalculation(abs(magnitude), deadZone); + normalisedMagnitude = G_BasicDeadZoneCalculation(magnitude, deadZone); // Apply the deadzone to the xy axes joystickvector->xaxis = (normalisedXAxis * normalisedMagnitude) / JOYAXISRANGE; joystickvector->yaxis = (normalisedYAxis * normalisedMagnitude) / JOYAXISRANGE; - } - // Cap the values so they don't go above the correct maximum - joystickvector->xaxis = min(joystickvector->xaxis, JOYAXISRANGE); - joystickvector->xaxis = max(joystickvector->xaxis, -JOYAXISRANGE - 1); - joystickvector->yaxis = min(joystickvector->yaxis, JOYAXISRANGE); - joystickvector->yaxis = max(joystickvector->yaxis, -JOYAXISRANGE - 1); + // Cap the values so they don't go above the correct maximum + joystickvector->xaxis = min(joystickvector->xaxis, JOYAXISRANGE); + joystickvector->xaxis = max(joystickvector->xaxis, -JOYAXISRANGE); + joystickvector->yaxis = min(joystickvector->yaxis, JOYAXISRANGE); + joystickvector->yaxis = max(joystickvector->yaxis, -JOYAXISRANGE); + } } // @@ -1073,8 +1063,6 @@ boolean ticcmd_centerviewdown[2]; // For simple controls, lock the camera behind mobj_t *ticcmd_ztargetfocus[2]; // Locking onto an object? void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) { - UINT8 forplayer = ssplayer - 1; - boolean forcestrafe = false; boolean forcefullinput = false; INT32 tspeed, forward, side, axis, strafeaxis, moveaxis, turnaxis, lookaxis, i; @@ -1083,17 +1071,15 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) const INT32 speed = 1; // these ones used for multiple conditions - boolean turnleft, turnright, strafelkey, straferkey, movefkey, movebkey, mouseaiming; - boolean analogaxismove, digitalaxismove, thisjoyaiming; + boolean turnleft, turnright, strafelkey, straferkey, movefkey, movebkey, mouseaiming, analogjoystickmove, gamepadjoystickmove, thisjoyaiming; boolean strafeisturn; // Simple controls only player_t *player = &players[ssplayer == 2 ? secondarydisplayplayer : consoleplayer]; camera_t *thiscam = ((ssplayer == 1 || player->bot == BOT_2PHUMAN) ? &camera : &camera2); angle_t *myangle = (ssplayer == 1 ? &localangle : &localangle2); INT32 *myaiming = (ssplayer == 1 ? &localaiming : &localaiming2); - gamepad_t *gamepad = &gamepads[forplayer]; angle_t drawangleoffset = (player->powers[pw_carry] == CR_ROLLOUT) ? ANGLE_180 : 0; - INT32 chasecam, chasefreelook, alwaysfreelook, usegamepad, invertmouse, turnmultiplier, mousemove; + INT32 chasecam, chasefreelook, alwaysfreelook, usejoystick, invertmouse, turnmultiplier, mousemove; controlstyle_e controlstyle = G_ControlStyle(ssplayer); INT32 mdx, mdy, mldy; @@ -1107,11 +1093,14 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) static fixed_t tta_factor[2] = {FRACUNIT, FRACUNIT}; // disables turn-to-angle when manually turning camera until movement happens boolean centerviewdown = false; + UINT8 forplayer = ssplayer-1; + if (ssplayer == 1) { chasecam = cv_chasecam.value; chasefreelook = cv_chasefreelook.value; alwaysfreelook = cv_alwaysfreelook.value; + usejoystick = cv_usejoystick.value; invertmouse = cv_invertmouse.value; turnmultiplier = cv_cam_turnmultiplier.value; mousemove = cv_mousemove.value; @@ -1125,6 +1114,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) chasecam = cv_chasecam2.value; chasefreelook = cv_chasefreelook2.value; alwaysfreelook = cv_alwaysfreelook2.value; + usejoystick = cv_usejoystick2.value; invertmouse = cv_invertmouse2.value; turnmultiplier = cv_cam2_turnmultiplier.value; mousemove = cv_mousemove2.value; @@ -1134,8 +1124,6 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) G_CopyTiccmd(cmd, I_BaseTiccmd2(), 1); // empty, or external driver } - usegamepad = cv_usegamepad[forplayer].value; - if (menuactive || CON_Ready() || chat_on) mdx = mdy = mldy = 0; @@ -1154,14 +1142,13 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) return; } - // Axes for turning or strafing are ignored here - turnright = G_CheckDigitalPlayerInput(forplayer, GC_TURNRIGHT); - turnleft = G_CheckDigitalPlayerInput(forplayer, GC_TURNLEFT); + turnright = PLAYERINPUTDOWN(ssplayer, GC_TURNRIGHT); + turnleft = PLAYERINPUTDOWN(ssplayer, GC_TURNLEFT); - straferkey = G_CheckDigitalPlayerInput(forplayer, GC_STRAFERIGHT); - strafelkey = G_CheckDigitalPlayerInput(forplayer, GC_STRAFELEFT); - movefkey = G_CheckDigitalPlayerInput(forplayer, GC_FORWARD); - movebkey = G_CheckDigitalPlayerInput(forplayer, GC_BACKWARD); + straferkey = PLAYERINPUTDOWN(ssplayer, GC_STRAFERIGHT); + strafelkey = PLAYERINPUTDOWN(ssplayer, GC_STRAFELEFT); + movefkey = PLAYERINPUTDOWN(ssplayer, GC_FORWARD); + movebkey = PLAYERINPUTDOWN(ssplayer, GC_BACKWARD); if (strafeisturn) { @@ -1170,10 +1157,10 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) straferkey = strafelkey = false; } - mouseaiming = (G_PlayerInputDown(forplayer, GC_MOUSEAIMING)) ^ + mouseaiming = (PLAYERINPUTDOWN(ssplayer, GC_MOUSEAIMING)) ^ ((chasecam && !player->spectator) ? chasefreelook : alwaysfreelook); - analogaxismove = usegamepad && !gamepad->digital; - digitalaxismove = usegamepad && gamepad->digital; + analogjoystickmove = usejoystick && !Joystick.bGamepadStyle; + gamepadjoystickmove = usejoystick && Joystick.bGamepadStyle; thisjoyaiming = (chasecam && !player->spectator) ? chasefreelook : alwaysfreelook; @@ -1182,38 +1169,19 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) *myaiming = 0; joyaiming[forplayer] = thisjoyaiming; - turnaxis = G_JoyAxis(forplayer, JA_TURN); + turnaxis = PlayerJoyAxis(ssplayer, JA_TURN); if (strafeisturn) - turnaxis += G_JoyAxis(forplayer, JA_STRAFE); - lookaxis = G_JoyAxis(forplayer, JA_LOOK); - - if (usegamepad) - { - turnaxis -= GetAnalogInput(forplayer, GC_TURNLEFT); - turnaxis += GetAnalogInput(forplayer, GC_TURNRIGHT); - - if (strafeisturn) - { - turnaxis -= GetAnalogInput(forplayer, GC_STRAFELEFT); - turnaxis += GetAnalogInput(forplayer, GC_STRAFERIGHT); - } - - lookaxis += GetAnalogInput(forplayer, GC_LOOKUP); - lookaxis -= GetAnalogInput(forplayer, GC_LOOKDOWN); - } - - // Handle deadzones + turnaxis += PlayerJoyAxis(ssplayer, JA_STRAFE); + lookaxis = PlayerJoyAxis(ssplayer, JA_LOOK); lookjoystickvector.xaxis = turnaxis; lookjoystickvector.yaxis = lookaxis; G_HandleAxisDeadZone(forplayer, &lookjoystickvector); - // Do digital axis turning - if (digitalaxismove && lookjoystickvector.xaxis != 0) + if (gamepadjoystickmove && lookjoystickvector.xaxis != 0) { turnright = turnright || (lookjoystickvector.xaxis > 0); turnleft = turnleft || (lookjoystickvector.xaxis < 0); } - forward = side = 0; // use two stage accelerative turning @@ -1252,10 +1220,10 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) if (turnleft) side -= sidemove[speed]; - if (analogaxismove && lookjoystickvector.xaxis != 0) + if (analogjoystickmove && lookjoystickvector.xaxis != 0) { - // JOYAXISRANGE is supposed to be 32767 (divide by 32768) - side += ((lookjoystickvector.xaxis * sidemove[1]) >> 15); + // JOYAXISRANGE is supposed to be 1023 (divide by 1024) + side += ((lookjoystickvector.xaxis * sidemove[1]) >> 10); } } else if (controlstyle == CS_LMAOGALOG) // Analog @@ -1273,69 +1241,47 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) else if (turnleft) cmd->angleturn = (INT16)(cmd->angleturn + ((angleturn[tspeed] * turnmultiplier)>>FRACBITS)); - if (analogaxismove && lookjoystickvector.xaxis != 0) + if (analogjoystickmove && lookjoystickvector.xaxis != 0) { - // JOYAXISRANGE should be 32767 (divide by 32768) - cmd->angleturn = (INT16)(cmd->angleturn - ((((lookjoystickvector.xaxis * angleturn[1]) >> 15) * turnmultiplier)>>FRACBITS)); // ANALOG! + // JOYAXISRANGE should be 1023 (divide by 1024) + cmd->angleturn = (INT16)(cmd->angleturn - ((((lookjoystickvector.xaxis * angleturn[1]) >> 10) * turnmultiplier)>>FRACBITS)); // ANALOG! } if (turnright || turnleft || abs(cmd->angleturn) > angleturn[2]) tta_factor[forplayer] = 0; // suspend turn to angle } - // Strafing axes (moving left and right) - if (strafeisturn) - strafeaxis = 0; - else - { - strafeaxis = G_JoyAxis(forplayer, JA_STRAFE); - - if (usegamepad && CheckAxesUsable(forplayer, GC_STRAFELEFT, GC_STRAFERIGHT)) - { - strafeaxis -= GetAnalogInput(forplayer, GC_STRAFELEFT); - strafeaxis += GetAnalogInput(forplayer, GC_STRAFERIGHT); - } - } - - // Moving axes (moving forwards and backwards) - moveaxis = G_JoyAxis(forplayer, JA_MOVE); - if (usegamepad && CheckAxesUsable(forplayer, GC_FORWARD, GC_BACKWARD)) - { - moveaxis -= GetAnalogInput(forplayer, GC_FORWARD); - moveaxis += GetAnalogInput(forplayer, GC_BACKWARD); - } - + strafeaxis = strafeisturn ? 0 : PlayerJoyAxis(ssplayer, JA_STRAFE); + moveaxis = PlayerJoyAxis(ssplayer, JA_MOVE); movejoystickvector.xaxis = strafeaxis; movejoystickvector.yaxis = moveaxis; G_HandleAxisDeadZone(forplayer, &movejoystickvector); - if (digitalaxismove && movejoystickvector.xaxis != 0) + if (gamepadjoystickmove && movejoystickvector.xaxis != 0) { - // Do digital axis movement if (movejoystickvector.xaxis > 0) side += sidemove[speed]; else if (movejoystickvector.xaxis < 0) side -= sidemove[speed]; } - else if (analogaxismove && movejoystickvector.xaxis != 0) + else if (analogjoystickmove && movejoystickvector.xaxis != 0) { - // JOYAXISRANGE is supposed to be 32767 (divide by 32768) - side += ((movejoystickvector.xaxis * sidemove[1]) >> 15); + // JOYAXISRANGE is supposed to be 1023 (divide by 1024) + side += ((movejoystickvector.xaxis * sidemove[1]) >> 10); } // forward with key or button - // also handles digital axis movement - if (movefkey || (digitalaxismove && movejoystickvector.yaxis < 0) + if (movefkey || (gamepadjoystickmove && movejoystickvector.yaxis < 0) || ((player->powers[pw_carry] == CR_NIGHTSMODE) - && (G_CheckDigitalPlayerInput(forplayer, GC_LOOKUP) || (digitalaxismove && lookjoystickvector.yaxis > 0)))) + && (PLAYERINPUTDOWN(ssplayer, GC_LOOKUP) || (gamepadjoystickmove && lookjoystickvector.yaxis > 0)))) forward = forwardmove[speed]; - if (movebkey || (digitalaxismove && movejoystickvector.yaxis > 0) + if (movebkey || (gamepadjoystickmove && movejoystickvector.yaxis > 0) || ((player->powers[pw_carry] == CR_NIGHTSMODE) - && (G_CheckDigitalPlayerInput(forplayer, GC_LOOKDOWN) || (digitalaxismove && lookjoystickvector.yaxis < 0)))) + && (PLAYERINPUTDOWN(ssplayer, GC_LOOKDOWN) || (gamepadjoystickmove && lookjoystickvector.yaxis < 0)))) forward -= forwardmove[speed]; - if (analogaxismove && movejoystickvector.yaxis != 0) - forward -= ((movejoystickvector.yaxis * forwardmove[1]) >> 15); // ANALOG! + if (analogjoystickmove && movejoystickvector.yaxis != 0) + forward -= ((movejoystickvector.yaxis * forwardmove[1]) >> 10); // ANALOG! // some people strafe left & right with mouse buttons // those people are weird @@ -1344,54 +1290,53 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) if (strafelkey) side -= sidemove[speed]; - if (G_PlayerInputDown(forplayer, GC_WEAPONNEXT)) + if (PLAYERINPUTDOWN(ssplayer, GC_WEAPONNEXT)) cmd->buttons |= BT_WEAPONNEXT; // Next Weapon - if (G_PlayerInputDown(forplayer, GC_WEAPONPREV)) + if (PLAYERINPUTDOWN(ssplayer, GC_WEAPONPREV)) cmd->buttons |= BT_WEAPONPREV; // Previous Weapon #if NUM_WEAPONS > 10 -#error "Add extra inputs to g_input.h/gamecontrols_e" +"Add extra inputs to g_input.h/gamecontrols_e" #endif - //use the four avaliable bits to determine the weapon. cmd->buttons &= ~BT_WEAPONMASK; for (i = 0; i < NUM_WEAPONS; ++i) - if (G_PlayerInputDown(forplayer, GC_WEPSLOT1 + i)) + if (PLAYERINPUTDOWN(ssplayer, GC_WEPSLOT1 + i)) { cmd->buttons |= (UINT16)(i + 1); break; } // fire with any button/key - axis = G_JoyAxis(forplayer, JA_FIRE); - if (G_PlayerInputDown(forplayer, GC_FIRE) || (usegamepad && axis > 0)) + axis = PlayerJoyAxis(ssplayer, JA_FIRE); + if (PLAYERINPUTDOWN(ssplayer, GC_FIRE) || (usejoystick && axis > 0)) cmd->buttons |= BT_ATTACK; // fire normal with any button/key - axis = G_JoyAxis(forplayer, JA_FIRENORMAL); - if (G_PlayerInputDown(forplayer, GC_FIRENORMAL) || (usegamepad && axis > 0)) + axis = PlayerJoyAxis(ssplayer, JA_FIRENORMAL); + if (PLAYERINPUTDOWN(ssplayer, GC_FIRENORMAL) || (usejoystick && axis > 0)) cmd->buttons |= BT_FIRENORMAL; - if (G_PlayerInputDown(forplayer, GC_TOSSFLAG)) + if (PLAYERINPUTDOWN(ssplayer, GC_TOSSFLAG)) cmd->buttons |= BT_TOSSFLAG; // Lua scriptable buttons - if (G_PlayerInputDown(forplayer, GC_CUSTOM1)) + if (PLAYERINPUTDOWN(ssplayer, GC_CUSTOM1)) cmd->buttons |= BT_CUSTOM1; - if (G_PlayerInputDown(forplayer, GC_CUSTOM2)) + if (PLAYERINPUTDOWN(ssplayer, GC_CUSTOM2)) cmd->buttons |= BT_CUSTOM2; - if (G_PlayerInputDown(forplayer, GC_CUSTOM3)) + if (PLAYERINPUTDOWN(ssplayer, GC_CUSTOM3)) cmd->buttons |= BT_CUSTOM3; - // spin with any button/key - axis = G_JoyAxis(forplayer, JA_SPIN); - if (G_PlayerInputDown(forplayer, GC_SPIN) || (usegamepad && axis > 0)) + // use with any button/key + axis = PlayerJoyAxis(ssplayer, JA_SPIN); + if (PLAYERINPUTDOWN(ssplayer, GC_SPIN) || (usejoystick && axis > 0)) cmd->buttons |= BT_SPIN; // Centerview can be a toggle in simple mode! { static boolean last_centerviewdown[2], centerviewhold[2]; // detect taps for toggle behavior - boolean down = G_PlayerInputDown(forplayer, GC_CENTERVIEW); + boolean down = PLAYERINPUTDOWN(ssplayer, GC_CENTERVIEW); if (!(controlstyle == CS_SIMPLE && cv_cam_centertoggle[forplayer].value)) centerviewdown = down; @@ -1490,7 +1435,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) if (ticcmd_centerviewdown[forplayer] && controlstyle == CS_SIMPLE) controlstyle = CS_LEGACY; - if (G_PlayerInputDown(forplayer, GC_CAMRESET)) + if (PLAYERINPUTDOWN(ssplayer, GC_CAMRESET)) { if (thiscam->chase && !resetdown[forplayer]) P_ResetCamera(&players[ssplayer == 1 ? displayplayer : secondarydisplayplayer], thiscam); @@ -1500,9 +1445,10 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) else resetdown[forplayer] = false; + // jump button - axis = G_JoyAxis(forplayer, JA_JUMP); - if (G_PlayerInputDown(forplayer, GC_JUMP) || (usegamepad && axis > 0)) + axis = PlayerJoyAxis(ssplayer, JA_JUMP); + if (PLAYERINPUTDOWN(ssplayer, GC_JUMP) || (usejoystick && axis > 0)) cmd->buttons |= BT_JUMP; // player aiming shit, ahhhh... @@ -1512,6 +1458,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) (player->mo && (player->mo->eflags & MFE_VERTICALFLIP) && (!thiscam->chase || player->pflags & PF_FLIPCAM)) //because chasecam's not inverted ? -1 : 1; // set to -1 or 1 to multiply + INT32 configlookaxis = ssplayer == 1 ? cv_lookaxis.value : cv_lookaxis2.value; // mouse look stuff (mouse look is not the same as mouse aim) if (mouseaiming) @@ -1522,21 +1469,21 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) *myaiming += (mldy<<19)*player_invert*screen_invert; } - if (joyaiming[forplayer] && lookjoystickvector.yaxis != 0) - *myaiming += (lookjoystickvector.yaxis<<11) * screen_invert; + if (analogjoystickmove && joyaiming[forplayer] && lookjoystickvector.yaxis != 0 && configlookaxis != 0) + *myaiming += (lookjoystickvector.yaxis<<16) * screen_invert; // spring back if not using keyboard neither mouselookin' - if (!keyboard_look[forplayer] && !joyaiming[forplayer] && !mouseaiming) + if (!keyboard_look[forplayer] && configlookaxis == 0 && !joyaiming[forplayer] && !mouseaiming) *myaiming = 0; if (!(player->powers[pw_carry] == CR_NIGHTSMODE)) { - if (G_CheckDigitalPlayerInput(forplayer, GC_LOOKUP) || (digitalaxismove && lookjoystickvector.yaxis < 0)) + if (PLAYERINPUTDOWN(ssplayer, GC_LOOKUP) || (gamepadjoystickmove && lookjoystickvector.yaxis < 0)) { *myaiming += KB_LOOKSPEED * screen_invert; keyboard_look[forplayer] = true; } - else if (G_CheckDigitalPlayerInput(forplayer, GC_LOOKDOWN) || (digitalaxismove && lookjoystickvector.yaxis > 0)) + else if (PLAYERINPUTDOWN(ssplayer, GC_LOOKDOWN) || (gamepadjoystickmove && lookjoystickvector.yaxis > 0)) { *myaiming -= KB_LOOKSPEED * screen_invert; keyboard_look[forplayer] = true; @@ -1769,57 +1716,6 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n) return dest; } -static player_t *G_GetInputPlayer(UINT8 which) -{ - if (which == 0) - return &players[displayplayer]; - else if (which == 1) - { - if (splitscreen) - return &players[secondarydisplayplayer]; - else if (playeringame[1] && players[1].bot == BOT_2PHUMAN) - return &players[1]; - } - - return NULL; -} - -// Returns a player's gamepad index, even if it's disabled -// Gamepad indexes correspond to the local player index. -INT16 G_GetGamepadForPlayer(player_t *player) -{ - for (UINT8 i = 0; i < 2; i++) - { - if (player == G_GetInputPlayer(i)) - return i; - } - - return -1; -} - -// Gets the user-set gamepad device for a specific player -INT32 G_GetGamepadDeviceIndex(INT32 player) -{ -#ifdef GAMEPAD_HOTPLUG - if (atoi(cv_usegamepad[player].string) > I_NumGamepads()) - return atoi(cv_usegamepad[player].string); - else -#endif - return cv_usegamepad[player].value; -} - -void G_OnGamepadDisconnect(UINT8 which) -{ - if (!cv_gamepad_autopause.value) - return; - - if (gamestate != GS_LEVEL || paused || netgame || splitscreen) - return; - - if (which == 0 || (which == 1 && playeringame[1] && players[1].bot == BOT_2PHUMAN)) - COM_ImmedExecute("pause"); -} - // User has designated that they want // analog ON, so tell the game to stop // fudging with it. @@ -1891,25 +1787,6 @@ static void AutoBrake2_OnChange(void) SendWeaponPref2(); } -static void G_ResetInputs(void) -{ - memset(gamekeydown, 0, sizeof (gamekeydown)); - - for (UINT8 i = 0; i < NUM_GAMEPADS; i++) - { - for (UINT8 j = 0; j < NUM_GAMEPAD_BUTTONS; j++) - gamepads[i].buttons[j] = 0; - - for (UINT8 j = 0; j < NUM_GAMEPAD_AXES; j++) - gamepads[i].axes[j] = 0; - } - - G_SetMouseDeltas(0, 0, 1); - G_SetMouseDeltas(0, 0, 2); - - P_StopRumble(NULL); -} - // // G_DoLoadLevel // @@ -1978,7 +1855,14 @@ void G_DoLoadLevel(boolean resetplayer) P_ResetCamera(&players[secondarydisplayplayer], &camera2); // clear cmd building stuff - G_ResetInputs(); + memset(gamekeydown, 0, sizeof (gamekeydown)); + for (i = 0;i < JOYAXISSET; i++) + { + joyxmove[i] = joyymove[i] = 0; + joy2xmove[i] = joy2ymove[i] = 0; + } + G_SetMouseDeltas(0, 0, 1); + G_SetMouseDeltas(0, 0, 2); // clear hud messages remains (usually from game startup) CON_ClearHUD(); @@ -2160,14 +2044,11 @@ static boolean ViewpointSwitchResponder(event_t *ev) // boolean G_Responder(event_t *ev) { - INT32 evtype = ev->type; - INT32 key = G_RemapGamepadEvent(ev, &evtype); - // any other key pops up menu if in demos if (gameaction == ga_nothing && !singledemo && ((demoplayback && !modeattacking && !titledemo) || gamestate == GS_TITLESCREEN)) { - if (evtype == ev_keydown && !(gamestate == GS_TITLESCREEN && finalecount < TICRATE)) + if (ev->type == ev_keydown && ev->key != 301 && !(gamestate == GS_TITLESCREEN && finalecount < TICRATE)) { M_StartControlPanel(); return true; @@ -2192,7 +2073,7 @@ boolean G_Responder(event_t *ev) return true; // chat ate the event if (AM_Responder(ev)) return true; // automap ate it - // map the event (key/mouse/gamepad) to a gamecontrol + // map the event (key/mouse/joy) to a gamecontrol } // Intro else if (gamestate == GS_INTRO) @@ -2247,16 +2128,16 @@ boolean G_Responder(event_t *ev) // update keys current state G_MapEventsToControls(ev); - switch (evtype) + switch (ev->type) { case ev_keydown: - if (key == gamecontrol[GC_PAUSE][0] - || key == gamecontrol[GC_PAUSE][1] - || key == KEY_PAUSE) + if (ev->key == gamecontrol[GC_PAUSE][0] + || ev->key == gamecontrol[GC_PAUSE][1] + || ev->key == KEY_PAUSE) { if (modeattacking && !demoplayback && (gamestate == GS_LEVEL)) { - pausebreakkey = (key == KEY_PAUSE); + pausebreakkey = (ev->key == KEY_PAUSE); if (menuactive || pausedelay < 0 || leveltime < 2) return true; @@ -2281,8 +2162,8 @@ boolean G_Responder(event_t *ev) } } } - if (key == gamecontrol[GC_CAMTOGGLE][0] - || key == gamecontrol[GC_CAMTOGGLE][1]) + if (ev->key == gamecontrol[GC_CAMTOGGLE][0] + || ev->key == gamecontrol[GC_CAMTOGGLE][1]) { if (!camtoggledelay) { @@ -2290,8 +2171,8 @@ boolean G_Responder(event_t *ev) CV_SetValue(&cv_chasecam, cv_chasecam.value ? 0 : 1); } } - if (key == gamecontrolbis[GC_CAMTOGGLE][0] - || key == gamecontrolbis[GC_CAMTOGGLE][1]) + if (ev->key == gamecontrolbis[GC_CAMTOGGLE][0] + || ev->key == gamecontrolbis[GC_CAMTOGGLE][1]) { if (!camtoggledelay2) { @@ -2304,9 +2185,15 @@ boolean G_Responder(event_t *ev) case ev_keyup: return false; // always let key up events filter down - case ev_mouse: // eat events - case ev_gamepad_axis: - return true; + case ev_mouse: + return true; // eat events + + case ev_joystick: + return true; // eat events + + case ev_joystick2: + return true; // eat events + default: break; @@ -3300,7 +3187,14 @@ void G_DoReborn(INT32 playernum) P_ResetCamera(&players[secondarydisplayplayer], &camera2); // clear cmd building stuff - G_ResetInputs(); + memset(gamekeydown, 0, sizeof (gamekeydown)); + for (i = 0; i < JOYAXISSET; i++) + { + joyxmove[i] = joyymove[i] = 0; + joy2xmove[i] = joy2ymove[i] = 0; + } + G_SetMouseDeltas(0, 0, 1); + G_SetMouseDeltas(0, 0, 2); // clear hud messages remains (usually from game startup) CON_ClearHUD(); @@ -4708,7 +4602,11 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) } save_p += VERSIONSIZE; - P_StopRumble(NULL); +// if (demoplayback) // reset game engine +// G_StopDemo(); + +// paused = false; +// automapactive = false; // dearchive all the modifications if (!P_LoadGame(mapoverride)) @@ -4971,7 +4869,6 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean { INT32 i; - P_StopRumble(NULL); Y_CleanupScreenBuffer(); if (paused) diff --git a/src/g_game.h b/src/g_game.h index 6c24054a0..dca043f2e 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -68,14 +68,10 @@ typedef enum { #define P_ControlStyle(player) ((((player)->pflags & PF_ANALOGMODE) ? CS_LMAOGALOG : 0) | (((player)->pflags & PF_DIRECTIONCHAR) ? CS_STANDARD : 0)) extern consvar_t cv_autobrake, cv_autobrake2; +extern consvar_t cv_sideaxis,cv_turnaxis,cv_moveaxis,cv_lookaxis,cv_jumpaxis,cv_spinaxis,cv_fireaxis,cv_firenaxis,cv_deadzone,cv_digitaldeadzone; +extern consvar_t cv_sideaxis2,cv_turnaxis2,cv_moveaxis2,cv_lookaxis2,cv_jumpaxis2,cv_spinaxis2,cv_fireaxis2,cv_firenaxis2,cv_deadzone2,cv_digitaldeadzone2; extern consvar_t cv_ghost_bestscore, cv_ghost_besttime, cv_ghost_bestrings, cv_ghost_last, cv_ghost_guest; -extern consvar_t cv_sideaxis[2], cv_turnaxis[2], cv_moveaxis[2], cv_lookaxis[2], - cv_jumpaxis[2], cv_spinaxis[2], cv_fireaxis[2], cv_firenaxis[2], - cv_deadzone[2], cv_digitaldeadzone[2]; - -extern CV_PossibleValue_t joyaxis_cons_t[]; - // hi here's some new controls extern consvar_t cv_cam_shiftfacing[2], cv_cam_turnfacing[2], cv_cam_turnfacingability[2], cv_cam_turnfacingspindash[2], cv_cam_turnfacinginput[2], @@ -88,12 +84,10 @@ typedef enum LOCK_INTERESTS = 1<<2, } lockassist_e; -// Legacy axis stuff -#define JOYAXISSET 4 // 4 Sets of 2 axes typedef enum { - JA_NONE, + JA_NONE = 0, JA_TURN, JA_MOVE, JA_LOOK, @@ -107,7 +101,8 @@ typedef enum JA_FIRENORMAL, } joyaxis_e; -INT16 G_JoyAxis(UINT8 which, joyaxis_e axissel); +INT32 JoyAxis(joyaxis_e axissel); +INT32 Joy2Axis(joyaxis_e axissel); // mouseaiming (looking up/down with the mouse or keyboard) #define KB_LOOKSPEED (1<<25) @@ -127,15 +122,6 @@ ticcmd_t *G_CopyTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n); // copy ticcmd_t to and fro network packets ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n); -// gets the user-set gamepad device for a specific player -INT32 G_GetGamepadDeviceIndex(INT32 player); - -// returns a player's gamepad index -INT16 G_GetGamepadForPlayer(player_t *player); - -// called when a player's gamepad is disconnected -void G_OnGamepadDisconnect(UINT8 which); - // clip the console player aiming to the view INT16 G_ClipAimingPitch(INT32 *aiming); INT16 G_SoftwareClipAimingPitch(INT32 *aiming); diff --git a/src/g_input.c b/src/g_input.c index 465db0316..79bd2a4a2 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -8,14 +8,12 @@ // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file g_input.c -/// \brief handle mouse/keyboard/gamepad inputs, +/// \brief handle mouse/keyboard/joystick inputs, /// maps inputs to game controls (forward, spin, jump...) #include "doomdef.h" #include "doomstat.h" -#include "g_game.h" #include "g_input.h" -#include "i_gamepad.h" #include "keys.h" #include "hu_stuff.h" // need HUFONT start & end #include "d_net.h" @@ -36,7 +34,8 @@ consvar_t cv_controlperkey = CVAR_INIT ("controlperkey", "One", CV_SAVE, onecont mouse_t mouse; mouse_t mouse2; -gamepad_t gamepads[NUM_GAMEPADS]; +// joystick values are repeated +INT32 joyxmove[JOYAXISSET], joyymove[JOYAXISSET], joy2xmove[JOYAXISSET], joy2ymove[JOYAXISSET]; // current state of the keys: true if pushed UINT8 gamekeydown[NUMINPUTS]; @@ -87,77 +86,114 @@ const INT32 gcl_jump_spin[num_gcl_jump_spin] = { GC_JUMP, GC_SPIN }; -static boolean CheckInputDown(UINT8 which, gamecontrols_e gc, boolean checkaxes) -{ - INT32 (*controls)[2] = which == 0 ? gamecontrol : gamecontrolbis; - - for (unsigned i = 0; i < 2; i++) - { - INT32 key = controls[gc][i]; - - if (key >= KEY_GAMEPAD && key < KEY_AXES) - { - if (gamepads[which].buttons[key - KEY_GAMEPAD]) - return true; - } - else if (checkaxes && (key >= KEY_AXES && key < KEY_INV_AXES + NUM_GAMEPAD_AXES)) - { - const UINT16 jdeadzone = G_GetGamepadDigitalDeadZone(which); - const INT16 value = G_GetGamepadAxisValue(which, (key - KEY_AXES) % NUM_GAMEPAD_AXES); - - if (abs(value) > jdeadzone) - return true; - } - else if (gamekeydown[key]) - return true; - } - - return false; -} - -boolean G_PlayerInputDown(UINT8 which, gamecontrols_e gc) -{ - return CheckInputDown(which, gc, true); -} - -boolean G_CheckDigitalPlayerInput(UINT8 which, gamecontrols_e gc) -{ - return CheckInputDown(which, gc, false); -} - -SINT8 G_PlayerInputIsAnalog(UINT8 which, gamecontrols_e gc, UINT8 settings) -{ - INT32 (*controls)[2] = which == 0 ? gamecontrol : gamecontrolbis; - INT32 key = controls[gc][settings]; - - if (key >= KEY_AXES && key < KEY_AXES + NUM_GAMEPAD_AXES) - return 1; - else if (key >= KEY_INV_AXES && key < KEY_INV_AXES + NUM_GAMEPAD_AXES) - return -1; - - return 0; -} - -INT16 G_GetAnalogPlayerInput(UINT8 which, gamecontrols_e gc, UINT8 settings) -{ - INT32 (*controls)[2] = which == 0 ? gamecontrol : gamecontrolbis; - INT32 key = controls[gc][settings]; - - if (key >= KEY_AXES && key < KEY_INV_AXES + NUM_GAMEPAD_AXES) - return G_GetGamepadAxisValue(which, (key - KEY_AXES) % NUM_GAMEPAD_AXES); - - return 0; -} - typedef struct { UINT8 time; UINT8 state; UINT8 clicks; } dclick_t; - static dclick_t mousedclicks[MOUSEBUTTONS]; +static dclick_t joydclicks[JOYBUTTONS + JOYHATS*4]; static dclick_t mouse2dclicks[MOUSEBUTTONS]; +static dclick_t joy2dclicks[JOYBUTTONS + JOYHATS*4]; + +// protos +static UINT8 G_CheckDoubleClick(UINT8 state, dclick_t *dt); + +// +// Remaps the inputs to game controls. +// +// A game control can be triggered by one or more keys/buttons. +// +// Each key/mousebutton/joybutton triggers ONLY ONE game control. +// +void G_MapEventsToControls(event_t *ev) +{ + INT32 i; + UINT8 flag; + + switch (ev->type) + { + case ev_keydown: + if (ev->key < NUMINPUTS) + gamekeydown[ev->key] = 1; +#ifdef PARANOIA + else + { + CONS_Debug(DBG_GAMELOGIC, "Bad downkey input %d\n",ev->key); + } + +#endif + break; + + case ev_keyup: + if (ev->key < NUMINPUTS) + gamekeydown[ev->key] = 0; +#ifdef PARANOIA + else + { + CONS_Debug(DBG_GAMELOGIC, "Bad upkey input %d\n",ev->key); + } +#endif + break; + + case ev_mouse: // buttons are virtual keys + mouse.rdx = ev->x; + mouse.rdy = ev->y; + break; + + case ev_joystick: // buttons are virtual keys + i = ev->key; + if (i >= JOYAXISSET || menuactive || CON_Ready() || chat_on) + break; + if (ev->x != INT32_MAX) joyxmove[i] = ev->x; + if (ev->y != INT32_MAX) joyymove[i] = ev->y; + break; + + case ev_joystick2: // buttons are virtual keys + i = ev->key; + if (i >= JOYAXISSET || menuactive || CON_Ready() || chat_on) + break; + if (ev->x != INT32_MAX) joy2xmove[i] = ev->x; + if (ev->y != INT32_MAX) joy2ymove[i] = ev->y; + break; + + case ev_mouse2: // buttons are virtual keys + if (menuactive || CON_Ready() || chat_on) + break; + mouse2.rdx = ev->x; + mouse2.rdy = ev->y; + break; + + default: + break; + } + + // ALWAYS check for mouse & joystick double-clicks even if no mouse event + for (i = 0; i < MOUSEBUTTONS; i++) + { + flag = G_CheckDoubleClick(gamekeydown[KEY_MOUSE1+i], &mousedclicks[i]); + gamekeydown[KEY_DBLMOUSE1+i] = flag; + } + + for (i = 0; i < JOYBUTTONS + JOYHATS*4; i++) + { + flag = G_CheckDoubleClick(gamekeydown[KEY_JOY1+i], &joydclicks[i]); + gamekeydown[KEY_DBLJOY1+i] = flag; + } + + for (i = 0; i < MOUSEBUTTONS; i++) + { + flag = G_CheckDoubleClick(gamekeydown[KEY_2MOUSE1+i], &mouse2dclicks[i]); + gamekeydown[KEY_DBL2MOUSE1+i] = flag; + } + + for (i = 0; i < JOYBUTTONS + JOYHATS*4; i++) + { + flag = G_CheckDoubleClick(gamekeydown[KEY_2JOY1+i], &joy2dclicks[i]); + gamekeydown[KEY_DBL2JOY1+i] = flag; + } +} // // General double-click detection routine for any kind of input. @@ -189,641 +225,6 @@ static UINT8 G_CheckDoubleClick(UINT8 state, dclick_t *dt) return false; } -// -// Remaps the inputs to game controls. -// -// A game control can be triggered by one or more keys/buttons. -// -// Each key/mouse button/gamepad button triggers ONLY ONE game control. -// -void G_MapEventsToControls(event_t *ev) -{ - INT32 i; - UINT8 flag; - - switch (ev->type) - { - case ev_keydown: - if (ev->key < NUMINPUTS) - gamekeydown[ev->key] = 1; -#ifdef PARANOIA - else - CONS_Debug(DBG_GAMELOGIC, "Bad downkey input %d\n",ev->key); - -#endif - break; - - case ev_keyup: - if (ev->key < NUMINPUTS) - gamekeydown[ev->key] = 0; -#ifdef PARANOIA - else - CONS_Debug(DBG_GAMELOGIC, "Bad upkey input %d\n",ev->key); -#endif - break; - - case ev_gamepad_down: - case ev_gamepad_up: -#ifdef PARANOIA - if (ev->which < NUM_GAMEPADS) -#endif - gamepads[ev->which].buttons[ev->key] = ev->type == ev_gamepad_down ? 1 : 0; - break; - - case ev_gamepad_axis: -#ifdef PARANOIA - if (ev->which < NUM_GAMEPADS) -#endif - gamepads[ev->which].axes[ev->key] = ev->x; - break; - - case ev_mouse: - mouse.rdx = ev->x; - mouse.rdy = ev->y; - break; - - case ev_mouse2: - mouse2.rdx = ev->x; - mouse2.rdy = ev->y; - break; - - default: - break; - } - - // ALWAYS check for mouse double-clicks even if there were no such events - for (i = 0; i < MOUSEBUTTONS; i++) - { - flag = G_CheckDoubleClick(gamekeydown[KEY_MOUSE1+i], &mousedclicks[i]); - gamekeydown[KEY_DBLMOUSE1+i] = flag; - } - - for (i = 0; i < MOUSEBUTTONS; i++) - { - flag = G_CheckDoubleClick(gamekeydown[KEY_2MOUSE1+i], &mouse2dclicks[i]); - gamekeydown[KEY_DBL2MOUSE1+i] = flag; - } -} - -const char *const gamepad_button_names[NUM_GAMEPAD_BUTTONS + 1] = { - "a", - "b", - "x", - "y", - "back", - "guide", - "start", - "left-stick", - "right-stick", - "left-shoulder", - "right-shoulder", - "dpad-up", - "dpad-down", - "dpad-left", - "dpad-right", - "misc1", - "paddle1", - "paddle2", - "paddle3", - "paddle4", - "touchpad", - NULL}; - -const char *const gamepad_axis_names[NUM_GAMEPAD_AXES + 1] = { - "left-x", - "left-y", - "right-x", - "right-y", - "trigger-left", - "trigger-right", - NULL}; - -boolean G_GamepadTypeIsXbox(gamepadtype_e type) -{ - switch (type) - { - case GAMEPAD_TYPE_XBOX360: - case GAMEPAD_TYPE_XBOXONE: - case GAMEPAD_TYPE_XBOX_SERIES_XS: - case GAMEPAD_TYPE_XBOX_ELITE: - return true; - default: - return false; - } -} - -boolean G_GamepadTypeIsPlayStation(gamepadtype_e type) -{ - switch (type) - { - case GAMEPAD_TYPE_PS3: - case GAMEPAD_TYPE_PS4: - case GAMEPAD_TYPE_PS5: - return true; - default: - return false; - } -} - -boolean G_GamepadTypeIsNintendoSwitch(gamepadtype_e type) -{ - switch (type) - { - case GAMEPAD_TYPE_NINTENDO_SWITCH_PRO: - case GAMEPAD_TYPE_NINTENDO_SWITCH_JOY_CON_GRIP: - return true; - default: - return G_GamepadTypeIsJoyCon(type); - } -} - -boolean G_GamepadTypeIsJoyCon(gamepadtype_e type) -{ - switch (type) - { - case GAMEPAD_TYPE_NINTENDO_SWITCH_JOY_CON_LEFT: - case GAMEPAD_TYPE_NINTENDO_SWITCH_JOY_CON_RIGHT: - return true; - default: - return false; - } -} - -boolean G_RumbleSupported(UINT8 which) -{ - if (!I_RumbleSupported() || which >= NUM_GAMEPADS) - return 0; - - return I_GetGamepadRumbleSupported(which); -} - -boolean G_RumbleGamepad(UINT8 which, fixed_t large_magnitude, fixed_t small_magnitude, tic_t duration) -{ - haptic_t effect; - - if (!G_RumbleSupported(which)) - return false; - - effect.large_magnitude = large_magnitude; - effect.small_magnitude = small_magnitude; - effect.duration = duration; - - return I_RumbleGamepad(which, &effect); -} - -void G_StopGamepadRumble(UINT8 which) -{ - if (G_RumbleSupported(which)) - I_StopGamepadRumble(which); -} - -fixed_t G_GetLargeMotorFreq(UINT8 which) -{ - if (!G_RumbleSupported(which) || which >= NUM_GAMEPADS) - return 0; - - gamepad_t *gamepad = &gamepads[which]; - return gamepad->rumble.data.large_magnitude; -} - -fixed_t G_GetSmallMotorFreq(UINT8 which) -{ - if (!G_RumbleSupported(which) || which >= NUM_GAMEPADS) - return 0; - - gamepad_t *gamepad = &gamepads[which]; - return gamepad->rumble.data.small_magnitude; -} - -boolean G_GetGamepadRumblePaused(UINT8 which) -{ - return I_GetGamepadRumblePaused(which); -} - -boolean G_SetLargeMotorFreq(UINT8 which, fixed_t freq) -{ - return I_SetGamepadLargeMotorFreq(which, freq); -} - -boolean G_SetSmallMotorFreq(UINT8 which, fixed_t freq) -{ - return I_SetGamepadSmallMotorFreq(which, freq); -} - -void G_SetGamepadRumblePaused(UINT8 which, boolean pause) -{ - if (G_RumbleSupported(which)) - I_SetGamepadRumblePaused(which, pause); -} - -// Obtains the value of an axis, and makes it digital if needed -INT16 G_GamepadAxisEventValue(UINT8 which, INT16 value) -{ - gamepad_t *gamepad = &gamepads[which]; - - if (gamepad->digital) - { - const UINT16 jdeadzone = G_GetGamepadDigitalDeadZone(which); - - if (value < -jdeadzone) - value = -JOYAXISRANGE - 1; - else if (value > jdeadzone) - value = JOYAXISRANGE; - else - value = 0; - } - - return value; -} - -INT16 G_GetGamepadAxisValue(UINT8 which, gamepad_axis_e axis) -{ - gamepad_t *gamepad = &gamepads[which]; - - if (axis >= NUM_GAMEPAD_AXES) - return 0; - - return G_GamepadAxisEventValue(which, gamepad->axes[axis]); -} - -fixed_t G_GetAdjustedGamepadAxis(UINT8 which, gamepad_axis_e axis, boolean applyDeadzone) -{ - gamepad_t *gamepad = &gamepads[which]; - - if (axis >= NUM_GAMEPAD_AXES) - return 0; - - INT32 value = gamepad->axes[axis]; - - if (applyDeadzone && gamepad->digital) - { - INT16 deadzone = G_GetGamepadDigitalDeadZone(which); - - if (value < -deadzone) - value = -JOYAXISRANGE; - else if (value > deadzone) - value = JOYAXISRANGE; - else - value = 0; - } - else if (applyDeadzone) - { - INT32 sign = value < 0 ? -1 : 1; - INT16 deadzone = G_GetGamepadDeadZone(which); - INT32 magnitude = value * value; - INT32 nAxis = magnitude / JOYAXISRANGE; - INT32 nMagnitude = G_BasicDeadZoneCalculation(magnitude, deadzone); - - value = (nAxis * nMagnitude) / JOYAXISRANGE; - value = min(value * sign, JOYAXISRANGE); - value = max(value, -JOYAXISRANGE); - } - - return (value / 32767.0) * FRACUNIT; -} - -static UINT16 CalcGamepadDeadZone(fixed_t deadzone) -{ - INT32 value = (JOYAXISRANGE * deadzone) / FRACUNIT; - - if (value < 0) - value = 0; - else if (value > JOYAXISRANGE) - value = JOYAXISRANGE; - - return value; -} - -UINT16 G_GetGamepadDeadZone(UINT8 which) -{ - return CalcGamepadDeadZone(cv_deadzone[which].value); -} - -UINT16 G_GetGamepadDigitalDeadZone(UINT8 which) -{ - return CalcGamepadDeadZone(cv_digitaldeadzone[which].value); -} - -// Take a magnitude of two axes, and adjust it to take out the deadzone -// Will return a value between 0 and JOYAXISRANGE -INT32 G_BasicDeadZoneCalculation(INT32 magnitude, const UINT16 jdeadzone) -{ - INT32 deadzoneAppliedValue = 0; - INT32 adjustedMagnitude = abs(magnitude); - - if (jdeadzone >= JOYAXISRANGE && adjustedMagnitude >= JOYAXISRANGE) // If the deadzone and magnitude are both 100%... - return JOYAXISRANGE; // ...return 100% input directly, to avoid dividing by 0 - else if (adjustedMagnitude > jdeadzone) // Otherwise, calculate how much the magnitude exceeds the deadzone - { - adjustedMagnitude = min(adjustedMagnitude, JOYAXISRANGE); - - adjustedMagnitude -= jdeadzone; - - deadzoneAppliedValue = (adjustedMagnitude * JOYAXISRANGE) / (JOYAXISRANGE - jdeadzone); - } - - return deadzoneAppliedValue; -} - -INT32 G_RemapGamepadEvent(event_t *event, INT32 *type) -{ - if (event->type == ev_gamepad_down) - { - *type = ev_keydown; - return KEY_GAMEPAD + event->key; - } - else if (event->type == ev_gamepad_up) - { - *type = ev_keyup; - return KEY_GAMEPAD + event->key; - } - else if (event->type == ev_gamepad_axis) - { - const UINT16 jdeadzone = G_GetGamepadDigitalDeadZone(event->which); - const INT16 value = G_GetGamepadAxisValue(event->which, event->key); - - if (value < -jdeadzone || value > jdeadzone) - *type = ev_keyup; - else - *type = ev_keydown; - - if (value < -jdeadzone) - return KEY_INV_AXES + event->key; - else - return KEY_AXES + event->key; - } - - return event->key; -} - -typedef struct -{ - const char *name; - const char *menu1; - const char *menu2; -} button_strings_t; - -#define DEF_NAME_BUTTON(str) {.name = str, .menu1 = str " Button", .menu2 = "the " str " Button"} -#define DEF_NAME_SIMPLE(str) {.name = str, .menu1 = NULL, .menu2 = "the " str} -#define DEF_NAME_DPAD(a, b) {.name = "D-Pad " a, .menu1 = "D-Pad " b, .menu2 = a} - -#define PARTIAL_DEF_START [GAMEPAD_BUTTON_A] = { NULL } -#define PARTIAL_DEF_END [NUM_GAMEPAD_BUTTONS - 1] = { NULL } - -static const char *GetStringFromButtonList(const button_strings_t *names, gamepad_button_e button, gamepad_string_e type) -{ - switch (type) - { - case GAMEPAD_STRING_DEFAULT: - return names[button].name; - case GAMEPAD_STRING_MENU1: - if (names[button].menu1) - return names[button].menu1; - else - return names[button].name; - case GAMEPAD_STRING_MENU2: - if (names[button].menu2) - return names[button].menu2; - else - return names[button].name; - } - - return NULL; -} - -const char *G_GetGamepadButtonString(gamepadtype_e type, gamepad_button_e button, gamepad_string_e strtype) -{ - static const button_strings_t base_names[] = { - [GAMEPAD_BUTTON_A] = DEF_NAME_BUTTON("A"), - [GAMEPAD_BUTTON_B] = DEF_NAME_BUTTON("B"), - [GAMEPAD_BUTTON_X] = DEF_NAME_BUTTON("X"), - [GAMEPAD_BUTTON_Y] = DEF_NAME_BUTTON("Y"), - [GAMEPAD_BUTTON_BACK] = DEF_NAME_BUTTON("Back"), - [GAMEPAD_BUTTON_GUIDE] = DEF_NAME_BUTTON("Guide"), - [GAMEPAD_BUTTON_START] = DEF_NAME_BUTTON("Start"), - [GAMEPAD_BUTTON_LEFTSTICK] = DEF_NAME_SIMPLE("Left Stick"), - [GAMEPAD_BUTTON_RIGHTSTICK] = DEF_NAME_SIMPLE("Right Stick"), - [GAMEPAD_BUTTON_LEFTSHOULDER] = DEF_NAME_SIMPLE("Left Shoulder"), - [GAMEPAD_BUTTON_RIGHTSHOULDER] = DEF_NAME_SIMPLE("Right Shoulder"), - [GAMEPAD_BUTTON_DPAD_UP] = DEF_NAME_DPAD("Up", "\x1A"), - [GAMEPAD_BUTTON_DPAD_DOWN] = DEF_NAME_DPAD("Down", "\x1B"), - [GAMEPAD_BUTTON_DPAD_LEFT] = DEF_NAME_DPAD("Left", "\x1C"), - [GAMEPAD_BUTTON_DPAD_RIGHT] = DEF_NAME_DPAD("Right", "\x1D"), - [GAMEPAD_BUTTON_PADDLE1] = DEF_NAME_SIMPLE("Paddle 1"), - [GAMEPAD_BUTTON_PADDLE2] = DEF_NAME_SIMPLE("Paddle 2"), - [GAMEPAD_BUTTON_PADDLE3] = DEF_NAME_SIMPLE("Paddle 3"), - [GAMEPAD_BUTTON_PADDLE4] = DEF_NAME_SIMPLE("Paddle 4"), - [GAMEPAD_BUTTON_TOUCHPAD] = DEF_NAME_SIMPLE("Touchpad"), - - // This one's a bit weird - // Suffix the numbers in the event SDL adds more misc buttons - [GAMEPAD_BUTTON_MISC1] = { - .name = "Misc. Button", - .menu1 = "Gamepad Misc.", - .menu2 = "the Misc. Button" - }, - }; - - button_strings_t const *names = NULL; - - if (G_GamepadTypeIsXbox(type)) - { - #define BASE_XBOX_NAMES \ - [GAMEPAD_BUTTON_LEFTSHOULDER] = DEF_NAME_SIMPLE("Left Bumper"), \ - [GAMEPAD_BUTTON_RIGHTSHOULDER] = DEF_NAME_SIMPLE("Right Bumper") - - static const button_strings_t xbox_names[] = { PARTIAL_DEF_START, - BASE_XBOX_NAMES, - PARTIAL_DEF_END }; - - static const button_strings_t series_xs_names[] = { PARTIAL_DEF_START, - BASE_XBOX_NAMES, - [GAMEPAD_BUTTON_MISC1] = DEF_NAME_BUTTON("Share"), - PARTIAL_DEF_END }; - - static const button_strings_t elite_names[] = { PARTIAL_DEF_START, - BASE_XBOX_NAMES, - [GAMEPAD_BUTTON_PADDLE1] = DEF_NAME_SIMPLE("P1 Paddle"), - [GAMEPAD_BUTTON_PADDLE2] = DEF_NAME_SIMPLE("P2 Paddle"), - [GAMEPAD_BUTTON_PADDLE3] = DEF_NAME_SIMPLE("P3 Paddle"), - [GAMEPAD_BUTTON_PADDLE4] = DEF_NAME_SIMPLE("P4 Paddle"), - PARTIAL_DEF_END }; - - if (type == GAMEPAD_TYPE_XBOX_SERIES_XS) // X|S controllers have a Share button - names = series_xs_names; - else if (type == GAMEPAD_TYPE_XBOX_ELITE) // Elite controller has paddles - names = elite_names; - else - names = xbox_names; - - #undef BASE_XBOX_NAMES - } - else if (G_GamepadTypeIsPlayStation(type)) - { - #define BASE_PS_NAMES \ - [GAMEPAD_BUTTON_A] = DEF_NAME_BUTTON("Cross"), \ - [GAMEPAD_BUTTON_B] = DEF_NAME_BUTTON("Circle"), \ - [GAMEPAD_BUTTON_X] = DEF_NAME_BUTTON("Square"), \ - [GAMEPAD_BUTTON_Y] = DEF_NAME_BUTTON("Triangle"), \ - [GAMEPAD_BUTTON_BACK] = DEF_NAME_BUTTON("Select"), \ - [GAMEPAD_BUTTON_GUIDE] = DEF_NAME_BUTTON("PS"), \ - [GAMEPAD_BUTTON_LEFTSTICK] = DEF_NAME_BUTTON("L3"), \ - [GAMEPAD_BUTTON_RIGHTSTICK] = DEF_NAME_BUTTON("R3"), \ - [GAMEPAD_BUTTON_LEFTSHOULDER] = DEF_NAME_BUTTON("L1"), \ - [GAMEPAD_BUTTON_RIGHTSHOULDER] = DEF_NAME_BUTTON("R1") - - static const button_strings_t ps_names[] = { - BASE_PS_NAMES, - PARTIAL_DEF_END }; - - static const button_strings_t ps5_names[] = { - BASE_PS_NAMES, - [GAMEPAD_BUTTON_MISC1] = DEF_NAME_BUTTON("Microphone"), - PARTIAL_DEF_END }; - - names = type == GAMEPAD_TYPE_PS5 ? ps5_names : ps_names; - #undef BASE_PS_NAMES - } - else if (G_GamepadTypeIsNintendoSwitch(type)) - { - static const button_strings_t switch_names[] = { PARTIAL_DEF_START, - [GAMEPAD_BUTTON_BACK] = DEF_NAME_BUTTON("-"), - [GAMEPAD_BUTTON_GUIDE] = DEF_NAME_BUTTON("HOME"), - [GAMEPAD_BUTTON_START] = DEF_NAME_BUTTON("+"), - [GAMEPAD_BUTTON_LEFTSHOULDER] = DEF_NAME_BUTTON("L"), - [GAMEPAD_BUTTON_RIGHTSHOULDER] = DEF_NAME_BUTTON("R"), - [GAMEPAD_BUTTON_MISC1] = DEF_NAME_BUTTON("Capture"), - PARTIAL_DEF_END }; - - names = switch_names; - } - else if (type == GAMEPAD_TYPE_AMAZON_LUNA) - { - static const button_strings_t luna_names[] = { PARTIAL_DEF_START, - [GAMEPAD_BUTTON_MISC1] = DEF_NAME_BUTTON("Microphone"), - PARTIAL_DEF_END }; - - names = luna_names; - } - - const char *str = NULL; - - if (names) - str = GetStringFromButtonList(names, button, strtype); - if (str == NULL) - str = GetStringFromButtonList(base_names, button, strtype); - if (str) - return str; - - return "Unknown"; -} - -#undef DEF_NAME_BUTTON -#undef DEF_NAME_SIMPLE -#undef DEF_NAME_DPAD - -#undef PARTIAL_DEF_START -#undef PARTIAL_DEF_END - -typedef struct -{ - const char *name; - const char *menu1; - const char *menu2; - const char *name_inv; - const char *menu1_inv; - const char *menu2_inv; -} axis_strings_t; - -#define DEF_NAME_AXIS(str, a, inv_a, b, inv_b) {\ - str " " a, str " " b, "the " str " " b, \ - str " " inv_a, str " " inv_b, "the " str " " inv_b} -#define DEF_NAME_TRIGGER(str) {str, NULL, "the " str, NULL, NULL, NULL} -#define DEF_NAME_BUTTON(str) {str, str " Button", "the " str " Button", NULL, NULL, NULL} - -#define PARTIAL_DEF_START [GAMEPAD_AXIS_LEFTX] = { NULL } - -static const char *GetStringFromAxisList(const axis_strings_t *names, gamepad_axis_e axis, gamepad_string_e type, boolean inv) -{ - switch (type) - { - case GAMEPAD_STRING_DEFAULT: - if (inv && names[axis].name_inv) - return names[axis].name_inv; - else - return names[axis].name; - break; - case GAMEPAD_STRING_MENU1: - if (inv && names[axis].menu1_inv) - return names[axis].menu1_inv; - if (names[axis].menu1) - return names[axis].menu1; - else - return names[axis].name; - break; - case GAMEPAD_STRING_MENU2: - if (inv && names[axis].menu2_inv) - return names[axis].menu2_inv; - if (names[axis].menu2) - return names[axis].menu2; - else - return names[axis].name; - break; - } - - return NULL; -} - -const char *G_GetGamepadAxisString(gamepadtype_e type, gamepad_axis_e axis, gamepad_string_e strtype, boolean inv) -{ - static const axis_strings_t base_names[] = { - [GAMEPAD_AXIS_LEFTX] = DEF_NAME_AXIS("Left Stick", "X", "X-", "\x1D", "\x1C"), - [GAMEPAD_AXIS_LEFTY] = DEF_NAME_AXIS("Left Stick", "Y", "Y-", "\x1B", "\x1A"), - [GAMEPAD_AXIS_RIGHTX] = DEF_NAME_AXIS("Right Stick", "X", "X-", "\x1D", "\x1C"), - [GAMEPAD_AXIS_RIGHTY] = DEF_NAME_AXIS("Right Stick", "Y", "Y-", "\x1B", "\x1A"), - [GAMEPAD_AXIS_TRIGGERLEFT] = DEF_NAME_TRIGGER("Left Trigger"), - [GAMEPAD_AXIS_TRIGGERRIGHT] = DEF_NAME_TRIGGER("Right Trigger") - }; - - axis_strings_t const *names = NULL; - - if (G_GamepadTypeIsPlayStation(type)) - { - static const axis_strings_t ps_names[] = { PARTIAL_DEF_START, - [GAMEPAD_AXIS_TRIGGERLEFT] = DEF_NAME_BUTTON("L2"), - [GAMEPAD_AXIS_TRIGGERRIGHT] = DEF_NAME_BUTTON("R2"), - }; - - names = ps_names; - } - else if (G_GamepadTypeIsNintendoSwitch(type)) - { - static const axis_strings_t switch_names[] = { PARTIAL_DEF_START, - [GAMEPAD_AXIS_TRIGGERLEFT] = DEF_NAME_BUTTON("ZL"), - [GAMEPAD_AXIS_TRIGGERRIGHT] = DEF_NAME_BUTTON("ZR"), - }; - - names = switch_names; - } - - const char *str = NULL; - - if (names) - str = GetStringFromAxisList(names, axis, strtype, inv); - if (str == NULL) - str = GetStringFromAxisList(base_names, axis, strtype, inv); - if (str) - return str; - - return "Unknown"; -} - -#undef DEF_NAME_AXIS -#undef DEF_NAME_TRIGGER -#undef DEF_NAME_BUTTON - -#undef PARTIAL_DEF_START - typedef struct { INT32 keynum; @@ -842,17 +243,20 @@ static keyname_t keynames[] = {KEY_NUMLOCK, "numlock"}, {KEY_SCROLLLOCK, "scrolllock"}, - // satya nadella keys + // bill gates keys {KEY_LEFTWIN, "leftwin"}, {KEY_RIGHTWIN, "rightwin"}, {KEY_MENU, "menu"}, {KEY_LSHIFT, "lshift"}, {KEY_RSHIFT, "rshift"}, + {KEY_LSHIFT, "shift"}, {KEY_LCTRL, "lctrl"}, {KEY_RCTRL, "rctrl"}, + {KEY_LCTRL, "ctrl"}, {KEY_LALT, "lalt"}, {KEY_RALT, "ralt"}, + {KEY_LALT, "alt"}, // keypad keys {KEY_KPADSLASH, "keypad /"}, @@ -900,7 +304,7 @@ static keyname_t keynames[] = {'`', "TILDE"}, {KEY_PAUSE, "pause/break"}, - // virtual keys for mouse buttons and gamepad buttons + // virtual keys for mouse buttons and joystick buttons {KEY_MOUSE1+0,"mouse1"}, {KEY_MOUSE1+1,"mouse2"}, {KEY_MOUSE1+2,"mouse3"}, @@ -909,8 +313,8 @@ static keyname_t keynames[] = {KEY_MOUSE1+5,"mouse6"}, {KEY_MOUSE1+6,"mouse7"}, {KEY_MOUSE1+7,"mouse8"}, - {KEY_2MOUSE1+0,"sec_mouse1"}, - {KEY_2MOUSE1+1,"sec_mouse2"}, + {KEY_2MOUSE1+0,"sec_mouse2"}, // BP: sorry my mouse handler swap button 1 and 2 + {KEY_2MOUSE1+1,"sec_mouse1"}, {KEY_2MOUSE1+2,"sec_mouse3"}, {KEY_2MOUSE1+3,"sec_mouse4"}, {KEY_2MOUSE1+4,"sec_mouse5"}, @@ -922,48 +326,58 @@ static keyname_t keynames[] = {KEY_2MOUSEWHEELUP, "wheel 2 up"}, {KEY_2MOUSEWHEELDOWN, "wheel 2 down"}, -#define DEF_GAMEPAD_NAME(btn, name) {KEY_GAMEPAD+GAMEPAD_BUTTON_##btn, name} -#define DEF_GAMEPAD_AXIS(ax, name) \ - {KEY_AXES+GAMEPAD_AXIS_##ax, name}, \ - {KEY_INV_AXES+GAMEPAD_AXIS_##ax, name "-"} - - DEF_GAMEPAD_NAME(A, "a button"), - DEF_GAMEPAD_NAME(B, "b button"), - DEF_GAMEPAD_NAME(X, "x button"), - DEF_GAMEPAD_NAME(Y, "y button"), - - DEF_GAMEPAD_NAME(BACK, "back button"), - DEF_GAMEPAD_NAME(GUIDE, "guide button"), - DEF_GAMEPAD_NAME(START, "start button"), - DEF_GAMEPAD_NAME(LEFTSTICK, "left stick"), - DEF_GAMEPAD_NAME(RIGHTSTICK, "right stick"), - - DEF_GAMEPAD_NAME(LEFTSHOULDER, "left shoulder"), - DEF_GAMEPAD_NAME(RIGHTSHOULDER, "right shoulder"), - - DEF_GAMEPAD_NAME(DPAD_UP, "d-pad up"), - DEF_GAMEPAD_NAME(DPAD_DOWN, "d-pad down"), - DEF_GAMEPAD_NAME(DPAD_LEFT, "d-pad left"), - DEF_GAMEPAD_NAME(DPAD_RIGHT, "d-pad right"), - - DEF_GAMEPAD_NAME(MISC1, "gamepad misc 1"), - DEF_GAMEPAD_NAME(PADDLE1, "paddle 1"), - DEF_GAMEPAD_NAME(PADDLE2, "paddle 2"), - DEF_GAMEPAD_NAME(PADDLE3, "paddle 3"), - DEF_GAMEPAD_NAME(PADDLE4, "paddle 4"), - DEF_GAMEPAD_NAME(TOUCHPAD, "touchpad"), - - DEF_GAMEPAD_AXIS(LEFTX, "left stick x"), - DEF_GAMEPAD_AXIS(LEFTY, "left stick y"), - - DEF_GAMEPAD_AXIS(RIGHTX, "right stick x"), - DEF_GAMEPAD_AXIS(RIGHTY, "right stick y"), - - DEF_GAMEPAD_AXIS(TRIGGERLEFT, "left trigger"), - DEF_GAMEPAD_AXIS(TRIGGERRIGHT, "right trigger"), - -#undef DEF_GAMEPAD_NAME -#undef DEF_GAMEPAD_AXIS + {KEY_JOY1+0, "joy1"}, + {KEY_JOY1+1, "joy2"}, + {KEY_JOY1+2, "joy3"}, + {KEY_JOY1+3, "joy4"}, + {KEY_JOY1+4, "joy5"}, + {KEY_JOY1+5, "joy6"}, + {KEY_JOY1+6, "joy7"}, + {KEY_JOY1+7, "joy8"}, + {KEY_JOY1+8, "joy9"}, +#if !defined (NOMOREJOYBTN_1S) + // we use up to 32 buttons in DirectInput + {KEY_JOY1+9, "joy10"}, + {KEY_JOY1+10, "joy11"}, + {KEY_JOY1+11, "joy12"}, + {KEY_JOY1+12, "joy13"}, + {KEY_JOY1+13, "joy14"}, + {KEY_JOY1+14, "joy15"}, + {KEY_JOY1+15, "joy16"}, + {KEY_JOY1+16, "joy17"}, + {KEY_JOY1+17, "joy18"}, + {KEY_JOY1+18, "joy19"}, + {KEY_JOY1+19, "joy20"}, + {KEY_JOY1+20, "joy21"}, + {KEY_JOY1+21, "joy22"}, + {KEY_JOY1+22, "joy23"}, + {KEY_JOY1+23, "joy24"}, + {KEY_JOY1+24, "joy25"}, + {KEY_JOY1+25, "joy26"}, + {KEY_JOY1+26, "joy27"}, + {KEY_JOY1+27, "joy28"}, + {KEY_JOY1+28, "joy29"}, + {KEY_JOY1+29, "joy30"}, + {KEY_JOY1+30, "joy31"}, + {KEY_JOY1+31, "joy32"}, +#endif + // the DOS version uses Allegro's joystick support + {KEY_HAT1+0, "hatup"}, + {KEY_HAT1+1, "hatdown"}, + {KEY_HAT1+2, "hatleft"}, + {KEY_HAT1+3, "hatright"}, + {KEY_HAT1+4, "hatup2"}, + {KEY_HAT1+5, "hatdown2"}, + {KEY_HAT1+6, "hatleft2"}, + {KEY_HAT1+7, "hatright2"}, + {KEY_HAT1+8, "hatup3"}, + {KEY_HAT1+9, "hatdown3"}, + {KEY_HAT1+10, "hatleft3"}, + {KEY_HAT1+11, "hatright3"}, + {KEY_HAT1+12, "hatup4"}, + {KEY_HAT1+13, "hatdown4"}, + {KEY_HAT1+14, "hatleft4"}, + {KEY_HAT1+15, "hatright4"}, {KEY_DBLMOUSE1+0, "dblmouse1"}, {KEY_DBLMOUSE1+1, "dblmouse2"}, @@ -973,154 +387,172 @@ static keyname_t keynames[] = {KEY_DBLMOUSE1+5, "dblmouse6"}, {KEY_DBLMOUSE1+6, "dblmouse7"}, {KEY_DBLMOUSE1+7, "dblmouse8"}, - {KEY_DBL2MOUSE1+0, "dblsec_mouse1"}, - {KEY_DBL2MOUSE1+1, "dblsec_mouse2"}, + {KEY_DBL2MOUSE1+0, "dblsec_mouse2"}, // BP: sorry my mouse handler swap button 1 and 2 + {KEY_DBL2MOUSE1+1, "dblsec_mouse1"}, {KEY_DBL2MOUSE1+2, "dblsec_mouse3"}, {KEY_DBL2MOUSE1+3, "dblsec_mouse4"}, {KEY_DBL2MOUSE1+4, "dblsec_mouse5"}, {KEY_DBL2MOUSE1+5, "dblsec_mouse6"}, {KEY_DBL2MOUSE1+6, "dblsec_mouse7"}, - {KEY_DBL2MOUSE1+7, "dblsec_mouse8"} -}; + {KEY_DBL2MOUSE1+7, "dblsec_mouse8"}, -#define NUMKEYNAMES (sizeof(keynames) / sizeof(keyname_t)) - -static keyname_t displaykeynames[] = -{ - {KEY_SPACE, "Space Bar"}, - {KEY_CAPSLOCK, "Caps Lock"}, - {KEY_ENTER, "Enter"}, - {KEY_TAB, "Tab"}, - {KEY_ESCAPE, "Escape"}, - {KEY_BACKSPACE, "Backspace"}, - - {KEY_NUMLOCK, "Num Lock"}, - {KEY_SCROLLLOCK, "Scroll Lock"}, - -#ifdef _WIN32 - {KEY_LEFTWIN, "Left Windows"}, - {KEY_RIGHTWIN, "Right Windows"}, -#else - {KEY_LEFTWIN, "Left Super"}, - {KEY_RIGHTWIN, "Right Super"}, + {KEY_DBLJOY1+0, "dbljoy1"}, + {KEY_DBLJOY1+1, "dbljoy2"}, + {KEY_DBLJOY1+2, "dbljoy3"}, + {KEY_DBLJOY1+3, "dbljoy4"}, + {KEY_DBLJOY1+4, "dbljoy5"}, + {KEY_DBLJOY1+5, "dbljoy6"}, + {KEY_DBLJOY1+6, "dbljoy7"}, + {KEY_DBLJOY1+7, "dbljoy8"}, +#if !defined (NOMOREJOYBTN_1DBL) + {KEY_DBLJOY1+8, "dbljoy9"}, + {KEY_DBLJOY1+9, "dbljoy10"}, + {KEY_DBLJOY1+10, "dbljoy11"}, + {KEY_DBLJOY1+11, "dbljoy12"}, + {KEY_DBLJOY1+12, "dbljoy13"}, + {KEY_DBLJOY1+13, "dbljoy14"}, + {KEY_DBLJOY1+14, "dbljoy15"}, + {KEY_DBLJOY1+15, "dbljoy16"}, + {KEY_DBLJOY1+16, "dbljoy17"}, + {KEY_DBLJOY1+17, "dbljoy18"}, + {KEY_DBLJOY1+18, "dbljoy19"}, + {KEY_DBLJOY1+19, "dbljoy20"}, + {KEY_DBLJOY1+20, "dbljoy21"}, + {KEY_DBLJOY1+21, "dbljoy22"}, + {KEY_DBLJOY1+22, "dbljoy23"}, + {KEY_DBLJOY1+23, "dbljoy24"}, + {KEY_DBLJOY1+24, "dbljoy25"}, + {KEY_DBLJOY1+25, "dbljoy26"}, + {KEY_DBLJOY1+26, "dbljoy27"}, + {KEY_DBLJOY1+27, "dbljoy28"}, + {KEY_DBLJOY1+28, "dbljoy29"}, + {KEY_DBLJOY1+29, "dbljoy30"}, + {KEY_DBLJOY1+30, "dbljoy31"}, + {KEY_DBLJOY1+31, "dbljoy32"}, #endif + {KEY_DBLHAT1+0, "dblhatup"}, + {KEY_DBLHAT1+1, "dblhatdown"}, + {KEY_DBLHAT1+2, "dblhatleft"}, + {KEY_DBLHAT1+3, "dblhatright"}, + {KEY_DBLHAT1+4, "dblhatup2"}, + {KEY_DBLHAT1+5, "dblhatdown2"}, + {KEY_DBLHAT1+6, "dblhatleft2"}, + {KEY_DBLHAT1+7, "dblhatright2"}, + {KEY_DBLHAT1+8, "dblhatup3"}, + {KEY_DBLHAT1+9, "dblhatdown3"}, + {KEY_DBLHAT1+10, "dblhatleft3"}, + {KEY_DBLHAT1+11, "dblhatright3"}, + {KEY_DBLHAT1+12, "dblhatup4"}, + {KEY_DBLHAT1+13, "dblhatdown4"}, + {KEY_DBLHAT1+14, "dblhatleft4"}, + {KEY_DBLHAT1+15, "dblhatright4"}, - {KEY_MENU, "Menu"}, + {KEY_2JOY1+0, "sec_joy1"}, + {KEY_2JOY1+1, "sec_joy2"}, + {KEY_2JOY1+2, "sec_joy3"}, + {KEY_2JOY1+3, "sec_joy4"}, + {KEY_2JOY1+4, "sec_joy5"}, + {KEY_2JOY1+5, "sec_joy6"}, + {KEY_2JOY1+6, "sec_joy7"}, + {KEY_2JOY1+7, "sec_joy8"}, +#if !defined (NOMOREJOYBTN_2S) + // we use up to 32 buttons in DirectInput + {KEY_2JOY1+8, "sec_joy9"}, + {KEY_2JOY1+9, "sec_joy10"}, + {KEY_2JOY1+10, "sec_joy11"}, + {KEY_2JOY1+11, "sec_joy12"}, + {KEY_2JOY1+12, "sec_joy13"}, + {KEY_2JOY1+13, "sec_joy14"}, + {KEY_2JOY1+14, "sec_joy15"}, + {KEY_2JOY1+15, "sec_joy16"}, + {KEY_2JOY1+16, "sec_joy17"}, + {KEY_2JOY1+17, "sec_joy18"}, + {KEY_2JOY1+18, "sec_joy19"}, + {KEY_2JOY1+19, "sec_joy20"}, + {KEY_2JOY1+20, "sec_joy21"}, + {KEY_2JOY1+21, "sec_joy22"}, + {KEY_2JOY1+22, "sec_joy23"}, + {KEY_2JOY1+23, "sec_joy24"}, + {KEY_2JOY1+24, "sec_joy25"}, + {KEY_2JOY1+25, "sec_joy26"}, + {KEY_2JOY1+26, "sec_joy27"}, + {KEY_2JOY1+27, "sec_joy28"}, + {KEY_2JOY1+28, "sec_joy29"}, + {KEY_2JOY1+29, "sec_joy30"}, + {KEY_2JOY1+30, "sec_joy31"}, + {KEY_2JOY1+31, "sec_joy32"}, +#endif + // the DOS version uses Allegro's joystick support + {KEY_2HAT1+0, "sec_hatup"}, + {KEY_2HAT1+1, "sec_hatdown"}, + {KEY_2HAT1+2, "sec_hatleft"}, + {KEY_2HAT1+3, "sec_hatright"}, + {KEY_2HAT1+4, "sec_hatup2"}, + {KEY_2HAT1+5, "sec_hatdown2"}, + {KEY_2HAT1+6, "sec_hatleft2"}, + {KEY_2HAT1+7, "sec_hatright2"}, + {KEY_2HAT1+8, "sec_hatup3"}, + {KEY_2HAT1+9, "sec_hatdown3"}, + {KEY_2HAT1+10, "sec_hatleft3"}, + {KEY_2HAT1+11, "sec_hatright3"}, + {KEY_2HAT1+12, "sec_hatup4"}, + {KEY_2HAT1+13, "sec_hatdown4"}, + {KEY_2HAT1+14, "sec_hatleft4"}, + {KEY_2HAT1+15, "sec_hatright4"}, - {KEY_LSHIFT, "Left Shift"}, - {KEY_RSHIFT, "Right Shift"}, - {KEY_LCTRL, "Left Ctrl"}, - {KEY_RCTRL, "Right Ctrl"}, - {KEY_LALT, "Left Alt"}, - {KEY_RALT, "Right Alt"}, + {KEY_DBL2JOY1+0, "dblsec_joy1"}, + {KEY_DBL2JOY1+1, "dblsec_joy2"}, + {KEY_DBL2JOY1+2, "dblsec_joy3"}, + {KEY_DBL2JOY1+3, "dblsec_joy4"}, + {KEY_DBL2JOY1+4, "dblsec_joy5"}, + {KEY_DBL2JOY1+5, "dblsec_joy6"}, + {KEY_DBL2JOY1+6, "dblsec_joy7"}, + {KEY_DBL2JOY1+7, "dblsec_joy8"}, +#if !defined (NOMOREJOYBTN_2DBL) + {KEY_DBL2JOY1+8, "dblsec_joy9"}, + {KEY_DBL2JOY1+9, "dblsec_joy10"}, + {KEY_DBL2JOY1+10, "dblsec_joy11"}, + {KEY_DBL2JOY1+11, "dblsec_joy12"}, + {KEY_DBL2JOY1+12, "dblsec_joy13"}, + {KEY_DBL2JOY1+13, "dblsec_joy14"}, + {KEY_DBL2JOY1+14, "dblsec_joy15"}, + {KEY_DBL2JOY1+15, "dblsec_joy16"}, + {KEY_DBL2JOY1+16, "dblsec_joy17"}, + {KEY_DBL2JOY1+17, "dblsec_joy18"}, + {KEY_DBL2JOY1+18, "dblsec_joy19"}, + {KEY_DBL2JOY1+19, "dblsec_joy20"}, + {KEY_DBL2JOY1+20, "dblsec_joy21"}, + {KEY_DBL2JOY1+21, "dblsec_joy22"}, + {KEY_DBL2JOY1+22, "dblsec_joy23"}, + {KEY_DBL2JOY1+23, "dblsec_joy24"}, + {KEY_DBL2JOY1+24, "dblsec_joy25"}, + {KEY_DBL2JOY1+25, "dblsec_joy26"}, + {KEY_DBL2JOY1+26, "dblsec_joy27"}, + {KEY_DBL2JOY1+27, "dblsec_joy28"}, + {KEY_DBL2JOY1+28, "dblsec_joy29"}, + {KEY_DBL2JOY1+29, "dblsec_joy30"}, + {KEY_DBL2JOY1+30, "dblsec_joy31"}, + {KEY_DBL2JOY1+31, "dblsec_joy32"}, +#endif + {KEY_DBL2HAT1+0, "dblsec_hatup"}, + {KEY_DBL2HAT1+1, "dblsec_hatdown"}, + {KEY_DBL2HAT1+2, "dblsec_hatleft"}, + {KEY_DBL2HAT1+3, "dblsec_hatright"}, + {KEY_DBL2HAT1+4, "dblsec_hatup2"}, + {KEY_DBL2HAT1+5, "dblsec_hatdown2"}, + {KEY_DBL2HAT1+6, "dblsec_hatleft2"}, + {KEY_DBL2HAT1+7, "dblsec_hatright2"}, + {KEY_DBL2HAT1+8, "dblsec_hatup3"}, + {KEY_DBL2HAT1+9, "dblsec_hatdown3"}, + {KEY_DBL2HAT1+10, "dblsec_hatleft3"}, + {KEY_DBL2HAT1+11, "dblsec_hatright3"}, + {KEY_DBL2HAT1+12, "dblsec_hatup4"}, + {KEY_DBL2HAT1+13, "dblsec_hatdown4"}, + {KEY_DBL2HAT1+14, "dblsec_hatleft4"}, + {KEY_DBL2HAT1+15, "dblsec_hatright4"}, - {KEY_KEYPAD0, "Keypad 0"}, - {KEY_KEYPAD1, "Keypad 1"}, - {KEY_KEYPAD2, "Keypad 2"}, - {KEY_KEYPAD3, "Keypad 3"}, - {KEY_KEYPAD4, "Keypad 4"}, - {KEY_KEYPAD5, "Keypad 5"}, - {KEY_KEYPAD6, "Keypad 6"}, - {KEY_KEYPAD7, "Keypad 7"}, - {KEY_KEYPAD8, "Keypad 8"}, - {KEY_KEYPAD9, "Keypad 9"}, - {KEY_PLUSPAD, "Keypad +"}, - {KEY_MINUSPAD, "Keypad -"}, - {KEY_KPADSLASH, "Keypad /"}, - {KEY_KPADDEL, "Keypad ."}, - - {KEY_UPARROW, "Up Arrow"}, - {KEY_DOWNARROW, "Down Arrow"}, - {KEY_LEFTARROW, "Left Arrow"}, - {KEY_RIGHTARROW, "Right Arrow"}, - - {KEY_HOME, "Home"}, - {KEY_END, "End"}, - {KEY_PGUP, "Page Up"}, - {KEY_PGDN, "Page Down"}, - {KEY_INS, "Insert"}, - {KEY_DEL, "Delete"}, - - {KEY_F1, "F1"}, - {KEY_F2, "F2"}, - {KEY_F3, "F3"}, - {KEY_F4, "F4"}, - {KEY_F5, "F5"}, - {KEY_F6, "F6"}, - {KEY_F7, "F7"}, - {KEY_F8, "F8"}, - {KEY_F9, "F9"}, - {KEY_F10, "F10"}, - {KEY_F11, "F11"}, - {KEY_F12, "F12"}, - - {'`', "Tilde"}, - {KEY_PAUSE, "Pause/Break"}, - - {KEY_MOUSE1+0, "Left Mouse Button"}, - {KEY_MOUSE1+1, "Right Mouse Button"}, - {KEY_MOUSE1+2, "Middle Mouse Button"}, - {KEY_MOUSE1+3, "X1 Mouse Button"}, - {KEY_MOUSE1+4, "X2 Mouse Button"}, - - {KEY_2MOUSE1+0, "Sec. Mouse Left Button"}, - {KEY_2MOUSE1+1, "Sec. Mouse Right Button"}, - {KEY_2MOUSE1+2, "Sec. Mouse Middle Button"}, - {KEY_2MOUSE1+3, "Sec. Mouse X1 Button"}, - {KEY_2MOUSE1+4, "Sec. Mouse X2 Button"}, - - {KEY_MOUSEWHEELUP, "Mouse Wheel Up"}, - {KEY_MOUSEWHEELDOWN, "Mouse Wheel Down"}, - {KEY_2MOUSEWHEELUP, "Sec. Mouse Wheel Up"}, - {KEY_2MOUSEWHEELDOWN, "Sec. Mouse Wheel Down"}, - -#define DEF_GAMEPAD_NAME(btn, name) {KEY_GAMEPAD+GAMEPAD_BUTTON_##btn, name} -#define DEF_GAMEPAD_AXIS(ax, name) {KEY_AXES+GAMEPAD_AXIS_##ax, name} - - DEF_GAMEPAD_NAME(A, "A Button"), - DEF_GAMEPAD_NAME(B, "B Button"), - DEF_GAMEPAD_NAME(X, "X Button"), - DEF_GAMEPAD_NAME(Y, "Y Button"), - - DEF_GAMEPAD_NAME(BACK, "Back Button"), - DEF_GAMEPAD_NAME(GUIDE, "Guide Button"), - DEF_GAMEPAD_NAME(START, "Start Button"), - DEF_GAMEPAD_NAME(LEFTSTICK, "Left Stick Button"), - DEF_GAMEPAD_NAME(RIGHTSTICK, "Right Stick Button"), - - DEF_GAMEPAD_NAME(LEFTSHOULDER, "Left Shoulder"), - DEF_GAMEPAD_NAME(RIGHTSHOULDER, "Right Shoulder"), - - DEF_GAMEPAD_NAME(DPAD_UP, "D-Pad Up"), - DEF_GAMEPAD_NAME(DPAD_DOWN, "D-Pad Down"), - DEF_GAMEPAD_NAME(DPAD_LEFT, "D-Pad Left"), - DEF_GAMEPAD_NAME(DPAD_RIGHT, "D-Pad Right"), - - DEF_GAMEPAD_NAME(MISC1, "Gamepad Misc. 1"), - DEF_GAMEPAD_NAME(PADDLE1, "Paddle 1"), - DEF_GAMEPAD_NAME(PADDLE2, "Paddle 2"), - DEF_GAMEPAD_NAME(PADDLE3, "Paddle 3"), - DEF_GAMEPAD_NAME(PADDLE4, "Paddle 4"), - DEF_GAMEPAD_NAME(TOUCHPAD, "Touchpad"), - - {KEY_INV_AXES + GAMEPAD_AXIS_LEFTX, "Left Stick \x1C"}, - {KEY_AXES + GAMEPAD_AXIS_LEFTX, "Left Stick \x1D"}, - {KEY_INV_AXES + GAMEPAD_AXIS_LEFTY, "Left Stick \x1A"}, - {KEY_AXES + GAMEPAD_AXIS_LEFTY, "Left Stick \x1B"}, - {KEY_INV_AXES + GAMEPAD_AXIS_RIGHTX, "Right Stick \x1C"}, - {KEY_AXES + GAMEPAD_AXIS_RIGHTX, "Right Stick \x1D"}, - {KEY_INV_AXES + GAMEPAD_AXIS_RIGHTY, "Right Stick \x1A"}, - {KEY_AXES + GAMEPAD_AXIS_RIGHTY, "Right Stick \x1B"}, - - DEF_GAMEPAD_AXIS(TRIGGERLEFT, "Left Trigger"), - DEF_GAMEPAD_AXIS(TRIGGERRIGHT, "Right Trigger"), - -#undef DEF_GAMEPAD_NAME -#undef DEF_GAMEPAD_AXIS }; -#define NUMDISPLAYKEYNAMES (sizeof(displaykeynames) / sizeof(keyname_t)) - static const char *gamecontrolname[NUM_GAMECONTROLS] = { "nothing", // a key/button mapped to GC_NULL has no effect @@ -1168,6 +600,8 @@ static const char *gamecontrolname[NUM_GAMECONTROLS] = "custom3", }; +#define NUMKEYNAMES (sizeof (keynames)/sizeof (keyname_t)) + // // Detach any keys associated to the given game control // - pass the pointer to the gamecontrol table for the player being edited @@ -1188,7 +622,7 @@ void G_ClearAllControlKeys(void) } // -// Returns the name of a key (or virtual key for mouse and gamepad) +// Returns the name of a key (or virtual key for mouse and joy) // the input value being an keynum // const char *G_KeyNumToName(INT32 keynum) @@ -1211,44 +645,7 @@ const char *G_KeyNumToName(INT32 keynum) return keynames[j].name; // create a name for unknown keys - snprintf(keynamestr, sizeof keynamestr, "KEY%d", keynum); - return keynamestr; -} - -const char *G_GetDisplayNameForKey(INT32 keynum) -{ - static char keynamestr[32]; - - UINT32 j; - - // find a description for special keys - for (j = 0; j < NUMDISPLAYKEYNAMES; j++) - if (displaykeynames[j].keynum == keynum) - return displaykeynames[j].name; - - // return a string with the ascii char if displayable - if (keynum > ' ' && keynum <= 'z' && keynum != KEY_CONSOLE) - { - snprintf(keynamestr, sizeof keynamestr, "%c Key", toupper((char)keynum)); - return keynamestr; - } - - // unnamed mouse buttons - if (keynum >= KEY_MOUSE1 && keynum <= KEY_MOUSE1+7) - { - j = (keynum - KEY_MOUSE1) + 1; - snprintf(keynamestr, sizeof keynamestr, "Mouse Button #%d", j); - return keynamestr; - } - else if (keynum >= KEY_2MOUSE1 && keynum <= KEY_2MOUSE1+7) - { - j = (keynum - KEY_2MOUSE1) + 1; - snprintf(keynamestr, sizeof keynamestr, "Sec. Mouse Button #%d", j); - return keynamestr; - } - - // create a name for unknown keys - snprintf(keynamestr, sizeof keynamestr, "Unknown Key %d", keynum); + sprintf(keynamestr, "KEY%d", keynum); return keynamestr; } @@ -1275,36 +672,6 @@ INT32 G_KeyNameToNum(const char *keystr) return 0; } -const char *G_GamepadTypeToString(gamepadtype_e type) -{ - static const char *names[] = { - "xbox-360", - "xbox-one", - "xbox-series-xs", - "xbox-elite", - "ps3", - "ps4", - "ps5", - "switch-pro", - "switch-joy-con-grip", - "switch-joy-con-left", - "switch-joy-con-right", - "stadia", - "amazon-luna", - "steam-controller", - "virtual", - "unknown" - }; - - return names[type]; -} - -void G_InitGamepads(void) -{ - for (UINT8 i = 0; i < NUM_GAMEPADS; i++) - gamepads[i].num = i; -} - void G_DefineDefaultControls(void) { INT32 i; @@ -1372,36 +739,36 @@ void G_DefineDefaultControls(void) gamecontroldefault[i][GC_VIEWPOINTNEXT][0] = KEY_F12; // Gamepad controls -- same for both schemes - gamecontroldefault[i][GC_JUMP ][1] = GAMEPAD_KEY(A); // A - gamecontroldefault[i][GC_SPIN ][1] = GAMEPAD_KEY(X); // X - gamecontroldefault[i][GC_CUSTOM1 ][1] = GAMEPAD_KEY(B); // B - gamecontroldefault[i][GC_CUSTOM2 ][1] = GAMEPAD_KEY(Y); // Y - gamecontroldefault[i][GC_CUSTOM3 ][1] = GAMEPAD_KEY(LEFTSTICK); // Left Stick - gamecontroldefault[i][GC_CENTERVIEW ][1] = GAMEPAD_KEY(RIGHTSTICK); // Right Stick - gamecontroldefault[i][GC_WEAPONPREV ][1] = GAMEPAD_KEY(LEFTSHOULDER); // LB - gamecontroldefault[i][GC_WEAPONNEXT ][1] = GAMEPAD_KEY(RIGHTSHOULDER); // RB - gamecontroldefault[i][GC_SCREENSHOT ][1] = GAMEPAD_KEY(BACK); // Back - gamecontroldefault[i][GC_SYSTEMMENU ][0] = GAMEPAD_KEY(START); // Start - gamecontroldefault[i][GC_CAMTOGGLE ][1] = GAMEPAD_KEY(DPAD_UP); // D-Pad Up - gamecontroldefault[i][GC_VIEWPOINTNEXT][1] = GAMEPAD_KEY(DPAD_DOWN); // D-Pad Down - gamecontroldefault[i][GC_TOSSFLAG ][1] = GAMEPAD_KEY(DPAD_LEFT); // D-Pad Left - gamecontroldefault[i][GC_SCORES ][1] = GAMEPAD_KEY(DPAD_RIGHT); // D-Pad Right + gamecontroldefault[i][GC_JUMP ][1] = KEY_JOY1+0; // A + gamecontroldefault[i][GC_SPIN ][1] = KEY_JOY1+2; // X + gamecontroldefault[i][GC_CUSTOM1 ][1] = KEY_JOY1+1; // B + gamecontroldefault[i][GC_CUSTOM2 ][1] = KEY_JOY1+3; // Y + gamecontroldefault[i][GC_CUSTOM3 ][1] = KEY_JOY1+8; // Left Stick + gamecontroldefault[i][GC_CENTERVIEW ][1] = KEY_JOY1+9; // Right Stick + gamecontroldefault[i][GC_WEAPONPREV ][1] = KEY_JOY1+4; // LB + gamecontroldefault[i][GC_WEAPONNEXT ][1] = KEY_JOY1+5; // RB + gamecontroldefault[i][GC_SCREENSHOT ][1] = KEY_JOY1+6; // Back + gamecontroldefault[i][GC_SYSTEMMENU ][0] = KEY_JOY1+7; // Start + gamecontroldefault[i][GC_CAMTOGGLE ][1] = KEY_HAT1+0; // D-Pad Up + gamecontroldefault[i][GC_VIEWPOINTNEXT][1] = KEY_HAT1+1; // D-Pad Down + gamecontroldefault[i][GC_TOSSFLAG ][1] = KEY_HAT1+2; // D-Pad Left + gamecontroldefault[i][GC_SCORES ][1] = KEY_HAT1+3; // D-Pad Right - // Second player only has gamepad defaults - gamecontrolbisdefault[i][GC_JUMP ][1] = GAMEPAD_KEY(A); // A - gamecontrolbisdefault[i][GC_SPIN ][1] = GAMEPAD_KEY(X); // X - gamecontrolbisdefault[i][GC_CUSTOM1 ][1] = GAMEPAD_KEY(B); // B - gamecontrolbisdefault[i][GC_CUSTOM2 ][1] = GAMEPAD_KEY(Y); // Y - gamecontrolbisdefault[i][GC_CUSTOM3 ][1] = GAMEPAD_KEY(LEFTSTICK); // Left Stick - gamecontrolbisdefault[i][GC_CENTERVIEW ][1] = GAMEPAD_KEY(RIGHTSTICK); // Right Stick - gamecontrolbisdefault[i][GC_WEAPONPREV ][1] = GAMEPAD_KEY(LEFTSHOULDER); // LB - gamecontrolbisdefault[i][GC_WEAPONNEXT ][1] = GAMEPAD_KEY(RIGHTSHOULDER); // RB - gamecontrolbisdefault[i][GC_SCREENSHOT ][1] = GAMEPAD_KEY(BACK); // Back - //gamecontrolbisdefault[i][GC_SYSTEMMENU ][0] = GAMEPAD_KEY(START); // Start - gamecontrolbisdefault[i][GC_CAMTOGGLE ][1] = GAMEPAD_KEY(DPAD_UP); // D-Pad Up - gamecontrolbisdefault[i][GC_VIEWPOINTNEXT][1] = GAMEPAD_KEY(DPAD_DOWN); // D-Pad Down - gamecontrolbisdefault[i][GC_TOSSFLAG ][1] = GAMEPAD_KEY(DPAD_LEFT); // D-Pad Left - //gamecontrolbisdefault[i][GC_SCORES ][1] = GAMEPAD_KEY(DPAD_RIGHT); // D-Pad Right + // Second player controls only have joypad defaults + gamecontrolbisdefault[i][GC_JUMP ][1] = KEY_2JOY1+0; // A + gamecontrolbisdefault[i][GC_SPIN ][1] = KEY_2JOY1+2; // X + gamecontrolbisdefault[i][GC_CUSTOM1 ][1] = KEY_2JOY1+1; // B + gamecontrolbisdefault[i][GC_CUSTOM2 ][1] = KEY_2JOY1+3; // Y + gamecontrolbisdefault[i][GC_CUSTOM3 ][1] = KEY_2JOY1+8; // Left Stick + gamecontrolbisdefault[i][GC_CENTERVIEW ][1] = KEY_2JOY1+9; // Right Stick + gamecontrolbisdefault[i][GC_WEAPONPREV ][1] = KEY_2JOY1+4; // LB + gamecontrolbisdefault[i][GC_WEAPONNEXT ][1] = KEY_2JOY1+5; // RB + gamecontrolbisdefault[i][GC_SCREENSHOT ][1] = KEY_2JOY1+6; // Back + //gamecontrolbisdefault[i][GC_SYSTEMMENU ][0] = KEY_2JOY1+7; // Start + gamecontrolbisdefault[i][GC_CAMTOGGLE ][1] = KEY_2HAT1+0; // D-Pad Up + gamecontrolbisdefault[i][GC_VIEWPOINTNEXT][1] = KEY_2HAT1+1; // D-Pad Down + gamecontrolbisdefault[i][GC_TOSSFLAG ][1] = KEY_2HAT1+2; // D-Pad Left + //gamecontrolbisdefault[i][GC_SCORES ][1] = KEY_2HAT1+3; // D-Pad Right } } diff --git a/src/g_input.h b/src/g_input.h index fe623034a..400e3fd12 100644 --- a/src/g_input.h +++ b/src/g_input.h @@ -8,7 +8,7 @@ // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file g_input.h -/// \brief handle mouse/keyboard/gamepad inputs, +/// \brief handle mouse/keyboard/joystick inputs, /// maps inputs to game controls (forward, spin, jump...) #ifndef __G_INPUT__ @@ -17,178 +17,45 @@ #include "d_event.h" #include "keys.h" #include "command.h" -#include "m_fixed.h" // number of total 'button' inputs, include keyboard keys, plus virtual // keys (mousebuttons and joybuttons becomes keys) #define NUMKEYS 256 -// Max gamepads that can be used by every player -#define NUM_GAMEPADS 2 - -// Max gamepads that can be detected -#define MAX_CONNECTED_GAMEPADS 4 - -// Max mouse buttons #define MOUSEBUTTONS 8 - -typedef enum -{ - GAMEPAD_TYPE_UNKNOWN, - - GAMEPAD_TYPE_XBOX360, - GAMEPAD_TYPE_XBOXONE, - GAMEPAD_TYPE_XBOX_SERIES_XS, - GAMEPAD_TYPE_XBOX_ELITE, - - GAMEPAD_TYPE_PS3, - GAMEPAD_TYPE_PS4, - GAMEPAD_TYPE_PS5, - - GAMEPAD_TYPE_NINTENDO_SWITCH_PRO, - GAMEPAD_TYPE_NINTENDO_SWITCH_JOY_CON_GRIP, - GAMEPAD_TYPE_NINTENDO_SWITCH_JOY_CON_LEFT, - GAMEPAD_TYPE_NINTENDO_SWITCH_JOY_CON_RIGHT, - - GAMEPAD_TYPE_GOOGLE_STADIA, - GAMEPAD_TYPE_AMAZON_LUNA, - GAMEPAD_TYPE_STEAM_CONTROLLER, - - GAMEPAD_TYPE_VIRTUAL -} gamepadtype_e; - -boolean G_GamepadTypeIsXbox(gamepadtype_e type); -boolean G_GamepadTypeIsPlayStation(gamepadtype_e type); -boolean G_GamepadTypeIsNintendoSwitch(gamepadtype_e type); -boolean G_GamepadTypeIsJoyCon(gamepadtype_e type); - -const char *G_GamepadTypeToString(gamepadtype_e type); - -typedef enum -{ - GAMEPAD_BUTTON_A, - GAMEPAD_BUTTON_B, - GAMEPAD_BUTTON_X, - GAMEPAD_BUTTON_Y, - GAMEPAD_BUTTON_BACK, - GAMEPAD_BUTTON_GUIDE, - GAMEPAD_BUTTON_START, - GAMEPAD_BUTTON_LEFTSTICK, - GAMEPAD_BUTTON_RIGHTSTICK, - GAMEPAD_BUTTON_LEFTSHOULDER, - GAMEPAD_BUTTON_RIGHTSHOULDER, - GAMEPAD_BUTTON_DPAD_UP, - GAMEPAD_BUTTON_DPAD_DOWN, - GAMEPAD_BUTTON_DPAD_LEFT, - GAMEPAD_BUTTON_DPAD_RIGHT, - - // According to SDL, this button can be: - // the Xbox Series X|S share button - // the PS5 microphone button - // the Nintendo Switch (Pro or Joy-Con) capture button - // the Amazon Luna microphone button - GAMEPAD_BUTTON_MISC1, - - // Xbox Elite paddles - GAMEPAD_BUTTON_PADDLE1, - GAMEPAD_BUTTON_PADDLE2, - GAMEPAD_BUTTON_PADDLE3, - GAMEPAD_BUTTON_PADDLE4, - - // PS4/PS5 touchpad button - GAMEPAD_BUTTON_TOUCHPAD, - - NUM_GAMEPAD_BUTTONS -} gamepad_button_e; - -typedef enum -{ - GAMEPAD_AXIS_LEFTX, - GAMEPAD_AXIS_LEFTY, - GAMEPAD_AXIS_RIGHTX, - GAMEPAD_AXIS_RIGHTY, - GAMEPAD_AXIS_TRIGGERLEFT, - GAMEPAD_AXIS_TRIGGERRIGHT, - - NUM_GAMEPAD_AXES -} gamepad_axis_e; - -extern const char *const gamepad_button_names[NUM_GAMEPAD_BUTTONS + 1]; -extern const char *const gamepad_axis_names[NUM_GAMEPAD_AXES + 1]; - -// Haptic effects -typedef struct -{ - fixed_t large_magnitude; // Magnitude of the large motor - fixed_t small_magnitude; // Magnitude of the small motor - tic_t duration; // The total duration of the effect, in tics -} haptic_t; - -// Gamepad info for each player on the system -typedef struct -{ - // Gamepad index - UINT8 num; - - // Gamepad is connected and being used by a player - boolean connected; - - // What kind of controller this is (Xbox 360, DualShock, Joy-Con, etc.) - gamepadtype_e type; - - // Treat this gamepad's axes as if it they were buttons - boolean digital; - - struct { - boolean supported; // Gamepad can rumble - boolean active; // Rumble is active - boolean paused; // Rumble is paused - haptic_t data; // Current haptic effect status - } rumble; - - UINT8 buttons[NUM_GAMEPAD_BUTTONS]; // Current state of all buttons - INT16 axes[NUM_GAMEPAD_AXES]; // Current state of all axes -} gamepad_t; - -void G_InitGamepads(void); - -typedef enum -{ - GAMEPAD_STRING_DEFAULT, // A - GAMEPAD_STRING_MENU1, // A Button - GAMEPAD_STRING_MENU2 // the A Button -} gamepad_string_e; - -const char *G_GetGamepadButtonString(gamepadtype_e type, gamepad_button_e button, gamepad_string_e strtype); -const char *G_GetGamepadAxisString(gamepadtype_e type, gamepad_axis_e button, gamepad_string_e strtype, boolean inv); - -extern gamepad_t gamepads[NUM_GAMEPADS]; +#define JOYBUTTONS 32 // 32 buttons +#define JOYHATS 4 // 4 hats +#define JOYAXISSET 4 // 4 Sets of 2 axises // -// mouse and gamepad buttons are handled as 'virtual' keys +// mouse and joystick buttons are handled as 'virtual' keys // typedef enum { KEY_MOUSE1 = NUMKEYS, - KEY_GAMEPAD = KEY_MOUSE1 + MOUSEBUTTONS, - KEY_AXES = KEY_GAMEPAD + NUM_GAMEPAD_BUTTONS, // Sure, why not. - KEY_INV_AXES = KEY_AXES + NUM_GAMEPAD_AXES, + KEY_JOY1 = KEY_MOUSE1 + MOUSEBUTTONS, + KEY_HAT1 = KEY_JOY1 + JOYBUTTONS, - KEY_DBLMOUSE1 = KEY_INV_AXES + NUM_GAMEPAD_AXES, // double clicks + KEY_DBLMOUSE1 =KEY_HAT1 + JOYHATS*4, // double clicks + KEY_DBLJOY1 = KEY_DBLMOUSE1 + MOUSEBUTTONS, + KEY_DBLHAT1 = KEY_DBLJOY1 + JOYBUTTONS, - KEY_2MOUSE1 = KEY_DBLMOUSE1 + MOUSEBUTTONS, - KEY_DBL2MOUSE1 = KEY_2MOUSE1 + MOUSEBUTTONS, + KEY_2MOUSE1 = KEY_DBLHAT1 + JOYHATS*4, + KEY_2JOY1 = KEY_2MOUSE1 + MOUSEBUTTONS, + KEY_2HAT1 = KEY_2JOY1 + JOYBUTTONS, - KEY_MOUSEWHEELUP = KEY_DBL2MOUSE1 + MOUSEBUTTONS, - KEY_MOUSEWHEELDOWN, - KEY_2MOUSEWHEELUP, - KEY_2MOUSEWHEELDOWN, + KEY_DBL2MOUSE1 = KEY_2HAT1 + JOYHATS*4, + KEY_DBL2JOY1 = KEY_DBL2MOUSE1 + MOUSEBUTTONS, + KEY_DBL2HAT1 = KEY_DBL2JOY1 + JOYBUTTONS, - NUMINPUTS + KEY_MOUSEWHEELUP = KEY_DBL2HAT1 + JOYHATS*4, + KEY_MOUSEWHEELDOWN = KEY_MOUSEWHEELUP + 1, + KEY_2MOUSEWHEELUP = KEY_MOUSEWHEELDOWN + 1, + KEY_2MOUSEWHEELDOWN = KEY_2MOUSEWHEELUP + 1, + + NUMINPUTS = KEY_2MOUSEWHEELDOWN + 1, } key_input_e; -#define GAMEPAD_KEY(key) (KEY_GAMEPAD + GAMEPAD_BUTTON_##key) - typedef enum { GC_NULL = 0, // a key/button mapped to GC_NULL has no effect @@ -274,22 +141,19 @@ typedef struct extern mouse_t mouse; extern mouse_t mouse2; +extern INT32 joyxmove[JOYAXISSET], joyymove[JOYAXISSET], joy2xmove[JOYAXISSET], joy2ymove[JOYAXISSET]; + // current state of the keys: true if pushed extern UINT8 gamekeydown[NUMINPUTS]; // two key codes (or virtual key) per game control extern INT32 gamecontrol[NUM_GAMECONTROLS][2]; extern INT32 gamecontrolbis[NUM_GAMECONTROLS][2]; // secondary splitscreen player - -// default control storage, use 0 (gcs_custom) for memory retention -extern INT32 gamecontroldefault[num_gamecontrolschemes][NUM_GAMECONTROLS][2]; +extern INT32 gamecontroldefault[num_gamecontrolschemes][NUM_GAMECONTROLS][2]; // default control storage, use 0 (gcs_custom) for memory retention extern INT32 gamecontrolbisdefault[num_gamecontrolschemes][NUM_GAMECONTROLS][2]; - -boolean G_PlayerInputDown(UINT8 which, gamecontrols_e gc); -boolean G_CheckDigitalPlayerInput(UINT8 which, gamecontrols_e gc); - -SINT8 G_PlayerInputIsAnalog(UINT8 which, gamecontrols_e gc, UINT8 settings); -INT16 G_GetAnalogPlayerInput(UINT8 which, gamecontrols_e gc, UINT8 settings); +#define PLAYER1INPUTDOWN(gc) (gamekeydown[gamecontrol[gc][0]] || gamekeydown[gamecontrol[gc][1]]) +#define PLAYER2INPUTDOWN(gc) (gamekeydown[gamecontrolbis[gc][0]] || gamekeydown[gamecontrolbis[gc][1]]) +#define PLAYERINPUTDOWN(p, gc) ((p) == 2 ? PLAYER2INPUTDOWN(gc) : PLAYER1INPUTDOWN(gc)) #define num_gcl_tutorial_check 6 #define num_gcl_tutorial_used 8 @@ -317,37 +181,13 @@ extern const INT32 gcl_jump_spin[num_gcl_jump_spin]; // remaps the input event to a game control. void G_MapEventsToControls(event_t *ev); -boolean G_RumbleSupported(UINT8 which); -boolean G_RumbleGamepad(UINT8 which, fixed_t large_magnitude, fixed_t small_magnitude, tic_t duration); -void G_StopGamepadRumble(UINT8 which); - -fixed_t G_GetLargeMotorFreq(UINT8 which); -fixed_t G_GetSmallMotorFreq(UINT8 which); -boolean G_GetGamepadRumblePaused(UINT8 which); -boolean G_SetLargeMotorFreq(UINT8 which, fixed_t freq); -boolean G_SetSmallMotorFreq(UINT8 which, fixed_t freq); -void G_SetGamepadRumblePaused(UINT8 which, boolean pause); - -INT16 G_GamepadAxisEventValue(UINT8 which, INT16 value); -INT16 G_GetGamepadAxisValue(UINT8 which, gamepad_axis_e axis); -fixed_t G_GetAdjustedGamepadAxis(UINT8 which, gamepad_axis_e axis, boolean applyDeadzone); - -UINT16 G_GetGamepadDeadZone(UINT8 which); -UINT16 G_GetGamepadDigitalDeadZone(UINT8 which); -INT32 G_BasicDeadZoneCalculation(INT32 magnitude, const UINT16 jdeadzone); - -INT32 G_RemapGamepadEvent(event_t *event, INT32 *type); - // returns the name of a key const char *G_KeyNumToName(INT32 keynum); INT32 G_KeyNameToNum(const char *keystr); -const char *G_GetDisplayNameForKey(INT32 keynum); - // detach any keys associated to the given game control void G_ClearControlKeys(INT32 (*setupcontrols)[2], INT32 control); void G_ClearAllControlKeys(void); - void Command_Setcontrol_f(void); void Command_Setcontrol2_f(void); void G_DefineDefaultControls(void); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 805aa694f..c037abcd7 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -877,7 +877,7 @@ void HU_Ticker(void) hu_tick++; hu_tick &= 7; // currently only to blink chat input cursor - if (G_PlayerInputDown(0, GC_SCORES)) + if (PLAYER1INPUTDOWN(GC_SCORES)) hu_showscores = !chat_on; else hu_showscores = false; @@ -1052,6 +1052,26 @@ boolean HU_Responder(event_t *ev) // only KeyDown events now... + /*// Shoot, to prevent P1 chatting from ruining the game for everyone else, it's either: + // A. completely disallow opening chat entirely in online splitscreen + // or B. iterate through all controls to make sure it's bound to player 1 before eating + // You can see which one I chose. + // (Unless if you're sharing a keyboard, since you probably establish when you start chatting that you have dibs on it...) + // (Ahhh, the good ol days when I was a kid who couldn't afford an extra USB controller...) + + if (ev->key >= KEY_MOUSE1) + { + INT32 i; + for (i = 0; i < NUM_GAMECONTROLS; i++) + { + if (gamecontrol[i][0] == ev->key || gamecontrol[i][1] == ev->key) + break; + } + + if (i == NUM_GAMECONTROLS) + return false; + }*/ //We don't actually care about that unless we get splitscreen netgames. :V + #ifndef NONET c = (INT32)ev->key; diff --git a/src/i_gamepad.h b/src/i_gamepad.h deleted file mode 100644 index 730109b54..000000000 --- a/src/i_gamepad.h +++ /dev/null @@ -1,58 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file i_gamepad.h -/// \brief Gamepads - -#ifndef __I_GAMEPAD_H__ -#define __I_GAMEPAD_H__ - -#include "g_input.h" -#include "p_haptic.h" - -// So m_menu knows whether to store cv_usegamepad value or string -#define GAMEPAD_HOTPLUG - -// Value range for axes -#define JOYAXISRANGE INT16_MAX -#define OLDJOYAXISRANGE 1023 - -// Starts all gamepads -void I_InitGamepads(void); - -// Returns the number of gamepads on the system -INT32 I_NumGamepads(void); - -// Changes a gamepad's device -void I_ChangeGamepad(UINT8 which); - -// Toggles a gamepad's digital axis setting -void I_SetGamepadDigital(UINT8 which, boolean enable); - -// Shuts down all gamepads -void I_ShutdownGamepads(void); - -// Returns the name of a gamepad from its index -const char *I_GetGamepadName(INT32 joyindex); - -// Gamepad rumble interface -boolean I_RumbleSupported(void); -boolean I_RumbleGamepad(UINT8 which, const haptic_t *effect); - -boolean I_GetGamepadRumblePaused(UINT8 which); - -boolean I_SetGamepadLargeMotorFreq(UINT8 which, fixed_t freq); -boolean I_SetGamepadSmallMotorFreq(UINT8 which, fixed_t freq); -void I_SetGamepadRumblePaused(UINT8 which, boolean pause); - -boolean I_GetGamepadRumbleSupported(UINT8 which); - -void I_StopGamepadRumble(UINT8 which); - -#endif // __I_GAMEPAD_H__ diff --git a/src/i_joy.h b/src/i_joy.h new file mode 100644 index 000000000..27584cea6 --- /dev/null +++ b/src/i_joy.h @@ -0,0 +1,58 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file i_joy.h +/// \brief share joystick information with game control code + +#ifndef __I_JOY_H__ +#define __I_JOY_H__ + +#include "g_input.h" + +/*! + \brief -JOYAXISRANGE to +JOYAXISRANGE for each axis + + (1024-1) so we can do a right shift instead of division + (doesnt matter anyway, just give enough precision) + a gamepad will return -1, 0, or 1 in the event data + an analog type joystick will return a value + from -JOYAXISRANGE to +JOYAXISRANGE for each axis +*/ + +#define JOYAXISRANGE 1023 + +// detect a bug if we increase JOYBUTTONS above DIJOYSTATE's number of buttons +#if (JOYBUTTONS > 64) +"JOYBUTTONS is greater than INT64 bits can hold" +#endif + +/** \brief The struct JoyType_s + + share some joystick information (maybe 2 for splitscreen), to the game input code, + actually, we need to know if it is a gamepad or analog controls +*/ + +struct JoyType_s +{ + /*! if true, we MUST Poll() to get new joystick data, + that is: we NEED the DIRECTINPUTDEVICE2 ! (watchout NT compatibility) */ + INT32 bJoyNeedPoll; + /*! this joystick is a gamepad, read: digital axes + if FALSE, interpret the joystick event data as JOYAXISRANGE (see above) */ + INT32 bGamepadStyle; + +}; +typedef struct JoyType_s JoyType_t; +/** \brief Joystick info + for palyer 1 and 2's joystick/gamepad +*/ + +extern JoyType_t Joystick, Joystick2; + +#endif // __I_JOY_H__ diff --git a/src/i_system.h b/src/i_system.h index f3ca5aac5..7153aa735 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -101,6 +101,90 @@ ticcmd_t *I_BaseTiccmd2(void); */ void I_Quit(void) FUNCNORETURN; +typedef enum +{ + EvilForce = -1, + //Constant + ConstantForce = 0, + //Ramp + RampForce, + //Periodics + SquareForce, + SineForce, + TriangleForce, + SawtoothUpForce, + SawtoothDownForce, + //MAX + NumberofForces, +} FFType; + +typedef struct JoyFF_s +{ + INT32 ForceX; ///< The X of the Force's Vel + INT32 ForceY; ///< The Y of the Force's Vel + //All + UINT32 Duration; ///< The total duration of the effect, in microseconds + INT32 Gain; //< /The gain to be applied to the effect, in the range from 0 through 10,000. + //All, CONSTANTFORCE -10,000 to 10,000 + INT32 Magnitude; ///< Magnitude of the effect, in the range from 0 through 10,000. + //RAMPFORCE + INT32 Start; ///< Magnitude at the start of the effect, in the range from -10,000 through 10,000. + INT32 End; ///< Magnitude at the end of the effect, in the range from -10,000 through 10,000. + //PERIODIC + INT32 Offset; ///< Offset of the effect. + UINT32 Phase; ///< Position in the cycle of the periodic effect at which playback begins, in the range from 0 through 35,999 + UINT32 Period; ///< Period of the effect, in microseconds. +} JoyFF_t; + +/** \brief Forcefeedback for the first joystick + + \param Type what kind of Effect + \param Effect Effect Info + + \return void +*/ + +void I_Tactile(FFType Type, const JoyFF_t *Effect); + +/** \brief Forcefeedback for the second joystick + + \param Type what kind of Effect + \param Effect Effect Info + + \return void +*/ +void I_Tactile2(FFType Type, const JoyFF_t *Effect); + +/** \brief to set up the first joystick scale +*/ +void I_JoyScale(void); + +/** \brief to set up the second joystick scale +*/ +void I_JoyScale2(void); + +// Called by D_SRB2Main. + +/** \brief to startup the first joystick +*/ +void I_InitJoystick(void); + +/** \brief to startup the second joystick +*/ +void I_InitJoystick2(void); + +/** \brief return the number of joystick on the system +*/ +INT32 I_NumJoys(void); + +/** \brief The *I_GetJoyName function + + \param joyindex which joystick + + \return joystick name +*/ +const char *I_GetJoyName(INT32 joyindex); + #ifndef NOMUMBLE #include "p_mobj.h" // mobj_t #include "s_sound.h" // listener_t @@ -209,7 +293,15 @@ const CPUInfoFlags *I_CPUInfo(void); */ const char *I_LocateWad(void); -/** \brief Mice events +/** \brief First Joystick's events +*/ +void I_GetJoystickEvents(void); + +/** \brief Second Joystick's events +*/ +void I_GetJoystick2Events(void); + +/** \brief Mouses events */ void I_GetMouseEvents(void); diff --git a/src/lua_inputlib.c b/src/lua_inputlib.c index 88efc3490..1710b0355 100644 --- a/src/lua_inputlib.c +++ b/src/lua_inputlib.c @@ -15,7 +15,6 @@ #include "g_game.h" #include "hu_stuff.h" #include "i_system.h" -#include "i_gamepad.h" #include "lua_script.h" #include "lua_libs.h" @@ -31,7 +30,7 @@ static int lib_gameControlDown(lua_State *L) int i = luaL_checkinteger(L, 1); if (i < 0 || i >= NUM_GAMECONTROLS) return luaL_error(L, "GC_* constant %d out of range (0 - %d)", i, NUM_GAMECONTROLS-1); - lua_pushinteger(L, G_PlayerInputDown(0, i)); + lua_pushinteger(L, PLAYER1INPUTDOWN(i)); return 1; } @@ -40,7 +39,7 @@ static int lib_gameControl2Down(lua_State *L) int i = luaL_checkinteger(L, 1); if (i < 0 || i >= NUM_GAMECONTROLS) return luaL_error(L, "GC_* constant %d out of range (0 - %d)", i, NUM_GAMECONTROLS-1); - lua_pushinteger(L, G_PlayerInputDown(1, i)); + lua_pushinteger(L, PLAYER2INPUTDOWN(i)); return 1; } @@ -67,14 +66,14 @@ static int lib_gameControl2ToKeyNum(lua_State *L) static int lib_joyAxis(lua_State *L) { int i = luaL_checkinteger(L, 1); - lua_pushinteger(L, G_JoyAxis(0, i) / 32); + lua_pushinteger(L, JoyAxis(i)); return 1; } static int lib_joy2Axis(lua_State *L) { int i = luaL_checkinteger(L, 1); - lua_pushinteger(L, G_JoyAxis(1, i) / 32); + lua_pushinteger(L, Joy2Axis(i)); return 1; } diff --git a/src/m_cheat.c b/src/m_cheat.c index f94377450..89c8009ae 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -199,41 +199,39 @@ static UINT8 cht_CheckCheat(cheatseq_t *cht, char key) boolean cht_Responder(event_t *ev) { - UINT8 ch = 0; + UINT8 ret = 0, ch = 0; + if (ev->type != ev_keydown) + return false; - if (ev->type == ev_gamepad_down) + if (ev->key > 0xFF) { + // map some fake (joy) inputs into keys + // map joy inputs into keys switch (ev->key) { - case GAMEPAD_BUTTON_DPAD_UP: + case KEY_JOY1: + case KEY_JOY1 + 2: + ch = KEY_ENTER; + break; + case KEY_HAT1: ch = KEY_UPARROW; break; - case GAMEPAD_BUTTON_DPAD_DOWN: + case KEY_HAT1 + 1: ch = KEY_DOWNARROW; break; - case GAMEPAD_BUTTON_DPAD_LEFT: + case KEY_HAT1 + 2: ch = KEY_LEFTARROW; break; - case GAMEPAD_BUTTON_DPAD_RIGHT: + case KEY_HAT1 + 3: ch = KEY_RIGHTARROW; break; - case GAMEPAD_BUTTON_START: - ch = KEY_ENTER; - break; default: // no mapping return false; } } - else if (ev->type == ev_keydown) - { - if (ev->key > 0xFF) - return false; - + else ch = (UINT8)ev->key; - } - - UINT8 ret = 0; ret += cht_CheckCheat(&cheat_ultimate, (char)ch); ret += cht_CheckCheat(&cheat_ultimate_joy, (char)ch); diff --git a/src/m_menu.c b/src/m_menu.c index 51d13df98..82d078062 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -41,8 +41,6 @@ #include "v_video.h" #include "i_video.h" -#include "i_gamepad.h" -#include "g_input.h" #include "keys.h" #include "z_zone.h" #include "w_wad.h" @@ -64,6 +62,8 @@ #include "i_sound.h" #include "fastcmp.h" +#include "i_joy.h" // for joystick menu controls + #include "p_saveg.h" // Only for NEWSKINSAVES // Condition Sets @@ -72,6 +72,13 @@ // And just some randomness for the exits. #include "m_random.h" +#if defined(HAVE_SDL) +#include "SDL.h" +#if SDL_VERSION_ATLEAST(2,0,0) +#include "sdl/sdlmain.h" // JOYSTICK_HOTPLUG +#endif +#endif + #if defined (__GNUC__) && (__GNUC__ >= 4) #define FIXUPO0 #endif @@ -141,12 +148,7 @@ typedef enum levellist_mode_t levellistmode = LLM_CREATESERVER; UINT8 maplistoption = 0; -static struct -{ - char name[29]; - INT32 index; -} gamepadInfo[MAX_CONNECTED_GAMEPADS + 1]; - +static char joystickInfo[MAX_JOYSTICKS+1][29]; #ifndef NONET static UINT32 serverlistpage; #endif @@ -161,7 +163,6 @@ static INT16 itemOn = 1; // menu item skull is on, Hack by Tails 09-18-2002 static INT16 skullAnimCounter = 10; // skull animation counter static boolean setupcontrols_secondaryplayer; -static consvar_t *setupcontrols_joycvar = NULL; static INT32 (*setupcontrols)[2]; // pointer to the gamecontrols of the player being edited // shhh... what am I doing... nooooo! @@ -310,17 +311,17 @@ menu_t MP_MainDef; menu_t OP_ChangeControlsDef; menu_t OP_MPControlsDef, OP_MiscControlsDef; menu_t OP_P1ControlsDef, OP_P2ControlsDef, OP_MouseOptionsDef; -menu_t OP_Mouse2OptionsDef, OP_Gamepad1Def, OP_Gamepad2Def; +menu_t OP_Mouse2OptionsDef, OP_Joystick1Def, OP_Joystick2Def; menu_t OP_CameraOptionsDef, OP_Camera2OptionsDef; menu_t OP_PlaystyleDef; static void M_VideoModeMenu(INT32 choice); static void M_Setup1PControlsMenu(INT32 choice); static void M_Setup2PControlsMenu(INT32 choice); -static void M_Setup1PGamepadMenu(INT32 choice); -static void M_Setup2PGamepadMenu(INT32 choice); +static void M_Setup1PJoystickMenu(INT32 choice); +static void M_Setup2PJoystickMenu(INT32 choice); static void M_Setup1PPlaystyleMenu(INT32 choice); static void M_Setup2PPlaystyleMenu(INT32 choice); -static void M_AssignGamepad(INT32 choice); +static void M_AssignJoystick(INT32 choice); static void M_ChangeControl(INT32 choice); // Video & Sound @@ -374,8 +375,7 @@ static void M_DrawSetupChoosePlayerMenu(void); static void M_DrawControlsDefMenu(void); static void M_DrawCameraOptionsMenu(void); static void M_DrawPlaystyleMenu(void); -static void M_DrawGamepadMenu(void); -static void M_DrawControlConfigMenu(void); +static void M_DrawControl(void); static void M_DrawMainVideoMenu(void); static void M_DrawVideoMode(void); static void M_DrawColorMenu(void); @@ -386,7 +386,7 @@ static void M_DrawConnectMenu(void); static void M_DrawMPMainMenu(void); static void M_DrawRoomMenu(void); #endif -static void M_DrawGamepadList(void); +static void M_DrawJoystick(void); static void M_DrawSetupMultiPlayerMenu(void); // Handling functions @@ -1084,7 +1084,7 @@ static menuitem_t OP_P1ControlsMenu[] = { {IT_CALL | IT_STRING, NULL, "Control Configuration...", M_Setup1PControlsMenu, 10}, {IT_SUBMENU | IT_STRING, NULL, "Mouse Options...", &OP_MouseOptionsDef, 20}, - {IT_SUBMENU | IT_STRING, NULL, "Gamepad Options...", &OP_Gamepad1Def , 30}, + {IT_SUBMENU | IT_STRING, NULL, "Gamepad Options...", &OP_Joystick1Def , 30}, {IT_SUBMENU | IT_STRING, NULL, "Camera Options...", &OP_CameraOptionsDef, 50}, @@ -1096,7 +1096,7 @@ static menuitem_t OP_P2ControlsMenu[] = { {IT_CALL | IT_STRING, NULL, "Control Configuration...", M_Setup2PControlsMenu, 10}, {IT_SUBMENU | IT_STRING, NULL, "Second Mouse Options...", &OP_Mouse2OptionsDef, 20}, - {IT_SUBMENU | IT_STRING, NULL, "Second Gamepad Options...", &OP_Gamepad2Def , 30}, + {IT_SUBMENU | IT_STRING, NULL, "Second Gamepad Options...", &OP_Joystick2Def , 30}, {IT_SUBMENU | IT_STRING, NULL, "Camera Options...", &OP_Camera2OptionsDef, 50}, @@ -1160,43 +1160,43 @@ static menuitem_t OP_ChangeControlsMenu[] = {IT_CALL | IT_STRING2, NULL, "Custom Action 3", M_ChangeControl, GC_CUSTOM3 }, }; -static menuitem_t OP_Gamepad1Menu[] = +static menuitem_t OP_Joystick1Menu[] = { - {IT_STRING | IT_CALL, NULL, "Select Gamepad...", M_Setup1PGamepadMenu, 10}, - {IT_STRING | IT_CVAR, NULL, "Move \x17 Axis" , &cv_moveaxis[0] , 30}, - {IT_STRING | IT_CVAR, NULL, "Move \x18 Axis" , &cv_sideaxis[0] , 40}, - {IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis[0] , 50}, - {IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis[0] , 60}, - {IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis[0] , 70}, - {IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis[0] , 80}, - {IT_STRING | IT_CVAR, NULL, "Fire Axis" , &cv_fireaxis[0] , 90}, - {IT_STRING | IT_CVAR, NULL, "Fire Normal Axis" , &cv_firenaxis[0] ,100}, + {IT_STRING | IT_CALL, NULL, "Select Gamepad...", M_Setup1PJoystickMenu, 10}, + {IT_STRING | IT_CVAR, NULL, "Move \x17 Axis" , &cv_moveaxis , 30}, + {IT_STRING | IT_CVAR, NULL, "Move \x18 Axis" , &cv_sideaxis , 40}, + {IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis , 50}, + {IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis , 60}, + {IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis , 70}, + {IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis , 80}, + {IT_STRING | IT_CVAR, NULL, "Fire Axis" , &cv_fireaxis , 90}, + {IT_STRING | IT_CVAR, NULL, "Fire Normal Axis" , &cv_firenaxis ,100}, {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook, 120}, {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook, 130}, - {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Analog Deadzone", &cv_deadzone[0], 140}, - {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Digital Deadzone", &cv_digitaldeadzone[0], 150}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Analog Deadzone", &cv_deadzone, 140}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Digital Deadzone", &cv_digitaldeadzone, 150}, }; -static menuitem_t OP_Gamepad2Menu[] = +static menuitem_t OP_Joystick2Menu[] = { - {IT_STRING | IT_CALL, NULL, "Select Gamepad...", M_Setup2PGamepadMenu, 10}, - {IT_STRING | IT_CVAR, NULL, "Move \x17 Axis" , &cv_moveaxis[1] , 30}, - {IT_STRING | IT_CVAR, NULL, "Move \x18 Axis" , &cv_sideaxis[1] , 40}, - {IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis[1] , 50}, - {IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis[1] , 60}, - {IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis[1] , 70}, - {IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis[1] , 80}, - {IT_STRING | IT_CVAR, NULL, "Fire Axis" , &cv_fireaxis[1] , 90}, - {IT_STRING | IT_CVAR, NULL, "Fire Normal Axis" , &cv_firenaxis[1] ,100}, + {IT_STRING | IT_CALL, NULL, "Select Gamepad...", M_Setup2PJoystickMenu, 10}, + {IT_STRING | IT_CVAR, NULL, "Move \x17 Axis" , &cv_moveaxis2 , 30}, + {IT_STRING | IT_CVAR, NULL, "Move \x18 Axis" , &cv_sideaxis2 , 40}, + {IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis2 , 50}, + {IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis2 , 60}, + {IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis2 , 70}, + {IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis2 , 80}, + {IT_STRING | IT_CVAR, NULL, "Fire Axis" , &cv_fireaxis2 , 90}, + {IT_STRING | IT_CVAR, NULL, "Fire Normal Axis" , &cv_firenaxis2 ,100}, {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook2,120}, {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook2, 130}, - {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Analog Deadzone", &cv_deadzone[1],140}, - {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Digital Deadzone", &cv_digitaldeadzone[1],150}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Analog Deadzone", &cv_deadzone2,140}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Digital Deadzone", &cv_digitaldeadzone2,150}, }; -static menuitem_t OP_GamepadSetMenu[MAX_CONNECTED_GAMEPADS + 1]; +static menuitem_t OP_JoystickSetMenu[1+MAX_JOYSTICKS]; static menuitem_t OP_MouseOptionsMenu[] = { @@ -2093,21 +2093,21 @@ menu_t OP_Mouse2OptionsDef = DEFAULTMENUSTYLE( MTREE3(MN_OP_MAIN, MN_OP_P2CONTROLS, MN_OP_P2MOUSE), "M_CONTRO", OP_Mouse2OptionsMenu, &OP_P2ControlsDef, 35, 30); -menu_t OP_Gamepad1Def = GAMEPADMENUSTYLE( +menu_t OP_Joystick1Def = DEFAULTMENUSTYLE( MTREE3(MN_OP_MAIN, MN_OP_P1CONTROLS, MN_OP_P1JOYSTICK), - "M_CONTRO", OP_Gamepad1Menu, &OP_P1ControlsDef, 50, 30); -menu_t OP_Gamepad2Def = GAMEPADMENUSTYLE( + "M_CONTRO", OP_Joystick1Menu, &OP_P1ControlsDef, 50, 30); +menu_t OP_Joystick2Def = DEFAULTMENUSTYLE( MTREE3(MN_OP_MAIN, MN_OP_P2CONTROLS, MN_OP_P2JOYSTICK), - "M_CONTRO", OP_Gamepad2Menu, &OP_P2ControlsDef, 50, 30); + "M_CONTRO", OP_Joystick2Menu, &OP_P2ControlsDef, 50, 30); -menu_t OP_GamepadSetDef = +menu_t OP_JoystickSetDef = { MTREE4(MN_OP_MAIN, 0, 0, MN_OP_JOYSTICKSET), // second and third level set on runtime "M_CONTRO", - sizeof (OP_GamepadSetMenu)/sizeof (menuitem_t), - &OP_Gamepad1Def, - OP_GamepadSetMenu, - M_DrawGamepadList, + sizeof (OP_JoystickSetMenu)/sizeof (menuitem_t), + &OP_Joystick1Def, + OP_JoystickSetMenu, + M_DrawJoystick, 60, 40, 0, NULL @@ -3198,28 +3198,13 @@ static void Command_Manual_f(void) itemOn = 0; } -static INT32 RemapGamepadButton(event_t *ev) -{ - switch (ev->key) - { - case GAMEPAD_BUTTON_A: return KEY_ENTER; - case GAMEPAD_BUTTON_B: return KEY_ESCAPE; - case GAMEPAD_BUTTON_X: return KEY_BACKSPACE; - case GAMEPAD_BUTTON_DPAD_UP: return KEY_UPARROW; - case GAMEPAD_BUTTON_DPAD_DOWN: return KEY_DOWNARROW; - case GAMEPAD_BUTTON_DPAD_LEFT: return KEY_LEFTARROW; - case GAMEPAD_BUTTON_DPAD_RIGHT: return KEY_RIGHTARROW; - } - - return KEY_GAMEPAD + ev->key; -} - // // M_Responder // boolean M_Responder(event_t *ev) { INT32 ch = -1; +// INT32 i; static tic_t joywait = 0, mousewait = 0; static INT32 pjoyx = 0, pjoyy = 0; static INT32 pmousex = 0, pmousey = 0; @@ -3237,8 +3222,6 @@ boolean M_Responder(event_t *ev) if (CON_Ready() && gamestate != GS_WAITINGPLAYERS) return false; - boolean useEventHandler = false; - if (noFurtherInput) { // Ignore input after enter/escape/other buttons @@ -3247,69 +3230,80 @@ boolean M_Responder(event_t *ev) } else if (menuactive) { - if (currentMenu->menuitems[itemOn].status == IT_MSGHANDLER) - useEventHandler = currentMenu->menuitems[itemOn].alphaKey == MM_EVENTHANDLER; - if (ev->type == ev_keydown) { keydown++; ch = ev->key; - // added 5-2-98 remap virtual keys (mouse buttons) + // added 5-2-98 remap virtual keys (mouse & joystick buttons) switch (ch) { case KEY_MOUSE1: + case KEY_JOY1: ch = KEY_ENTER; break; + case KEY_JOY1 + 3: + ch = 'n'; + break; case KEY_MOUSE1 + 1: + case KEY_JOY1 + 1: ch = KEY_ESCAPE; break; + case KEY_JOY1 + 2: + ch = KEY_BACKSPACE; + break; + case KEY_HAT1: + ch = KEY_UPARROW; + break; + case KEY_HAT1 + 1: + ch = KEY_DOWNARROW; + break; + case KEY_HAT1 + 2: + ch = KEY_LEFTARROW; + break; + case KEY_HAT1 + 3: + ch = KEY_RIGHTARROW; + break; } } - else if (ev->type == ev_gamepad_down) + else if (ev->type == ev_joystick && ev->key == 0 && joywait < I_GetTime()) { - keydown++; - ch = RemapGamepadButton(ev); - } - else if (ev->type == ev_gamepad_axis && ev->which == 0 && joywait < I_GetTime()) - { - const UINT16 jdeadzone = G_GetGamepadDigitalDeadZone(0); - const INT16 value = G_GamepadAxisEventValue(0, ev->x); - - if (ev->key == GAMEPAD_AXIS_LEFTY) + const INT32 jdeadzone = (JOYAXISRANGE * cv_digitaldeadzone.value) / FRACUNIT; + if (ev->y != INT32_MAX) { - if (abs(value) > jdeadzone) + if (Joystick.bGamepadStyle || abs(ev->y) > jdeadzone) { - if (value < 0 && pjoyy >= 0) + if (ev->y < 0 && pjoyy >= 0) { ch = KEY_UPARROW; joywait = I_GetTime() + NEWTICRATE/7; } - else if (value > 0 && pjoyy <= 0) + else if (ev->y > 0 && pjoyy <= 0) { ch = KEY_DOWNARROW; joywait = I_GetTime() + NEWTICRATE/7; } - pjoyy = value; + pjoyy = ev->y; } else pjoyy = 0; } - else if (ev->key == GAMEPAD_AXIS_LEFTX) + + if (ev->x != INT32_MAX) { - if (abs(value) > jdeadzone) + if (Joystick.bGamepadStyle || abs(ev->x) > jdeadzone) { - if (value < 0 && pjoyx >= 0) + if (ev->x < 0 && pjoyx >= 0) { ch = KEY_LEFTARROW; joywait = I_GetTime() + NEWTICRATE/17; } - else if (value > 0 && pjoyx <= 0) + else if (ev->x > 0 && pjoyx <= 0) { ch = KEY_RIGHTARROW; joywait = I_GetTime() + NEWTICRATE/17; } - pjoyx = value; + pjoyx = ev->x; } else pjoyx = 0; @@ -3345,29 +3339,13 @@ boolean M_Responder(event_t *ev) pmousex = lastx += 30; } } - else if (ev->type == ev_keyup || ev->type == ev_gamepad_up) // Preserve event for other responders + else if (ev->type == ev_keyup) // Preserve event for other responders keydown = 0; } - // Preserve event for other responders - else if (ev->type == ev_keydown || ev->type == ev_gamepad_down) - { + else if (ev->type == ev_keydown) // Preserve event for other responders ch = ev->key; - if (ev->type == ev_gamepad_down) - ch += KEY_GAMEPAD; - } - else if (ev->type == ev_gamepad_axis) - { - const UINT16 jdeadzone = G_GetGamepadDigitalDeadZone(0); - const INT16 value = G_GamepadAxisEventValue(0, ev->x); - - if (value > jdeadzone) - ch = KEY_AXES + ev->key; - else if (value < -jdeadzone) - ch = KEY_INV_AXES + ev->key; - } - - if (!useEventHandler && ch == -1) + if (ch == -1) return false; else if (ch == gamecontrol[GC_SYSTEMMENU][0] || ch == gamecontrol[GC_SYSTEMMENU][1]) // allow remappable ESC key ch = KEY_ESCAPE; @@ -3455,25 +3433,27 @@ boolean M_Responder(event_t *ev) if (currentMenu->menuitems[itemOn].status == IT_MSGHANDLER) { - if (!useEventHandler) + if (currentMenu->menuitems[itemOn].alphaKey != MM_EVENTHANDLER) { - UINT16 type = currentMenu->menuitems[itemOn].alphaKey; - if (type == MM_YESNO && !(ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE || ch == KEY_ENTER || ch == KEY_DEL)) - return true; - if (routine) - routine(ch); - if (type == MM_YESNO) + if (ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE || ch == KEY_ENTER || ch == KEY_DEL) { + if (routine) + routine(ch); if (stopstopmessage) stopstopmessage = false; else M_StopMessage(0); noFurtherInput = true; + return true; } return true; } else { + // dirty hack: for customising controls, I want only buttons/keys, not moves + if (ev->type == ev_mouse || ev->type == ev_mouse2 || ev->type == ev_joystick + || ev->type == ev_joystick2) + return true; if (routine) { void (*otherroutine)(event_t *sev) = currentMenu->menuitems[itemOn].itemaction; @@ -3739,7 +3719,6 @@ void M_StartControlPanel(void) currentMenu = &SPauseDef; itemOn = spause_continue; - } else // multiplayer { @@ -3784,9 +3763,6 @@ void M_StartControlPanel(void) } CON_ToggleOff(); // move away console - - if (P_AutoPause()) - P_PauseRumble(NULL); } void M_EndModeAttackRun(void) @@ -3815,7 +3791,6 @@ void M_ClearMenus(boolean callexitmenufunc) hidetitlemap = false; I_UpdateMouseGrab(); - P_UnpauseRumble(NULL); } // @@ -3985,10 +3960,10 @@ void M_Init(void) at all if every item just calls the same function, and nothing more. Now just automate the definition. */ - for (i = 0; i < MAX_CONNECTED_GAMEPADS + 1; ++i) + for (i = 0; i <= MAX_JOYSTICKS; ++i) { - OP_GamepadSetMenu[i].status = ( IT_NOTHING|IT_CALL ); - OP_GamepadSetMenu[i].itemaction = M_AssignGamepad; + OP_JoystickSetMenu[i].status = ( IT_NOTHING|IT_CALL ); + OP_JoystickSetMenu[i].itemaction = M_AssignJoystick; } #ifndef NONET @@ -4218,6 +4193,26 @@ static void M_DrawStaticBox(fixed_t x, fixed_t y, INT32 flags, fixed_t w, fixed_ W_UnlockCachedPatch(patch); } +// +// Draw border for the savegame description +// +#if 0 // once used for joysticks and savegames, now no longer +static void M_DrawSaveLoadBorder(INT32 x,INT32 y) +{ + INT32 i; + + V_DrawScaledPatch (x-8,y+7,0,W_CachePatchName("M_LSLEFT",PU_PATCH)); + + for (i = 0;i < 24;i++) + { + V_DrawScaledPatch (x,y+7,0,W_CachePatchName("M_LSCNTR",PU_PATCH)); + x += 8; + } + + V_DrawScaledPatch (x,y+7,0,W_CachePatchName("M_LSRGHT",PU_PATCH)); +} +#endif + // horizontally centered text static void M_CentreText(INT32 y, const char *string) { @@ -6156,10 +6151,7 @@ void M_StartMessage(const char *string, void *routine, MessageDef.menuitems[0].text = message; MessageDef.menuitems[0].alphaKey = (UINT8)itemtype; - - if (routine == NULL && itemtype != MM_NOTHING) - itemtype = MM_NOTHING; - + if (!routine && itemtype != MM_NOTHING) itemtype = MM_NOTHING; switch (itemtype) { case MM_NOTHING: @@ -6167,7 +6159,9 @@ void M_StartMessage(const char *string, void *routine, MessageDef.menuitems[0].itemaction = M_StopMessage; break; case MM_YESNO: - case MM_KEYHANDLER: + MessageDef.menuitems[0].status = IT_MSGHANDLER; + MessageDef.menuitems[0].itemaction = routine; + break; case MM_EVENTHANDLER: MessageDef.menuitems[0].status = IT_MSGHANDLER; MessageDef.menuitems[0].itemaction = routine; @@ -6199,6 +6193,7 @@ void M_StartMessage(const char *string, void *routine, MessageDef.lastOn = (INT16)((strlines<<8)+max); + //M_SetupNextMenu(); currentMenu = &MessageDef; itemOn = 0; } @@ -11409,7 +11404,7 @@ static void M_ConnectMenuModChecks(INT32 choice) if (modifiedgame) { - M_StartMessage(M_GetText("You have add-ons loaded.\nYou won't be able to join netgames!\n\nTo play online, restart the game\nand don't load any addons.\nSRB2 will automatically add\neverything you need when you join.\n\n(Press a key)\n"),M_ConnectMenu,MM_KEYHANDLER); + M_StartMessage(M_GetText("You have add-ons loaded.\nYou won't be able to join netgames!\n\nTo play online, restart the game\nand don't load any addons.\nSRB2 will automatically add\neverything you need when you join.\n\n(Press a key)\n"),M_ConnectMenu,MM_EVENTHANDLER); return; } @@ -12602,147 +12597,183 @@ static void M_SetupScreenshotMenu(void) item->status = (IT_STRING | IT_CVAR); } -// ============ -// GAMEPAD MENU -// ============ +// ============= +// JOYSTICK MENU +// ============= // Start the controls menu, setting it up for either the console player, // or the secondary splitscreen player -static void M_DrawGamepadList(void) +static void M_DrawJoystick(void) { - INT32 i; - - INT32 compareval = G_GetGamepadDeviceIndex(0); - INT32 compareval2 = G_GetGamepadDeviceIndex(1); + INT32 i, compareval2, compareval; // draw title (or big pic) M_DrawMenuTitle(); - for (i = 0; i < MAX_CONNECTED_GAMEPADS + 1; i++) + for (i = 0; i <= MAX_JOYSTICKS; i++) // See MAX_JOYSTICKS { - M_DrawTextBox(OP_GamepadSetDef.x-8, OP_GamepadSetDef.y+LINEHEIGHT*i-12, 28, 1); + M_DrawTextBox(OP_JoystickSetDef.x-8, OP_JoystickSetDef.y+LINEHEIGHT*i-12, 28, 1); + //M_DrawSaveLoadBorder(OP_JoystickSetDef.x+4, OP_JoystickSetDef.y+1+LINEHEIGHT*i); + +#ifdef JOYSTICK_HOTPLUG + if (atoi(cv_usejoystick2.string) > I_NumJoys()) + compareval2 = atoi(cv_usejoystick2.string); + else + compareval2 = cv_usejoystick2.value; + + if (atoi(cv_usejoystick.string) > I_NumJoys()) + compareval = atoi(cv_usejoystick.string); + else + compareval = cv_usejoystick.value; +#else + compareval2 = cv_usejoystick2.value; + compareval = cv_usejoystick.value; +#endif if ((setupcontrols_secondaryplayer && (i == compareval2)) || (!setupcontrols_secondaryplayer && (i == compareval))) - V_DrawString(OP_GamepadSetDef.x, OP_GamepadSetDef.y+LINEHEIGHT*i-4,V_GREENMAP,gamepadInfo[i].name); + V_DrawString(OP_JoystickSetDef.x, OP_JoystickSetDef.y+LINEHEIGHT*i-4,V_GREENMAP,joystickInfo[i]); else - V_DrawString(OP_GamepadSetDef.x, OP_GamepadSetDef.y+LINEHEIGHT*i-4,0,gamepadInfo[i].name); + V_DrawString(OP_JoystickSetDef.x, OP_JoystickSetDef.y+LINEHEIGHT*i-4,0,joystickInfo[i]); if (i == itemOn) { - V_DrawScaledPatch(currentMenu->x - 24, OP_GamepadSetDef.y+LINEHEIGHT*i-4, 0, + V_DrawScaledPatch(currentMenu->x - 24, OP_JoystickSetDef.y+LINEHEIGHT*i-4, 0, W_CachePatchName("M_CURSOR", PU_PATCH)); } } } -boolean M_OnGamepadMenu(void) +void M_SetupJoystickMenu(INT32 choice) { - return currentMenu == &OP_GamepadSetDef; -} + INT32 i = 0; + const char *joyNA = "Unavailable"; + INT32 n = I_NumJoys(); + (void)choice; -void M_UpdateGamepadMenu(void) -{ - INT32 i = 0, j = 1; - INT32 n = I_NumGamepads(); + strcpy(joystickInfo[i], "None"); - strcpy(gamepadInfo[i].name, "None"); - gamepadInfo[i].index = 0; - - for (i = 1; i < MAX_CONNECTED_GAMEPADS + 1; i++) + for (i = 1; i <= MAX_JOYSTICKS; i++) { - if (i <= n && (I_GetGamepadName(i)) != NULL) - strlcpy(gamepadInfo[j].name, I_GetGamepadName(i), sizeof gamepadInfo[j].name); + if (i <= n && (I_GetJoyName(i)) != NULL) + strncpy(joystickInfo[i], I_GetJoyName(i), 28); else - strlcpy(gamepadInfo[j].name, "Unavailable", sizeof gamepadInfo[j].name); + strcpy(joystickInfo[i], joyNA); - gamepadInfo[j].index = j; - -#ifdef GAMEPAD_HOTPLUG - // Update cv_usegamepad.string here so that the user can +#ifdef JOYSTICK_HOTPLUG + // We use cv_usejoystick.string as the USER-SET var + // and cv_usejoystick.value as the INTERNAL var + // + // In practice, if cv_usejoystick.string == 0, this overrides + // cv_usejoystick.value and always disables + // + // Update cv_usejoystick.string here so that the user can // properly change this value. - for (INT32 jn = 0; jn < NUM_GAMEPADS; jn++) - { - if (i == cv_usegamepad[jn].value) - CV_SetValue(&cv_usegamepad[jn], i); - } + if (i == cv_usejoystick.value) + CV_SetValue(&cv_usejoystick, i); + if (i == cv_usejoystick2.value) + CV_SetValue(&cv_usejoystick2, i); #endif - - j++; } + + M_SetupNextMenu(&OP_JoystickSetDef); } -static void M_SetupGamepadMenu(void) -{ - M_UpdateGamepadMenu(); - M_SetupNextMenu(&OP_GamepadSetDef); - - if (setupcontrols_secondaryplayer) - itemOn = G_GetGamepadDeviceIndex(1); - else - itemOn = G_GetGamepadDeviceIndex(0); -} - -static void M_Setup1PGamepadMenu(INT32 choice) +static void M_Setup1PJoystickMenu(INT32 choice) { setupcontrols_secondaryplayer = false; - setupcontrols_joycvar = &cv_usegamepad[0]; - OP_GamepadSetDef.prevMenu = &OP_Gamepad1Def; - OP_GamepadSetDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); - OP_GamepadSetDef.menuid &= ~(((1 << MENUBITS) - 1) << (MENUBITS*2)); - OP_GamepadSetDef.menuid |= MN_OP_P1CONTROLS << MENUBITS; - OP_GamepadSetDef.menuid |= MN_OP_P1JOYSTICK << (MENUBITS*2); - - M_SetupGamepadMenu(); - (void)choice; + OP_JoystickSetDef.prevMenu = &OP_Joystick1Def; + OP_JoystickSetDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); + OP_JoystickSetDef.menuid &= ~(((1 << MENUBITS) - 1) << (MENUBITS*2)); + OP_JoystickSetDef.menuid |= MN_OP_P1CONTROLS << MENUBITS; + OP_JoystickSetDef.menuid |= MN_OP_P1JOYSTICK << (MENUBITS*2); + M_SetupJoystickMenu(choice); } -static void M_Setup2PGamepadMenu(INT32 choice) +static void M_Setup2PJoystickMenu(INT32 choice) { setupcontrols_secondaryplayer = true; - setupcontrols_joycvar = &cv_usegamepad[1]; - OP_GamepadSetDef.prevMenu = &OP_Gamepad2Def; - OP_GamepadSetDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); - OP_GamepadSetDef.menuid &= ~(((1 << MENUBITS) - 1) << (MENUBITS*2)); - OP_GamepadSetDef.menuid |= MN_OP_P2CONTROLS << MENUBITS; - OP_GamepadSetDef.menuid |= MN_OP_P2JOYSTICK << (MENUBITS*2); - - M_SetupGamepadMenu(); - (void)choice; + OP_JoystickSetDef.prevMenu = &OP_Joystick2Def; + OP_JoystickSetDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); + OP_JoystickSetDef.menuid &= ~(((1 << MENUBITS) - 1) << (MENUBITS*2)); + OP_JoystickSetDef.menuid |= MN_OP_P2CONTROLS << MENUBITS; + OP_JoystickSetDef.menuid |= MN_OP_P2JOYSTICK << (MENUBITS*2); + M_SetupJoystickMenu(choice); } -static void M_AssignGamepad(INT32 choice) +static void M_AssignJoystick(INT32 choice) { -#ifdef GAMEPAD_HOTPLUG - INT32 this = gamepadInfo[choice].index; +#ifdef JOYSTICK_HOTPLUG + INT32 oldchoice, oldstringchoice; + INT32 numjoys = I_NumJoys(); - // Detect if other players are using this gamepad index - for (INT32 i = 0; this && i < NUM_GAMEPADS; i++) + if (setupcontrols_secondaryplayer) { - // Ignore yourself - if (i == (INT32)setupcontrols_secondaryplayer) - continue; + oldchoice = oldstringchoice = atoi(cv_usejoystick2.string) > numjoys ? atoi(cv_usejoystick2.string) : cv_usejoystick2.value; + CV_SetValue(&cv_usejoystick2, choice); - INT32 other = G_GetGamepadDeviceIndex(i); - - // Ignore gamepads that are disconnected - // (the game will deal with it when they are connected) - if (other > I_NumGamepads()) - continue; - - if (other == this) + // Just in case last-minute changes were made to cv_usejoystick.value, + // update the string too + // But don't do this if we're intentionally setting higher than numjoys + if (choice <= numjoys) { - M_StartMessage("This gamepad is used by another\n" - "player. Reset the gamepad\n" - "for that player first.\n\n" - "(Press a key)\n", NULL, MM_NOTHING); - return; + CV_SetValue(&cv_usejoystick2, cv_usejoystick2.value); + + // reset this so the comparison is valid + if (oldchoice > numjoys) + oldchoice = cv_usejoystick2.value; + + if (oldchoice != choice) + { + if (choice && oldstringchoice > numjoys) // if we did not select "None", we likely selected a used device + CV_SetValue(&cv_usejoystick2, (oldstringchoice > numjoys ? oldstringchoice : oldchoice)); + + if (oldstringchoice == + (atoi(cv_usejoystick2.string) > numjoys ? atoi(cv_usejoystick2.string) : cv_usejoystick2.value)) + M_StartMessage("This gamepad is used by another\n" + "player. Reset the gamepad\n" + "for that player first.\n\n" + "(Press a key)\n", NULL, MM_NOTHING); + } } } -#endif + else + { + oldchoice = oldstringchoice = atoi(cv_usejoystick.string) > numjoys ? atoi(cv_usejoystick.string) : cv_usejoystick.value; + CV_SetValue(&cv_usejoystick, choice); - CV_SetValue(setupcontrols_joycvar, this); + // Just in case last-minute changes were made to cv_usejoystick.value, + // update the string too + // But don't do this if we're intentionally setting higher than numjoys + if (choice <= numjoys) + { + CV_SetValue(&cv_usejoystick, cv_usejoystick.value); + + // reset this so the comparison is valid + if (oldchoice > numjoys) + oldchoice = cv_usejoystick.value; + + if (oldchoice != choice) + { + if (choice && oldstringchoice > numjoys) // if we did not select "None", we likely selected a used device + CV_SetValue(&cv_usejoystick, (oldstringchoice > numjoys ? oldstringchoice : oldchoice)); + + if (oldstringchoice == + (atoi(cv_usejoystick.string) > numjoys ? atoi(cv_usejoystick.string) : cv_usejoystick.value)) + M_StartMessage("This gamepad is used by another\n" + "player. Reset the gamepad\n" + "for that player first.\n\n" + "(Press a key)\n", NULL, MM_NOTHING); + } + } + } +#else + if (setupcontrols_secondaryplayer) + CV_SetValue(&cv_usejoystick2, choice); + else + CV_SetValue(&cv_usejoystick, choice); +#endif } // ============= @@ -12813,26 +12844,10 @@ static void M_Setup2PControlsMenu(INT32 choice) M_SetupNextMenu(&OP_ChangeControlsDef); } -static const char *M_GetKeyName(UINT8 player, INT32 key) -{ - gamepadtype_e type = GAMEPAD_TYPE_UNKNOWN; - if (cv_usegamepad[player].value) - type = gamepads[player].type; - - if (key >= KEY_GAMEPAD && key < KEY_GAMEPAD + NUM_GAMEPAD_BUTTONS) - return G_GetGamepadButtonString(type, key - KEY_GAMEPAD, GAMEPAD_STRING_MENU1); - else if (key >= KEY_AXES && key < KEY_AXES + NUM_GAMEPAD_AXES) - return G_GetGamepadAxisString(type, key - KEY_AXES, GAMEPAD_STRING_MENU1, false); - else if (key >= KEY_INV_AXES && key < KEY_INV_AXES + NUM_GAMEPAD_AXES) - return G_GetGamepadAxisString(type, key - KEY_INV_AXES, GAMEPAD_STRING_MENU1, true); - - return G_GetDisplayNameForKey(key); -} - #define controlheight 18 // Draws the Customise Controls menu -static void M_DrawControlConfigMenu(void) +static void M_DrawControl(void) { char tmp[50]; INT32 x, y, i, max, cursory = 0, iter; @@ -12912,38 +12927,40 @@ static void M_DrawControlConfigMenu(void) if (currentMenu->menuitems[i].status == IT_CONTROL) { - INT32 right = x + V_StringWidth(currentMenu->menuitems[i].text, 0); V_DrawString(x, y, ((i == itemOn) ? V_YELLOWMAP : 0), currentMenu->menuitems[i].text); - keys[0] = setupcontrols[currentMenu->menuitems[i].alphaKey][0]; keys[1] = setupcontrols[currentMenu->menuitems[i].alphaKey][1]; tmp[0] ='\0'; if (keys[0] == KEY_NULL && keys[1] == KEY_NULL) + { strcpy(tmp, "---"); + } else { if (keys[0] != KEY_NULL) - strcat(tmp, M_GetKeyName(setupcontrols_secondaryplayer, keys[0])); - if (keys[0] != KEY_NULL && keys[1] != KEY_NULL) - strcat(tmp, " or "); - if (keys[1] != KEY_NULL) - strcat(tmp, M_GetKeyName(setupcontrols_secondaryplayer, keys[1])); - } + strcat (tmp, G_KeyNumToName (keys[0])); - INT32 left = BASEVIDWIDTH-currentMenu->x-V_StringWidth(tmp, V_ALLOWLOWERCASE); - if (left - 8 <= right) - V_DrawRightAlignedThinString(BASEVIDWIDTH-currentMenu->x, y+1, V_ALLOWLOWERCASE | V_YELLOWMAP, tmp); - else - V_DrawRightAlignedString(BASEVIDWIDTH-currentMenu->x, y, V_ALLOWLOWERCASE | V_YELLOWMAP, tmp); + if (keys[0] != KEY_NULL && keys[1] != KEY_NULL) + strcat(tmp," or "); + + if (keys[1] != KEY_NULL) + strcat (tmp, G_KeyNumToName (keys[1])); + + + } + V_DrawRightAlignedString(BASEVIDWIDTH-currentMenu->x, y, V_YELLOWMAP, tmp); } + /*else if (currentMenu->menuitems[i].status == IT_GRAYEDOUT2) + V_DrawString(x, y, V_TRANSLUCENT, currentMenu->menuitems[i].text);*/ else if ((currentMenu->menuitems[i].status == IT_HEADER) && (i != max-1)) M_DrawLevelPlatterHeader(y, currentMenu->menuitems[i].text, true, false); y += SMALLLINEHEIGHT; } - V_DrawScaledPatch(currentMenu->x - 20, cursory, 0, W_CachePatchName("M_CURSOR", PU_PATCH)); + V_DrawScaledPatch(currentMenu->x - 20, cursory, 0, + W_CachePatchName("M_CURSOR", PU_PATCH)); } #undef controlbuffer @@ -12951,55 +12968,55 @@ static void M_DrawControlConfigMenu(void) static INT32 controltochange; static char controltochangetext[33]; -static void M_ChangeControlResponse(event_t *ev) +static void M_ChangecontrolResponse(event_t *ev) { - // dirty hack: for customising controls, I want only buttons/keys, not moves - if (ev->type == ev_mouse || ev->type == ev_mouse2) - return; - - INT32 ch = ev->key; - - // Remap gamepad events - if (ev->type == ev_gamepad_down) - ch += KEY_GAMEPAD; - else if (ev->type == ev_gamepad_axis) - { - const UINT16 jdeadzone = G_GetGamepadDigitalDeadZone(ev->which); - const INT16 value = G_GamepadAxisEventValue(ev->which, ev->x); - - if (value > jdeadzone) - ch += KEY_AXES; - else if (value < -jdeadzone) - ch += KEY_INV_AXES; - else - return; - } - else if (ev->type != ev_keydown) - return; + INT32 control; + INT32 found; + INT32 ch = ev->key; // ESCAPE cancels; dummy out PAUSE if (ch != KEY_ESCAPE && ch != KEY_PAUSE) { - INT32 control = controltochange; + + switch (ev->type) + { + // ignore mouse/joy movements, just get buttons + case ev_mouse: + case ev_mouse2: + case ev_joystick: + case ev_joystick2: + ch = KEY_NULL; // no key + break; + + // keypad arrows are converted for the menu in cursor arrows + // so use the event instead of ch + case ev_keydown: + ch = ev->key; + break; + + default: + break; + } + + control = controltochange; // check if we already entered this key - INT32 found = -1; - if (setupcontrols[control][0] == ch) + found = -1; + if (setupcontrols[control][0] ==ch) found = 0; - else if (setupcontrols[control][1] == ch) + else if (setupcontrols[control][1] ==ch) found = 1; - if (found >= 0) { -#define CHECK_DBL(key, length) (ch >= key && ch <= key+length) -#define SET_DBL(key, dblkey) ch-key+dblkey - // replace mouse clicks by double clicks - if (CHECK_DBL(KEY_MOUSE1, MOUSEBUTTONS)) - setupcontrols[control][found] = SET_DBL(KEY_MOUSE1, KEY_DBLMOUSE1); - else if (CHECK_DBL(KEY_2MOUSE1, MOUSEBUTTONS)) - setupcontrols[control][found] = SET_DBL(KEY_2MOUSE1, KEY_DBL2MOUSE1); -#undef CHECK_DBL -#undef SET_DBL + // replace mouse and joy clicks by double clicks + if (ch >= KEY_MOUSE1 && ch <= KEY_MOUSE1+MOUSEBUTTONS) + setupcontrols[control][found] = ch-KEY_MOUSE1+KEY_DBLMOUSE1; + else if (ch >= KEY_JOY1 && ch <= KEY_JOY1+JOYBUTTONS) + setupcontrols[control][found] = ch-KEY_JOY1+KEY_DBLJOY1; + else if (ch >= KEY_2MOUSE1 && ch <= KEY_2MOUSE1+MOUSEBUTTONS) + setupcontrols[control][found] = ch-KEY_2MOUSE1+KEY_DBL2MOUSE1; + else if (ch >= KEY_2JOY1 && ch <= KEY_2JOY1+JOYBUTTONS) + setupcontrols[control][found] = ch-KEY_2JOY1+KEY_DBL2JOY1; } else { @@ -13014,11 +13031,9 @@ static void M_ChangeControlResponse(event_t *ev) found = 0; setupcontrols[control][1] = KEY_NULL; //replace key 1,clear key2 } - - G_CheckDoubleUsage(ch, true); + (void)G_CheckDoubleUsage(ch, true); setupcontrols[control][found] = ch; } - S_StartSound(NULL, sfx_strpst); } else if (ch == KEY_PAUSE) @@ -13034,7 +13049,7 @@ static void M_ChangeControlResponse(event_t *ev) sprintf(tmp, M_GetText("The \x82Pause Key \x80is enabled, but \nit is not configurable. \n\nHit another key for\n%s\nESC for Cancel"), controltochangetext); - M_StartMessage(tmp, M_ChangeControlResponse, MM_EVENTHANDLER); + M_StartMessage(tmp, M_ChangecontrolResponse, MM_EVENTHANDLER); currentMenu->prevMenu = prev; S_StartSound(NULL, sfx_s3k42); @@ -13060,150 +13075,7 @@ static void M_ChangeControl(INT32 choice) currentMenu->menuitems[choice].text); strlcpy(controltochangetext, currentMenu->menuitems[choice].text, 33); - M_StartMessage(tmp, M_ChangeControlResponse, MM_EVENTHANDLER); -} - -static const char *M_GetGamepadAxisName(consvar_t *cv) -{ - switch (cv->value) - { - case 0: - return "None"; - - case 1: // X - return "L. Stick X"; - case 2: // Y - return "L. Stick Y"; - case 3: // X - return "R. Stick X"; - case 4: // Y - return "R. Stick Y"; - - case -1: // X- - return "L. Stick X (inv.)"; - case -2: // Y- - return "L. Stick Y (inv.)"; - case -3: // X- - return "R. Stick X (inv.)"; - case -4: // Y- - return "R. Stick Y (inv.)"; - - case 5: - return "L. Trigger"; - case 6: - return "R. Trigger"; - - default: - return cv->string; - } -} - -static void M_DrawGamepadMenu(void) -{ - INT32 x, y, i, cursory = 0; - INT32 right, left; - - // DRAW MENU - x = currentMenu->x; - y = currentMenu->y; - - // draw title (or big pic) - M_DrawMenuTitle(); - - for (i = 0; i < currentMenu->numitems; i++) - { - if (i == itemOn) - cursory = y; - switch (currentMenu->menuitems[i].status & IT_DISPLAY) - { - case IT_NOTHING: - case IT_DYBIGSPACE: - y += LINEHEIGHT; - break; - case IT_STRING: - case IT_WHITESTRING: - if (currentMenu->menuitems[i].alphaKey) - y = currentMenu->y+currentMenu->menuitems[i].alphaKey; - if (i == itemOn) - cursory = y; - - if ((currentMenu->menuitems[i].status & IT_DISPLAY)==IT_STRING) - V_DrawString(x, y, 0, currentMenu->menuitems[i].text); - else - V_DrawString(x, y, V_YELLOWMAP, currentMenu->menuitems[i].text); - - right = x + V_StringWidth(currentMenu->menuitems[i].text, 0); - - // Cvar specific handling - switch (currentMenu->menuitems[i].status & IT_TYPE) - case IT_CVAR: - { - consvar_t *cv = (consvar_t *)currentMenu->menuitems[i].itemaction; - switch (currentMenu->menuitems[i].status & IT_CVARTYPE) - { - case IT_CV_SLIDER: - M_DrawSlider(x, y, cv, (i == itemOn)); - break; - default: - { - const char *str = cv->string; - INT32 flags = V_YELLOWMAP; - INT32 width = V_StringWidth(str, flags); - - if (cv->PossibleValue == joyaxis_cons_t) - { - str = M_GetGamepadAxisName(cv); - flags |= V_ALLOWLOWERCASE; - - width = V_StringWidth(str, flags); - left = BASEVIDWIDTH - x - width; - - if (left - 16 <= right) - { - width = V_ThinStringWidth(str, flags); - V_DrawRightAlignedThinString(BASEVIDWIDTH - x, y + 1, flags, str); - } - else - V_DrawRightAlignedString(BASEVIDWIDTH - x, y, flags, str); - } - else - V_DrawRightAlignedString(BASEVIDWIDTH - x, y, flags, str); - - if (i == itemOn) - { - V_DrawCharacter(BASEVIDWIDTH - x - 10 - width - (skullAnimCounter/5), y, - '\x1C' | V_YELLOWMAP, false); - V_DrawCharacter(BASEVIDWIDTH - x + 2 + (skullAnimCounter/5), y, - '\x1D' | V_YELLOWMAP, false); - } - break; - } - } - break; - } - y += STRINGHEIGHT; - break; - case IT_TRANSTEXT: - if (currentMenu->menuitems[i].alphaKey) - y = currentMenu->y+currentMenu->menuitems[i].alphaKey; - V_DrawString(x, y, V_TRANSLUCENT, currentMenu->menuitems[i].text); - y += SMALLLINEHEIGHT; - break; - case IT_HEADERTEXT: // draws 16 pixels to the left, in yellow text - if (currentMenu->menuitems[i].alphaKey) - y = currentMenu->y+currentMenu->menuitems[i].alphaKey; - - //V_DrawString(x-16, y, V_YELLOWMAP, currentMenu->menuitems[i].text); - M_DrawLevelPlatterHeader(y - (lsheadingheight - 12), currentMenu->menuitems[i].text, true, false); - y += SMALLLINEHEIGHT; - break; - } - } - - // DRAW THE SKULL CURSOR - V_DrawScaledPatch(currentMenu->x - 24, cursory, 0, - W_CachePatchName("M_CURSOR", PU_PATCH)); - V_DrawString(currentMenu->x, cursory, V_YELLOWMAP, currentMenu->menuitems[itemOn].text); + M_StartMessage(tmp, M_ChangecontrolResponse, MM_EVENTHANDLER); } static void M_Setup1PPlaystyleMenu(INT32 choice) diff --git a/src/m_menu.h b/src/m_menu.h index 8d023811d..a7072b0c1 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -223,9 +223,8 @@ typedef enum { MM_NOTHING = 0, // is just displayed until the user do someting MM_YESNO, // routine is called with only 'y' or 'n' in param - MM_KEYHANDLER, // the same of above but without 'y' or 'n' restriction - MM_EVENTHANDLER // the same of above but routine is void routine(event_t *) - // (ex: set control) + MM_EVENTHANDLER // the same of above but without 'y' or 'n' restriction + // and routine is void routine(event_t *) (ex: set control) } menumessagetype_t; void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtype); @@ -362,11 +361,9 @@ extern menu_t *currentMenu; extern menu_t MainDef; extern menu_t SP_LoadDef; -// Call when a gamepad is connected or disconnected -void M_UpdateGamepadMenu(void); - -// Returns true if the player is on the gamepad selection menu -boolean M_OnGamepadMenu(void); +// Call upon joystick hotplug +void M_SetupJoystickMenu(INT32 choice); +extern menu_t OP_JoystickSetDef; // Stuff for customizing the player select screen typedef struct @@ -541,19 +538,6 @@ void M_FreePlayerSetupColors(void); NULL\ } -#define GAMEPADMENUSTYLE(id, header, source, prev, x, y)\ -{\ - id,\ - header,\ - sizeof(source)/sizeof(menuitem_t),\ - prev,\ - source,\ - M_DrawGamepadMenu,\ - x, y,\ - 0,\ - NULL\ -} - #define MAPPLATTERMENUSTYLE(id, header, source)\ {\ id,\ @@ -574,7 +558,7 @@ void M_FreePlayerSetupColors(void); sizeof (source)/sizeof (menuitem_t),\ prev,\ source,\ - M_DrawControlConfigMenu,\ + M_DrawControl,\ 24, 40,\ 0,\ NULL\ diff --git a/src/p_haptic.c b/src/p_haptic.c deleted file mode 100644 index dbfa58737..000000000 --- a/src/p_haptic.c +++ /dev/null @@ -1,115 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 2021-2022 by Jaime "Lactozilla" Passos. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file p_haptic.c -/// \brief Haptic feedback - -#include "p_haptic.h" -#include "g_game.h" -#include "d_netcmd.h" -#include "i_gamepad.h" -#include "doomstat.h" - -// Helper function: Returns the gamepad index for a player if it's enabled -static INT16 GetGamepadIndex(player_t *player) -{ - INT16 index = G_GetGamepadForPlayer(player); - - if (index >= 0 && cv_usegamepad[index].value) - return index; - - return -1; -} - -// Rumbles a player's gamepad, or all gamepads -boolean P_DoRumble(player_t *player, fixed_t large_magnitude, fixed_t small_magnitude, tic_t duration) -{ - if (!I_RumbleSupported()) - return false; - - // Rumble every gamepad - if (player == NULL) - { - for (UINT8 i = 0; i < NUM_GAMEPADS; i++) - { - if (cv_gamepad_rumble[i].value) - G_RumbleGamepad(i, large_magnitude, small_magnitude, duration); - } - - return true; - } - - INT16 which = GetGamepadIndex(player); - if (which < 0 || !cv_gamepad_rumble[which].value) - return false; - - return G_RumbleGamepad((UINT8)which, large_magnitude, small_magnitude, duration); -} - -// Pauses or unpauses gamepad rumble for a player (or all of them) -// Rumble is paused or unpaused regardless if it's enabled or not -static void SetRumblePaused(player_t *player, boolean pause) -{ - INT16 which = GetGamepadIndex(player); - - if (which >= 0) - G_SetGamepadRumblePaused((UINT8)which, pause); - else if (player == NULL) - { - // Pause or unpause every gamepad - for (UINT8 i = 0; i < NUM_GAMEPADS; i++) - G_SetGamepadRumblePaused(i, pause); - } -} - -void P_PauseRumble(player_t *player) -{ - SetRumblePaused(player, true); -} - -void P_UnpauseRumble(player_t *player) -{ - SetRumblePaused(player, false); -} - -boolean P_IsRumbleEnabled(player_t *player) -{ - INT16 which = GetGamepadIndex(player); - if (which < 0 || !cv_gamepad_rumble[which].value) - return false; - - return G_RumbleSupported((UINT8)which); -} - -boolean P_IsRumblePaused(player_t *player) -{ - INT16 which = GetGamepadIndex(player); - if (which < 0 || !cv_gamepad_rumble[which].value) - return false; - - return G_GetGamepadRumblePaused((UINT8)which); -} - -// Stops gamepad rumble for a player (or all of them) -void P_StopRumble(player_t *player) -{ - if (!I_RumbleSupported()) - return; - - if (player) - { - INT16 which = GetGamepadIndex(player); - if (which >= 0) - G_StopGamepadRumble((UINT8)which); - return; - } - - // Stop every gamepad instead - for (UINT8 i = 0; i < NUM_GAMEPADS; i++) - G_StopGamepadRumble(i); -} diff --git a/src/p_haptic.h b/src/p_haptic.h deleted file mode 100644 index 1bd4f9199..000000000 --- a/src/p_haptic.h +++ /dev/null @@ -1,27 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 2021-2022 by Jaime "Lactozilla" Passos. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file p_haptic.h -/// \brief Haptic feedback - -#ifndef __P_HAPTIC__ -#define __P_HAPTIC__ - -#include "doomdef.h" -#include "p_local.h" - -boolean P_DoRumble(player_t *player, fixed_t large_magnitude, fixed_t small_magnitude, tic_t duration); -void P_PauseRumble(player_t *player); -void P_UnpauseRumble(player_t *player); -boolean P_IsRumbleEnabled(player_t *player); -boolean P_IsRumblePaused(player_t *player); -void P_StopRumble(player_t *player); - -#define P_DoRumbleCombined(player, magnitude, dur) P_DoRumble(player, magnitude, magnitude, dur); - -#endif // __P_HAPTIC__ diff --git a/src/p_inter.c b/src/p_inter.c index f3c13e315..dd3e0f9c2 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -13,7 +13,6 @@ #include "doomdef.h" #include "i_system.h" -#include "i_gamepad.h" #include "am_map.h" #include "g_game.h" #include "m_random.h" @@ -25,7 +24,6 @@ #include "lua_hook.h" #include "m_cond.h" // unlockables, emblems, etc #include "p_setup.h" -#include "p_haptic.h" #include "m_cheat.h" // objectplace #include "m_misc.h" #include "v_video.h" // video flags for CEchos @@ -35,6 +33,54 @@ #define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : "" #define CTFTEAMENDCODE(pl) pl->ctfteam ? "\x80" : "" +void P_ForceFeed(const player_t *player, INT32 attack, INT32 fade, tic_t duration, INT32 period) +{ + BasicFF_t Basicfeed; + if (!player) + return; + Basicfeed.Duration = (UINT32)(duration * (100L/TICRATE)); + Basicfeed.ForceX = Basicfeed.ForceY = 1; + Basicfeed.Gain = 25000; + Basicfeed.Magnitude = period*10; + Basicfeed.player = player; + /// \todo test FFB + P_RampConstant(&Basicfeed, attack, fade); +} + +void P_ForceConstant(const BasicFF_t *FFInfo) +{ + JoyFF_t ConstantQuake; + if (!FFInfo || !FFInfo->player) + return; + ConstantQuake.ForceX = FFInfo->ForceX; + ConstantQuake.ForceY = FFInfo->ForceY; + ConstantQuake.Duration = FFInfo->Duration; + ConstantQuake.Gain = FFInfo->Gain; + ConstantQuake.Magnitude = FFInfo->Magnitude; + if (FFInfo->player == &players[consoleplayer]) + I_Tactile(ConstantForce, &ConstantQuake); + else if (splitscreen && FFInfo->player == &players[secondarydisplayplayer]) + I_Tactile2(ConstantForce, &ConstantQuake); +} +void P_RampConstant(const BasicFF_t *FFInfo, INT32 Start, INT32 End) +{ + JoyFF_t RampQuake; + if (!FFInfo || !FFInfo->player) + return; + RampQuake.ForceX = FFInfo->ForceX; + RampQuake.ForceY = FFInfo->ForceY; + RampQuake.Duration = FFInfo->Duration; + RampQuake.Gain = FFInfo->Gain; + RampQuake.Magnitude = FFInfo->Magnitude; + RampQuake.Start = Start; + RampQuake.End = End; + if (FFInfo->player == &players[consoleplayer]) + I_Tactile(ConstantForce, &RampQuake); + else if (splitscreen && FFInfo->player == &players[secondarydisplayplayer]) + I_Tactile2(ConstantForce, &RampQuake); +} + + // // GET STUFF // @@ -3011,8 +3057,6 @@ static boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, IN player_t *player = target->player; (void)damage; //unused parm - P_DoRumbleCombined(player, FRACUNIT, TICRATE / 6); - // If flashing or invulnerable, ignore the tag, if (player->powers[pw_flashing] || player->powers[pw_invulnerability]) return false; @@ -3116,8 +3160,6 @@ static boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *sou { player_t *player = target->player; - (void)damage; - if (!(damagetype & DMG_CANHURTSELF)) { // You can't kill yourself, idiot... @@ -3180,8 +3222,6 @@ static boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *sou static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) { - (void)damage; - player->pflags &= ~PF_SLIDING; player->powers[pw_carry] = CR_NONE; @@ -3202,7 +3242,7 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) // Get rid of emeralds player->powers[pw_emeralds] = 0; - P_DoRumbleCombined(player, FRACUNIT, TICRATE / 3); + P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); P_ResetPlayer(player); @@ -3242,9 +3282,7 @@ static void P_SuperDamage(player_t *player, mobj_t *inflictor, mobj_t *source, I fixed_t fallbackspeed; angle_t ang; - (void)damage; - - P_DoRumbleCombined(player, FRACUNIT, TICRATE / 6); + P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); if (player->mo->eflags & MFE_VERTICALFLIP) player->mo->z--; @@ -3325,14 +3363,12 @@ void P_RemoveShield(player_t *player) static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) { - (void)damage; - // Must do pain first to set flashing -- P_RemoveShield can cause damage P_DoPlayerPain(player, source, inflictor); P_RemoveShield(player); - P_DoRumbleCombined(player, FRACUNIT, TICRATE / 6); + P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); if (damagetype == DMG_SPIKE) // spikes S_StartSound(player->mo, sfx_spkdth); @@ -3361,7 +3397,7 @@ static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, IN { P_DoPlayerPain(player, source, inflictor); - P_DoRumbleCombined(player, FRACUNIT, TICRATE / 6); + P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); if (damagetype == DMG_SPIKE) // spikes S_StartSound(player->mo, sfx_spkdth); @@ -3692,6 +3728,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da damage = 1; P_KillPlayer(player, source, damage); } + + P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); } // Killing dead. Just for kicks. diff --git a/src/p_local.h b/src/p_local.h index 31a9e6c9d..2b3020997 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -453,6 +453,18 @@ extern mobj_t **blocklinks; // for thing chains // // P_INTER // +typedef struct BasicFF_s +{ + INT32 ForceX; ///< The X of the Force's Vel + INT32 ForceY; ///< The Y of the Force's Vel + const player_t *player; ///< Player of Rumble + //All + UINT32 Duration; ///< The total duration of the effect, in microseconds + INT32 Gain; ///< /The gain to be applied to the effect, in the range from 0 through 10,000. + //All, CONSTANTFORCE �10,000 to 10,000 + INT32 Magnitude; ///< Magnitude of the effect, in the range from 0 through 10,000. +} BasicFF_t; + /* Damage/death types, for P_DamageMobj and related */ //// Damage types //#define DMG_NORMAL 0 (unneeded?) @@ -473,6 +485,9 @@ extern mobj_t **blocklinks; // for thing chains #define DMG_CANHURTSELF 0x40 // Flag - can hurt self/team indirectly, such as through mines #define DMG_DEATHMASK DMG_INSTAKILL // if bit 7 is set, this is a death type instead of a damage type +void P_ForceFeed(const player_t *player, INT32 attack, INT32 fade, tic_t duration, INT32 period); +void P_ForceConstant(const BasicFF_t *FFInfo); +void P_RampConstant(const BasicFF_t *FFInfo, INT32 Start, INT32 End); void P_RemoveShield(player_t *player); void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source); boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype); diff --git a/src/p_user.c b/src/p_user.c index 4ca4e6c8a..c3f47f70c 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -5331,9 +5331,9 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) // disabled because it seemed to disorient people and Z-targeting exists now /*if (!demoplayback) { - if (player == &players[consoleplayer] && cv_cam_turnfacingability[0].value > 0 && !(G_PlayerInputDown(0, GC_TURNLEFT) || G_PlayerInputDown(0, GC_TURNRIGHT))) + if (player == &players[consoleplayer] && cv_cam_turnfacingability[0].value > 0 && !(PLAYER1INPUTDOWN(GC_TURNLEFT) || PLAYER1INPUTDOWN(GC_TURNRIGHT))) P_SetPlayerAngle(player, player->mo->angle);; - else if (player == &players[secondarydisplayplayer] && cv_cam_turnfacingability[1].value > 0 && !(G_PlayerInputDown(1, GC_TURNLEFT) || G_PlayerInputDown(1, GC_TURNRIGHT))) + else if (player == &players[secondarydisplayplayer] && cv_cam_turnfacingability[1].value > 0 && !(PLAYER2INPUTDOWN(GC_TURNLEFT) || PLAYER2INPUTDOWN(GC_TURNRIGHT))) P_SetPlayerAngle(player, player->mo->angle); }*/ } @@ -7342,7 +7342,7 @@ static void P_NiGHTSMovement(player_t *player) else if (cmd->forwardmove < 0) newangle = 270; } - else // AngleFixed(R_PointToAngle2()) results in slight inaccuracy! Don't use it unless movement is on both axes. + else // AngleFixed(R_PointToAngle2()) results in slight inaccuracy! Don't use it unless movement is on both axises. newangle = (INT16)FixedInt(AngleFixed(R_PointToAngle2(0,0, cmd->sidemove*FRACUNIT, cmd->forwardmove*FRACUNIT))); newangle -= player->viewrollangle / ANG1; diff --git a/src/sdl/Sourcefile b/src/sdl/Sourcefile index ef6a8b0dc..82d5ce073 100644 --- a/src/sdl/Sourcefile +++ b/src/sdl/Sourcefile @@ -2,7 +2,6 @@ i_net.c i_system.c i_main.c i_video.c -i_gamepad.c dosstr.c endtxt.c hwsym_sdl.c diff --git a/src/sdl/i_gamepad.c b/src/sdl/i_gamepad.c deleted file mode 100644 index 69f03d662..000000000 --- a/src/sdl/i_gamepad.c +++ /dev/null @@ -1,914 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2022 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file i_gamepad.c -/// \brief Gamepads - -#ifdef HAVE_SDL -#include "../i_gamepad.h" -#include "../i_system.h" -#include "../doomdef.h" -#include "../d_main.h" -#include "../d_netcmd.h" -#include "../g_game.h" -#include "../m_argv.h" -#include "../m_menu.h" -#include "../z_zone.h" - -#include "SDL.h" -#include "SDL_joystick.h" -#include "sdlmain.h" - -static void Controller_ChangeDevice(UINT8 num); -static void Controller_Close(UINT8 num); -static void Controller_StopRumble(UINT8 num); - -static ControllerInfo controllers[NUM_GAMEPADS]; - -static boolean rumble_supported = false; -static boolean rumble_paused = false; - -// This attempts to initialize the gamepad subsystems -static boolean InitGamepadSubsystems(void) -{ - if (M_CheckParm("-noxinput")) - SDL_SetHintWithPriority(SDL_HINT_XINPUT_ENABLED, "0", SDL_HINT_OVERRIDE); - if (M_CheckParm("-nohidapi")) - SDL_SetHintWithPriority(SDL_HINT_JOYSTICK_HIDAPI, "0", SDL_HINT_OVERRIDE); - - if (SDL_WasInit(GAMEPAD_INIT_FLAGS) == 0) - { - if (SDL_InitSubSystem(GAMEPAD_INIT_FLAGS) == -1) - { - CONS_Printf(M_GetText("Couldn't initialize game controller subsystems: %s\n"), SDL_GetError()); - return false; - } - } - - return true; -} - -void I_InitGamepads(void) -{ - if (M_CheckParm("-nojoy")) - return; - - CONS_Printf("I_InitGamepads()...\n"); - - if (!InitGamepadSubsystems()) - return; - - rumble_supported = !M_CheckParm("-norumble"); - - for (UINT8 i = 0; i < NUM_GAMEPADS; i++) - controllers[i].info = &gamepads[i]; - - for (UINT8 i = 0; i < NUM_GAMEPADS; i++) - Controller_ChangeDevice(i); -} - -INT32 I_NumGamepads(void) -{ - if (SDL_WasInit(GAMEPAD_INIT_FLAGS) == GAMEPAD_INIT_FLAGS) - return SDL_NumJoysticks(); - else - return 0; -} - -// From the SDL source code -#define USB_VENDOR_MICROSOFT 0x045e -#define USB_VENDOR_PDP 0x0e6f -#define USB_VENDOR_POWERA_ALT 0x20d6 - -#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1 0x02e3 -#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 0x0b00 -#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH 0x0b05 -#define USB_PRODUCT_XBOX_SERIES_X 0x0b12 -#define USB_PRODUCT_XBOX_SERIES_X_BLE 0x0b13 -#define USB_PRODUCT_XBOX_SERIES_X_VICTRIX_GAMBIT 0x02d6 -#define USB_PRODUCT_XBOX_SERIES_X_PDP_BLUE 0x02d9 -#define USB_PRODUCT_XBOX_SERIES_X_PDP_AFTERGLOW 0x02da -#define USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO2 0x4001 -#define USB_PRODUCT_XBOX_SERIES_X_POWERA_SPECTRA 0x4002 - -static boolean IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id) -{ - if (vendor_id == USB_VENDOR_MICROSOFT) { - if (product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1 || - product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 || - product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH) { - return true; - } - } - - return false; -} - -static boolean IsJoystickXboxSeriesXS(Uint16 vendor_id, Uint16 product_id) -{ - if (vendor_id == USB_VENDOR_MICROSOFT) { - if (product_id == USB_PRODUCT_XBOX_SERIES_X || - product_id == USB_PRODUCT_XBOX_SERIES_X_BLE) { - return true; - } - } - else if (vendor_id == USB_VENDOR_PDP) { - if (product_id == USB_PRODUCT_XBOX_SERIES_X_VICTRIX_GAMBIT || - product_id == USB_PRODUCT_XBOX_SERIES_X_PDP_BLUE || - product_id == USB_PRODUCT_XBOX_SERIES_X_PDP_AFTERGLOW) { - return true; - } - } - else if (vendor_id == USB_VENDOR_POWERA_ALT) { - if ((product_id >= 0x2001 && product_id <= 0x201a) || - product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO2 || - product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_SPECTRA) { - return true; - } - } - - return false; -} - -// Opens a controller device -static boolean Controller_OpenDevice(UINT8 which, INT32 devindex) -{ - if (SDL_WasInit(GAMEPAD_INIT_FLAGS) == 0) - { - CONS_Debug(DBG_GAMELOGIC, M_GetText("Game controller subsystems not started\n")); - return false; - } - - if (devindex <= 0) - return false; - - if (SDL_NumJoysticks() == 0) - { - CONS_Debug(DBG_GAMELOGIC, M_GetText("Found no controllers on this system\n")); - return false; - } - - devindex--; - - if (!SDL_IsGameController(devindex)) - { - CONS_Debug(DBG_GAMELOGIC, M_GetText("Device index %d isn't a game controller\n"), devindex); - return false; - } - - ControllerInfo *controller = &controllers[which]; - SDL_GameController *newdev = SDL_GameControllerOpen(devindex); - - // Handle the edge case where the device <-> controller index assignment can change due to hotplugging - // This indexing is SDL's responsibility and there's not much we can do about it. - // - // Example: - // 1. Plug Controller A -> Index 0 opened - // 2. Plug Controller B -> Index 1 opened - // 3. Unplug Controller A -> Index 0 closed, Index 1 active - // 4. Unplug Controller B -> Index 0 inactive, Index 1 closed - // 5. Plug Controller B -> Index 0 opened - // 6. Plug Controller A -> Index 0 REPLACED, opened as Controller A; Index 1 is now Controller B - if (controller->dev) - { - if (controller->dev == newdev // same device, nothing to do - || (newdev == NULL && SDL_GameControllerGetAttached(controller->dev))) // we failed, but already have a working device - return true; - - // Else, we're changing devices, so close the controller - CONS_Debug(DBG_GAMELOGIC, M_GetText("Controller %d device is changing; closing controller...\n"), which); - Controller_Close(which); - } - - if (newdev == NULL) - { - CONS_Debug(DBG_GAMELOGIC, M_GetText("Controller %d: Couldn't open device - %s\n"), which, SDL_GetError()); - controller->started = false; - } - else - { - controller->dev = newdev; - controller->joydev = SDL_GameControllerGetJoystick(controller->dev); - controller->started = true; - - CONS_Debug(DBG_GAMELOGIC, M_GetText("Controller %d: %s\n"), which, SDL_GameControllerName(controller->dev)); - - #define GAMEPAD_TYPE_CASE(ctrl) \ - case SDL_CONTROLLER_TYPE_##ctrl: \ - controller->info->type = GAMEPAD_TYPE_##ctrl; \ - break - - switch (SDL_GameControllerGetType(newdev)) - { - GAMEPAD_TYPE_CASE(UNKNOWN); - GAMEPAD_TYPE_CASE(XBOX360); - GAMEPAD_TYPE_CASE(XBOXONE); - GAMEPAD_TYPE_CASE(PS3); - GAMEPAD_TYPE_CASE(PS4); - GAMEPAD_TYPE_CASE(PS5); - GAMEPAD_TYPE_CASE(NINTENDO_SWITCH_PRO); - GAMEPAD_TYPE_CASE(GOOGLE_STADIA); - GAMEPAD_TYPE_CASE(AMAZON_LUNA); - GAMEPAD_TYPE_CASE(VIRTUAL); - default: break; - } - - #undef GAMEPAD_BUTTON_CASE - - // Check the device vendor and product to find out what controller this actually is - Uint16 vendor = SDL_JoystickGetDeviceVendor(devindex); - Uint16 product = SDL_JoystickGetDeviceProduct(devindex); - - if (IsJoystickXboxSeriesXS(vendor, product)) - controller->info->type = GAMEPAD_TYPE_XBOX_SERIES_XS; - else if (IsJoystickXboxOneElite(vendor, product)) - controller->info->type = GAMEPAD_TYPE_XBOX_ELITE; - - CONS_Debug(DBG_GAMELOGIC, M_GetText(" Type: %s\n"), G_GamepadTypeToString(controller->info->type)); - - // Change the ring LEDs on Xbox 360 controllers - // TODO: Doesn't seem to work? - SDL_GameControllerSetPlayerIndex(controller->dev, which); - - // Check if rumble is supported - if (SDL_GameControllerHasRumble(controller->dev) == SDL_TRUE) - { - controller->info->rumble.supported = true; - CONS_Debug(DBG_GAMELOGIC, M_GetText(" Rumble supported: Yes\n")); - } - else - { - controller->info->rumble.supported = false; - CONS_Debug(DBG_GAMELOGIC, M_GetText(" Rumble supported: No\n"));; - } - - controller->info->connected = true; - } - - return controller->started; -} - -// Initializes a controller -static INT32 Controller_Init(SDL_GameController **newcontroller, UINT8 which, INT32 *index) -{ - ControllerInfo *info = &controllers[which]; - SDL_GameController *controller = NULL; - INT32 device = (*index); - - if (device && SDL_IsGameController(device - 1)) - controller = SDL_GameControllerOpen(device - 1); - if (newcontroller) - (*newcontroller) = controller; - - if (controller && info->dev == controller) // don't override an active device - (*index) = I_GetControllerIndex(info->dev) + 1; - else if (controller && Controller_OpenDevice(which, device)) - { - // SDL's device indexes are unstable, so cv_usegamepad may not match - // the actual device index. So let's cheat a bit and find the device's current index. - info->lastindex = I_GetControllerIndex(info->dev) + 1; - return 1; - } - else - { - (*index) = 0; - return 0; - } - - return -1; -} - -// Changes a controller's device -static void Controller_ChangeDevice(UINT8 num) -{ - SDL_GameController *newjoy = NULL; - - if (!Controller_Init(&newjoy, num, &cv_usegamepad[num].value) && controllers[num].lastindex) - Controller_Close(num); - - I_CloseInactiveController(newjoy); -} - -static boolean Controller_IsAnyUsingDevice(SDL_GameController *dev) -{ - for (UINT8 i = 0; i < NUM_GAMEPADS; i++) - { - if (controllers[i].dev == dev) - return true; - } - - return false; -} - -static boolean Controller_IsAnyOtherUsingDevice(SDL_GameController *dev, UINT8 thisjoy) -{ - for (UINT8 i = 0; i < NUM_GAMEPADS; i++) - { - if (i == thisjoy) - continue; - else if (controllers[i].dev == dev) - return true; - } - - return false; -} - -void I_ControllerDeviceAdded(INT32 which) -{ - if (!SDL_IsGameController(which)) - return; - - SDL_GameController *newjoy = SDL_GameControllerOpen(which); - - CONS_Debug(DBG_GAMELOGIC, "Gamepad device index %d added\n", which + 1); - - // Because SDL's device index is unstable, we're going to cheat here a bit: - // For the first controller setting that is NOT active: - // 1. Set cv_usegamepadX.value to the new device index (this does not change what is written to config.cfg) - // 2. Set OTHERS' cv_usegamepadX.value to THEIR new device index, because it likely changed - // * If device doesn't exist, switch cv_usegamepad back to default value (.string) - // * BUT: If that default index is being occupied, use ANOTHER cv_usegamepad's default value! - for (UINT8 this = 0; this < NUM_GAMEPADS && newjoy; this++) - { - if ((!controllers[this].dev || !SDL_GameControllerGetAttached(controllers[this].dev)) - && !Controller_IsAnyOtherUsingDevice(newjoy, this)) // don't override a currently active device - { - cv_usegamepad[this].value = which + 1; - - // Go through every other device - for (UINT8 other = 0; other < NUM_GAMEPADS; other++) - { - if (other == this) - { - // Don't change this controller's index - continue; - } - else if (controllers[other].dev) - { - // Update this controller's index if the device is open - cv_usegamepad[other].value = I_GetControllerIndex(controllers[other].dev) + 1; - } - else if (atoi(cv_usegamepad[other].string) != controllers[this].lastindex - && atoi(cv_usegamepad[other].string) != cv_usegamepad[this].value) - { - // If the user-set index for the other controller doesn't - // match this controller's current or former internal index, - // then use the other controller's internal index - cv_usegamepad[other].value = atoi(cv_usegamepad[other].string); - } - else if (atoi(cv_usegamepad[this].string) != controllers[this].lastindex - && atoi(cv_usegamepad[this].string) != cv_usegamepad[this].value) - { - // If the user-set index for this controller doesn't match - // its current or former internal index, then use this - // controller's internal index - cv_usegamepad[other].value = atoi(cv_usegamepad[this].string); - } - else - { - // Try again - cv_usegamepad[other].value = 0; - continue; - } - - break; - } - - break; - } - } - - // Was cv_usegamepad disabled in settings? - for (UINT8 i = 0; i < NUM_GAMEPADS; i++) - { - if (!strcmp(cv_usegamepad[i].string, "0") || !cv_usegamepad[i].value) - cv_usegamepad[i].value = 0; - else if (atoi(cv_usegamepad[i].string) <= I_NumGamepads() // don't mess if we intentionally set higher than NumJoys - && cv_usegamepad[i].value) // update the cvar ONLY if a device exists - CV_SetValue(&cv_usegamepad[i], cv_usegamepad[i].value); - } - - // Update all gamepads' init states - // This is a little wasteful since cv_usegamepad already calls this, but - // we need to do this in case CV_SetValue did nothing because the string was already same. - // if the device is already active, this should do nothing, effectively. - for (UINT8 i = 0; i < NUM_GAMEPADS; i++) - { - Controller_ChangeDevice(i); - CONS_Debug(DBG_GAMELOGIC, "Controller %d device index: %d\n", i, controllers[i].lastindex); - } - - if (M_OnGamepadMenu()) - M_UpdateGamepadMenu(); - - I_CloseInactiveController(newjoy); -} - -void I_ControllerDeviceRemoved(void) -{ - for (UINT8 this = 0; this < NUM_GAMEPADS; this++) - { - if (controllers[this].dev && !SDL_GameControllerGetAttached(controllers[this].dev)) - { - CONS_Debug(DBG_GAMELOGIC, "Controller %d removed, device index: %d\n", this, controllers[this].lastindex); - G_OnGamepadDisconnect(this); - Controller_Close(this); - } - - // Update the device indexes, because they likely changed - // * If device doesn't exist, switch cv_usegamepad back to default value (.string) - // * BUT: If that default index is being occupied, use ANOTHER cv_usegamepad's default value! - if (controllers[this].dev) - cv_usegamepad[this].value = controllers[this].lastindex = I_GetControllerIndex(controllers[this].dev) + 1; - else - { - for (UINT8 other = 0; other < NUM_GAMEPADS; other++) - { - if (other == this) - continue; - - if (atoi(cv_usegamepad[this].string) != controllers[other].lastindex) - { - // Update this internal index if this user-set index - // doesn't match the other's former internal index - cv_usegamepad[this].value = atoi(cv_usegamepad[this].string); - } - else if (atoi(cv_usegamepad[other].string) != controllers[other].lastindex) - { - // Otherwise, set this internal index to the other's - // user-set index, if the other user-set index is not the - // same as the other's former internal index - cv_usegamepad[this].value = atoi(cv_usegamepad[other].string); - } - else - { - // Try again - cv_usegamepad[this].value = 0; - continue; - } - - break; - } - } - - // Was cv_usegamepad disabled in settings? - if (!strcmp(cv_usegamepad[this].string, "0")) - cv_usegamepad[this].value = 0; - else if (atoi(cv_usegamepad[this].string) <= I_NumGamepads() // don't mess if we intentionally set higher than NumJoys - && cv_usegamepad[this].value) // update the cvar ONLY if a device exists - CV_SetValue(&cv_usegamepad[this], cv_usegamepad[this].value); - - CONS_Debug(DBG_GAMELOGIC, "Controller %d device index: %d\n", this, controllers[this].lastindex); - } - - if (M_OnGamepadMenu()) - M_UpdateGamepadMenu(); -} - -// Close the controller device if there isn't any controller using it -void I_CloseInactiveController(SDL_GameController *dev) -{ - if (!Controller_IsAnyUsingDevice(dev)) - SDL_GameControllerClose(dev); -} - -// Cheat to get the device index for a game controller handle -INT32 I_GetControllerIndex(SDL_GameController *dev) -{ - INT32 i, count = SDL_NumJoysticks(); - - for (i = 0; dev && i < count; i++) - { - SDL_GameController *test = SDL_GameControllerOpen(i); - if (test && test == dev) - return i; - else - I_CloseInactiveController(test); - } - - return -1; -} - -// Changes a gamepad's device -void I_ChangeGamepad(UINT8 which) -{ - if (which >= NUM_GAMEPADS) - return; - - if (controllers[which].started) - Controller_StopRumble(which); - - Controller_ChangeDevice(which); -} - -// Returns the name of a controller from its index -const char *I_GetGamepadName(INT32 joyindex) -{ - static char joyname[256]; - joyname[0] = '\0'; - - if (SDL_WasInit(GAMEPAD_INIT_FLAGS) == GAMEPAD_INIT_FLAGS) - { - const char *tempname = SDL_GameControllerNameForIndex(joyindex - 1); - if (tempname) - strlcpy(joyname, tempname, sizeof joyname); - } - - return joyname; -} - -// Toggles a gamepad's digital axis setting -void I_SetGamepadDigital(UINT8 which, boolean enable) -{ - if (which >= NUM_GAMEPADS) - return; - - gamepads[which].digital = enable; -} - -static gamepad_t *Controller_GetFromID(SDL_JoystickID which, UINT8 *found) -{ - // Determine the joystick IDs for each current open controller - for (UINT8 i = 0; i < NUM_GAMEPADS; i++) - { - if (which == SDL_JoystickInstanceID(controllers[i].joydev)) - { - (*found) = i; - return &gamepads[i]; - } - } - - (*found) = UINT8_MAX; - - return NULL; -} - -void I_HandleControllerButtonEvent(SDL_ControllerButtonEvent evt, Uint32 type) -{ - event_t event; - - gamepad_t *gamepad = Controller_GetFromID(evt.which, &event.which); - if (gamepad == NULL) - return; - - if (type == SDL_CONTROLLERBUTTONUP) - event.type = ev_gamepad_up; - else if (type == SDL_CONTROLLERBUTTONDOWN) - event.type = ev_gamepad_down; - else - return; - -#define GAMEPAD_BUTTON_CASE(btn) \ - case SDL_CONTROLLER_BUTTON_##btn: \ - event.key = GAMEPAD_BUTTON_##btn; \ - break - - switch (evt.button) - { - GAMEPAD_BUTTON_CASE(A); - GAMEPAD_BUTTON_CASE(B); - GAMEPAD_BUTTON_CASE(X); - GAMEPAD_BUTTON_CASE(Y); - GAMEPAD_BUTTON_CASE(BACK); - GAMEPAD_BUTTON_CASE(GUIDE); - GAMEPAD_BUTTON_CASE(START); - GAMEPAD_BUTTON_CASE(LEFTSTICK); - GAMEPAD_BUTTON_CASE(RIGHTSTICK); - GAMEPAD_BUTTON_CASE(LEFTSHOULDER); - GAMEPAD_BUTTON_CASE(RIGHTSHOULDER); - GAMEPAD_BUTTON_CASE(DPAD_UP); - GAMEPAD_BUTTON_CASE(DPAD_DOWN); - GAMEPAD_BUTTON_CASE(DPAD_LEFT); - GAMEPAD_BUTTON_CASE(DPAD_RIGHT); - GAMEPAD_BUTTON_CASE(MISC1); - GAMEPAD_BUTTON_CASE(PADDLE1); - GAMEPAD_BUTTON_CASE(PADDLE2); - GAMEPAD_BUTTON_CASE(PADDLE3); - GAMEPAD_BUTTON_CASE(PADDLE4); - GAMEPAD_BUTTON_CASE(TOUCHPAD); - default: return; - } - -#undef GAMEPAD_BUTTON_CASE - - D_PostEvent(&event); -} - -void I_HandleControllerAxisEvent(SDL_ControllerAxisEvent evt) -{ - event_t event; - - gamepad_t *gamepad = Controller_GetFromID(evt.which, &event.which); - if (gamepad == NULL) - return; - -#define GAMEPAD_AXIS_CASE(btn) \ - case SDL_CONTROLLER_AXIS_##btn: \ - event.key = GAMEPAD_AXIS_##btn; \ - break - - switch (evt.axis) - { - GAMEPAD_AXIS_CASE(LEFTX); - GAMEPAD_AXIS_CASE(LEFTY); - GAMEPAD_AXIS_CASE(RIGHTX); - GAMEPAD_AXIS_CASE(RIGHTY); - GAMEPAD_AXIS_CASE(TRIGGERLEFT); - GAMEPAD_AXIS_CASE(TRIGGERRIGHT); - default: return; - } - -#undef GAMEPAD_AXIS_CASE - - event.type = ev_gamepad_axis; - event.x = evt.value; - - D_PostEvent(&event); -} - -static void Controller_StopRumble(UINT8 num) -{ - ControllerInfo *controller = &controllers[num]; - - controller->rumble.large_magnitude = 0; - controller->rumble.small_magnitude = 0; - controller->rumble.time_left = 0; - controller->rumble.expiration = 0; - - gamepad_t *gamepad = controller->info; - - gamepad->rumble.active = false; - gamepad->rumble.paused = false; - gamepad->rumble.data.large_magnitude = 0; - gamepad->rumble.data.small_magnitude = 0; - gamepad->rumble.data.duration = 0; - - if (gamepad->rumble.supported) - SDL_GameControllerRumble(controller->dev, 0, 0, 0); -} - -static void Controller_Close(UINT8 num) -{ - ControllerInfo *controller = &controllers[num]; - - // Close the game controller device - if (controller->dev) - { - Controller_StopRumble(num); - SDL_GameControllerClose(controller->dev); - } - - controller->dev = NULL; - controller->joydev = NULL; - controller->lastindex = -1; - controller->started = false; - - // Reset gamepad info - gamepad_t *gamepad = controller->info; - - if (gamepad) - { - gamepad->type = GAMEPAD_TYPE_UNKNOWN; - gamepad->connected = false; - gamepad->digital = false; - gamepad->rumble.supported = false; - - for (UINT8 i = 0; i < NUM_GAMEPAD_BUTTONS; i++) - gamepad->buttons[i] = 0; - - for (UINT8 i = 0; i < NUM_GAMEPAD_AXES; i++) - gamepad->axes[i] = 0; - } -} - -void I_ShutdownGamepads(void) -{ - for (UINT8 i = 0; i < NUM_GAMEPADS; i++) - Controller_Close(i); -} - -boolean I_RumbleSupported(void) -{ - return rumble_supported; -} - -static boolean Controller_Rumble(ControllerInfo *c) -{ - if (SDL_GameControllerRumble(c->dev, c->rumble.large_magnitude, c->rumble.small_magnitude, 0) == -1) - return false; - - return true; -} - -void I_ToggleControllerRumble(boolean unpause) -{ - if (!I_RumbleSupported() || rumble_paused == !unpause) - return; - - rumble_paused = !unpause; - - for (UINT8 i = 0; i < NUM_GAMEPADS; i++) - { - ControllerInfo *controller = &controllers[i]; - if (!controller->started || !controller->info->rumble.supported) - continue; - - if (rumble_paused) - SDL_GameControllerRumble(controller->dev, 0, 0, 0); - else if (!controller->info->rumble.paused) - { - if (!Controller_Rumble(controller)) - controller->rumble.expiration = controller->rumble.time_left = 0; - } - } -} - -void I_UpdateControllers(void) -{ - if (SDL_WasInit(GAMEPAD_INIT_FLAGS) != GAMEPAD_INIT_FLAGS) - return; - - for (UINT8 i = 0; i < NUM_GAMEPADS; i++) - { - ControllerInfo *controller = &controllers[i]; - if (!controller->started || !controller->info->rumble.supported || controller->info->rumble.paused) - continue; - - if (controller->rumble.expiration && - SDL_TICKS_PASSED(SDL_GetTicks(), controller->rumble.expiration)) - { - // Enough time has passed, so stop the effect - Controller_StopRumble(i); - } - } - - SDL_JoystickUpdate(); -} - -// Converts duration in tics to milliseconds -#define TICS_TO_MS(tics) ((INT32)(tics * (1000.0f/TICRATE))) - -boolean I_RumbleGamepad(UINT8 which, const haptic_t *effect) -{ - if (!I_RumbleSupported() || which >= NUM_GAMEPADS) - return false; - - ControllerInfo *controller = &controllers[which]; - if (!controller->started || !controller->info->rumble.supported) - return false; - - UINT16 duration = min(TICS_TO_MS(effect->duration), UINT16_MAX); - UINT16 large_magnitude = max(0, min(effect->large_magnitude, UINT16_MAX)); - UINT16 small_magnitude = max(0, min(effect->small_magnitude, UINT16_MAX)); - - CONS_Debug(DBG_GAMELOGIC, "Starting rumble effect for controller %d:\n", which); - CONS_Debug(DBG_GAMELOGIC, " Large motor magnitude: %f\n", large_magnitude / 65535.0f); - CONS_Debug(DBG_GAMELOGIC, " Small motor magnitude: %f\n", small_magnitude / 65535.0f); - - if (!duration) - CONS_Debug(DBG_GAMELOGIC, " Duration: forever\n"); - else - CONS_Debug(DBG_GAMELOGIC, " Duration: %dms\n", duration); - - controller->rumble.large_magnitude = large_magnitude; - controller->rumble.small_magnitude = small_magnitude; - - if (!rumble_paused && !Controller_Rumble(controller)) - { - Controller_StopRumble(which); - return false; - } - - controller->rumble.time_left = 0; - - if (duration) - controller->rumble.expiration = SDL_GetTicks() + duration; - else - controller->rumble.expiration = 0; - - // Update gamepad rumble info - gamepad_t *gamepad = controller->info; - - gamepad->rumble.active = true; - gamepad->rumble.paused = false; - gamepad->rumble.data.large_magnitude = effect->large_magnitude; - gamepad->rumble.data.small_magnitude = effect->small_magnitude; - gamepad->rumble.data.duration = effect->duration; - - return true; -} - -#undef TICS_TO_MS - -#define SET_MOTOR_FREQ(type) \ - if (!I_RumbleSupported() || which >= NUM_GAMEPADS) \ - return false; \ - \ - ControllerInfo *controller = &controllers[which]; \ - if (!controller->started || !controller->info->rumble.supported) \ - return false; \ - \ - gamepad_t *gamepad = controller->info; \ - if (gamepad->rumble.data.type##_magnitude == freq) \ - return true; \ - \ - UINT16 frequency = max(0, min(freq, UINT16_MAX)); \ - \ - controller->rumble.type##_magnitude = frequency; \ - \ - if (!rumble_paused && !gamepad->rumble.paused && !Controller_Rumble(controller)) \ - { \ - Controller_StopRumble(which); \ - return false; \ - } \ - \ - gamepad->rumble.data.type##_magnitude = freq; \ - gamepad->rumble.active = true; \ - return true - -boolean I_SetGamepadLargeMotorFreq(UINT8 which, fixed_t freq) -{ - SET_MOTOR_FREQ(large); -} - -boolean I_SetGamepadSmallMotorFreq(UINT8 which, fixed_t freq) -{ - SET_MOTOR_FREQ(small); -} - -void I_SetGamepadRumblePaused(UINT8 which, boolean pause) -{ - if (!I_RumbleSupported() || which >= NUM_GAMEPADS) - return; - - ControllerInfo *controller = &controllers[which]; - if (!controller->started || !controller->info->rumble.supported) - return; - - if (pause == controller->info->rumble.paused) - return; - else if (pause) - { - if (!rumble_paused) - SDL_GameControllerRumble(controller->dev, 0, 0, 0); - - if (controller->rumble.expiration) - { - controller->rumble.time_left = controller->rumble.expiration - SDL_GetTicks(); - controller->rumble.expiration = 0; - } - } - else - { - if (!rumble_paused) - SDL_GameControllerRumble(controller->dev, controller->rumble.large_magnitude, controller->rumble.small_magnitude, 0); - - if (controller->rumble.time_left) - controller->rumble.expiration = SDL_GetTicks() + controller->rumble.time_left; - } - - controller->info->rumble.paused = pause; -} - -boolean I_GetGamepadRumbleSupported(UINT8 which) -{ - if (!I_RumbleSupported() || which >= NUM_GAMEPADS) - return false; - - ControllerInfo *controller = &controllers[which]; - if (!controller->started) - return false; - - return controller->info->rumble.supported; -} - -boolean I_GetGamepadRumblePaused(UINT8 which) -{ - if (!I_RumbleSupported() || which >= NUM_GAMEPADS) - return false; - - ControllerInfo *controller = &controllers[which]; - if (!controller->started || !controller->info->rumble.supported) - return false; - - return controller->info->rumble.paused; -} - -void I_StopGamepadRumble(UINT8 which) -{ - if (!I_RumbleSupported() || which >= NUM_GAMEPADS) - return; - - ControllerInfo *controller = &controllers[which]; - if (!controller->started || !controller->info->rumble.supported) - return; - - Controller_StopRumble(which); -} -#endif diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index ee082fd5d..818d0f0c4 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -185,7 +185,6 @@ static char returnWadPath[256]; #include "../i_video.h" #include "../i_sound.h" #include "../i_system.h" -#include "../i_gamepad.h" #include "../i_threads.h" #include "../screen.h" //vid.WndParent #include "../d_net.h" @@ -194,6 +193,8 @@ static char returnWadPath[256]; #include "endtxt.h" #include "sdlmain.h" +#include "../i_joy.h" + #include "../m_argv.h" #include "../r_main.h" // Frame interpolation/uncapped @@ -211,6 +212,41 @@ static char returnWadPath[256]; #include "../byteptr.h" #endif +/** \brief The JoyReset function + + \param JoySet Joystick info to reset + + \return void +*/ +static void JoyReset(SDLJoyInfo_t *JoySet) +{ + if (JoySet->dev) + { + SDL_JoystickClose(JoySet->dev); + } + JoySet->dev = NULL; + JoySet->oldjoy = -1; + JoySet->axises = JoySet->buttons = JoySet->hats = JoySet->balls = 0; + //JoySet->scale +} + +/** \brief First joystick up and running +*/ +static INT32 joystick_started = 0; + +/** \brief SDL info about joystick 1 +*/ +SDLJoyInfo_t JoyInfo; + + +/** \brief Second joystick up and running +*/ +static INT32 joystick2_started = 0; + +/** \brief SDL inof about joystick 2 +*/ +SDLJoyInfo_t JoyInfo2; + #ifdef HAVE_TERMIOS static INT32 fdmouse2 = -1; static INT32 mouse2_started = 0; @@ -903,17 +939,721 @@ INT32 I_GetKey (void) return rc; } +// +// I_JoyScale +// +void I_JoyScale(void) +{ + Joystick.bGamepadStyle = cv_joyscale.value==0; + JoyInfo.scale = Joystick.bGamepadStyle?1:cv_joyscale.value; +} + +void I_JoyScale2(void) +{ + Joystick2.bGamepadStyle = cv_joyscale2.value==0; + JoyInfo2.scale = Joystick2.bGamepadStyle?1:cv_joyscale2.value; +} + +// Cheat to get the device index for a joystick handle +INT32 I_GetJoystickDeviceIndex(SDL_Joystick *dev) +{ + INT32 i, count = SDL_NumJoysticks(); + + for (i = 0; dev && i < count; i++) + { + SDL_Joystick *test = SDL_JoystickOpen(i); + if (test && test == dev) + return i; + else if (JoyInfo.dev != test && JoyInfo2.dev != test) + SDL_JoystickClose(test); + } + + return -1; +} + +/** \brief Joystick 1 buttons states +*/ +static UINT64 lastjoybuttons = 0; + +/** \brief Joystick 1 hats state +*/ +static UINT64 lastjoyhats = 0; + +/** \brief Shuts down joystick 1 + + + \return void + + +*/ +void I_ShutdownJoystick(void) +{ + INT32 i; + event_t event; + event.type=ev_keyup; + event.x = 0; + event.y = 0; + + lastjoybuttons = lastjoyhats = 0; + + // emulate the up of all joystick buttons + for (i=0;i= 0; i--) + { + joybuttons <<= 1; + if (SDL_JoystickGetButton(JoyInfo.dev,i)) + joybuttons |= 1; + } + + if (joybuttons != lastjoybuttons) + { + INT64 j = 1; // keep only bits that changed since last time + INT64 newbuttons = joybuttons ^ lastjoybuttons; + lastjoybuttons = joybuttons; + + for (i = 0; i < JOYBUTTONS; i++, j <<= 1) + { + if (newbuttons & j) // button changed state? + { + if (joybuttons & j) + event.type = ev_keydown; + else + event.type = ev_keyup; + event.key = KEY_JOY1 + i; + D_PostEvent(&event); + } + } + } +#endif + + for (i = JoyInfo.hats - 1; i >= 0; i--) + { + Uint8 hat = SDL_JoystickGetHat(JoyInfo.dev, i); + + if (hat & SDL_HAT_UP ) joyhats|=(UINT64)0x1<<(0 + 4*i); + if (hat & SDL_HAT_DOWN ) joyhats|=(UINT64)0x1<<(1 + 4*i); + if (hat & SDL_HAT_LEFT ) joyhats|=(UINT64)0x1<<(2 + 4*i); + if (hat & SDL_HAT_RIGHT) joyhats|=(UINT64)0x1<<(3 + 4*i); + } + + if (joyhats != lastjoyhats) + { + INT64 j = 1; // keep only bits that changed since last time + INT64 newhats = joyhats ^ lastjoyhats; + lastjoyhats = joyhats; + + for (i = 0; i < JOYHATS*4; i++, j <<= 1) + { + if (newhats & j) // hat changed state? + { + if (joyhats & j) + event.type = ev_keydown; + else + event.type = ev_keyup; + event.key = KEY_HAT1 + i; + D_PostEvent(&event); + } + } + } + +#if 0 + // send joystick axis positions + event.type = ev_joystick; + + for (i = JOYAXISSET - 1; i >= 0; i--) + { + event.key = i; + if (i*2 + 1 <= JoyInfo.axises) + axisx = SDL_JoystickGetAxis(JoyInfo.dev, i*2 + 0); + else axisx = 0; + if (i*2 + 2 <= JoyInfo.axises) + axisy = SDL_JoystickGetAxis(JoyInfo.dev, i*2 + 1); + else axisy = 0; + + + // -32768 to 32767 + axisx = axisx/32; + axisy = axisy/32; + + + if (Joystick.bGamepadStyle) + { + // gamepad control type, on or off, live or die + if (axisx < -(JOYAXISRANGE/2)) + event.x = -1; + else if (axisx > (JOYAXISRANGE/2)) + event.x = 1; + else event.x = 0; + if (axisy < -(JOYAXISRANGE/2)) + event.y = -1; + else if (axisy > (JOYAXISRANGE/2)) + event.y = 1; + else event.y = 0; + } + else + { + + axisx = JoyInfo.scale?((axisx/JoyInfo.scale)*JoyInfo.scale):axisx; + axisy = JoyInfo.scale?((axisy/JoyInfo.scale)*JoyInfo.scale):axisy; + +#ifdef SDL_JDEADZONE + if (-SDL_JDEADZONE <= axisx && axisx <= SDL_JDEADZONE) axisx = 0; + if (-SDL_JDEADZONE <= axisy && axisy <= SDL_JDEADZONE) axisy = 0; +#endif + + // analog control style , just send the raw data + event.x = axisx; // x axis + event.y = axisy; // y axis + } + D_PostEvent(&event); + } +#endif +} + +/** \brief Open joystick handle + + \param fname name of joystick + + \return axises + + +*/ +static int joy_open(int joyindex) +{ + SDL_Joystick *newdev = NULL; + int num_joy = 0; + + if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) + { + CONS_Printf(M_GetText("Joystick subsystem not started\n")); + return -1; + } + + if (joyindex <= 0) + return -1; + + num_joy = SDL_NumJoysticks(); + + if (num_joy == 0) + { + CONS_Printf("%s", M_GetText("Found no joysticks on this system\n")); + return -1; + } + + newdev = SDL_JoystickOpen(joyindex-1); + + // Handle the edge case where the device <-> joystick index assignment can change due to hotplugging + // This indexing is SDL's responsibility and there's not much we can do about it. + // + // Example: + // 1. Plug Controller A -> Index 0 opened + // 2. Plug Controller B -> Index 1 opened + // 3. Unplug Controller A -> Index 0 closed, Index 1 active + // 4. Unplug Controller B -> Index 0 inactive, Index 1 closed + // 5. Plug Controller B -> Index 0 opened + // 6. Plug Controller A -> Index 0 REPLACED, opened as Controller A; Index 1 is now Controller B + if (JoyInfo.dev) + { + if (JoyInfo.dev == newdev // same device, nothing to do + || (newdev == NULL && SDL_JoystickGetAttached(JoyInfo.dev))) // we failed, but already have a working device + return JoyInfo.axises; + // Else, we're changing devices, so send neutral joy events + CONS_Debug(DBG_GAMELOGIC, "Joystick1 device is changing; resetting events...\n"); + I_ShutdownJoystick(); + } + + JoyInfo.dev = newdev; + + if (JoyInfo.dev == NULL) + { + CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick1: Couldn't open device - %s\n"), SDL_GetError()); + return -1; + } + else + { + CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick1: %s\n"), SDL_JoystickName(JoyInfo.dev)); + JoyInfo.axises = SDL_JoystickNumAxes(JoyInfo.dev); + if (JoyInfo.axises > JOYAXISSET*2) + JoyInfo.axises = JOYAXISSET*2; + /* if (joyaxes<2) + { + I_OutputMsg("Not enought axes?\n"); + return 0; + }*/ + + JoyInfo.buttons = SDL_JoystickNumButtons(JoyInfo.dev); + if (JoyInfo.buttons > JOYBUTTONS) + JoyInfo.buttons = JOYBUTTONS; + + JoyInfo.hats = SDL_JoystickNumHats(JoyInfo.dev); + if (JoyInfo.hats > JOYHATS) + JoyInfo.hats = JOYHATS; + + JoyInfo.balls = SDL_JoystickNumBalls(JoyInfo.dev); + + //Joystick.bGamepadStyle = !stricmp(SDL_JoystickName(JoyInfo.dev), "pad"); + + return JoyInfo.axises; + } +} + +//Joystick2 + +/** \brief Joystick 2 buttons states +*/ +static UINT64 lastjoy2buttons = 0; + +/** \brief Joystick 2 hats state +*/ +static UINT64 lastjoy2hats = 0; + +/** \brief Shuts down joystick 2 + + + \return void +*/ +void I_ShutdownJoystick2(void) +{ + INT32 i; + event_t event; + event.type = ev_keyup; + event.x = 0; + event.y = 0; + + lastjoy2buttons = lastjoy2hats = 0; + + // emulate the up of all joystick buttons + for (i = 0; i < JOYBUTTONS; i++) + { + event.key = KEY_2JOY1 + i; + D_PostEvent(&event); + } + + // emulate the up of all joystick hats + for (i = 0; i < JOYHATS*4; i++) + { + event.key = KEY_2HAT1 + i; + D_PostEvent(&event); + } + + // reset joystick position + event.type = ev_joystick2; + for (i = 0; i < JOYAXISSET; i++) + { + event.key = i; + D_PostEvent(&event); + } + + joystick2_started = 0; + JoyReset(&JoyInfo2); + + // don't shut down the subsystem here, because hotplugging +} + +void I_GetJoystick2Events(void) +{ + static event_t event = {0,0,0,0,false}; + INT32 i = 0; + UINT64 joyhats = 0; +#if 0 + INT64 joybuttons = 0; + INT32 axisx, axisy; +#endif + + if (!joystick2_started) + return; + + if (!JoyInfo2.dev) //I_ShutdownJoystick2(); + return; + + +#if 0 + //faB: look for as much buttons as g_input code supports, + // we don't use the others + for (i = JoyInfo2.buttons - 1; i >= 0; i--) + { + joybuttons <<= 1; + if (SDL_JoystickGetButton(JoyInfo2.dev,i)) + joybuttons |= 1; + } + + if (joybuttons != lastjoy2buttons) + { + INT64 j = 1; // keep only bits that changed since last time + INT64 newbuttons = joybuttons ^ lastjoy2buttons; + lastjoy2buttons = joybuttons; + + for (i = 0; i < JOYBUTTONS; i++, j <<= 1) + { + if (newbuttons & j) // button changed state? + { + if (joybuttons & j) + event.type = ev_keydown; + else + event.type = ev_keyup; + event.key = KEY_2JOY1 + i; + D_PostEvent(&event); + } + } + } +#endif + + for (i = JoyInfo2.hats - 1; i >= 0; i--) + { + Uint8 hat = SDL_JoystickGetHat(JoyInfo2.dev, i); + + if (hat & SDL_HAT_UP ) joyhats|=(UINT64)0x1<<(0 + 4*i); + if (hat & SDL_HAT_DOWN ) joyhats|=(UINT64)0x1<<(1 + 4*i); + if (hat & SDL_HAT_LEFT ) joyhats|=(UINT64)0x1<<(2 + 4*i); + if (hat & SDL_HAT_RIGHT) joyhats|=(UINT64)0x1<<(3 + 4*i); + } + + if (joyhats != lastjoy2hats) + { + INT64 j = 1; // keep only bits that changed since last time + INT64 newhats = joyhats ^ lastjoy2hats; + lastjoy2hats = joyhats; + + for (i = 0; i < JOYHATS*4; i++, j <<= 1) + { + if (newhats & j) // hat changed state? + { + if (joyhats & j) + event.type = ev_keydown; + else + event.type = ev_keyup; + event.key = KEY_2HAT1 + i; + D_PostEvent(&event); + } + } + } + +#if 0 + // send joystick axis positions + event.type = ev_joystick2; + + for (i = JOYAXISSET - 1; i >= 0; i--) + { + event.key = i; + if (i*2 + 1 <= JoyInfo2.axises) + axisx = SDL_JoystickGetAxis(JoyInfo2.dev, i*2 + 0); + else axisx = 0; + if (i*2 + 2 <= JoyInfo2.axises) + axisy = SDL_JoystickGetAxis(JoyInfo2.dev, i*2 + 1); + else axisy = 0; + + // -32768 to 32767 + axisx = axisx/32; + axisy = axisy/32; + + if (Joystick2.bGamepadStyle) + { + // gamepad control type, on or off, live or die + if (axisx < -(JOYAXISRANGE/2)) + event.x = -1; + else if (axisx > (JOYAXISRANGE/2)) + event.x = 1; + else + event.x = 0; + if (axisy < -(JOYAXISRANGE/2)) + event.y = -1; + else if (axisy > (JOYAXISRANGE/2)) + event.y = 1; + else + event.y = 0; + } + else + { + + axisx = JoyInfo2.scale?((axisx/JoyInfo2.scale)*JoyInfo2.scale):axisx; + axisy = JoyInfo2.scale?((axisy/JoyInfo2.scale)*JoyInfo2.scale):axisy; + +#ifdef SDL_JDEADZONE + if (-SDL_JDEADZONE <= axisx && axisx <= SDL_JDEADZONE) axisx = 0; + if (-SDL_JDEADZONE <= axisy && axisy <= SDL_JDEADZONE) axisy = 0; +#endif + + // analog control style , just send the raw data + event.x = axisx; // x axis + event.y = axisy; // y axis + } + D_PostEvent(&event); + } +#endif +} + +/** \brief Open joystick handle + + \param fname name of joystick + + \return axises + + +*/ +static int joy_open2(int joyindex) +{ + SDL_Joystick *newdev = NULL; + int num_joy = 0; + + if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) + { + CONS_Printf(M_GetText("Joystick subsystem not started\n")); + return -1; + } + + if (joyindex <= 0) + return -1; + + num_joy = SDL_NumJoysticks(); + + if (num_joy == 0) + { + CONS_Printf("%s", M_GetText("Found no joysticks on this system\n")); + return -1; + } + + newdev = SDL_JoystickOpen(joyindex-1); + + // Handle the edge case where the device <-> joystick index assignment can change due to hotplugging + // This indexing is SDL's responsibility and there's not much we can do about it. + // + // Example: + // 1. Plug Controller A -> Index 0 opened + // 2. Plug Controller B -> Index 1 opened + // 3. Unplug Controller A -> Index 0 closed, Index 1 active + // 4. Unplug Controller B -> Index 0 inactive, Index 1 closed + // 5. Plug Controller B -> Index 0 opened + // 6. Plug Controller A -> Index 0 REPLACED, opened as Controller A; Index 1 is now Controller B + if (JoyInfo2.dev) + { + if (JoyInfo2.dev == newdev // same device, nothing to do + || (newdev == NULL && SDL_JoystickGetAttached(JoyInfo2.dev))) // we failed, but already have a working device + return JoyInfo.axises; + // Else, we're changing devices, so send neutral joy events + CONS_Debug(DBG_GAMELOGIC, "Joystick2 device is changing; resetting events...\n"); + I_ShutdownJoystick2(); + } + + JoyInfo2.dev = newdev; + + if (JoyInfo2.dev == NULL) + { + CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick2: couldn't open device - %s\n"), SDL_GetError()); + return -1; + } + else + { + CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick2: %s\n"), SDL_JoystickName(JoyInfo2.dev)); + JoyInfo2.axises = SDL_JoystickNumAxes(JoyInfo2.dev); + if (JoyInfo2.axises > JOYAXISSET*2) + JoyInfo2.axises = JOYAXISSET*2; +/* if (joyaxes<2) + { + I_OutputMsg("Not enought axes?\n"); + return 0; + }*/ + + JoyInfo2.buttons = SDL_JoystickNumButtons(JoyInfo2.dev); + if (JoyInfo2.buttons > JOYBUTTONS) + JoyInfo2.buttons = JOYBUTTONS; + + JoyInfo2.hats = SDL_JoystickNumHats(JoyInfo2.dev); + if (JoyInfo2.hats > JOYHATS) + JoyInfo2.hats = JOYHATS; + + JoyInfo2.balls = SDL_JoystickNumBalls(JoyInfo2.dev); + + //Joystick.bGamepadStyle = !stricmp(SDL_JoystickName(JoyInfo2.dev), "pad"); + + return JoyInfo2.axises; + } +} + +// +// I_InitJoystick +// +void I_InitJoystick(void) +{ + SDL_Joystick *newjoy = NULL; + + //I_ShutdownJoystick(); + if (M_CheckParm("-nojoy")) + return; + + if (M_CheckParm("-noxinput")) + SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE); + + if (M_CheckParm("-nohidapi")) + SDL_SetHintWithPriority("SDL_JOYSTICK_HIDAPI", "0", SDL_HINT_OVERRIDE); + + if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) + { + CONS_Printf("I_InitJoystick()...\n"); + + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) + { + CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError()); + return; + } + } + + if (cv_usejoystick.value) + newjoy = SDL_JoystickOpen(cv_usejoystick.value-1); + + if (newjoy && JoyInfo2.dev == newjoy) // don't override an active device + cv_usejoystick.value = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1; + else if (newjoy && joy_open(cv_usejoystick.value) != -1) + { + // SDL's device indexes are unstable, so cv_usejoystick may not match + // the actual device index. So let's cheat a bit and find the device's current index. + JoyInfo.oldjoy = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1; + joystick_started = 1; + } + else + { + if (JoyInfo.oldjoy) + I_ShutdownJoystick(); + cv_usejoystick.value = 0; + joystick_started = 0; + } + + if (JoyInfo.dev != newjoy && JoyInfo2.dev != newjoy) + SDL_JoystickClose(newjoy); +} + +void I_InitJoystick2(void) +{ + SDL_Joystick *newjoy = NULL; + + //I_ShutdownJoystick2(); + if (M_CheckParm("-nojoy")) + return; + + if (M_CheckParm("-noxinput")) + SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE); + + if (M_CheckParm("-nohidapi")) + SDL_SetHintWithPriority("SDL_JOYSTICK_HIDAPI", "0", SDL_HINT_OVERRIDE); + + if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) + { + CONS_Printf("I_InitJoystick2()...\n"); + + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) + { + CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError()); + return; + } + } + + if (cv_usejoystick2.value) + newjoy = SDL_JoystickOpen(cv_usejoystick2.value-1); + + if (newjoy && JoyInfo.dev == newjoy) // don't override an active device + cv_usejoystick2.value = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1; + else if (newjoy && joy_open2(cv_usejoystick2.value) != -1) + { + // SDL's device indexes are unstable, so cv_usejoystick may not match + // the actual device index. So let's cheat a bit and find the device's current index. + JoyInfo2.oldjoy = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1; + joystick2_started = 1; + } + else + { + if (JoyInfo2.oldjoy) + I_ShutdownJoystick2(); + cv_usejoystick2.value = 0; + joystick2_started = 0; + } + + if (JoyInfo.dev != newjoy && JoyInfo2.dev != newjoy) + SDL_JoystickClose(newjoy); +} + static void I_ShutdownInput(void) { - I_ShutdownGamepads(); + // Yes, the name is misleading: these send neutral events to + // clean up the unplugged joystick's input + // Note these methods are internal to this file, not called elsewhere. + I_ShutdownJoystick(); + I_ShutdownJoystick2(); - if (SDL_WasInit(GAMEPAD_INIT_FLAGS) == GAMEPAD_INIT_FLAGS) + if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) { - CONS_Printf("Shutting down game controller subsystems\n"); - SDL_QuitSubSystem(GAMEPAD_INIT_FLAGS); + CONS_Printf("Shutting down joy system\n"); + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + I_OutputMsg("I_Joystick: SDL's Joystick system has been shutdown\n"); } } +INT32 I_NumJoys(void) +{ + INT32 numjoy = 0; + if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) + numjoy = SDL_NumJoysticks(); + return numjoy; +} + +static char joyname[255]; // joystick name is straight from the driver + +const char *I_GetJoyName(INT32 joyindex) +{ + const char *tempname = NULL; + joyname[0] = 0; + joyindex--; //SDL's Joystick System starts at 0, not 1 + if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) + { + tempname = SDL_JoystickNameForIndex(joyindex); + if (tempname) + strncpy(joyname, tempname, 255); + } + return joyname; +} + #ifndef NOMUMBLE #ifdef HAVE_MUMBLE // Best Mumble positional audio settings: @@ -1373,6 +2113,23 @@ void I_StartupMouse2(void) #endif } +// +// I_Tactile +// +void I_Tactile(FFType pFFType, const JoyFF_t *FFEffect) +{ + // UNUSED. + (void)pFFType; + (void)FFEffect; +} + +void I_Tactile2(FFType pFFType, const JoyFF_t *FFEffect) +{ + // UNUSED. + (void)pFFType; + (void)FFEffect; +} + /** \brief empty ticcmd for player 1 */ static ticcmd_t emptycmd; diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 81b20b51e..6e971a5d8 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -66,7 +66,7 @@ #include "../m_menu.h" #include "../d_main.h" #include "../s_sound.h" -#include "../i_gamepad.h" +#include "../i_joy.h" #include "../st_stuff.h" #include "../hu_stuff.h" #include "../g_game.h" @@ -449,10 +449,51 @@ static void SurfaceInfo(const SDL_Surface *infoSurface, const char *SurfaceText) static void VID_Command_Info_f (void) { +#if 0 + SDL2STUB(); +#else +#if 0 + const SDL_VideoInfo *videoInfo; + videoInfo = SDL_GetVideoInfo(); //Alam: Double-Check + if (videoInfo) + { + CONS_Printf("%s", M_GetText("Video Interface Capabilities:\n")); + if (videoInfo->hw_available) + CONS_Printf("%s", M_GetText(" Hardware surfaces\n")); + if (videoInfo->wm_available) + CONS_Printf("%s", M_GetText(" Window manager\n")); + //UnusedBits1 :6 + //UnusedBits2 :1 + if (videoInfo->blit_hw) + CONS_Printf("%s", M_GetText(" Accelerated blits HW-2-HW\n")); + if (videoInfo->blit_hw_CC) + CONS_Printf("%s", M_GetText(" Accelerated blits HW-2-HW with Colorkey\n")); + if (videoInfo->wm_available) + CONS_Printf("%s", M_GetText(" Accelerated blits HW-2-HW with Alpha\n")); + if (videoInfo->blit_sw) + { + CONS_Printf("%s", M_GetText(" Accelerated blits SW-2-HW\n")); + if (!M_CheckParm("-noblit")) videoblitok = SDL_TRUE; + } + if (videoInfo->blit_sw_CC) + CONS_Printf("%s", M_GetText(" Accelerated blits SW-2-HW with Colorkey\n")); + if (videoInfo->blit_sw_A) + CONS_Printf("%s", M_GetText(" Accelerated blits SW-2-HW with Alpha\n")); + if (videoInfo->blit_fill) + CONS_Printf("%s", M_GetText(" Accelerated Color filling\n")); + //UnusedBits3 :16 + if (videoInfo->video_mem) + CONS_Printf(M_GetText(" There is %i KB of video memory\n"), videoInfo->video_mem); + else + CONS_Printf("%s", M_GetText(" There no video memory for SDL\n")); + //*vfmt + } +#else if (!M_CheckParm("-noblit")) videoblitok = SDL_TRUE; - +#endif SurfaceInfo(bufSurface, M_GetText("Current Engine Mode")); SurfaceInfo(vidSurface, M_GetText("Current Video Mode")); +#endif } static void VID_Command_ModeList_f(void) @@ -487,6 +528,61 @@ static void VID_Command_Mode_f (void) setmodeneeded = modenum+1; // request vid mode change } +static inline void SDLJoyRemap(event_t *event) +{ + (void)event; +} + +static INT32 SDLJoyAxis(const Sint16 axis, evtype_t which) +{ + // -32768 to 32767 + INT32 raxis = axis/32; + if (which == ev_joystick) + { + if (Joystick.bGamepadStyle) + { + // gamepad control type, on or off, live or die + if (raxis < -(JOYAXISRANGE/2)) + raxis = -1; + else if (raxis > (JOYAXISRANGE/2)) + raxis = 1; + else + raxis = 0; + } + else + { + raxis = JoyInfo.scale!=1?((raxis/JoyInfo.scale)*JoyInfo.scale):raxis; + +#ifdef SDL_JDEADZONE + if (-SDL_JDEADZONE <= raxis && raxis <= SDL_JDEADZONE) + raxis = 0; +#endif + } + } + else if (which == ev_joystick2) + { + if (Joystick2.bGamepadStyle) + { + // gamepad control type, on or off, live or die + if (raxis < -(JOYAXISRANGE/2)) + raxis = -1; + else if (raxis > (JOYAXISRANGE/2)) + raxis = 1; + else raxis = 0; + } + else + { + raxis = JoyInfo2.scale!=1?((raxis/JoyInfo2.scale)*JoyInfo2.scale):raxis; + +#ifdef SDL_JDEADZONE + if (-SDL_JDEADZONE <= raxis && raxis <= SDL_JDEADZONE) + raxis = 0; +#endif + } + } + return raxis; +} + static void Impl_HandleWindowEvent(SDL_WindowEvent evt) { static SDL_bool firsttimeonmouse = SDL_TRUE; @@ -518,13 +614,13 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) // Tell game we got focus back, resume music if necessary window_notinfocus = false; if (!paused) - S_ResumeAudio(); + S_ResumeAudio(); //resume it - I_ToggleControllerRumble(true); - P_UnpauseRumble(NULL); - - if (!firsttimeonmouse && cv_usemouse.value) - I_StartupMouse(); + if (!firsttimeonmouse) + { + if (cv_usemouse.value) I_StartupMouse(); + } + //else firsttimeonmouse = SDL_FALSE; if (USE_MOUSEINPUT && !IgnoreMouse()) SDLdoGrabMouse(); @@ -533,45 +629,43 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) { // Tell game we lost focus, pause music window_notinfocus = true; - - if (!cv_playmusicifunfocused.value) + if (! cv_playmusicifunfocused.value) S_PauseAudio(); - if (!cv_playsoundsifunfocused.value) + if (! cv_playsoundsifunfocused.value) S_StopSounds(); if (!disable_mouse) + { SDLforceUngrabMouse(); - + } memset(gamekeydown, 0, NUMKEYS); // TODO this is a scary memset - I_ToggleControllerRumble(false); - if (P_AutoPause()) - P_PauseRumble(NULL); - if (MOUSE_MENU) + { SDLdoUngrabMouse(); + } } + } static void Impl_HandleKeyboardEvent(SDL_KeyboardEvent evt, Uint32 type) { event_t event; - if (type == SDL_KEYUP) + { event.type = ev_keyup; + } else if (type == SDL_KEYDOWN) + { event.type = ev_keydown; + } else + { return; - + } event.key = Impl_SDL_Scancode_To_Keycode(evt.keysym.scancode); - if (!event.key) - return; - event.repeated = (evt.repeat != 0); - event.which = 0; - - D_PostEvent(&event); + if (event.key) D_PostEvent(&event); } static void Impl_HandleMouseMotionEvent(SDL_MouseMotionEvent evt) @@ -636,35 +730,32 @@ static void Impl_HandleMouseButtonEvent(SDL_MouseButtonEvent evt, Uint32 type) if (SDL_GetMouseFocus() != window || IgnoreMouse()) return; + /// \todo inputEvent.button.which if (USE_MOUSEINPUT) { if (type == SDL_MOUSEBUTTONUP) - event.type = ev_keyup; - else if (type == SDL_MOUSEBUTTONDOWN) - event.type = ev_keydown; - else - return; - - switch (evt.button) { - case SDL_BUTTON_LEFT: - event.key = KEY_MOUSE1+0; - break; - case SDL_BUTTON_RIGHT: - event.key = KEY_MOUSE1+1; - break; - case SDL_BUTTON_MIDDLE: - event.key = KEY_MOUSE1+2; - break; - case SDL_BUTTON_X1: - event.key = KEY_MOUSE1+3; - break; - case SDL_BUTTON_X2: - event.key = KEY_MOUSE1+4; - break; + event.type = ev_keyup; + } + else if (type == SDL_MOUSEBUTTONDOWN) + { + event.type = ev_keydown; + } + else return; + if (evt.button == SDL_BUTTON_MIDDLE) + event.key = KEY_MOUSE1+2; + else if (evt.button == SDL_BUTTON_RIGHT) + event.key = KEY_MOUSE1+1; + else if (evt.button == SDL_BUTTON_LEFT) + event.key = KEY_MOUSE1; + else if (evt.button == SDL_BUTTON_X1) + event.key = KEY_MOUSE1+3; + else if (evt.button == SDL_BUTTON_X2) + event.key = KEY_MOUSE1+4; + if (event.type == ev_keyup || event.type == ev_keydown) + { + D_PostEvent(&event); } - - D_PostEvent(&event); } } @@ -695,6 +786,111 @@ static void Impl_HandleMouseWheelEvent(SDL_MouseWheelEvent evt) } } +static void Impl_HandleJoystickAxisEvent(SDL_JoyAxisEvent evt) +{ + event_t event; + SDL_JoystickID joyid[2]; + + // Determine the Joystick IDs for each current open joystick + joyid[0] = SDL_JoystickInstanceID(JoyInfo.dev); + joyid[1] = SDL_JoystickInstanceID(JoyInfo2.dev); + + evt.axis++; + event.key = event.x = event.y = INT32_MAX; + + if (evt.which == joyid[0]) + { + event.type = ev_joystick; + } + else if (evt.which == joyid[1]) + { + event.type = ev_joystick2; + } + else return; + //axis + if (evt.axis > JOYAXISSET*2) + return; + //vaule + if (evt.axis%2) + { + event.key = evt.axis / 2; + event.x = SDLJoyAxis(evt.value, event.type); + } + else + { + evt.axis--; + event.key = evt.axis / 2; + event.y = SDLJoyAxis(evt.value, event.type); + } + D_PostEvent(&event); +} + +#if 0 +static void Impl_HandleJoystickHatEvent(SDL_JoyHatEvent evt) +{ + event_t event; + SDL_JoystickID joyid[2]; + + // Determine the Joystick IDs for each current open joystick + joyid[0] = SDL_JoystickInstanceID(JoyInfo.dev); + joyid[1] = SDL_JoystickInstanceID(JoyInfo2.dev); + + if (evt.hat >= JOYHATS) + return; // ignore hats with too high an index + + if (evt.which == joyid[0]) + { + event.key = KEY_HAT1 + (evt.hat*4); + } + else if (evt.which == joyid[1]) + { + event.key = KEY_2HAT1 + (evt.hat*4); + } + else return; + + // NOTE: UNFINISHED +} +#endif + +static void Impl_HandleJoystickButtonEvent(SDL_JoyButtonEvent evt, Uint32 type) +{ + event_t event; + SDL_JoystickID joyid[2]; + + // Determine the Joystick IDs for each current open joystick + joyid[0] = SDL_JoystickInstanceID(JoyInfo.dev); + joyid[1] = SDL_JoystickInstanceID(JoyInfo2.dev); + + if (evt.which == joyid[0]) + { + event.key = KEY_JOY1; + } + else if (evt.which == joyid[1]) + { + event.key = KEY_2JOY1; + } + else return; + if (type == SDL_JOYBUTTONUP) + { + event.type = ev_keyup; + } + else if (type == SDL_JOYBUTTONDOWN) + { + event.type = ev_keydown; + } + else return; + if (evt.button < JOYBUTTONS) + { + event.key += evt.button; + } + else return; + + SDLJoyRemap(&event); + if (event.type != ev_console) D_PostEvent(&event); +} + + + void I_GetEvent(void) { SDL_Event evt; @@ -732,18 +928,147 @@ void I_GetEvent(void) case SDL_MOUSEWHEEL: Impl_HandleMouseWheelEvent(evt.wheel); break; - case SDL_CONTROLLERAXISMOTION: - I_HandleControllerAxisEvent(evt.caxis); + case SDL_JOYAXISMOTION: + Impl_HandleJoystickAxisEvent(evt.jaxis); break; - case SDL_CONTROLLERBUTTONUP: - case SDL_CONTROLLERBUTTONDOWN: - I_HandleControllerButtonEvent(evt.cbutton, evt.type); +#if 0 + case SDL_JOYHATMOTION: + Impl_HandleJoystickHatEvent(evt.jhat) break; - case SDL_CONTROLLERDEVICEADDED: - I_ControllerDeviceAdded(evt.cdevice.which); +#endif + case SDL_JOYBUTTONUP: + case SDL_JOYBUTTONDOWN: + Impl_HandleJoystickButtonEvent(evt.jbutton, evt.type); break; - case SDL_CONTROLLERDEVICEREMOVED: - I_ControllerDeviceRemoved(); + case SDL_JOYDEVICEADDED: + { + SDL_Joystick *newjoy = SDL_JoystickOpen(evt.jdevice.which); + + CONS_Debug(DBG_GAMELOGIC, "Joystick device index %d added\n", evt.jdevice.which + 1); + + // Because SDL's device index is unstable, we're going to cheat here a bit: + // For the first joystick setting that is NOT active: + // 1. Set cv_usejoystickX.value to the new device index (this does not change what is written to config.cfg) + // 2. Set OTHERS' cv_usejoystickX.value to THEIR new device index, because it likely changed + // * If device doesn't exist, switch cv_usejoystick back to default value (.string) + // * BUT: If that default index is being occupied, use ANOTHER cv_usejoystick's default value! + if (newjoy && (!JoyInfo.dev || !SDL_JoystickGetAttached(JoyInfo.dev)) + && JoyInfo2.dev != newjoy) // don't override a currently active device + { + cv_usejoystick.value = evt.jdevice.which + 1; + + if (JoyInfo2.dev) + cv_usejoystick2.value = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1; + else if (atoi(cv_usejoystick2.string) != JoyInfo.oldjoy + && atoi(cv_usejoystick2.string) != cv_usejoystick.value) + cv_usejoystick2.value = atoi(cv_usejoystick2.string); + else if (atoi(cv_usejoystick.string) != JoyInfo.oldjoy + && atoi(cv_usejoystick.string) != cv_usejoystick.value) + cv_usejoystick2.value = atoi(cv_usejoystick.string); + else // we tried... + cv_usejoystick2.value = 0; + } + else if (newjoy && (!JoyInfo2.dev || !SDL_JoystickGetAttached(JoyInfo2.dev)) + && JoyInfo.dev != newjoy) // don't override a currently active device + { + cv_usejoystick2.value = evt.jdevice.which + 1; + + if (JoyInfo.dev) + cv_usejoystick.value = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1; + else if (atoi(cv_usejoystick.string) != JoyInfo2.oldjoy + && atoi(cv_usejoystick.string) != cv_usejoystick2.value) + cv_usejoystick.value = atoi(cv_usejoystick.string); + else if (atoi(cv_usejoystick2.string) != JoyInfo2.oldjoy + && atoi(cv_usejoystick2.string) != cv_usejoystick2.value) + cv_usejoystick.value = atoi(cv_usejoystick2.string); + else // we tried... + cv_usejoystick.value = 0; + } + + // Was cv_usejoystick disabled in settings? + if (!strcmp(cv_usejoystick.string, "0") || !cv_usejoystick.value) + cv_usejoystick.value = 0; + else if (atoi(cv_usejoystick.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys + && cv_usejoystick.value) // update the cvar ONLY if a device exists + CV_SetValue(&cv_usejoystick, cv_usejoystick.value); + + if (!strcmp(cv_usejoystick2.string, "0") || !cv_usejoystick2.value) + cv_usejoystick2.value = 0; + else if (atoi(cv_usejoystick2.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys + && cv_usejoystick2.value) // update the cvar ONLY if a device exists + CV_SetValue(&cv_usejoystick2, cv_usejoystick2.value); + + // Update all joysticks' init states + // This is a little wasteful since cv_usejoystick already calls this, but + // we need to do this in case CV_SetValue did nothing because the string was already same. + // if the device is already active, this should do nothing, effectively. + I_InitJoystick(); + I_InitJoystick2(); + + CONS_Debug(DBG_GAMELOGIC, "Joystick1 device index: %d\n", JoyInfo.oldjoy); + CONS_Debug(DBG_GAMELOGIC, "Joystick2 device index: %d\n", JoyInfo2.oldjoy); + + // update the menu + if (currentMenu == &OP_JoystickSetDef) + M_SetupJoystickMenu(0); + + if (JoyInfo.dev != newjoy && JoyInfo2.dev != newjoy) + SDL_JoystickClose(newjoy); + } + break; + case SDL_JOYDEVICEREMOVED: + if (JoyInfo.dev && !SDL_JoystickGetAttached(JoyInfo.dev)) + { + CONS_Debug(DBG_GAMELOGIC, "Joystick1 removed, device index: %d\n", JoyInfo.oldjoy); + I_ShutdownJoystick(); + } + + if (JoyInfo2.dev && !SDL_JoystickGetAttached(JoyInfo2.dev)) + { + CONS_Debug(DBG_GAMELOGIC, "Joystick2 removed, device index: %d\n", JoyInfo2.oldjoy); + I_ShutdownJoystick2(); + } + + // Update the device indexes, because they likely changed + // * If device doesn't exist, switch cv_usejoystick back to default value (.string) + // * BUT: If that default index is being occupied, use ANOTHER cv_usejoystick's default value! + if (JoyInfo.dev) + cv_usejoystick.value = JoyInfo.oldjoy = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1; + else if (atoi(cv_usejoystick.string) != JoyInfo2.oldjoy) + cv_usejoystick.value = atoi(cv_usejoystick.string); + else if (atoi(cv_usejoystick2.string) != JoyInfo2.oldjoy) + cv_usejoystick.value = atoi(cv_usejoystick2.string); + else // we tried... + cv_usejoystick.value = 0; + + if (JoyInfo2.dev) + cv_usejoystick2.value = JoyInfo2.oldjoy = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1; + else if (atoi(cv_usejoystick2.string) != JoyInfo.oldjoy) + cv_usejoystick2.value = atoi(cv_usejoystick2.string); + else if (atoi(cv_usejoystick.string) != JoyInfo.oldjoy) + cv_usejoystick2.value = atoi(cv_usejoystick.string); + else // we tried... + cv_usejoystick2.value = 0; + + // Was cv_usejoystick disabled in settings? + if (!strcmp(cv_usejoystick.string, "0")) + cv_usejoystick.value = 0; + else if (atoi(cv_usejoystick.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys + && cv_usejoystick.value) // update the cvar ONLY if a device exists + CV_SetValue(&cv_usejoystick, cv_usejoystick.value); + + if (!strcmp(cv_usejoystick2.string, "0")) + cv_usejoystick2.value = 0; + else if (atoi(cv_usejoystick2.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys + && cv_usejoystick2.value) // update the cvar ONLY if a device exists + CV_SetValue(&cv_usejoystick2, cv_usejoystick2.value); + + CONS_Debug(DBG_GAMELOGIC, "Joystick1 device index: %d\n", JoyInfo.oldjoy); + CONS_Debug(DBG_GAMELOGIC, "Joystick2 device index: %d\n", JoyInfo2.oldjoy); + + // update the menu + if (currentMenu == &OP_JoystickSetDef) + M_SetupJoystickMenu(0); break; case SDL_QUIT: LUA_HookBool(true, HOOK(GameQuit)); @@ -761,7 +1086,6 @@ void I_GetEvent(void) //SDL_memset(&event, 0, sizeof(event_t)); event.type = ev_mouse; event.key = 0; - event.which = 0; event.x = (INT32)lround(mousemovex * ((float)wwidth / (float)realwidth)); event.y = (INT32)lround(mousemovey * ((float)wheight / (float)realheight)); D_PostEvent(&event); @@ -800,9 +1124,15 @@ void I_OsPolling(void) if (consolevent) I_GetConsoleEvents(); + if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) + { + SDL_JoystickUpdate(); + I_GetJoystickEvents(); + I_GetJoystick2Events(); + } - I_UpdateControllers(); I_GetMouseEvents(); + I_GetEvent(); mod = SDL_GetModState(); diff --git a/src/sdl/sdlmain.h b/src/sdl/sdlmain.h index bb178b233..6b6e79d97 100644 --- a/src/sdl/sdlmain.h +++ b/src/sdl/sdlmain.h @@ -23,41 +23,59 @@ extern SDL_bool consolevent; extern SDL_bool framebuffer; #include "../m_fixed.h" -#include "../i_gamepad.h" -// SDL info about all controllers -typedef struct +// SDL2 stub macro +#ifdef _MSC_VER +#define SDL2STUB() CONS_Printf("SDL2: stubbed: %s:%d\n", __FUNCTION__, __LINE__) +#else +#define SDL2STUB() CONS_Printf("SDL2: stubbed: %s:%d\n", __func__, __LINE__) +#endif + +// So m_menu knows whether to store cv_usejoystick value or string +#define JOYSTICK_HOTPLUG + +/** \brief The JoyInfo_s struct + + info about joystick +*/ +typedef struct SDLJoyInfo_s { - boolean started; // started - int lastindex; // last gamepad ID + /// Joystick handle + SDL_Joystick *dev; + /// number of old joystick + int oldjoy; + /// number of axies + int axises; + /// scale of axises + INT32 scale; + /// number of buttons + int buttons; + /// number of hats + int hats; + /// number of balls + int balls; - SDL_GameController *dev; - SDL_Joystick *joydev; +} SDLJoyInfo_t; - gamepad_t *info; // pointer to gamepad info +/** \brief SDL info about joystick 1 +*/ +extern SDLJoyInfo_t JoyInfo; - struct { - Uint16 large_magnitude; - Uint16 small_magnitude; - Uint32 expiration, time_left; - } rumble; -} ControllerInfo; +/** \brief joystick axis deadzone +*/ +#define SDL_JDEADZONE 153 +#undef SDL_JDEADZONE -#define GAMEPAD_INIT_FLAGS (SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) +/** \brief SDL inof about joystick 2 +*/ +extern SDLJoyInfo_t JoyInfo2; -void I_UpdateControllers(void); +// So we can call this from i_video event loop +void I_ShutdownJoystick(void); +void I_ShutdownJoystick2(void); -void I_ControllerDeviceAdded(INT32 which); -void I_ControllerDeviceRemoved(void); - -void I_HandleControllerButtonEvent(SDL_ControllerButtonEvent evt, Uint32 type); -void I_HandleControllerAxisEvent(SDL_ControllerAxisEvent evt); - -INT32 I_GetControllerIndex(SDL_GameController *dev); -void I_CloseInactiveController(SDL_GameController *dev); -void I_CloseInactiveHapticDevice(SDL_Haptic *dev); - -void I_ToggleControllerRumble(boolean unpause); +// Cheat to get the device index for a joystick handle +INT32 I_GetJoystickDeviceIndex(SDL_Joystick *dev); void I_GetConsoleEvents(void);