|
@@ -192,97 +192,97 @@ void CDECL NetworkTextMessage(NetworkAct
|
|
|
uint NetworkCalculateLag(const NetworkClientState *cs)
|
|
|
{
|
|
|
int lag = cs->last_frame_server - cs->last_frame;
|
|
|
// This client has missed his ACK packet after 1 DAY_TICKS..
|
|
|
// so we increase his lag for every frame that passes!
|
|
|
// The packet can be out by a max of _net_frame_freq
|
|
|
if (cs->last_frame_server + DAY_TICKS + _network_frame_freq < _frame_counter)
|
|
|
lag += _frame_counter - (cs->last_frame_server + DAY_TICKS + _network_frame_freq);
|
|
|
|
|
|
return lag;
|
|
|
}
|
|
|
|
|
|
|
|
|
// There was a non-recoverable error, drop back to the main menu with a nice
|
|
|
// error
|
|
|
static void NetworkError(StringID error_string)
|
|
|
{
|
|
|
_switch_mode = SM_MENU;
|
|
|
_switch_mode_errorstr = error_string;
|
|
|
}
|
|
|
|
|
|
static void ClientStartError(const char *error)
|
|
|
{
|
|
|
DEBUG(net, 0)("[NET] Client could not start network: %s",error);
|
|
|
NetworkError(STR_NETWORK_ERR_CLIENT_START);
|
|
|
}
|
|
|
|
|
|
static void ServerStartError(const char *error)
|
|
|
{
|
|
|
DEBUG(net, 0)("[NET] Server could not start network: %s",error);
|
|
|
NetworkError(STR_NETWORK_ERR_SERVER_START);
|
|
|
}
|
|
|
|
|
|
static void NetworkClientError(byte res, NetworkClientState *cs) {
|
|
|
// First, send a CLIENT_ERROR to the server, so he knows we are
|
|
|
// disconnection (and why!)
|
|
|
NetworkErrorCode errorno;
|
|
|
|
|
|
// We just want to close the connection..
|
|
|
if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) {
|
|
|
cs->quited = true;
|
|
|
NetworkCloseClient(cs);
|
|
|
_networking = false;
|
|
|
|
|
|
DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
switch(res) {
|
|
|
switch (res) {
|
|
|
case NETWORK_RECV_STATUS_DESYNC: errorno = NETWORK_ERROR_DESYNC; break;
|
|
|
case NETWORK_RECV_STATUS_SAVEGAME: errorno = NETWORK_ERROR_SAVEGAME_FAILED; break;
|
|
|
default: errorno = NETWORK_ERROR_GENERAL;
|
|
|
}
|
|
|
// This means we fucked up and the server closed the connection
|
|
|
if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL &&
|
|
|
res != NETWORK_RECV_STATUS_SERVER_BANNED) {
|
|
|
SEND_COMMAND(PACKET_CLIENT_ERROR)(errorno);
|
|
|
|
|
|
// Dequeue all commands before closing the socket
|
|
|
NetworkSend_Packets(DEREF_CLIENT(0));
|
|
|
}
|
|
|
|
|
|
_switch_mode = SM_MENU;
|
|
|
NetworkCloseClient(cs);
|
|
|
_networking = false;
|
|
|
}
|
|
|
|
|
|
// Find all IP-aliases for this host
|
|
|
static void NetworkFindIPs(void)
|
|
|
{
|
|
|
int i, last;
|
|
|
|
|
|
#if defined(BEOS_NET_SERVER) /* doesn't have neither getifaddrs or net/if.h */
|
|
|
/* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */
|
|
|
int _netstat(int fd, char **output, int verbose);
|
|
|
|
|
|
int seek_past_header(char **pos, const char *header) {
|
|
|
char *new_pos = strstr(*pos, header);
|
|
|
if (new_pos == 0) {
|
|
|
return B_ERROR;
|
|
|
}
|
|
|
*pos += strlen(header) + new_pos - *pos + 1;
|
|
|
return B_OK;
|
|
|
}
|
|
|
|
|
|
int output_length;
|
|
|
char *output_pointer = NULL;
|
|
|
char **output;
|
|
|
int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
|
i = 0;
|
|
|
|
|
|
// If something fails, make sure the list is empty
|
|
|
_network_ip_list[0] = 0;
|
|
|
|
|
|
if (sock < 0) {
|
|
|
DEBUG(net, 0)("Error creating socket!");
|
|
|
return;
|
|
@@ -1123,97 +1123,97 @@ static bool NetworkReceive(void)
|
|
|
|
|
|
// This sends all buffered commands (if possible)
|
|
|
static void NetworkSend(void)
|
|
|
{
|
|
|
NetworkClientState *cs;
|
|
|
FOR_ALL_CLIENTS(cs) {
|
|
|
if (cs->writable) {
|
|
|
NetworkSend_Packets(cs);
|
|
|
|
|
|
if (cs->status == STATUS_MAP) {
|
|
|
// This client is in the middle of a map-send, call the function for that
|
|
|
SEND_COMMAND(PACKET_SERVER_MAP)(cs);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Handle the local-command-queue
|
|
|
static void NetworkHandleLocalQueue(void)
|
|
|
{
|
|
|
CommandPacket *cp, **cp_prev;
|
|
|
|
|
|
cp_prev = &_local_command_queue;
|
|
|
|
|
|
while ( (cp = *cp_prev) != NULL) {
|
|
|
|
|
|
// The queue is always in order, which means
|
|
|
// that the first element will be executed first.
|
|
|
if (_frame_counter < cp->frame)
|
|
|
break;
|
|
|
|
|
|
if (_frame_counter > cp->frame) {
|
|
|
// If we reach here, it means for whatever reason, we've already executed
|
|
|
// past the command we need to execute.
|
|
|
DEBUG(net, 0)("[NET] Trying to execute a packet in the past!");
|
|
|
assert(0);
|
|
|
}
|
|
|
|
|
|
// We can execute this command
|
|
|
NetworkExecuteCommand(cp);
|
|
|
|
|
|
*cp_prev = cp->next;
|
|
|
free(cp);
|
|
|
}
|
|
|
|
|
|
// Just a safety check, to be removed in the future.
|
|
|
// Make sure that no older command appears towards the end of the queue
|
|
|
// In that case we missed executing it. This will never happen.
|
|
|
for(cp = _local_command_queue; cp; cp = cp->next) {
|
|
|
for (cp = _local_command_queue; cp; cp = cp->next) {
|
|
|
assert(_frame_counter < cp->frame);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
static bool NetworkDoClientLoop(void)
|
|
|
{
|
|
|
_frame_counter++;
|
|
|
|
|
|
NetworkHandleLocalQueue();
|
|
|
|
|
|
StateGameLoop();
|
|
|
|
|
|
// Check if we are in sync!
|
|
|
if (_sync_frame != 0) {
|
|
|
if (_sync_frame == _frame_counter) {
|
|
|
#ifdef NETWORK_SEND_DOUBLE_SEED
|
|
|
if (_sync_seed_1 != _random_seeds[0][0] || _sync_seed_2 != _random_seeds[0][1]) {
|
|
|
#else
|
|
|
if (_sync_seed_1 != _random_seeds[0][0]) {
|
|
|
#endif
|
|
|
NetworkError(STR_NETWORK_ERR_DESYNC);
|
|
|
DEBUG(net, 0)("[NET] Sync error detected!");
|
|
|
NetworkClientError(NETWORK_RECV_STATUS_DESYNC, DEREF_CLIENT(0));
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// If this is the first time we have a sync-frame, we
|
|
|
// need to let the server know that we are ready and at the same
|
|
|
// frame as he is.. so we can start playing!
|
|
|
if (_network_first_time) {
|
|
|
_network_first_time = false;
|
|
|
SEND_COMMAND(PACKET_CLIENT_ACK)();
|
|
|
}
|
|
|
|
|
|
_sync_frame = 0;
|
|
|
} else if (_sync_frame < _frame_counter) {
|
|
|
DEBUG(net, 1)("[NET] Missed frame for sync-test (%d / %d)", _sync_frame, _frame_counter);
|
|
|
_sync_frame = 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
// We have to do some UDP checking
|
|
|
void NetworkUDPGameLoop(void)
|
|
|
{
|