mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 22:56:30 -10:00
* add batch validation for tables * add batch validation for missions * handle server connection errors in a more useful way
325 lines
13 KiB
C
325 lines
13 KiB
C
/*
|
|
* Copyright (C) Volition, Inc. 2005. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
#ifndef _pilot_track_header
|
|
#define _pilot_track_header
|
|
|
|
#include "stats/scoring.h" // for medals count
|
|
|
|
//Pilot tracker client header
|
|
#define REGPORT 9243
|
|
|
|
#define MAX_NET_RETRIES 30
|
|
#define NET_ACK_TIMEOUT 2500
|
|
|
|
#define MAX_PXO_FILENAME_LEN 32
|
|
|
|
//This is for type
|
|
#define UNT_CONTROL 0
|
|
#define UNT_NEW_ID_REQUEST 1
|
|
#define UNT_VALIDAT_ID_REQUEST 2
|
|
#define UNT_LOOKUP_ID_REQUEST 3
|
|
#define UNT_UPDATE_ID_REQUEST 4
|
|
#define UNT_MOTD_REQUEST 5
|
|
#define UNT_MOTD_RESPONSE 6
|
|
#define UNT_PILOT_DATA_READ 7 // Request from the game for pilot info
|
|
#define UNT_PILOT_DATA_RESPONSE 8 // Mastertracker's response to a read request (has pilot data in this packet)
|
|
#define UNT_PILOT_DATA_WRITE 9 // Request from the server to write a user record
|
|
#define UNT_PILOT_WRITE_FAILED 10 // Server didn't update the pilots record for some reason
|
|
#define UNT_PILOT_WRITE_SUCCESS 11 // Server updated the pilots record
|
|
#define UNT_PILOT_READ_FAILED 12 // Couldn't find the record
|
|
#define UNT_LOGIN_AUTH_REQUEST 13 // Request login authentication by login/password only (returns tracker id)
|
|
#define UNT_LOGIN_NO_AUTH 14 // Couldn't login this user (code has reason)
|
|
#define UNT_LOGIN_AUTHENTICATED 15 // User was authenticated (data has sz string with tracker id)
|
|
#define UNT_VALID_FS_MSN_REQ 18 // Client asking if this is a valid mission
|
|
#define UNT_VALID_FS_MSN_RSP 19 // Server Response (code has the answer)
|
|
|
|
#define UNT_PILOT_DATA_READ_NEW 20 // New packet for requesting reads (tracker will get new security field when receiving this)
|
|
#define UNT_PILOT_DATA_WRITE_NEW 21 // New packet for requesting writes (tracker will compare security fields if this packet is used)
|
|
|
|
// 22 through 45 are D3 specific codes
|
|
#define UNT_VALID_FS2_MSN_REQ 46 // validated mission request to PXO for FS2
|
|
#define UNT_VALID_FS2_MSN_RSP 47 // validated mission response from PXO for FS2
|
|
|
|
// validate a squad war mission
|
|
#define UNT_VALID_SW_MSN_REQ 48 // send info about a squad war mission, wait for tracker response
|
|
#define UNT_VALID_SW_MSN_RSP 49 // response from the tracker
|
|
#define UNT_SW_RESULT_WRITE 50 // report on a finished squad war mission to the tracker
|
|
#define UNT_SW_RESULT_RESPONSE 51 // response on a squad war mission write request
|
|
|
|
#define UNT_CONTROL_VALIDATION 70 // UNT_CONTROL for validation packets
|
|
|
|
#define UNT_VALID_MSN_REQ 71 // Client asking if this is a valid mission
|
|
#define UNT_VALID_MSN_RSP 72 // Server response (code has the answer)
|
|
#define UNT_VALID_TBL_REQ 73 // Client asking if this is a valid table
|
|
#define UNT_VALID_TBL_RSP 74 // Server response (code has the answer)
|
|
|
|
#define UNT_VALID_DATA_REQ 75 // client asking for data validity check
|
|
#define UNT_VALID_DATA_RSP 76 // server response
|
|
|
|
|
|
//This is for code
|
|
#define CMD_NEW_USER_ACK 1
|
|
#define CMD_NEW_USER_NAK 2
|
|
#define CMD_VALIDATED_USER_ACK 3
|
|
#define CMD_UPDATED_USER_ACK 4
|
|
#define CMD_CLIENT_RECEIVED 5
|
|
#define CMD_FIND_USER_NAK 6
|
|
#define CMD_FIND_USER_ACK 7
|
|
#define CMD_UPDATED_USER_NAK 8
|
|
#define CMD_VALIDATED_USER_NAK 9
|
|
//Game designators for UNT_PILOT_DATA_REQUEST and UNT_PILOT_DATA_RESPONSE
|
|
#define CMD_GAME_FREESPACE 10
|
|
#define CMD_GAME_DESCENT3 11
|
|
#define CMD_GAME_FREESPACE2 12
|
|
#define CMD_GAME_FS2OPEN 13
|
|
|
|
//This is for xcode
|
|
#define REG_NAK_EMAIL 0 // failed to register the guy because of an invalid email address
|
|
#define REG_NAK_LOGIN 1 // failed to register the guy because an existing login exists
|
|
#define REG_NAK_ERROR 2 // failed to register because of an error on the tracker
|
|
#define REG_NAK_STRINGS 3 // failed to validate because of invalid password/login match
|
|
#define REG_NAK_UNKNOWN 4 // failed to validate because the player is unknown
|
|
#define REG_NAK_UPDATE_PL 5 // update info failed because login/passwd were not correct
|
|
#define REG_NAK_UPDATE_GEN 6 // update info failed in general (tracker problem)
|
|
#define REG_NAK_UPDATE_LOG 7 // update failed because login not found
|
|
#define REG_ACK_NEW_ID 8 // New id created, just used for return code, not net packets.
|
|
|
|
#define MAX_UDP_DATA_LENGH 500
|
|
#define PACKED_HEADER_ONLY_SIZE (sizeof(udp_packet_header)-MAX_UDP_DATA_LENGH)
|
|
//sizeof(update_id_request) //The largest packet
|
|
|
|
#define LOGIN_LEN 33
|
|
#define REAL_NAME_LEN 66
|
|
#define PASSWORD_LEN 17
|
|
#define EMAIL_LEN 100
|
|
#define TRACKER_ID_LEN 10
|
|
#define PILOT_NAME_LEN 20
|
|
#define MATCH_CODE_LEN 34
|
|
|
|
#define MAX_SQUAD_PLAYERS 4
|
|
#define MAX_SQUAD_RESPONSE_LEN 255
|
|
|
|
// data could be one of the following:
|
|
|
|
// type == UNT_NEW_ID_REQUEST
|
|
// Respond with ACK
|
|
typedef struct {
|
|
char first_name[REAL_NAME_LEN]; // Real Name
|
|
char last_name[REAL_NAME_LEN]; // Real Name
|
|
char login[LOGIN_LEN]; // Login id
|
|
char password[PASSWORD_LEN]; // password
|
|
char email[EMAIL_LEN]; // Email Address
|
|
unsigned char showemail; // 0==don't show 1 == show
|
|
unsigned char showname; // 0==don't show 1 == show
|
|
} new_id_request;
|
|
|
|
|
|
// type == UNT_VALIDAT_ID_REQUEST or UNT_LOOKUP_ID_REQUEST
|
|
typedef struct {
|
|
char login[LOGIN_LEN]; // Login id
|
|
char password[PASSWORD_LEN]; // password
|
|
char tracker_id[TRACKER_ID_LEN]; // Tracker ID
|
|
} validate_id_request;
|
|
|
|
// type == UNT_UPDATE_ID_REQUEST
|
|
typedef struct {
|
|
char old_login[LOGIN_LEN]; // Login before it's changed.
|
|
char old_password[PASSWORD_LEN]; // Password before it's changed
|
|
char tracker_id[TRACKER_ID_LEN]; // Tracker ID (not sure if we need it for updating, but maybe)
|
|
char first_name[REAL_NAME_LEN]; // Real Name
|
|
char last_name[REAL_NAME_LEN]; // Real Name
|
|
char login[LOGIN_LEN]; // Login id (new)
|
|
char password[PASSWORD_LEN]; // password (new)
|
|
char email[EMAIL_LEN]; // Email Address (new)
|
|
unsigned char showemail; // 0==don't show 1 == show
|
|
unsigned char showname; // 0==don't show 1 == show
|
|
} update_id_request;
|
|
|
|
typedef struct {
|
|
char pilot_name[PILOT_NAME_LEN]; // Login id
|
|
char tracker_id[TRACKER_ID_LEN]; // Tracker ID
|
|
char pad[2]; // 2-bytes padding
|
|
} pilot_request;
|
|
|
|
// type == UNT_VALID_SW_MSN_REQ
|
|
typedef struct squad_war_request {
|
|
int squad_plr1[MAX_SQUAD_PLAYERS]; // id #'s for all squad members in the match
|
|
int squad_plr2[MAX_SQUAD_PLAYERS]; // id #'s for all squad memebrs in the match
|
|
|
|
ubyte squad_count1; // # of players present in squad 1
|
|
ubyte squad_count2; // # of players present in squad 2
|
|
|
|
char match_code[MATCH_CODE_LEN]; // code for the match
|
|
|
|
char mission_filename[MAX_PXO_FILENAME_LEN]; // filename of mission
|
|
int mission_checksum; // mission checksum
|
|
} squad_war_request;
|
|
|
|
// type == UNT_SW_RESULT_WRITE
|
|
typedef struct squad_war_result {
|
|
char match_code[MATCH_CODE_LEN]; // code for the match
|
|
ubyte result; // result of the match, 0 == tie, 1 == one team won
|
|
ubyte squad_count1; // # of players in winning squad
|
|
ubyte squad_count2; // # of players in the losing squad
|
|
char pad[3]; // 3-bytes padding
|
|
int squad_winners[MAX_SQUAD_PLAYERS]; // list of players on the winning team
|
|
int squad_losers[MAX_SQUAD_PLAYERS]; // list of players on the losing team
|
|
} squad_war_result;
|
|
|
|
// type == UNT_VALID_SW_MSN_RSP and UNT_SW_RESULT_RESPONSE
|
|
typedef struct squad_war_response {
|
|
char reason[MAX_SQUAD_RESPONSE_LEN];
|
|
unsigned char accepted;
|
|
} squad_war_response;
|
|
|
|
// type == UNT_VALID_DATA_REQ and UNT_VAID_DATA_RSP
|
|
enum {
|
|
VDR_TYPE_TABLE = 0,
|
|
VDR_TYPE_MISSION = 1,
|
|
VDR_TYPE_SCRIPT = 2
|
|
};
|
|
|
|
enum {
|
|
VDR_FLAG_IDENT = 1<<0, // include mod ident in response
|
|
VDR_FLAG_STATUS = 1<<1 // include individual file valid status in response
|
|
};
|
|
|
|
struct valid_data_item {
|
|
uint32_t crc;
|
|
SCP_string name;
|
|
};
|
|
|
|
// NOTE: This is packed manually and should not be associated/copied/cast to the data block!!
|
|
struct vmt_valid_data_req_struct {
|
|
uint8_t type;
|
|
uint8_t flags;
|
|
uint8_t num_files;
|
|
|
|
SCP_vector<valid_data_item> files;
|
|
};
|
|
|
|
// NOTE: This is not used directly but listed here to document the packet
|
|
/*
|
|
struct vmt_valid_data_rsp_struct {
|
|
uint8_t flags;
|
|
|
|
// if VDR_FLAG_IDENT is set
|
|
short game_id;
|
|
SCP_string game_tag;
|
|
SCP_string game_name;
|
|
|
|
// if VDR_FLAG_STATUS is set
|
|
uint8_t status_count;
|
|
SCP_vector<uint32_t> status;
|
|
};
|
|
*/
|
|
|
|
|
|
#pragma pack(push, 1)
|
|
typedef struct {
|
|
unsigned char type; // type
|
|
unsigned short len; // Length of total packet, including this header
|
|
unsigned int code; // For control messages
|
|
unsigned short xcode; // For control/NAK messages and for sigs.
|
|
unsigned int sig; // To identify unique return ACKs
|
|
unsigned int security; // Just a random value, we store the last value used in the user record
|
|
// So we don't process the same request twice.
|
|
unsigned char data[MAX_UDP_DATA_LENGH];
|
|
} udp_packet_header;
|
|
#pragma pack(pop)
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// GAME SPECIFIC structures
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// FS2 Open
|
|
// NOTE: struct is packed when serialized, padding bytes ignored
|
|
const unsigned short MAX_FS2OPEN_COUNTS = 192;
|
|
struct vmt_fs2open_struct {
|
|
int tracker_id;
|
|
char pilot_name[PILOT_NAME_LEN];
|
|
|
|
int score;
|
|
int rank;
|
|
int assists;
|
|
int kill_count; // total alltime kills
|
|
int kill_count_ok; // total valid alltime kills (no friendlies)
|
|
unsigned int p_shots_fired; // primary weapon
|
|
unsigned int s_shots_fired; // secondary weapon
|
|
|
|
unsigned int p_shots_hit; // primary
|
|
unsigned int s_shots_hit; // secondary
|
|
|
|
unsigned int p_bonehead_hits; // hits/kills on the players own team
|
|
unsigned int s_bonehead_hits;
|
|
int bonehead_kills;
|
|
|
|
unsigned int missions_flown; // # of missions flown to completion
|
|
unsigned int flight_time; // total hours of flight time
|
|
unsigned int last_flown; // data/time of last mission flown
|
|
|
|
int security;
|
|
unsigned int checksum; // This value needs to be equal to whatever the checksum is once the packet is decoded
|
|
|
|
unsigned char virgin_pilot; // This pilot was just created if TRUE
|
|
|
|
char pad; // IGNORED!! 1-byte padding (alignment)
|
|
|
|
unsigned char num_medals;
|
|
unsigned char num_ships;
|
|
|
|
unsigned short counts[MAX_FS2OPEN_COUNTS]; // <-- This *must* be last entry!!!!
|
|
};
|
|
const unsigned short FS2OPEN_BLOCK_SIZE = sizeof(vmt_fs2open_struct) - 1; // ignore pad byte in size
|
|
|
|
#define vmt_stats_struct vmt_fs2open_struct
|
|
#define STATS_BLOCK_SIZE FS2OPEN_BLOCK_SIZE
|
|
|
|
//Function prototypes
|
|
int InitPilotTrackerClient();
|
|
void AckServer(unsigned int sig);
|
|
|
|
int SendFSPilotData(vmt_stats_struct *fs_pilot);
|
|
int GetFSPilotData(vmt_stats_struct *fs_pilot, const char *pilot_name, const char *tracker_id, int update_security);
|
|
int SendSWData(squad_war_result *sw_res, squad_war_response *sw_resp);
|
|
void PollPTrackNet();
|
|
|
|
//Definitions
|
|
#define STATE_IDLE 0
|
|
#define STATE_SENDING_PILOT 1
|
|
#define STATE_READING_PILOT 2
|
|
#define STATE_RECEIVED_PILOT 3
|
|
#define STATE_WROTE_PILOT 4
|
|
#define STATE_TIMED_OUT 5
|
|
#define STATE_PILOT_NOT_FOUND 6
|
|
#define STATE_WRITE_PILOT_FAILED 7
|
|
|
|
#define PILOT_REQ_TIMEOUT 30000
|
|
#define PILOT_REQ_RESEND_TIME 3500
|
|
|
|
|
|
#define PXO_ADD_DATA(d) do { memcpy(data+packet_size, &d, sizeof(d) ); packet_size += sizeof(d); } while (false)
|
|
#define PXO_ADD_SHORT(d) do { short swap = INTEL_SHORT(d); memcpy(data+packet_size, &swap, sizeof(d) ); packet_size += sizeof(d); } while (false)
|
|
#define PXO_ADD_USHORT(d) do { ushort swap = INTEL_SHORT(d); memcpy(data+packet_size, &swap, sizeof(d) ); packet_size += sizeof(d); } while (false)
|
|
#define PXO_ADD_INT(d) do { int swap = INTEL_INT(d); memcpy(data+packet_size, &swap, sizeof(d) ); packet_size += sizeof(d); } while (false)
|
|
#define PXO_ADD_UINT(d) do { uint swap = INTEL_INT(d); memcpy(data+packet_size, &swap, sizeof(d) ); packet_size += sizeof(d); } while (false)
|
|
#define PXO_ADD_STRING(d, l) do { size_t len = SDL_strlcpy(reinterpret_cast<char *>(data+packet_size), reinterpret_cast<const char *>(d), l-packet_size); packet_size += static_cast<unsigned short>(SDL_min(len+1, static_cast<size_t>(l-packet_size))); } while (0)
|
|
|
|
#define PXO_GET_DATA(d) do { memcpy(&d, data+offset, sizeof(d) ); offset += sizeof(d); } while(false)
|
|
#define PXO_GET_SHORT(d) do { short swap; memcpy(&swap, data+offset, sizeof(d) ); d = INTEL_SHORT(swap); offset += sizeof(d); } while(false)
|
|
#define PXO_GET_USHORT(d) do { ushort swap; memcpy(&swap, data+offset, sizeof(d) ); d = INTEL_SHORT(swap); offset += sizeof(d); } while(false)
|
|
#define PXO_GET_INT(d) do { int swap; memcpy(&swap, data+offset, sizeof(d) ); d = INTEL_INT(swap); offset += sizeof(d); } while(false)
|
|
#define PXO_GET_UINT(d) do { uint swap; memcpy(&swap, data+offset, sizeof(d) ); d = INTEL_INT(swap); offset += sizeof(d); } while(false)
|
|
#define PXO_GET_STRING(d) do { size_t len = SDL_strlcpy(d, reinterpret_cast<const char *>(data+offset), SDL_arraysize(d)); offset += static_cast<unsigned short>(SDL_min(len+1, SDL_arraysize(d))); } while(0)
|
|
|
|
#endif
|