mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 19:55:23 +00:00
432 lines
13 KiB
C++
432 lines
13 KiB
C++
/*
|
|
* Descent 3
|
|
* Copyright (C) 2024 Parallax Software
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
--- HISTORICAL COMMENTS FOLLOW ---
|
|
|
|
* $Logfile: /DescentIII/Main/mtclient/mtgametrack.cpp $
|
|
* $Revision: 1.1.1.1 $
|
|
* $Date: 2003-08-26 03:58:40 $
|
|
* $Author: kevinb $
|
|
*
|
|
* Game Tracker client code
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
*
|
|
* 17 10/03/01 12:44a Kevin
|
|
* Smaller version of pxo packets
|
|
*
|
|
* 16 9/02/99 3:16p Kevin
|
|
* Macintosh byte ordering fixes
|
|
*
|
|
* 15 8/25/99 2:38p Samir
|
|
* added byteswap.h for INTEL_INT.
|
|
*
|
|
* 14 8/24/99 5:47p Kevin
|
|
* Macintosh crap
|
|
*
|
|
* 13 7/06/99 5:52p Kevin
|
|
* PXO & multiplayer fixes for the patch
|
|
*
|
|
* 12 5/05/99 5:23p Kevin
|
|
* fixed some bugs on the gamelist
|
|
*
|
|
* 11 5/04/99 7:29p Kevin
|
|
* Fixed bug that caused the server to send his game info twice whenever
|
|
* the level starts.
|
|
*
|
|
* 10 5/04/99 5:39p Kevin
|
|
* connection dll & pxo game tracking improvements (added server type to
|
|
* list)
|
|
*
|
|
* 9 4/19/99 8:35p Jeff
|
|
* Compile under Linux
|
|
*
|
|
* 8 3/25/99 3:26p Kevin
|
|
* Made PXO games be based on your chat channel
|
|
*
|
|
* 7 1/07/99 11:51a Kevin
|
|
* Added support for joining servers on alternate ports and hosting behind
|
|
* a proxy/firewall
|
|
*
|
|
* 6 12/30/98 12:16p Kevin
|
|
* Auto Mission Download system
|
|
*
|
|
* 5 12/23/98 6:38p Kevin
|
|
* All UDP data (except gamespy) now uses one (registered) port number
|
|
*
|
|
* 4 10/19/98 9:50a Kevin
|
|
* Added nettest application
|
|
*
|
|
* 3 7/27/98 5:31p Kevin
|
|
* Sound/Bitmap exchange system
|
|
*
|
|
* 2 6/01/98 10:10a Kevin
|
|
* Added DLL connection interface and auto update DLL
|
|
*
|
|
* 1 5/21/98 11:08a Kevin
|
|
*
|
|
* 6 5/14/98 11:07a Kevin
|
|
* Made gameover packet to the tracker reliable
|
|
*
|
|
* 5 5/04/98 12:53p Kevin
|
|
* Fixed mastertracker resend stuff
|
|
*
|
|
* 4 4/30/98 3:49p Kevin
|
|
* Mastertracker pilot stats
|
|
*
|
|
* 3 4/24/98 3:50p Kevin
|
|
* Added mastertracker game tracking support
|
|
*
|
|
* 2 4/23/98 4:49p Kevin
|
|
* Added Master tracker Game tracker support
|
|
*
|
|
* 1 4/23/98 3:26p Kevin
|
|
* Initial version
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
/*
|
|
InitGameTracker(int game_type); //D3 or Freespace
|
|
//Call periodically so we can send our update, and make sure it is received
|
|
IdleGameTracker();
|
|
StartTrackerGame(void *buffer) //Call with a freespace_net_game_data or d3_net_game_data structure
|
|
//Call with a freespace_net_game_data or d3_net_game_data structure
|
|
//Updates our memory so when it is time, we send the latest game data
|
|
UpdateGameData(gamedata);
|
|
//Call to signify end of game
|
|
RequestGameList();//Sends a GNT_GAMELIST_REQ packet to the server.
|
|
game_list * GetGameList();//returns a pointer to a game_list struct
|
|
|
|
*/
|
|
#ifdef WIN32
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#include <cstring>
|
|
#include <ctime>
|
|
|
|
#include "pstypes.h"
|
|
#include "networking.h"
|
|
#include "mtgametrack.h"
|
|
#include "byteswap.h"
|
|
#include "mt_net.h"
|
|
|
|
// extern float DLLtimer_GetTime(void);
|
|
typedef float (*timer_GetTime_fp)();
|
|
|
|
extern timer_GetTime_fp DLLtimer_GetTime;
|
|
|
|
typedef void (*HandleGamePacket_fp)(uint8_t *data, int len, network_address *from);
|
|
|
|
typedef int (*nw_RegisterCallback_fp)(HandleGamePacket_fp, uint8_t id);
|
|
extern nw_RegisterCallback_fp DLLnw_RegisterCallback;
|
|
|
|
typedef int (*nw_DoReceiveCallbacks_fp)();
|
|
extern nw_DoReceiveCallbacks_fp DLLnw_DoReceiveCallbacks;
|
|
|
|
typedef int (*nw_SendWithID_fp)(uint8_t id, uint8_t *data, int len, network_address *who_to);
|
|
extern nw_SendWithID_fp DLLnw_SendWithID;
|
|
|
|
#if (defined(LOGGER) && (!defined(RELEASE)))
|
|
#define DLLmprintf(...) DLLDebug_ConsolePrintf(__VA_ARGS__)
|
|
#else
|
|
#define DLLmprintf(...)
|
|
#endif
|
|
|
|
typedef void (*Debug_ConsolePrintf_fp)(int n, const char *format, ...);
|
|
|
|
extern Debug_ConsolePrintf_fp DLLDebug_ConsolePrintf;
|
|
|
|
// Variables
|
|
|
|
game_list GameBuffer[MAX_GAME_BUFFERS];
|
|
int GameType; // d3 or fs
|
|
|
|
float LastTrackerUpdate;
|
|
float LastSentToTracker;
|
|
|
|
float LastGameOverPacket;
|
|
float FirstGameOverPacket;
|
|
|
|
int SendingGameOver;
|
|
|
|
uint32_t TrackerAckdUs;
|
|
uint32_t TrackerGameIsRunning;
|
|
|
|
game_packet_header TrackerGameData;
|
|
game_packet_header GameListReq;
|
|
game_packet_header TrackAckPacket;
|
|
game_packet_header GameOverPacket;
|
|
|
|
game_packet_header inpacket;
|
|
|
|
d3_net_game_data_tiny *D3TrackerGameData;
|
|
|
|
extern int DLLnw_ListenPort;
|
|
extern uint16_t DLLPXOPort;
|
|
extern char *DLLPXO_hosted_lobby_name;
|
|
|
|
int InitGameTrackerClient(int gametype) {
|
|
GameType = gametype;
|
|
LastTrackerUpdate = 0;
|
|
switch (gametype) {
|
|
case GT_FREESPACE:
|
|
// TrackerGameData.len = GAME_HEADER_ONLY_SIZE+sizeof(freespace_net_game_data);
|
|
break;
|
|
case GT_DESCENT3:
|
|
TrackerGameData.len = INTEL_INT(GAME_HEADER_ONLY_SIZE + sizeof(d3_net_game_data_short));
|
|
break;
|
|
case GT_D3TNG:
|
|
TrackerGameData.len = INTEL_INT(GAME_HEADER_ONLY_SIZE + sizeof(d3_net_game_data_tiny));
|
|
break;
|
|
}
|
|
TrackerGameData.game_type = gametype; // 1==freespace (GT_FREESPACE), 2==D3, 3==tuberacer, etc.
|
|
TrackerGameData.type = INTEL_INT(GNT_GAMEUPDATE_TINY); // Used to specify what to do ie. Add a new net game
|
|
// (GNT_GAMESTARTED), remove a net game (game over), etc.
|
|
|
|
D3TrackerGameData = (d3_net_game_data_tiny *)&TrackerGameData.data;
|
|
if (DLLPXOPort) {
|
|
D3TrackerGameData->options = 1;
|
|
D3TrackerGameData->arg1 = DLLPXOPort;
|
|
}
|
|
GameListReq.game_type = gametype;
|
|
GameListReq.type = INTEL_INT(GNT_GAMELIST_LITE_FILTER_REQ);
|
|
GameListReq.len = INTEL_INT(GAME_HEADER_ONLY_SIZE);
|
|
|
|
TrackAckPacket.game_type = gametype;
|
|
TrackAckPacket.len = INTEL_INT(GAME_HEADER_ONLY_SIZE);
|
|
TrackAckPacket.type = INTEL_INT(GNT_CLIENT_ACK);
|
|
|
|
GameOverPacket.game_type = gametype;
|
|
GameOverPacket.len = INTEL_INT(GAME_HEADER_ONLY_SIZE);
|
|
GameOverPacket.type = INTEL_INT(GNT_GAMEOVER);
|
|
|
|
SendingGameOver = 0;
|
|
|
|
DLLnw_RegisterCallback(HandleGamePacket, PXO_NETID_GAME_TRACKER);
|
|
return 1;
|
|
}
|
|
|
|
void IdleGameTracker() {
|
|
DLLnw_DoReceiveCallbacks();
|
|
// uint32_t bytesin;
|
|
// mprintf(0,"IdleGameTracker() entered.\n");
|
|
if ((TrackerGameIsRunning) && ((DLLtimer_GetTime() - LastTrackerUpdate) > TRACKER_UPDATE_INTERVAL)) {
|
|
|
|
struct tm *newtime;
|
|
time_t aclock;
|
|
time(&aclock); /* Get time in seconds */
|
|
newtime = localtime(&aclock);
|
|
// Time to update the tracker again
|
|
DLLmprintf(0, "[%.24s] Updating the PXO game tracker!\n", asctime(newtime));
|
|
SendGameTrackerPacker(&TrackerGameData);
|
|
// sendto(gamesock,(const char *)&TrackerGameData,TrackerGameData.len,0,(SOCKADDR
|
|
//*)>rackaddr,sizeof(SOCKADDR_IN));
|
|
TrackerAckdUs = 0;
|
|
LastTrackerUpdate = DLLtimer_GetTime();
|
|
LastSentToTracker = DLLtimer_GetTime();
|
|
} else if ((TrackerGameIsRunning) && (!TrackerAckdUs) &&
|
|
((DLLtimer_GetTime() - LastSentToTracker) > TRACKER_RESEND_TIME)) {
|
|
// We still haven't been acked by the last packet and it's time to resend.
|
|
|
|
struct tm *newtime;
|
|
time_t aclock;
|
|
time(&aclock); /* Get time in seconds */
|
|
newtime = localtime(&aclock);
|
|
// Time to update the tracker again
|
|
DLLmprintf(0, "[%.24s] (Resending) Updating the PXO game tracker!\n", asctime(newtime));
|
|
|
|
SendGameTrackerPacker(&TrackerGameData);
|
|
TrackerAckdUs = 0;
|
|
LastTrackerUpdate = DLLtimer_GetTime();
|
|
LastSentToTracker = DLLtimer_GetTime();
|
|
}
|
|
|
|
if (SendingGameOver) {
|
|
if ((DLLtimer_GetTime() - LastGameOverPacket) > TRACKER_RESEND_TIME) {
|
|
// resend
|
|
LastGameOverPacket = DLLtimer_GetTime();
|
|
SendGameTrackerPacker(&GameOverPacket);
|
|
} else if ((DLLtimer_GetTime() - FirstGameOverPacket) > TRACKER_TIMEOUT) {
|
|
// Giving up, it timed out.
|
|
SendingGameOver = 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void SendClientHolePunch(SOCKADDR_IN *addr) {
|
|
game_packet_header HolePunchAck;
|
|
network_address send_address;
|
|
|
|
memset(&send_address, 0, sizeof(network_address));
|
|
memcpy(send_address.address, &addr->sin_addr, 4);
|
|
send_address.port = htons(addr->sin_port);
|
|
send_address.connection_type = NP_TCP;
|
|
|
|
HolePunchAck.game_type = GameType;
|
|
HolePunchAck.type = INTEL_INT(GNT_NAT_HOLE_PUNCH_ACK);
|
|
HolePunchAck.len = INTEL_INT(GAME_HEADER_ONLY_SIZE);
|
|
HolePunchAck.sig = 0; // to make sure tracker ignores this packet when it's ACK'd there
|
|
|
|
DLLnw_SendWithID(PXO_NETID_GAME_TRACKER, (uint8_t *)&HolePunchAck, INTEL_INT(HolePunchAck.len), &send_address);
|
|
}
|
|
|
|
void HandleGamePacket(uint8_t *data, int len, network_address *from) {
|
|
|
|
memcpy(&inpacket, data, sizeof(inpacket));
|
|
|
|
// Check to make sure the packets ok
|
|
if (len) {
|
|
switch (INTEL_INT(inpacket.type)) {
|
|
case GNT_SERVER_ACK:
|
|
// The server got our packet so we can stop sending now
|
|
TrackerAckdUs = 1;
|
|
if (SendingGameOver) {
|
|
SendingGameOver = 2;
|
|
}
|
|
break;
|
|
case GNT_GAMELIST_LITE_DATA:
|
|
if (len < (GAME_HEADER_ONLY_SIZE + sizeof(game_list))) {
|
|
DLLmprintf(0, "(%d) packet is too small!\n", len);
|
|
}
|
|
// Woohoo! Game data! put it in the buffer (if one's free)
|
|
// DLLmprintf(0,"GNT_GAMELIST_LITE_DATA received.\n");
|
|
for (int i = 0; i < MAX_GAME_BUFFERS; i++) {
|
|
if (GameBuffer[i].game_type == GT_UNUSED) {
|
|
memset(&GameBuffer[i], 0, sizeof(game_list));
|
|
memcpy(&GameBuffer[i], inpacket.data, len - GAME_HEADER_ONLY_SIZE);
|
|
i = MAX_GAME_BUFFERS + 1;
|
|
}
|
|
}
|
|
break;
|
|
case GNT_NAT_HOLE_PUNCH_REQ:
|
|
if (len == (GAME_HEADER_ONLY_SIZE+sizeof(hole_punch_addr_ip6))) {
|
|
// we don't support IPv6 yet so skip this one
|
|
} else {
|
|
SOCKADDR_IN nataddr;
|
|
|
|
auto ipv4 = reinterpret_cast<hole_punch_addr *>(&inpacket.data);
|
|
nataddr.sin_addr.s_addr = ipv4->addr;
|
|
nataddr.sin_port = ipv4->port;
|
|
nataddr.sin_family = AF_INET;
|
|
|
|
SendClientHolePunch(&nataddr);
|
|
}
|
|
break;
|
|
}
|
|
// mprintf(0,"Sending ACK.\n");
|
|
AckPacket(inpacket.sig);
|
|
}
|
|
}
|
|
|
|
void UpdateGameData(void *buffer) {
|
|
if (GameType == GT_FREESPACE) {
|
|
// memcpy(FreeSpaceTrackerGameData,buffer,sizeof(freespace_net_game_data));
|
|
} else if (GameType == GT_DESCENT3) {
|
|
memcpy(D3TrackerGameData, buffer, sizeof(d3_net_game_data_short));
|
|
} else if (GameType == GT_D3TNG) {
|
|
memcpy(D3TrackerGameData, buffer, sizeof(d3_net_game_data_tiny));
|
|
}
|
|
}
|
|
|
|
game_list gl;
|
|
|
|
game_list *GetGameList() {
|
|
memset(&gl, 0, sizeof(gl));
|
|
for (auto & i : GameBuffer) {
|
|
if (i.game_type != GT_UNUSED) {
|
|
memcpy(&gl, &i, sizeof(gl));
|
|
i.game_type = GT_UNUSED;
|
|
return ≷
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void RequestGameList() {
|
|
// Zero out all games
|
|
for (auto & i : GameBuffer) {
|
|
memset(&i, 0, sizeof(game_list));
|
|
}
|
|
|
|
int len = strlen(DLLPXO_hosted_lobby_name) + 1;
|
|
memcpy(GameListReq.data, DLLPXO_hosted_lobby_name, len);
|
|
GameListReq.len = INTEL_INT((uint32_t)(GAME_HEADER_ONLY_SIZE + len));
|
|
SendGameTrackerPacker(&GameListReq);
|
|
}
|
|
|
|
int SendGameOver() {
|
|
IdleGameTracker();
|
|
|
|
if (SendingGameOver == 3) {
|
|
// Request timed out.
|
|
return 2;
|
|
}
|
|
if (SendingGameOver == 2) {
|
|
SendingGameOver = 0;
|
|
return 1;
|
|
}
|
|
if (SendingGameOver == 1) {
|
|
// Wait until it's sent.
|
|
return 0;
|
|
}
|
|
if (SendingGameOver == 0) {
|
|
LastGameOverPacket = DLLtimer_GetTime();
|
|
FirstGameOverPacket = DLLtimer_GetTime();
|
|
SendingGameOver = 1;
|
|
TrackerGameIsRunning = 0;
|
|
SendGameTrackerPacker(&GameOverPacket);
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void AckPacket(int sig) {
|
|
TrackAckPacket.sig = sig;
|
|
SendGameTrackerPacker(&TrackAckPacket);
|
|
}
|
|
|
|
void StartTrackerGame(void *buffer) {
|
|
|
|
struct tm *newtime;
|
|
time_t aclock;
|
|
time(&aclock); /* Get time in seconds */
|
|
newtime = localtime(&aclock);
|
|
// Time to update the tracker again
|
|
DLLmprintf(0, "[%.24s] Updating the PXO game tracker with a new game!\n", asctime(newtime));
|
|
|
|
if (GameType == GT_FREESPACE) {
|
|
// memcpy(FreeSpaceTrackerGameData,buffer,sizeof(freespace_net_game_data));
|
|
} else if (GameType == GT_DESCENT3) {
|
|
memcpy(D3TrackerGameData, buffer, sizeof(d3_net_game_data_short));
|
|
SendGameTrackerPacker(&TrackerGameData);
|
|
TrackerAckdUs = 0;
|
|
LastTrackerUpdate = DLLtimer_GetTime();
|
|
LastSentToTracker = DLLtimer_GetTime();
|
|
|
|
} else if (GameType == GT_D3TNG) {
|
|
memcpy(D3TrackerGameData, buffer, sizeof(d3_net_game_data_tiny));
|
|
SendGameTrackerPacker(&TrackerGameData);
|
|
TrackerAckdUs = 0;
|
|
LastTrackerUpdate = DLLtimer_GetTime();
|
|
LastSentToTracker = DLLtimer_GetTime();
|
|
}
|
|
TrackerGameIsRunning = 1;
|
|
// LastTrackerUpdate = 0;
|
|
}
|