Abstracting networking protocols - Step 4: Implemented new UDP layer with Client/Server communication, Packet Loss Prevention and strict Version checking. Netgames list will follow later.

This commit is contained in:
zicodxx 2009-11-24 09:48:53 +00:00
parent 57c71476fc
commit febe5d124d
38 changed files with 6414 additions and 2649 deletions

View file

@ -1,5 +1,9 @@
D2X-Rebirth Changelog
20091124
--------
include/args.h, INSTALL.txt, main/net_udp.c, main/net_udp.h, main/fireball.c, main/multi.c, main/multibot.c, main/multi.h, main/inferno.c, main/menu.c, main/object.c, main/kmatrix.c, main/kmatrix.h, main/newdemo.c, main/config.c, main/net_ipx.c, main/config.h, main/net_ipx.h, main/gamerend.c, main/gameseq.c, main/endlevel.c, main/vers_id.h, main/game.c, main/gauges.c, misc/args.c, SConstruct, d2x.ini, README.txt, arch/linux/ipx.c, arch/linux/ipx_kali.c, arch/win32/ipx.c: Abstracting networking protocols - Step 4: Implemented new UDP layer with Client/Server communication, Packet Loss Prevention and strict Version checking. Netgames list will follow later.
20091117
--------
arch/ogl/gr.c, arch/sdl/gr.c, include/gr.h, main/menu.c, main/piggy.c: Only list resolutions that can actually be used, using new gr_check_mode

View file

@ -26,19 +26,6 @@ For Mac OS X, an Xcode project is available (requires Xcode 2.1 or later). Xcode
The SConstruct file provides various options to compile this program.
To get a full list of all available commands, type scons -h within the Source directory.
Currently, the following variables are supported:
'sharepath=DIR' (non-Mac OS *NIX only) use DIR for shared game data. (default: /usr/local/share/games/d2x-rebirth)
'sdl_only=1' don't include OpenGL, use SDL-only instead
'sdlmixer=1' use SDL_Mixer for sound (includes external music support)
'asm=1' use ASSEMBLER code (only with sdl_only=1, requires NASM and x86)
'debug=1' build DEBUG binary which includes asserts, debugging output, cheats and more output
'profiler=1' do profiler build
'editor=1' build editor !EXPERIMENTAL!
'arm=1' compile for ARM architecture
editor is currently *not* supported and will not work.
To compile the source, type:
scons

View file

@ -53,13 +53,10 @@ See INSTALL.txt.
3. Multiplayer
DXX-Rebirth supports Multiplayer over (obsoleted) IPX and UDP/IP.
Using UDP/IP works over LAN and Internet. Since the Networking code of the Descent Engine is Peer-to-Peer, it is necessary for
all players (Host and Clients) to open port UDP 31017.
Clients can put an offset to this port by using '-ip_baseport OFFSET'.
Hosts can also use option '-ip_relay' to route players with closed ports. Use this with caution. It will increase Lag and Ping drastically.
Also game summary will not refresh correctly for relay-players until Host has escaped the level as well.
UDP/IP also supports IPv6 by compiling the game with the designated flag. Please note IPv4- and IPv6-builds cannot play together.
D2X-Rebirth supports Multiplayer over (obsoleted) IPX and UDP/IP.
Please note that UDP/IP generally supports more features of D2X-Rebirth and uses Packet Loss Prevention while IPX is mainly meant to play together with non-D1X-Rebirth games.
Using UDP/IP works over LAN and Internet. By default, each game communicates over UDP-Port 42424. This can be changed via the menus while creating a game and manually join a game, command-line argument or D2X.INI. To successfully host a game online, make sure UDP-Port 42424 (or otherwise if specified correctly) is opened on your Router/Firewall. Clients do not need to open any ports.
The game also supports IPv6 if built in while compiling and should be backwards compatible to IPv4 builds as good as possible.
4. Legal stuff

View file

@ -125,7 +125,6 @@ common_sources = [
'main/hostage.c',
'main/hud.c',
'main/inferno.c',
'main/ipxdrv.c',
'main/kconfig.c',
'main/kmatrix.c',
'main/laser.c',
@ -138,6 +137,7 @@ common_sources = [
'main/multi.c',
'main/multibot.c',
'main/net_ipx.c',
'main/net_udp.c',
'main/newdemo.c',
'main/newmenu.c',
'main/object.c',

View file

@ -16,7 +16,7 @@
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include "ipxdrv.h"
#include "net_ipx.h"
#include "console.h"
static int ipx_get_my_address( void )

View file

@ -2,7 +2,7 @@
#include <stdio.h>
#include <string.h>
#include <netinet/in.h> /* for htons & co. */
#include "ipxdrv.h"
#include "net_ipx.h"
#include "ukali.h"
#include "console.h"

View file

@ -4,7 +4,7 @@
#include <stdlib.h>
#include <winsock.h>
#include <wsipx.h>
#include "ipxdrv.h"
#include "net_ipx.h"
#include "console.h"
static int ipx_get_my_address( void )

View file

@ -42,9 +42,9 @@
;-norankings Disable multiplayer ranking system
;-playermessages View only messages from other players in multi - overrides -noredundancy
;-ipxnetwork <n> Use IPX network number <n>
;-ip_baseport <n> Use <p> as offset from normal port
;-ip_relay Relay players with closed port over host (increases traffic and lag)
;-ip_hostaddr <n> Use <n> as host ip address
;-udp_hostaddr <n> When manually joining a game use default IP Address <n> to connect to
;-udp_hostport <n> When manually joining a game use default UDP Port <n> to connect to
;-udp_myport <n> When hosting/joining a game use default UDP Port <n> to send packets from
Debug (use only if you know what you're doing):

View file

@ -74,9 +74,9 @@ typedef struct Arg
int MplNoRankings;
int MplPlayerMessages;
const char *MplIpxNetwork;
int MplIpBasePort;
int MplIpRelay;
char *MplIpHostAddr;
const char *MplUdpHostAddr;
int MplUdpHostPort;
int MplUdpMyPort;
char *EdiAutoLoad;
int EdiSaveHoardData;
int EdiMacData; // also used for some read routines in non-editor build

View file

@ -1,90 +0,0 @@
/*
*
* IPX-based driver interface
*
*/
#ifndef _NET_DRV_H
#define _NET_DRV_H
#include "pstypes.h"
#ifdef _WIN32
#include <winsock.h>
#else
#include <netinet/in.h> /* for htons & co. */
#endif
#define MAX_PACKET_DATA 1500
#define MAX_DATA_SIZE 542
#define MAX_IPX_DATA 576
#define IPX_DEFAULT_SOCKET 0x5130
#define NETPROTO_IPX 1
#define NETPROTO_KALINIX 2
typedef struct IPXAddressStruct {
ubyte Network[4];
ubyte Node[6];
ubyte Socket[2];
} IPXAddress_t;
typedef struct IPXPacketStructure {
ushort Checksum;
ushort Length;
ubyte TransportControl;
ubyte PacketType;
IPXAddress_t Destination;
IPXAddress_t Source;
} IPXPacket_t;
typedef struct socket_struct {
ushort socket;
int fd;
} socket_t;
struct recv_data {
/* all network order */
ubyte src_network[4];
ubyte src_node[6];
ushort src_socket;
ushort dst_socket;
int pkt_type;
};
struct net_driver {
int (*open_socket)(socket_t *sk, int port);
void (*close_socket)(socket_t *mysock);
int (*send_packet)(socket_t *mysock, IPXPacket_t *IPXHeader, ubyte *data, int dataLen);
int (*receive_packet)(socket_t *s, char *buffer, int bufsize, struct recv_data *rec);
int (*packet_ready)(socket_t *s);
int usepacketnum;//we can save 4 bytes
int type; // type of driver (NETPROTO_*). Can be used to make driver-specific rules in other parts of the multiplayer code.
};
extern int ipxdrv_general_packet_ready(int fd);
extern void ipxdrv_get_local_target( ubyte * server, ubyte * node, ubyte * local_target );
extern int ipxdrv_set(int arg);
extern int ipxdrv_change_default_socket( ushort socket_number );
extern ubyte * ipxdrv_get_my_local_address();
extern ubyte * ipxdrv_get_my_server_address();
extern int ipxdrv_get_packet_data( ubyte * data );
extern void ipxdrv_send_broadcast_packet_data( ubyte * data, int datasize );
extern void ipxdrv_send_packet_data( ubyte * data, int datasize, ubyte *network, ubyte *address, ubyte *immediate_address );
extern void ipxdrv_send_internetwork_packet_data( ubyte * data, int datasize, ubyte * server, ubyte *address );
extern int ipxdrv_type(void);
#ifndef __APPLE__
extern struct net_driver ipxdrv_ipx;
#endif
#ifdef __LINUX__
extern struct net_driver ipxdrv_kali;
#endif
extern unsigned char MyAddress[10];
extern ubyte broadcast_addr[];
extern ubyte null_addr[];
extern u_int32_t ipx_network;
#endif /* _NET_DRV_H */

View file

@ -58,7 +58,6 @@ static char *VSyncStr="VSync";
static char *MultisampleStr="Multisample";
static char *JukeboxOnStr="JukeboxOn";
static char *JukeboxPathStr="JukeboxPath";
static char *IPHostAddrStr="IPHostAddr";
int ReadConfigFile()
{
@ -92,7 +91,6 @@ int ReadConfigFile()
#else
strncpy(GameCfg.JukeboxPath, "::::Jukebox", PATH_MAX+1);
#endif
memset(GameCfg.MplIpHostAddr, '\x0', sizeof(GameCfg.MplIpHostAddr));
infile = PHYSFSX_openReadBuffered("descent.cfg");
@ -162,12 +160,6 @@ int ReadConfigFile()
p = strchr( GameCfg.JukeboxPath, '\n');
if ( p ) *p = 0;
}
else if (!strcmp(token, IPHostAddrStr)) {
char * p;
strncpy( GameCfg.MplIpHostAddr, value, 128 );
p = strchr( GameCfg.MplIpHostAddr, '\n');
if ( p ) *p = 0;
}
}
}
@ -214,7 +206,6 @@ int WriteConfigFile()
PHYSFSX_printf(infile, "%s=%i\n", MultisampleStr, GameCfg.Multisample);
PHYSFSX_printf(infile, "%s=%i\n", JukeboxOnStr, GameCfg.JukeboxOn);
PHYSFSX_printf(infile, "%s=%s\n", JukeboxPathStr, GameCfg.JukeboxPath);
PHYSFSX_printf(infile, "%s=%s\n", IPHostAddrStr, GameCfg.MplIpHostAddr);
PHYSFS_close(infile);

View file

@ -44,7 +44,6 @@ typedef struct Cfg
int Multisample;
int JukeboxOn;
char JukeboxPath[PATH_MAX+1];
char MplIpHostAddr[128];
} __pack__ Cfg;
extern struct Cfg GameCfg;

View file

@ -231,13 +231,6 @@ int start_endlevel_movie()
memcpy(gr_palette,save_pal,768);
}
#ifdef NETWORK
if (r==MOVIE_NOT_PLAYED && (Game_mode & GM_MULTI))
Kmatrix_nomovie_message=1;
else
Kmatrix_nomovie_message=0;
#endif
return (r);
}

View file

@ -530,7 +530,7 @@ int choose_drop_segment()
while ((segnum == -1) && (cur_drop_depth > BASE_NET_DROP_DEPTH/2)) {
pnum = (d_rand() * N_players) >> 15;
count = 0;
while ((count < N_players) && ((Players[pnum].connected == 0) || (pnum==Player_num) || ((Game_mode & (GM_TEAM|GM_CAPTURE)) && (get_team(pnum)==get_team(Player_num))))) {
while ((count < N_players) && ((Players[pnum].connected == CONNECT_DISCONNECTED) || (pnum==Player_num) || ((Game_mode & (GM_TEAM|GM_CAPTURE)) && (get_team(pnum)==get_team(Player_num))))) {
pnum = (pnum+1)%N_players;
count++;
}

View file

@ -1256,9 +1256,6 @@ int game_handler(window *wind, d_event *event, void *data)
}
if ( (Function_mode != FMODE_GAME ) && (Newdemo_state != ND_STATE_PLAYBACK ) && (Function_mode!=FMODE_EDITOR)
#ifdef NETWORK
&& !IWasKicked
#endif
) {
int choice, fmode;
fmode = Function_mode;
@ -1274,9 +1271,6 @@ int game_handler(window *wind, d_event *event, void *data)
Function_mode = FMODE_GAME;
}
#ifdef NETWORK
IWasKicked=0;
#endif
if (Function_mode != FMODE_GAME)
{
window_close(wind);

View file

@ -176,7 +176,7 @@ void show_netplayerinfo()
// general game information
y+=LINE_SPACING;
gr_printf(0x8000,y,"%s by %s",Netgame.game_name,Players[multi_who_is_master()].callsign);
gr_printf(0x8000,y,"%s",Netgame.game_name);
y+=LINE_SPACING;
gr_printf(0x8000,y,"%s - lvl: %i",Netgame.mission_title,Netgame.levelnum);
@ -206,8 +206,6 @@ void show_netplayerinfo()
gr_printf(x+FSPACX(8)*18,y,"ping");
gr_printf(x+FSPACX(8)*23,y,"efficiency");
multi_do_ping_frame();
// process players table
for (i=0; i<MAX_PLAYERS; i++)
{

View file

@ -1054,7 +1054,7 @@ void DoEndLevelScoreGlitz(int network)
#ifdef NETWORK
if ( network && (Game_mode & GM_NETWORK) )
newmenu_do2(NULL, title, c, m, (void (*))multi_endlevel_poll2, 0, STARS_BACKGROUND);
newmenu_do2(NULL, title, c, m, (void (*))multi_endlevel_poll1, 0, STARS_BACKGROUND);
else
#endif
// NOTE LINK TO ABOVE!!!
@ -1341,7 +1341,7 @@ void PlayerFinishedLevel(int secret_flag)
Players[Player_num].hostages_rescued_total += Players[Player_num].hostages_on_board;
if (Game_mode & GM_NETWORK)
Players[Player_num].connected = 2; // Finished but did not die
Players[Player_num].connected = CONNECT_WAITING; // Finished but did not die
last_drawn_cockpit = -1;
@ -1605,7 +1605,7 @@ void DoPlayerDead()
Players[Player_num].hostages_on_board = 0;
Players[Player_num].energy = 0;
Players[Player_num].shields = 0;
Players[Player_num].connected = 3;
Players[Player_num].connected = CONNECT_DIED_IN_MINE;
died_in_mine_message(); // Give them some indication of what happened
@ -2057,7 +2057,6 @@ void StartLevel(int random_flag)
{
if (Game_mode & GM_MULTI_COOP)
multi_send_score();
multi_send_position(Players[Player_num].objnum);
multi_send_reappear();
}

View file

@ -2523,7 +2523,7 @@ void hud_show_kill_list()
{
int color;
if (Players[player_num].connected != 1)
if (Players[player_num].connected != CONNECT_PLAYING)
gr_set_fontcolor(BM_XRGB(12, 12, 12), -1);
else if (Game_mode & GM_TEAM) {
color = get_team(player_num);

View file

@ -168,9 +168,9 @@ void print_commandline_help()
printf( " -norankings %s\n", "Disable multiplayer ranking system");
printf( " -playermessages %s\n", "View only messages from other players in multi - overrides -noredundancy");
printf( " -ipxnetwork <n> %s\n", "Use IPX network number <n>");
printf( " -ip_baseport <n> %s\n", "Use <n> as offset from normal port (allows multiple instances of d1x to be run on a single computer)");
printf( " -ip_relay %s\n", "Relay players with closed port over host (increases traffic and lag)");
printf( " -ip_hostaddr <n> %s\n", "Use <n> as host ip address");
printf( " -udp_hostaddr <n> %s\n", "When manually joining a game use default IP Address <n> to connect to");
printf( " -udp_hostport <n> %s\n", "When manually joining a game use default UDP Port <n> to connect to");
printf( " -udp_myport <n> %s\n", "When hosting/joining a game use default UDP Port <n> to send packets from");
#endif // NETWORK
#ifdef EDITOR

View file

@ -1,360 +0,0 @@
/*
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
*/
/*
*
* IPX-based driver interface
* This is the main interface to send packets via arch-dependend IPX-code layers.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#ifdef _MSC_VER
#include <WTypes.h>
#else
#include <sys/time.h>
#endif
#include "config.h"
#include "args.h"
#include "text.h"
#include "net_ipx.h"
#include "console.h"
#include "ipxdrv.h"
#include "checker.h"
ubyte broadcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
ubyte null_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
ubyte ipxdrv_installed=0;
u_int32_t ipx_network = 0;
ubyte MyAddress[10];
int ipx_packetnum = 0; /* Sequence number */
/* User defined routing stuff */
typedef struct user_address {
ubyte network[4];
ubyte node[6];
ubyte address[6];
} user_address;
socket_t socket_data;
#define MAX_USERS 64
int Ipx_num_users = 0;
user_address Ipx_users[MAX_USERS];
#define MAX_NETWORKS 64
int Ipx_num_networks = 0;
uint Ipx_networks[MAX_NETWORKS];
int ipxdrv_general_packet_ready(int fd)
{
fd_set set;
struct timeval tv;
FD_ZERO(&set);
FD_SET(fd, &set);
tv.tv_sec = tv.tv_usec = 0;
if (select(fd + 1, &set, NULL, NULL, &tv) > 0)
return 1;
else
return 0;
}
struct net_driver *driver = NULL;
ubyte * ipxdrv_get_my_server_address()
{
return (ubyte *)&ipx_network;
}
ubyte * ipxdrv_get_my_local_address()
{
return (ubyte *)(MyAddress + 4);
}
void ipxdrv_close()
{
if (ipxdrv_installed)
{
#ifdef _WIN32
WSACleanup();
#endif
driver->close_socket(&socket_data);
}
ipxdrv_installed = 0;
}
//---------------------------------------------------------------
// Initializes all driver internals.
// If socket_number==0, then opens next available socket.
// Returns: 0 if successful.
// -1 if socket already open.
// -2 if socket table full.
// -3 if driver not installed.
// -4 if couldn't allocate low dos memory
// -5 if error with getting internetwork address
int ipxdrv_init( int socket_number )
{
static int cleanup = 0;
#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
#endif
if (!driver)
return -1;
#ifdef _WIN32
wVersionRequested = MAKEWORD(2, 0);
if (WSAStartup( wVersionRequested, &wsaData))
{
return -1;
}
#endif
memset(MyAddress,0,10);
if (GameArg.MplIpxNetwork)
{
unsigned long n = strtol(GameArg.MplIpxNetwork, NULL, 16);
MyAddress[0] = n >> 24; MyAddress[1] = (n >> 16) & 255;
MyAddress[2] = (n >> 8) & 255; MyAddress[3] = n & 255;
con_printf(CON_DEBUG,"IPX: Using network %08x\n", (unsigned int)n);
}
if (driver->open_socket(&socket_data, socket_number))
{
return -3;
}
memcpy(&ipx_network, MyAddress, 4);
Ipx_num_networks = 0;
memcpy( &Ipx_networks[Ipx_num_networks++], &ipx_network, 4 );
ipxdrv_installed = 1;
if (!cleanup)
atexit(ipxdrv_close);
cleanup = 1;
return 0;
}
int ipxdrv_set(int arg)
{
int ipxdrv_err;
ipxdrv_close();
con_printf(CON_VERBOSE, "\n%s ", TXT_INITIALIZING_NETWORK);
switch (arg)
{
#ifndef __APPLE__
case NETPROTO_IPX:
driver = &ipxdrv_ipx;
break;
#endif
#ifdef __LINUX__
case NETPROTO_KALINIX:
driver = &ipxdrv_kali;
break;
#endif
default:
driver = NULL;
break;
}
if ((ipxdrv_err=ipxdrv_init(IPX_DEFAULT_SOCKET))==0)
{
con_printf(CON_VERBOSE, "%s %d.\n", TXT_IPX_CHANNEL, IPX_DEFAULT_SOCKET );
Network_active = 1;
}
else
{
switch (ipxdrv_err)
{
case 3:
con_printf(CON_VERBOSE, "%s\n", TXT_NO_NETWORK);
break;
case -2:
con_printf(CON_VERBOSE, "%s 0x%x.\n", TXT_SOCKET_ERROR, IPX_DEFAULT_SOCKET);
break;
case -4:
con_printf(CON_VERBOSE, "%s\n", TXT_MEMORY_IPX );
break;
default:
con_printf(CON_VERBOSE, "%s %d", TXT_ERROR_IPX, ipxdrv_err );
break;
}
con_printf(CON_VERBOSE, "%s\n",TXT_NETWORK_DISABLED);
Network_active = 0; // Assume no network
}
return ipxdrv_installed?0:-1;
}
int ipxdrv_get_packet_data( ubyte * data )
{
struct recv_data rd;
char *buf;
int size;
if (driver->usepacketnum)
buf=alloca(MAX_IPX_DATA);
else
buf=(char *)data;
memset(rd.src_network,1,4);
while (driver->packet_ready(&socket_data))
{
if ((size = driver->receive_packet(&socket_data, buf, MAX_IPX_DATA, &rd)) > 4)
{
if (!memcmp(rd.src_network, MyAddress, 10))
{
continue; /* don't get own pkts */
}
if (driver->usepacketnum)
{
memcpy(data, buf + 4, size - 4);
return size-4;
}
else
{
return size;
}
}
}
return 0;
}
void ipxdrv_send_packet_data( ubyte * data, int datasize, ubyte *network, ubyte *address, ubyte *immediate_address )
{
IPXPacket_t ipx_header;
if (!ipxdrv_installed)
return;
memcpy(ipx_header.Destination.Network, network, 4);
memcpy(ipx_header.Destination.Node, immediate_address, 6);
ipx_header.PacketType = 4; /* Packet Exchange */
if (driver->usepacketnum)
{
ubyte buf[MAX_IPX_DATA];
*(uint *)buf = ipx_packetnum++;
memcpy(buf + 4, data, datasize);
driver->send_packet(&socket_data, &ipx_header, buf, datasize + 4);
}
else
driver->send_packet(&socket_data, &ipx_header, data, datasize);//we can save 4 bytes
}
void ipxdrv_get_local_target( ubyte * server, ubyte * node, ubyte * local_target )
{
memcpy( local_target, node, 6 );
}
void ipxdrv_send_broadcast_packet_data( ubyte * data, int datasize )
{
int i, j;
ubyte local_address[6];
if (!ipxdrv_installed)
return;
// Set to all networks besides mine
for (i=0; i<Ipx_num_networks; i++ )
{
if ( memcmp( &Ipx_networks[i], &ipx_network, 4 ) )
{
ipxdrv_get_local_target( (ubyte *)&Ipx_networks[i], broadcast_addr, local_address );
ipxdrv_send_packet_data( data, datasize, (ubyte *)&Ipx_networks[i], broadcast_addr, local_address );
}
else
{
ipxdrv_send_packet_data( data, datasize, (ubyte *)&Ipx_networks[i], broadcast_addr, broadcast_addr );
}
}
// Send directly to all users not on my network or in the network list.
for (i=0; i<Ipx_num_users; i++ )
{
if ( memcmp( Ipx_users[i].network, &ipx_network, 4 ) )
{
for (j=0; j<Ipx_num_networks; j++ )
{
if (!memcmp( Ipx_users[i].network, &Ipx_networks[j], 4 ))
goto SkipUser;
}
ipxdrv_send_packet_data( data, datasize, Ipx_users[i].network, Ipx_users[i].node, Ipx_users[i].address );
SkipUser:
j = 0;
}
}
}
// Sends a non-localized packet... needs 4 byte server, 6 byte address
void ipxdrv_send_internetwork_packet_data( ubyte * data, int datasize, ubyte * server, ubyte *address )
{
ubyte local_address[6];
if (!ipxdrv_installed)
return;
#ifdef WORDS_NEED_ALIGNMENT
int zero = 0;
if (memcmp(server, &zero, 4))
#else // WORDS_NEED_ALIGNMENT
if ((*(uint *)server) != 0)
#endif // WORDS_NEED_ALIGNMENT
{
ipxdrv_get_local_target( server, address, local_address );
ipxdrv_send_packet_data( data, datasize, server, address, local_address );
}
else
{
// Old method, no server info.
ipxdrv_send_packet_data( data, datasize, server, address, address );
}
}
int ipxdrv_change_default_socket( ushort socket_number )
{
if ( !ipxdrv_installed )
return -3;
driver->close_socket(&socket_data);
if (driver->open_socket(&socket_data, socket_number))
{
return -3;
}
return 0;
}
// Return type of net_driver
int ipxdrv_type(void)
{
return driver->type;
}

View file

@ -14,6 +14,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
/*
*
* Kill matrix displayed at end of level.
* This source file contains code for both newer networking protocols and IPX. Pretty much redundant stuff but lets keep a clean cut until IPX dies completly.
*
*/
@ -54,20 +55,19 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
#define CENTERING_OFFSET(x) ((300 - (70 + (x)*25 ))/2)
#define CENTERSCREEN (SWIDTH/2)
int kmatrix_kills_changed = 0;
/* IPX CODE - START */
#define MAX_VIEW_TIME F1_0*15
#define ENDLEVEL_IDLE_TIME F1_0*10
fix StartAbortMenuTime;
char ConditionLetters[]={' ','P','E','D','E','E','V','W'};
char WaitingForOthers=0;
int Kmatrix_nomovie_message=0;
extern char MaxPowerupsAllowed[],PowerupsInMine[];
extern void newmenu_close();
void kmatrix_reactor (char *message);
void kmatrix_phallic ();
void kmatrix_redraw_coop();
void kmatrix_ipx_reactor (char *message);
void kmatrix_ipx_phallic ();
void kmatrix_ipx_redraw_coop();
void kmatrix_draw_item( int i, int *sorted )
void kmatrix_ipx_draw_item( int i, int *sorted )
{
int j, x, y;
char temp[10];
@ -113,7 +113,7 @@ void kmatrix_draw_item( int i, int *sorted )
gr_printf( x ,y,"%4d/%s",Players[sorted[i]].net_kills_total,temp);
}
void kmatrix_draw_coop_item( int i, int *sorted )
void kmatrix_ipx_draw_coop_item( int i, int *sorted )
{
int x, y;
@ -135,17 +135,10 @@ void kmatrix_draw_coop_item( int i, int *sorted )
gr_printf( x, y, "%d", Players[sorted[i]].net_killed_total);
}
void kmatrix_draw_names(int *sorted)
void kmatrix_ipx_draw_names(int *sorted)
{
int j, x, color;
if (Kmatrix_nomovie_message)
{
gr_set_fontcolor( BM_XRGB(63,0,0),-1 );
gr_printf( CENTERSCREEN-FSPACX(40), FSPACY(20), "(Movie not played)");
}
for (j=0; j<N_players; j++) {
if (Game_mode & GM_TEAM)
color = get_team(sorted[j]);
@ -154,7 +147,7 @@ void kmatrix_draw_names(int *sorted)
x = FSPACX (70 + CENTERING_OFFSET(N_players) + j*25);
if (Players[sorted[j]].connected==0)
if (Players[sorted[j]].connected==CONNECT_DISCONNECTED)
gr_set_fontcolor(gr_find_closest_color(31,31,31),-1);
else
gr_set_fontcolor(BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b),-1 );
@ -167,24 +160,17 @@ void kmatrix_draw_names(int *sorted)
gr_printf( x, FSPACY(40), "K/E");
}
void kmatrix_draw_coop_names(int *sorted)
void kmatrix_ipx_draw_coop_names(int *sorted)
{
sorted=sorted;
if (Kmatrix_nomovie_message)
{
gr_set_fontcolor( BM_XRGB(63,0,0),-1 );
gr_printf( CENTERSCREEN-FSPACX(40), FSPACY(20), "(Movie not played)");
}
gr_set_fontcolor( BM_XRGB(63,31,31),-1 );
gr_printf( CENTERSCREEN, FSPACY(40), "SCORE");
gr_set_fontcolor( BM_XRGB(63,31,31),-1 );
gr_printf( CENTERSCREEN+FSPACX(50), FSPACY(40), "DEATHS");
}
void kmatrix_draw_deaths(int *sorted)
void kmatrix_ipx_draw_deaths(int *sorted)
{
int y,x;
char reactor_message[50];
@ -228,81 +214,18 @@ void kmatrix_draw_deaths(int *sorted)
}
if (Countdown_seconds_left <=0)
kmatrix_reactor(TXT_REACTOR_EXPLODED);
kmatrix_ipx_reactor(TXT_REACTOR_EXPLODED);
else
{
sprintf((char *)&reactor_message, "%s: %d %s ", TXT_TIME_REMAINING, Countdown_seconds_left, TXT_SECONDS);
kmatrix_reactor ((char *)&reactor_message);
kmatrix_ipx_reactor ((char *)&reactor_message);
}
if (Game_mode & GM_HOARD)
kmatrix_phallic();
kmatrix_ipx_phallic();
}
void kmatrix_draw_coop_deaths(int *sorted)
{
int j, x, y;
char reactor_message[50];
y = FSPACY(55 + N_players * 9);
gr_set_fontcolor( BM_XRGB(31,31,31),-1 );
x = CENTERSCREEN+FSPACX(50);
gr_printf( x, y, TXT_DEATHS );
for (j=0; j<N_players; j++) {
x = CENTERSCREEN+FSPACX(50);
gr_printf( x, y, "%d", Players[sorted[j]].net_killed_total );
}
y = FSPACY(55 + 72 + 35);
x = FSPACX(35);
{
int sw, sh, aw;
gr_set_fontcolor(gr_find_closest_color(63,20,0),-1);
gr_get_string_size("P-Playing E-Escaped D-Died", &sw, &sh, &aw);
gr_printf( CENTERSCREEN-(sw/2), y,"P-Playing E-Escaped D-Died");
y+=(sh+5);
gr_get_string_size("V-Viewing scores W-Waiting", &sw, &sh, &aw);
gr_printf( CENTERSCREEN-(sw/2), y,"V-Viewing scores W-Waiting");
}
y+=FSPACY(20);
{
int sw, sh, aw;
gr_set_fontcolor(gr_find_closest_color(63,63,63),-1);
if (Players[Player_num].connected==CONNECT_KMATRIX_WAITING)
{
gr_get_string_size("Waiting for other players...",&sw, &sh, &aw);
gr_printf( CENTERSCREEN-(sw/2), y,"Waiting for other players...");
}
else
{
gr_get_string_size(TXT_PRESS_ANY_KEY2, &sw, &sh, &aw);
gr_printf( CENTERSCREEN-(sw/2), y, TXT_PRESS_ANY_KEY2);
}
}
if (Countdown_seconds_left <=0)
kmatrix_reactor(TXT_REACTOR_EXPLODED);
else
{
sprintf((char *)&reactor_message, "%s: %d %s ", TXT_TIME_REMAINING, Countdown_seconds_left, TXT_SECONDS);
kmatrix_reactor ((char *)&reactor_message);
}
}
void kmatrix_reactor (char *message)
void kmatrix_ipx_reactor (char *message)
{
static char oldmessage[50]={0};
int sw, sh, aw;
@ -323,7 +246,7 @@ void kmatrix_reactor (char *message)
extern int PhallicLimit,PhallicMan;
void kmatrix_phallic ()
void kmatrix_ipx_phallic ()
{
int sw, sh, aw;
char message[80];
@ -342,9 +265,7 @@ void kmatrix_phallic ()
gr_printf( CENTERSCREEN-(sw/2), FSPACY(55+72+3), message);
}
void load_stars(void);
void kmatrix_redraw()
void kmatrix_ipx_redraw()
{
int i, pcx_error, color;
int sorted[MAX_NUM_NET_PLAYERS];
@ -354,7 +275,7 @@ void kmatrix_redraw()
if (Game_mode & GM_MULTI_COOP)
{
kmatrix_redraw_coop();
kmatrix_ipx_redraw_coop();
return;
}
@ -375,7 +296,7 @@ void kmatrix_redraw()
multi_get_kill_list(sorted);
kmatrix_draw_names(sorted);
kmatrix_ipx_draw_names(sorted);
for (i=0; i<N_players; i++ ) {
if (Game_mode & GM_TEAM)
@ -383,20 +304,20 @@ void kmatrix_redraw()
else
color = sorted[i];
if (Players[sorted[i]].connected==0)
if (Players[sorted[i]].connected==CONNECT_DISCONNECTED)
gr_set_fontcolor(gr_find_closest_color(31,31,31),-1);
else
gr_set_fontcolor(BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b),-1 );
kmatrix_draw_item( i, sorted );
kmatrix_ipx_draw_item( i, sorted );
}
kmatrix_draw_deaths(sorted);
kmatrix_ipx_draw_deaths(sorted);
gr_palette_load(gr_palette);
}
void kmatrix_redraw_coop()
void kmatrix_ipx_redraw_coop()
{
int i, color;
int sorted[MAX_NUM_NET_PLAYERS];
@ -412,48 +333,38 @@ void kmatrix_redraw_coop()
multi_get_kill_list(sorted);
kmatrix_draw_coop_names(sorted);
kmatrix_ipx_draw_coop_names(sorted);
for (i=0; i<N_players; i++ ) {
color = sorted[i];
if (Players[sorted[i]].connected==0)
if (Players[sorted[i]].connected==CONNECT_DIED_IN_MINE)
gr_set_fontcolor(gr_find_closest_color(31,31,31),-1);
else
gr_set_fontcolor(BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b),-1 );
kmatrix_draw_coop_item( i, sorted );
kmatrix_ipx_draw_coop_item( i, sorted );
}
kmatrix_draw_deaths(sorted);
kmatrix_ipx_draw_deaths(sorted);
gr_palette_load(gr_palette);
}
#define MAX_VIEW_TIME F1_0*15
#define ENDLEVEL_IDLE_TIME F1_0*10
fix StartAbortMenuTime;
void kmatrix_view(int network)
void kmatrix_ipx_view(int network)
{
int i, k, done,choice;
fix entry_time = timer_get_approx_seconds();
int key;
int oldstates[MAX_PLAYERS];
int previous_seconds_left=-1;
int num_ready,num_escaped;
network=Game_mode & GM_NETWORK;
for (i=0;i<MAX_NUM_NET_PLAYERS;i++)
digi_kill_sound_linked_to_object (Players[i].objnum);
set_screen_mode( SCREEN_MENU );
WaitingForOthers=0;
game_flush_inputs();
done = 0;
@ -467,8 +378,7 @@ void kmatrix_view(int network)
while(!done)
{
timer_delay2(50);
kmatrix_redraw();
kmatrix_kills_changed = 0;
kmatrix_ipx_redraw();
//see if redbook song needs to be restarted
RBACheckFinishedHook();
@ -481,11 +391,10 @@ void kmatrix_view(int network)
{
if (Current_level_num==8)
{
Players[Player_num].connected=0;
Players[Player_num].connected=CONNECT_DISCONNECTED;
if (network)
multi_send_endlevel_packet();
multi_leave_game();
Kmatrix_nomovie_message=0;
longjmp(LeaveGame, 0);
return;
}
@ -500,22 +409,19 @@ void kmatrix_view(int network)
if (Game_mode & GM_NETWORK)
{
StartAbortMenuTime=timer_get_approx_seconds();
choice=nm_messagebox1( NULL,multi_endlevel_poll3, 2, TXT_YES, TXT_NO, TXT_ABORT_GAME );
choice=nm_messagebox1( NULL,multi_endlevel_poll2, 2, TXT_YES, TXT_NO, TXT_ABORT_GAME );
}
else
choice=nm_messagebox( NULL, 2, TXT_YES, TXT_NO, TXT_ABORT_GAME );
if (choice==0)
{
Players[Player_num].connected=0;
Players[Player_num].connected=CONNECT_DISCONNECTED;
if (network)
multi_send_endlevel_packet();
multi_leave_game();
Kmatrix_nomovie_message=0;
longjmp(LeaveGame, 0);
return;
}
else
kmatrix_kills_changed=1;
break;
case KEY_PRINT_SCREEN:
@ -536,11 +442,10 @@ void kmatrix_view(int network)
{
if (Current_level_num==8)
{
Players[Player_num].connected=0;
Players[Player_num].connected=CONNECT_DISCONNECTED;
if (network)
multi_send_endlevel_packet();
multi_leave_game();
Kmatrix_nomovie_message=0;
longjmp(LeaveGame, 0);
return;
}
@ -553,7 +458,7 @@ void kmatrix_view(int network)
if (network && (Game_mode & GM_NETWORK))
{
multi_endlevel_poll2(0, NULL, &key, 0);
multi_endlevel_poll1();
for (num_escaped=0,num_ready=0,i=0;i<N_players;i++)
{
@ -562,27 +467,26 @@ void kmatrix_view(int network)
// Check timeout for idle players
if (timer_get_approx_seconds() > Netgame.players[i].LastPacketTime+ENDLEVEL_IDLE_TIME)
{
Players[i].connected = 0;
multi_send_endlevel_sub(i);
Players[i].connected = CONNECT_DISCONNECTED;
}
}
// Important: Make sure we keep connected state CONNECT_KMATRIX_WAITING even if player exits kmatrix loop which will change to CONNECT_WAITING! If we don't get all palyer packets in sync and order this condition is very handy to keep all connections alive!
if ((oldstates[i]==CONNECT_END_MENU || oldstates[i]==CONNECT_KMATRIX_WAITING) && (Players[i].connected!=0 || Players[i].connected!=CONNECT_END_MENU || Players[i].connected!=CONNECT_KMATRIX_WAITING))
Players[i].connected=CONNECT_KMATRIX_WAITING;
// HACK: If a player legally exits kmatrix loop he will send the previous connect byte which can invalidate us from setting him to ready and let us stuck here forever... it's stupid to solve it this way, but for now I have no better idea.
if ((oldstates[i]==CONNECT_END_MENU || oldstates[i]==CONNECT_KMATRIX_WAITING) && // player was viewing scores before...
(Players[i].connected!=CONNECT_DISCONNECTED || Players[i].connected!=CONNECT_END_MENU || Players[i].connected!=CONNECT_KMATRIX_WAITING)) // ... but now he sends neither disconnect or further waiting signal - so he MUST be out of kmatrix already
Players[i].connected=CONNECT_KMATRIX_WAITING;
if (Players[i].connected!=oldstates[i])
{
if (ConditionLetters[Players[i].connected]!=ConditionLetters[oldstates[i]])
kmatrix_kills_changed=1;
oldstates[i]=Players[i].connected;
multi_send_endlevel_packet();
}
if (Players[i].connected==0 || Players[i].connected==CONNECT_KMATRIX_WAITING)
if (Players[i].connected==CONNECT_DISCONNECTED || Players[i].connected==CONNECT_KMATRIX_WAITING)
num_ready++;
if (Players[i].connected!=1)
if (Players[i].connected!=CONNECT_PLAYING)
num_escaped++;
}
@ -590,18 +494,6 @@ void kmatrix_view(int network)
done=1;
if (num_escaped>=N_players)
Countdown_seconds_left=-1;
if (previous_seconds_left != Countdown_seconds_left)
{
previous_seconds_left=Countdown_seconds_left;
kmatrix_kills_changed=1;
}
if ( kmatrix_kills_changed )
{
kmatrix_redraw();
kmatrix_kills_changed=0;
}
}
gr_flip();
}
@ -613,7 +505,324 @@ void kmatrix_view(int network)
game_flush_inputs();
Kmatrix_nomovie_message=0;
newmenu_close();
}
/* IPX CODE - END */
/* NEW CODE - START */
#define KMATRIX_VIEW_SEC 7 // Time after reactor explosion until new level - in seconds
void kmatrix_phallic ();
void kmatrix_redraw_coop();
void kmatrix_draw_item( int i, int *sorted )
{
int j, x, y;
char temp[10];
y = FSPACY(50+i*9);
gr_printf( FSPACX(CENTERING_OFFSET(N_players)), y, "%s", Players[sorted[i]].callsign );
for (j=0; j<N_players; j++)
{
x = FSPACX(70 + CENTERING_OFFSET(N_players) + j*25);
if (sorted[i]==sorted[j])
{
if (kill_matrix[sorted[i]][sorted[j]] == 0)
{
gr_set_fontcolor( BM_XRGB(10,10,10),-1 );
gr_printf( x, y, "%d", kill_matrix[sorted[i]][sorted[j]] );
}
else
{
gr_set_fontcolor( BM_XRGB(25,25,25),-1 );
gr_printf( x, y, "-%d", kill_matrix[sorted[i]][sorted[j]] );
}
}
else
{
if (kill_matrix[sorted[i]][sorted[j]] <= 0)
{
gr_set_fontcolor( BM_XRGB(10,10,10),-1 );
gr_printf( x, y, "%d", kill_matrix[sorted[i]][sorted[j]] );
}
else
{
gr_set_fontcolor( BM_XRGB(25,25,25),-1 );
gr_printf( x, y, "%d", kill_matrix[sorted[i]][sorted[j]] );
}
}
}
if (Players[sorted[i]].net_killed_total+Players[sorted[i]].net_kills_total==0)
sprintf (temp,"NA");
else
sprintf (temp,"%d%%",(int)((float)((float)Players[sorted[i]].net_kills_total/((float)Players[sorted[i]].net_killed_total+(float)Players[sorted[i]].net_kills_total))*100.0));
x = FSPACX(60 + CENTERING_OFFSET(N_players) + N_players*25);
gr_set_fontcolor( BM_XRGB(25,25,25),-1 );
gr_printf( x ,y,"%4d/%s",Players[sorted[i]].net_kills_total,temp);
}
void kmatrix_draw_coop_item( int i, int *sorted )
{
int x, y;
y = FSPACY(50+i*9);
gr_printf( FSPACX(CENTERING_OFFSET(N_players)), y, "%s", Players[sorted[i]].callsign );
x = CENTERSCREEN;
gr_set_fontcolor( BM_XRGB(60,40,10),-1 );
gr_printf( x, y, "%d", Players[sorted[i]].score );
x = CENTERSCREEN+FSPACX(50);
gr_set_fontcolor( BM_XRGB(60,40,10),-1 );
gr_printf( x, y, "%d", Players[sorted[i]].net_killed_total);
}
void kmatrix_draw_names(int *sorted)
{
int j, x, color;
for (j=0; j<N_players; j++)
{
if (Game_mode & GM_TEAM)
color = get_team(sorted[j]);
else
color = sorted[j];
x = FSPACX (70 + CENTERING_OFFSET(N_players) + j*25);
if (Players[sorted[j]].connected==CONNECT_DISCONNECTED)
gr_set_fontcolor(gr_find_closest_color(31,31,31),-1);
else
gr_set_fontcolor(BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b),-1 );
gr_printf( x, FSPACY(40), "%c", Players[sorted[j]].callsign[0] );
}
x = FSPACX(72 + CENTERING_OFFSET(N_players) + N_players*25);
gr_set_fontcolor( BM_XRGB(31,31,31),-1 );
gr_printf( x, FSPACY(40), "K/E");
}
void kmatrix_draw_coop_names(int *sorted)
{
sorted=sorted;
gr_set_fontcolor( BM_XRGB(63,31,31),-1 );
gr_printf( CENTERSCREEN, FSPACY(40), "SCORE");
gr_set_fontcolor( BM_XRGB(63,31,31),-1 );
gr_printf( CENTERSCREEN+FSPACX(50), FSPACY(40), "DEATHS");
}
extern int PhallicLimit,PhallicMan;
void kmatrix_phallic ()
{
int sw, sh, aw;
char message[80];
if (PhallicMan==-1)
strcpy (message,"There was no record set for this level.");
else
sprintf (message,"%s had the best record at %d points.",Players[PhallicMan].callsign,PhallicLimit);
grd_curcanv->cv_font = GAME_FONT;
gr_set_fontcolor(gr_find_closest_color(63,63,63),-1);
gr_get_string_size(message, &sw, &sh, &aw);
gr_printf( CENTERSCREEN-(sw/2), FSPACY(55+72+3), message);
}
void kmatrix_status_msg (fix time, int reactor)
{
grd_curcanv->cv_font = GAME_FONT;
gr_set_fontcolor(gr_find_closest_color(255,255,255),-1);
if (reactor)
gr_printf(0x8000, SHEIGHT-LINE_SPACING, "Waiting for players to finish level. Reactor time: T-%d", time);
else
gr_printf(0x8000, SHEIGHT-LINE_SPACING, "Level finished. Wait (%d) to proceed or ESC to Quit.", time);
}
void kmatrix_redraw()
{
int i, pcx_error, color;
int sorted[MAX_NUM_NET_PLAYERS];
pcx_error = pcx_read_fullscr(STARS_BACKGROUND, gr_palette);
Assert(pcx_error == PCX_ERROR_NONE);
if (Game_mode & GM_MULTI_COOP)
{
kmatrix_redraw_coop();
}
else
{
multi_sort_kill_list();
gr_set_current_canvas(NULL);
grd_curcanv->cv_font = MEDIUM3_FONT;
if (Game_mode & GM_CAPTURE)
gr_string( 0x8000, FSPACY(10), "CAPTURE THE FLAG SUMMARY");
else if (Game_mode & GM_HOARD)
gr_string( 0x8000, FSPACY(10), "HOARD SUMMARY");
else
gr_string( 0x8000, FSPACY(10), TXT_KILL_MATRIX_TITLE);
grd_curcanv->cv_font = GAME_FONT;
multi_get_kill_list(sorted);
kmatrix_draw_names(sorted);
for (i=0; i<N_players; i++ )
{
if (Game_mode & GM_TEAM)
color = get_team(sorted[i]);
else
color = sorted[i];
if (Players[sorted[i]].connected==CONNECT_DISCONNECTED)
gr_set_fontcolor(gr_find_closest_color(31,31,31),-1);
else
gr_set_fontcolor(BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b),-1 );
kmatrix_draw_item( i, sorted );
}
}
gr_palette_load(gr_palette);
}
void kmatrix_redraw_coop()
{
int i, color;
int sorted[MAX_NUM_NET_PLAYERS];
multi_sort_kill_list();
gr_set_current_canvas(NULL);
grd_curcanv->cv_font = MEDIUM3_FONT;
gr_string( 0x8000, FSPACY(10), "COOPERATIVE SUMMARY");
grd_curcanv->cv_font = GAME_FONT;
multi_get_kill_list(sorted);
kmatrix_draw_coop_names(sorted);
for (i=0; i<N_players; i++ )
{
color = sorted[i];
if (Players[sorted[i]].connected==CONNECT_DISCONNECTED)
gr_set_fontcolor(gr_find_closest_color(31,31,31),-1);
else
gr_set_fontcolor(BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b),-1 );
kmatrix_draw_coop_item( i, sorted );
}
gr_palette_load(gr_palette);
}
void kmatrix_view(int network)
{
int done = 0, i = 0, k = 0, choice = 0;
fix end_time = -1;
set_screen_mode( SCREEN_MENU );
game_flush_inputs();
for (i=0;i<MAX_NUM_NET_PLAYERS;i++)
digi_kill_sound_linked_to_object (Players[i].objnum);
while (!done)
{
int playing = 0;
fix time = timer_get_approx_seconds();
timer_delay2(50);
kmatrix_redraw();
RBACheckFinishedHook(); //see if redbook song needs to be restarted
if (network)
multi_do_protocol_frame(0, 1);
// Check if all connected players are also looking at this screen ...
for (i = 0; i < MAX_PLAYERS; i++)
if (Players[i].connected)
if (Players[i].connected != CONNECT_END_MENU && Players[i].connected != CONNECT_DIED_IN_MINE)
playing = 1;
// ... and let the reactor blow sky high!
if (!playing)
Countdown_seconds_left = -1;
// If Reactor is finished and end_time not inited, set the time when we will exit this loop
if (end_time == -1 && Countdown_seconds_left < 0 && !playing)
end_time = time + (KMATRIX_VIEW_SEC * F1_0);
// Check if end_time has been reached and exit loop
if (time >= end_time && end_time != -1)
done = 1;
if (playing)
kmatrix_status_msg(Countdown_seconds_left, 1);
else
kmatrix_status_msg(f2i(time-end_time), 0);
k = key_inkey();
switch( k )
{
case KEY_ESC:
if (network)
{
StartAbortMenuTime=timer_get_approx_seconds();
choice=nm_messagebox1( NULL,multi_endlevel_poll2, 2, TXT_YES, TXT_NO, TXT_ABORT_GAME );
}
else
choice=nm_messagebox( NULL, 2, TXT_YES, TXT_NO, TXT_ABORT_GAME );
if (choice==0)
{
Players[Player_num].connected=CONNECT_DISCONNECTED;
if (network)
multi_send_endlevel_packet();
multi_leave_game();
longjmp(LeaveGame, 0);
return;
}
break;
case KEY_PRINT_SCREEN:
save_screen_shot(0);
break;
default:
break;
}
gr_flip();
}
if (network)
multi_send_endlevel_packet(); // make sure
game_flush_inputs();
newmenu_close();
if (is_D2_OEM)
{
if (Current_level_num==8)
{
Players[Player_num].connected=CONNECT_DISCONNECTED;
if (network)
multi_send_endlevel_packet();
multi_leave_game();
longjmp(LeaveGame, 0);
return;
}
}
}
/* NEW CODE - END */

View file

@ -1,4 +1,3 @@
/* $Id: kmatrix.h,v 1.1.1.1 2006/03/17 19:57:28 zicodxx Exp $ */
/*
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
@ -22,8 +21,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
#ifndef _KMATRIX_H
#define _KMATRIX_H
extern int kmatrix_kills_changed;
void kmatrix_ipx_view(int network);
void kmatrix_view(int network);
#endif /* _KMATRIX_H */

View file

@ -45,11 +45,6 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
#include "text.h"
#include "gamefont.h"
#include "newmenu.h"
#ifdef NETWORK
# include "net_ipx.h"
# include "ipxdrv.h"
# include "multi.h"
#endif
#include "scores.h"
#include "playsave.h"
#include "kconfig.h"
@ -66,7 +61,11 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
#include "gauges.h"
#include "powerup.h"
#include "strutil.h"
#ifdef NETWORK
# include "net_ipx.h"
# include "net_udp.h"
# include "multi.h"
#endif
#ifdef EDITOR
#include "editor/editor.h"
#endif
@ -84,8 +83,6 @@ enum MENUS
MENU_SAVE_GAME,
MENU_DEMO_PLAY,
MENU_LOAD_LEVEL,
MENU_START_IPX_NETGAME,
MENU_JOIN_IPX_NETGAME,
MENU_CONFIG,
MENU_REJOIN_NETGAME,
MENU_DIFFICULTY,
@ -103,12 +100,12 @@ enum MENUS
// Only if networking is enabled...
#ifdef NETWORK
MENU_START_UDP_NETGAME,
MENU_JOIN_MANUAL_UDP_NETGAME,
MENU_JOIN_LIST_UDP_NETGAME,
MENU_START_IPX_NETGAME,
MENU_JOIN_IPX_NETGAME,
MENU_BROWSE_UDP_NETGAME, // UDP/IP support
MENU_START_UDP_NETGAME,
MENU_JOIN_UDP_NETGAME,
MENU_START_KALI_NETGAME, // Kali support
MENU_START_KALI_NETGAME, // xKali support (not Windows Kali! Windows Kali is over IPX!)
MENU_JOIN_KALI_NETGAME,
#endif
};
@ -121,10 +118,7 @@ enum MENUS
// Function Prototypes added after LINTING
void do_option(int select);
void do_new_game_menu(void);
#ifdef NETWORK
void do_multi_player_menu(void);
void do_ip_manual_join_menu();
#endif //NETWORK
void do_multi_player_menu();
extern void newmenu_close();
extern void ReorderPrimary();
extern void ReorderSecondary();
@ -337,6 +331,18 @@ void do_option ( int select)
#ifdef NETWORK
case MENU_START_UDP_NETGAME:
multi_protocol = MULTI_PROTO_UDP;
net_udp_start_game();
break;
case MENU_JOIN_MANUAL_UDP_NETGAME:
multi_protocol = MULTI_PROTO_UDP;
net_udp_manual_join_game();
break;
case MENU_JOIN_LIST_UDP_NETGAME:
multi_protocol = MULTI_PROTO_UDP;
//net_udp_list_join_game();
break;
case MENU_START_IPX_NETGAME:
multi_protocol = MULTI_PROTO_IPX;
ipxdrv_set(NETPROTO_IPX);
@ -357,12 +363,6 @@ void do_option ( int select)
ipxdrv_set(NETPROTO_KALINIX);
net_ipx_join_game();
break;
case MENU_START_UDP_NETGAME:
// FIXME
break;
case MENU_JOIN_UDP_NETGAME:
// FIXME
break;
case MENU_MULTIPLAYER:
do_multi_player_menu();
break;
@ -813,8 +813,8 @@ void do_misc_menu()
#ifdef NETWORK
void do_multi_player_menu()
{
int menu_choice[9];
newmenu_item m[9];
int menu_choice[12];
newmenu_item m[12];
int choice = 0, num_options = 0;
int old_game_mode;
@ -822,16 +822,24 @@ void do_multi_player_menu()
old_game_mode = Game_mode;
num_options = 0;
#ifdef NATIVE_IPX
ADD_ITEM("Start IPX Netgame", MENU_START_IPX_NETGAME, -1);
ADD_ITEM("Join IPX Netgame\n", MENU_JOIN_IPX_NETGAME, -1);
#endif //NATIVE_IPX
ADD_ITEM("Start UDP/IP Netgame", MENU_START_UDP_NETGAME, -1);
ADD_ITEM("Join UDP/IP Netgame\n", MENU_JOIN_UDP_NETGAME, -1);
#ifdef KALINIX
ADD_ITEM("Start Kali Netgame", MENU_START_KALI_NETGAME, -1);
ADD_ITEM("Join Kali Netgame", MENU_JOIN_KALI_NETGAME, -1);
#endif // KALINIX
m[num_options].type=NM_TYPE_TEXT; m[num_options].text="UDP:"; num_options++;
m[num_options].type=NM_TYPE_MENU; m[num_options].text="HOST GAME"; menu_choice[num_options]=MENU_START_UDP_NETGAME; num_options++;
m[num_options].type=NM_TYPE_MENU; m[num_options].text="FIND LAN GAMES"; menu_choice[num_options]=MENU_JOIN_LIST_UDP_NETGAME; num_options++;
//m[num_options].type=NM_TYPE_MENU; m[num_options].text="FIND LAN/ONLINE GAMES"; menu_choice[num_options]=MENU_JOIN_LIST_UDP_NETGAME; num_options++;
m[num_options].type=NM_TYPE_MENU; m[num_options].text="JOIN GAME MANUALLY"; menu_choice[num_options]=MENU_JOIN_MANUAL_UDP_NETGAME; num_options++;
#ifdef HAVE_NETIPX_IPX_H
m[num_options].type=NM_TYPE_TEXT; m[num_options].text=""; num_options++;
m[num_options].type=NM_TYPE_TEXT; m[num_options].text="IPX:"; num_options++;
m[num_options].type=NM_TYPE_MENU; m[num_options].text="HOST GAME"; menu_choice[num_options]=MENU_START_IPX_NETGAME; num_options++;
m[num_options].type=NM_TYPE_MENU; m[num_options].text="JOIN GAME"; menu_choice[num_options]=MENU_JOIN_IPX_NETGAME; num_options++;
#endif //HAVE_NETIPX_IPX_H
#ifdef __LINUX__
m[num_options].type=NM_TYPE_TEXT; m[num_options].text=""; num_options++;
m[num_options].type=NM_TYPE_TEXT; m[num_options].text="XKALI:"; num_options++;
m[num_options].type=NM_TYPE_MENU; m[num_options].text="HOST GAME"; menu_choice[num_options]=MENU_START_KALI_NETGAME; num_options++;
m[num_options].type=NM_TYPE_MENU; m[num_options].text="JOIN GAME"; menu_choice[num_options]=MENU_JOIN_KALI_NETGAME; num_options++;
#endif // __LINUX__
choice = newmenu_do1( NULL, TXT_MULTIPLAYER, num_options, m, NULL, choice );
@ -843,57 +851,6 @@ void do_multi_player_menu()
} while( choice > -1 );
}
void do_ip_manual_join_menu()
{
int menu_choice[3];
newmenu_item m[3];
int choice = 0, num_options = 0, j = 0;
int old_game_mode;
char buf[128]="";
if (*GameCfg.MplIpHostAddr) {
sprintf(buf,"%s",GameCfg.MplIpHostAddr);
for (j=0; buf[j] != '\0'; j++) {
switch (buf[j]) {
case ' ':
buf[j] = '\0';
}
}
}
if (*GameArg.MplIpHostAddr) {
sprintf(buf,"%s",GameArg.MplIpHostAddr);
for (j=0; buf[j] != '\0'; j++) {
switch (buf[j]) {
case ' ':
buf[j] = '\0';
}
}
}
do {
old_game_mode = Game_mode;
num_options = 0;
m[num_options].type = NM_TYPE_INPUT; m[num_options].text=buf; m[num_options].text_len=128;menu_choice[num_options]=-1; num_options++;
choice = newmenu_do1( NULL, "ENTER IP OR HOSTNAME", num_options, m, NULL, choice );
if ( choice > -1 ){
strncpy(GameCfg.MplIpHostAddr, buf, 128);
// FIXME !! UDPConnectManual(buf);
}
if (old_game_mode != Game_mode)
{
strncpy(GameCfg.MplIpHostAddr, buf, 128);
break; // leave menu
}
} while( choice > -1 );
}
#endif // NETWORK
void do_options_menu()

View file

@ -27,6 +27,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
#include "strutil.h"
#include "game.h"
#include "net_ipx.h"
#include "net_udp.h"
#include "multi.h"
#include "object.h"
#include "laser.h"
@ -148,12 +149,16 @@ int multi_leave_menu = 0;
int multi_quit_game = 0;
int PacketUrgent = 0;
// For rejoin object syncing
// For rejoin object syncing (used here and all protocols - globally)
int Network_send_objects = 0; // Are we in the process of sending objects to a player?
int Network_send_object_mode = 0; // What type of objects are we sending, static or dynamic?
int Network_send_objnum = -1; // What object are we sending next?
int Network_rejoined = 0; // Did WE rejoin this game?
int Network_new_game = 0; // Is this the first level of a new game?
int Network_sending_extras=0;
int Player_joining_extras=-1; // This is so we know who to send 'latecomer' packets to.
int Network_player_added = 0; // Is this a new player or a returning player?
ushort my_segments_checksum = 0;
@ -161,6 +166,10 @@ netgame_info Netgame;
bitmap_index multi_player_textures[MAX_NUM_NET_PLAYERS][N_PLAYER_SHIP_TEXTURES];
// Globals for protocol-bound Refuse-functions
char RefuseThisPlayer=0,WaitForRefuseAnswer=0,RefuseTeam,RefusePlayerName[12];
fix RefuseTimeLimit=0;
typedef struct netplayer_stats {
ubyte message_type;
ubyte Player_num; // Who am i?
@ -192,7 +201,7 @@ typedef struct netplayer_stats {
} netplayer_stats;
int message_length[MULTI_MAX_TYPE+1] = {
24, // POSITION
25, // POSITION
3, // REAPPEAR
8, // FIRE
5, // KILL
@ -247,7 +256,7 @@ int message_length[MULTI_MAX_TYPE+1] = {
2, // MULTI_CAPTURE_BONUS
2, // MULTI_GOT_FLAG
12, // MULTI_DROP_FLAG
142, // MULTI_ROBOT_CONTROLS
1, // MULTI_ROBOT_CONTROLS - UNUSED
2, // MULTI_FINISH_GAME
3, // MULTI_RANK
1, // MULTI_MODEM_PING
@ -301,6 +310,13 @@ int GetMyNetRanking()
return (rank+1);
}
void ClipRank (ubyte *rank)
{
// This function insures no crashes when dealing with D2 1.0
if (*rank > 9)
*rank = 0;
}
//
// Functions that replace what used to be macros
//
@ -413,25 +429,15 @@ int multi_objnum_is_past(int objnum)
case MULTI_PROTO_IPX:
return net_ipx_objnum_is_past(objnum);
break;
case MULTI_PROTO_UDP:
return net_udp_objnum_is_past(objnum);
break;
default:
Error("Protocol handling missing in multi_objnum_is_past\n");
break;
}
}
void multi_do_ping_frame()
{
switch (multi_protocol)
{
case MULTI_PROTO_IPX:
return net_ipx_ping_all();
break;
default:
Error("Protocol handling missing in multi_do_ping_frame\n");
break;
}
}
//
// Part 1 : functions whose main purpose in life is to divert the flow
// of execution to either network specific code based
@ -450,19 +456,20 @@ multi_endlevel_score(void)
if (Game_mode & GM_NETWORK)
{
old_connect = Players[Player_num].connected;
if (Players[Player_num].connected!=3)
if (Players[Player_num].connected!=CONNECT_DIED_IN_MINE)
Players[Player_num].connected = CONNECT_END_MENU;
Network_status = NETSTAT_ENDLEVEL;
}
#endif
// Do the actual screen we wish to show
Function_mode = FMODE_MENU;
kmatrix_view(Game_mode & GM_NETWORK);
if (multi_protocol == MULTI_PROTO_IPX)
kmatrix_ipx_view(Game_mode & GM_NETWORK);
else
kmatrix_view(Game_mode & GM_NETWORK);
Function_mode = FMODE_GAME;
@ -473,19 +480,16 @@ multi_endlevel_score(void)
Players[Player_num].connected = old_connect;
}
#ifndef SHAREWARE
if (Game_mode & GM_MULTI_COOP)
{
for (i = 0; i < MaxNumNetPlayers; i++)
// Reset keys
Players[i].flags &= ~(PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_GOLD_KEY);
}
for (i = 0; i < MaxNumNetPlayers; i++)
Players[i].flags &= ~(PLAYER_FLAGS_FLAG); // Clear capture flag
#endif
for (i=0;i<MAX_PLAYERS;i++)
Players[i].KillGoalCount=0;
@ -494,7 +498,6 @@ multi_endlevel_score(void)
MaxPowerupsAllowed[i]=0;
PowerupsInMine[i]=0;
}
}
int
@ -526,14 +529,12 @@ multi_new_game(void)
Players[i].KillGoalCount=0;
}
#ifndef SHAREWARE
for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++)
{
robot_controlled[i] = -1;
robot_agitation[i] = 0;
robot_fired[i] = 0;
}
#endif
team_kills[0] = team_kills[1] = 0;
Endlevel_sequence = 0;
@ -616,11 +617,9 @@ multi_sort_kill_list(void)
for (i = 0; i < MAX_NUM_NET_PLAYERS; i++)
{
#ifndef SHAREWARE
if (Game_mode & GM_MULTI_COOP)
kills[i] = Players[i].score;
else
#endif
if (Show_kill_list==2)
{
if (Players[i].net_killed_total+Players[i].net_kills_total==0)
@ -662,7 +661,6 @@ void multi_compute_kill(int killer, int killed)
char killed_name[(CALLSIGN_LEN*2)+4];
char killer_name[(CALLSIGN_LEN*2)+4];
kmatrix_kills_changed = 1;
Multi_killed_yourself=0;
// Both object numbers are localized already!
@ -700,7 +698,7 @@ void multi_compute_kill(int killer, int killed)
digi_play_sample( SOUND_HUD_KILL, F3_0 );
if (Control_center_destroyed)
Players[killed_pnum].connected=3;
Players[killed_pnum].connected=CONNECT_DIED_IN_MINE;
if (killer_type == OBJ_CNTRLCEN)
{
@ -720,7 +718,6 @@ void multi_compute_kill(int killer, int killed)
return;
}
#ifndef SHAREWARE
else if ((killer_type != OBJ_PLAYER) && (killer_type != OBJ_GHOST))
{
if (killer_id==PMINE_ID && killer_type!=OBJ_ROBOT)
@ -743,24 +740,6 @@ void multi_compute_kill(int killer, int killed)
Players[killed_pnum].net_killed_total++;
return;
}
#else
else if ((killer_type != OBJ_PLAYER) && (killer_type != OBJ_GHOST) && (killer_id!=PMINE_ID))
{
Int3(); // Illegal killer type?
return;
}
if (killer_id==PMINE_ID)
{
if (killed_pnum==Player_num)
HUD_init_message("You were killed by a mine!");
else
HUD_init_message("%s was killed by a mine!",killed_name);
Players[killed_pnum].net_killed_total++;
return;
}
#endif
killer_pnum = Objects[killer].id;
@ -883,6 +862,9 @@ void multi_do_protocol_frame(int force, int listen)
case MULTI_PROTO_IPX:
net_ipx_do_frame(force, listen);
break;
case MULTI_PROTO_UDP:
net_udp_do_frame(force, listen);
break;
default:
Error("Protocol handling missing in multi_do_protocol_frame\n");
break;
@ -920,12 +902,10 @@ multi_do_frame(void)
if (!multi_in_menu)
multi_leave_menu = 0;
#ifndef SHAREWARE
if (Game_mode & GM_MULTI_ROBOTS)
{
multi_check_robot_timeout();
}
#endif
multi_do_protocol_frame(0, 1);
@ -937,21 +917,20 @@ multi_do_frame(void)
}
void
multi_send_data(char *buf, int len, int repeat)
multi_send_data(char *buf, int len, int priority)
{
Assert(len == message_length[(int)buf[0]]);
Assert(buf[0] <= MULTI_MAX_TYPE);
// Assert(buf[0] >= 0);
if (Game_mode & GM_NETWORK)
Assert(buf[0] > 0);
if (Game_mode & GM_NETWORK)
{
switch (multi_protocol)
{
case MULTI_PROTO_IPX:
net_ipx_send_data((unsigned char *)buf, len, repeat);
net_ipx_send_data((unsigned char *)buf, len, priority);
break;
case MULTI_PROTO_UDP:
net_udp_send_data((unsigned char *)buf, len, priority);
break;
default:
Error("Protocol handling missing in multi_send_data_real\n");
@ -973,10 +952,10 @@ multi_leave_game(void)
if (Game_mode & GM_NETWORK)
{
Net_create_loc = 0;
multi_send_position(Players[Player_num].objnum);
AdjustMineSpawn();
multi_cap_objects();
drop_player_eggs(ConsoleObject);
multi_send_position(Players[Player_num].objnum);
multi_send_player_explode(MULTI_PLAYER_DROP);
}
@ -989,6 +968,9 @@ multi_leave_game(void)
case MULTI_PROTO_IPX:
net_ipx_leave_game();
break;
case MULTI_PROTO_UDP:
net_udp_leave_game();
break;
default:
Error("Protocol handling missing in multi_leave_game\n");
break;
@ -1024,6 +1006,9 @@ multi_endlevel(int *secret)
case MULTI_PROTO_IPX:
result = net_ipx_endlevel(secret);
break;
case MULTI_PROTO_UDP:
result = net_udp_endlevel(secret);
break;
default:
Error("Protocol handling missing in multi_endlevel\n");
break;
@ -1032,12 +1017,31 @@ multi_endlevel(int *secret)
return(result);
}
void multi_endlevel_poll1( int nitems, struct newmenu_item * menus, int * key, int citem )
{
switch (multi_protocol)
{
case MULTI_PROTO_IPX:
net_ipx_kmatrix_poll1( nitems, menus, key, citem );
break;
case MULTI_PROTO_UDP:
net_udp_kmatrix_poll1( nitems, menus, key, citem );
break;
default:
Error("Protocol handling missing in multi_endlevel_poll1\n");
break;
}
}
void multi_endlevel_poll2( int nitems, struct newmenu_item * menus, int * key, int citem )
{
switch (multi_protocol)
{
case MULTI_PROTO_IPX:
net_ipx_endlevel_poll2( nitems, menus, key, citem );
net_ipx_kmatrix_poll2( nitems, menus, key, citem );
break;
case MULTI_PROTO_UDP:
net_udp_kmatrix_poll2( nitems, menus, key, citem );
break;
default:
Error("Protocol handling missing in multi_endlevel_poll2\n");
@ -1045,19 +1049,6 @@ void multi_endlevel_poll2( int nitems, struct newmenu_item * menus, int * key, i
}
}
void multi_endlevel_poll3( int nitems, struct newmenu_item * menus, int * key, int citem )
{
switch (multi_protocol)
{
case MULTI_PROTO_IPX:
net_ipx_endlevel_poll3( nitems, menus, key, citem );
break;
default:
Error("Protocol handling missing in multi_endlevel_poll3\n");
break;
}
}
void multi_send_endlevel_packet()
{
switch (multi_protocol)
@ -1065,25 +1056,15 @@ void multi_send_endlevel_packet()
case MULTI_PROTO_IPX:
net_ipx_send_endlevel_packet();
break;
case MULTI_PROTO_UDP:
net_udp_send_endlevel_packet();
break;
default:
Error("Protocol handling missing in multi_send_endlevel_packet\n");
break;
}
}
void multi_send_endlevel_sub(int player_num)
{
switch (multi_protocol)
{
case MULTI_PROTO_IPX:
net_ipx_send_endlevel_sub(player_num);
break;
default:
Error("Protocol handling missing in multi_send_endlevel_sub\n");
break;
}
}
//
// Part 2 : functions that act on network messages and change the
// the state of the game in some way.
@ -1114,7 +1095,7 @@ multi_menu_poll(void)
// The following three [hackish] lines will go away eventually
calc_frame_time();
memset(&Controls,0,sizeof(control_info)); // from game.c (was in below function)
GameProcessFrame(void);
GameProcessFrame();
multi_in_menu--;
@ -1346,6 +1327,9 @@ void multi_send_message_end()
case MULTI_PROTO_IPX:
net_ipx_send_netgame_update();
break;
case MULTI_PROTO_UDP:
net_udp_send_netgame_update();
break;
default:
Error("Protocol handling missing in multi_send_message_end\n");
break;
@ -1417,7 +1401,10 @@ void multi_send_message_end()
switch (multi_protocol)
{
case MULTI_PROTO_IPX:
net_ipx_dump_player(Netgame.players[i].protocol.ipx.server,Netgame.players[i].protocol.ipx.node, 7);
net_ipx_dump_player(Netgame.players[i].protocol.ipx.server,Netgame.players[i].protocol.ipx.node, DUMP_KICKED);
break;
case MULTI_PROTO_UDP:
net_udp_dump_player(Netgame.players[i].protocol.udp.addr, DUMP_KICKED);
break;
default:
Error("Protocol handling missing in multi_send_message_end\n");
@ -1686,28 +1673,22 @@ multi_do_message(char *buf)
void
multi_do_position(char *buf)
{
ubyte pnum = 0;
#ifdef WORDS_BIGENDIAN
shortpos sp;
#endif
// This routine does only player positions, mode game only
int pnum = (Player_num+1)%2;
Assert(&Objects[Players[pnum].objnum] != ConsoleObject);
if (Game_mode & GM_NETWORK)
{
Int3(); // Get Jason, what the hell are we doing here?
// this is unused in IPX - position is forced within net_ipx_do_frame()
if (multi_protocol == MULTI_PROTO_IPX)
return;
}
pnum = buf[1];
#ifndef WORDS_BIGENDIAN
extract_shortpos(&Objects[Players[pnum].objnum], (shortpos *)(buf+1),0);
extract_shortpos(&Objects[Players[pnum].objnum], (shortpos *)(buf + 2),0);
#else
memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + 1), 9);
memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + 10), 14);
memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + 2), 9);
memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + 11), 14);
extract_shortpos(&Objects[Players[pnum].objnum], &sp, 1);
#endif
@ -1851,16 +1832,7 @@ multi_do_kill(char *buf)
if (killer > 0)
killer = objnum_remote_to_local(killer, (sbyte)buf[count+2]);
#ifdef SHAREWARE
if ((Objects[killed].type != OBJ_PLAYER) && (Objects[killed].type != OBJ_GHOST))
{
Int3();
return;
}
#endif
multi_compute_kill(killer, killed);
}
@ -1988,6 +1960,9 @@ multi_do_quit(char *buf)
case MULTI_PROTO_IPX:
net_ipx_disconnect_player(buf[1]);
break;
case MULTI_PROTO_UDP:
net_udp_disconnect_player(buf[1]);
break;
default:
Error("Protocol handling missing in multi_do_quit\n");
break;
@ -2020,10 +1995,8 @@ multi_do_cloak(char *buf)
Players[pnum].cloak_time = GameTime;
ai_do_cloak_stuff();
#ifndef SHAREWARE
if (Game_mode & GM_MULTI_ROBOTS)
multi_strip_robots(pnum);
#endif
if (Newdemo_state == ND_STATE_RECORDING)
newdemo_record_multi_cloak(pnum);
@ -2290,7 +2263,7 @@ void multi_do_req_player(char *buf)
extract_netplayer_stats( &ps, &Players[Player_num] );
ps.Player_num = Player_num;
ps.message_type = MULTI_SEND_PLAYER; // SET
multi_send_data((char*)&ps, sizeof(netplayer_stats), 0);
multi_send_data((char*)&ps, sizeof(netplayer_stats), 1);
}
}
@ -2461,7 +2434,7 @@ multi_send_destroy_controlcen(int objnum, int player)
multibuf[0] = (char)MULTI_CONTROLCEN;
PUT_INTEL_SHORT(multibuf+1, objnum);
multibuf[3] = player;
multi_send_data(multibuf, 4, 2);
multi_send_data(multibuf, 4, 1);
}
void multi_send_drop_marker (int player,vms_vector position,char messagenum,char text[])
@ -2497,12 +2470,15 @@ multi_send_endlevel_start(int secret)
multi_send_data(multibuf, 3, 1);
if (Game_mode & GM_NETWORK)
{
Players[Player_num].connected = 5;
Players[Player_num].connected = CONNECT_ESCAPE_TUNNEL;
switch (multi_protocol)
{
case MULTI_PROTO_IPX:
net_ipx_send_endlevel_packet();
break;
case MULTI_PROTO_UDP:
net_udp_send_endlevel_packet();
break;
default:
Error("Protocol handling missing in multi_send_endlevel_start\n");
break;
@ -2518,8 +2494,6 @@ multi_send_player_explode(char type)
Assert( (type == MULTI_PLAYER_DROP) || (type == MULTI_PLAYER_EXPLODE) );
multi_send_position(Players[Player_num].objnum);
if (Network_send_objects)
{
Network_send_objnum = -1;
@ -2580,7 +2554,7 @@ multi_send_player_explode(char type)
Int3(); // See Rob
}
multi_send_data(multibuf, message_length[MULTI_PLAYER_EXPLODE], 2);
multi_send_data(multibuf, message_length[MULTI_PLAYER_EXPLODE], 1);
if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)
multi_send_decloak();
if (Game_mode & GM_MULTI_ROBOTS)
@ -2809,10 +2783,12 @@ multi_send_message(void)
void
multi_send_reappear()
{
multi_send_position(Players[Player_num].objnum);
multibuf[0] = (char)MULTI_REAPPEAR;
PUT_INTEL_SHORT(multibuf+1, Players[Player_num].objnum);
multi_send_data(multibuf, 3, 2);
multi_send_data(multibuf, 3, 1);
PKilledFlags[Player_num]=0;
}
@ -2824,11 +2800,12 @@ multi_send_position(int objnum)
#endif
int count=0;
if (Game_mode & GM_NETWORK) {
// this is unused in IPX - position is forced within net_ipx_do_frame()
if (multi_protocol == MULTI_PROTO_IPX)
return;
}
multibuf[count++] = (char)MULTI_POSITION;
multibuf[count++] = (char)Player_num;
#ifndef WORDS_BIGENDIAN
create_shortpos((shortpos *)(multibuf+count), Objects+objnum,0);
count += sizeof(shortpos);
@ -2839,7 +2816,8 @@ multi_send_position(int objnum)
memcpy(&(multibuf[count]), (ubyte *)&(sp.xo), 14);
count += 14;
#endif
// send twice while first has priority so the next one will be attached to the next bigdata packet
multi_send_data(multibuf, count, 1);
multi_send_data(multibuf, count, 0);
}
@ -2872,10 +2850,8 @@ multi_send_kill(int objnum)
count += 3;
multi_send_data(multibuf, count, 1);
#ifndef SHAREWARE
if (Game_mode & GM_MULTI_ROBOTS)
multi_strip_robots(Player_num);
#endif
}
void
@ -2941,10 +2917,8 @@ multi_send_cloak(void)
multi_send_data(multibuf, 2, 1);
#ifndef SHAREWARE
if (Game_mode & GM_MULTI_ROBOTS)
multi_strip_robots(Player_num);
#endif
}
void
@ -2968,13 +2942,12 @@ multi_send_door_open(int segnum, int side,ubyte flag)
multibuf[3] = (sbyte)side;
multibuf[4] = flag;
multi_send_data(multibuf, 5, 2);
multi_send_data(multibuf, 5, 1);
}
extern void net_ipx_send_naked_packet (char *,short,int);
void
multi_send_door_open_specific(int pnum,int segnum, int side,ubyte flag)
void multi_send_door_open_specific(int pnum,int segnum, int side,ubyte flag)
{
// For sending doors only to a specific person (usually when they're joining)
@ -2991,6 +2964,9 @@ multi_send_door_open_specific(int pnum,int segnum, int side,ubyte flag)
case MULTI_PROTO_IPX:
net_ipx_send_naked_packet(multibuf, 5, pnum);
break;
case MULTI_PROTO_UDP:
net_udp_send_mdata_direct((ubyte *)multibuf, 5, pnum, 1);
break;
default:
Error("Protocol handling missing in multi_send_door_open_specific\n");
break;
@ -3054,6 +3030,8 @@ multi_send_create_powerup(int powerup_type, int segnum, int objnum, vms_vector *
#endif
int count = 0;
multi_send_position(Players[Player_num].objnum);
if (Game_mode & GM_NETWORK)
PowerupsInMine[powerup_type]++;
@ -3072,7 +3050,7 @@ multi_send_create_powerup(int powerup_type, int segnum, int objnum, vms_vector *
#endif
// -----------
// Total = 19
multi_send_data(multibuf, count, 2);
multi_send_data(multibuf, count, 1);
if (Network_send_objects && multi_objnum_is_past(objnum))
{
@ -3156,7 +3134,6 @@ multi_send_trigger(int triggernum)
multibuf[count] = (ubyte)triggernum; count += 1;
multi_send_data(multibuf, count, 1);
//multi_send_data(multibuf, count, 1); // twice?
}
void
@ -3176,11 +3153,30 @@ multi_send_hostage_door_status(int wallnum)
multi_send_data(multibuf, count, 0);
}
extern int ConsistencyCount;
extern int Drop_afterburner_blob_flag;
int PhallicLimit=0;
int PhallicMan=-1;
void multi_consistency_error(int reset)
{
static int count = 0;
if (reset)
count = 0;
if (++count < 10)
return;
Function_mode = FMODE_MENU;
nm_messagebox(NULL, 1, TXT_OK, TXT_CONSISTENCY_ERROR);
Function_mode = FMODE_GAME;
count = 0;
multi_quit_game = 1;
multi_leave_menu = 1;
multi_reset_stuff();
Function_mode = FMODE_MENU;
}
void multi_prep_level(void)
{
// Do any special stuff to the level required for games
@ -3202,7 +3198,7 @@ void multi_prep_level(void)
PhallicLimit=0;
PhallicMan=-1;
Drop_afterburner_blob_flag=0;
ConsistencyCount=0;
multi_consistency_error(1);
for (i=0;i<MAX_NUM_NET_PLAYERS;i++)
PKilledFlags[i]=0;
@ -3216,14 +3212,12 @@ void multi_prep_level(void)
Netgame.players[i].LastPacketTime = 0;
}
#ifndef SHAREWARE
for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++)
{
robot_controlled[i] = -1;
robot_agitation[i] = 0;
robot_fired[i] = 0;
}
#endif
Viewer = ConsoleObject = &Objects[Players[Player_num].objnum];
@ -3418,8 +3412,11 @@ int multi_level_sync(void)
case MULTI_PROTO_IPX:
return net_ipx_level_sync();
break;
case MULTI_PROTO_UDP:
return net_udp_level_sync();
break;
default:
Error("Protocol handling missing in multi_levl_sync\n");
Error("Protocol handling missing in multi_level_sync\n");
break;
}
}
@ -3545,35 +3542,48 @@ int multi_delete_extra_objects()
return nnp;
}
int
multi_i_am_master(void)
// Returns 1 if player is Master/Host of this game
int multi_i_am_master(void)
{
// I am the lowest numbered player in this game?
// IPX has variable Hosts, but we might not want to continue this for newer protocols
if (multi_protocol == MULTI_PROTO_IPX)
{
int i;
int i;
if (!(Game_mode & GM_NETWORK))
return (Player_num == 0);
if (!(Game_mode & GM_NETWORK))
for (i = 0; i < Player_num; i++)
if (Players[i].connected)
return 0;
return 1;
}
else
{
return (Player_num == 0);
for (i = 0; i < Player_num; i++)
if (Players[i].connected)
return 0;
return 1;
}
}
// Returns the Player_num of Master/Host of this game
int multi_who_is_master(void)
{
// Who is the master of this game?
// IPX has variable Hosts, but we might not want to continue this for newer protocols
if (multi_protocol == MULTI_PROTO_IPX)
{
int i;
int i;
if (!(Game_mode & GM_NETWORK))
return (Player_num == 0);
if (!(Game_mode & GM_NETWORK))
return (Player_num == 0);
for (i = 0; i < N_players; i++)
if (Players[i].connected)
return i;
return Player_num;
for (i = 0; i < N_players; i++)
if (Players[i].connected)
return i;
return Player_num;
}
else
{
return 0;
}
}
void change_playernum_to( int new_Player_num )
@ -3679,6 +3689,8 @@ void multi_send_drop_weapon (int objnum,int seed)
int count=0;
int ammo_count;
multi_send_position(Players[Player_num].objnum);
objp = &Objects[objnum];
ammo_count = objp->ctype.powerup_info.count;
@ -3701,7 +3713,7 @@ void multi_send_drop_weapon (int objnum,int seed)
if (Game_mode & GM_NETWORK)
PowerupsInMine[objp->id]++;
multi_send_data(multibuf, 12, 2);
multi_send_data(multibuf, 12, 1);
}
void multi_do_drop_weapon (char *buf)
@ -3835,7 +3847,6 @@ void multi_send_wall_status (int wallnum,ubyte type,ubyte flags,ubyte state)
multibuf[count]=flags; count++;
multibuf[count]=state; count++;
multi_send_data(multibuf, count, 1); // twice, just to be sure
multi_send_data(multibuf, count, 1);
}
@ -3860,6 +3871,9 @@ void multi_send_wall_status_specific (int pnum,int wallnum,ubyte type,ubyte flag
net_ipx_send_naked_packet(multibuf, count,pnum); // twice, just to be sure
net_ipx_send_naked_packet(multibuf, count,pnum);
break;
case MULTI_PROTO_UDP:
net_udp_send_mdata_direct((ubyte *)multibuf, count, pnum, 1);
break;
default:
Error("Protocol handling missing in multi_send_wall_status_specific\n");
break;
@ -4026,6 +4040,9 @@ void multi_send_light_specific (int pnum,int segnum,ubyte val)
case MULTI_PROTO_IPX:
net_ipx_send_naked_packet(multibuf, count, pnum);
break;
case MULTI_PROTO_UDP:
net_udp_send_mdata_direct((ubyte *)multibuf, count, pnum, 1);
break;
default:
Error("Protocol handling missing in multi_send_light_specific\n");
break;
@ -4125,7 +4142,6 @@ void multi_send_active_door (int i)
PUT_INTEL_SHORT(multibuf + count, ActiveDoors[i].back_wallnum[1]); count += 2;
PUT_INTEL_INT(multibuf + count, ActiveDoors[i].time); count += 4;
#endif
//multi_send_data (multibuf,sizeof(struct active_door)+3,1);
multi_send_data (multibuf,count,1);
}
#endif // 0 (never used)
@ -4174,7 +4190,7 @@ void multi_do_sound_function (char *buf)
char pnum,whichfunc;
int sound;
if (Players[Player_num].connected!=1)
if (Players[Player_num].connected!=CONNECT_PLAYING)
return;
pnum=buf[1];
@ -4216,8 +4232,6 @@ void multi_do_capture_bonus(char *buf)
char pnum=buf[1];
int TheGoal;
kmatrix_kills_changed = 1;
if (pnum==Player_num)
HUD_init_message("You have Scored!");
else
@ -4276,8 +4290,6 @@ void multi_do_orb_bonus(char *buf)
int TheGoal;
int bonus=GetOrbBonus (buf[2]);
kmatrix_kills_changed = 1;
if (pnum==Player_num)
HUD_init_message("You have scored %d points!",bonus);
else
@ -4490,7 +4502,7 @@ void multi_send_drop_flag (int objnum,int seed)
if (Game_mode & GM_NETWORK)
PowerupsInMine[objp->id]++;
multi_send_data(multibuf, 12, 2);
multi_send_data(multibuf, 12, 1);
}
void multi_do_drop_flag (char *buf)
@ -4532,63 +4544,6 @@ extern int robot_fired[MAX_ROBOTS_CONTROLLED];
extern sbyte robot_fire_buf[MAX_ROBOTS_CONTROLLED][18+3];
void multi_send_robot_controls (char pnum)
{
int count=2;
multibuf[0]=MULTI_ROBOT_CONTROLS;
multibuf[1]=pnum;
memcpy (&(multibuf[count]),&robot_controlled,MAX_ROBOTS_CONTROLLED*4);
count+=(MAX_ROBOTS_CONTROLLED*4);
memcpy (&(multibuf[count]),&robot_agitation,MAX_ROBOTS_CONTROLLED*4);
count+=(MAX_ROBOTS_CONTROLLED*4);
memcpy (&(multibuf[count]),&robot_controlled_time,MAX_ROBOTS_CONTROLLED*4);
count+=(MAX_ROBOTS_CONTROLLED*4);
memcpy (&(multibuf[count]),&robot_last_send_time,MAX_ROBOTS_CONTROLLED*4);
count+=(MAX_ROBOTS_CONTROLLED*4);
memcpy (&(multibuf[count]),&robot_last_message_time,MAX_ROBOTS_CONTROLLED*4);
count+=(MAX_ROBOTS_CONTROLLED*4);
memcpy (&(multibuf[count]),&robot_send_pending,MAX_ROBOTS_CONTROLLED*4);
count+=(MAX_ROBOTS_CONTROLLED*4);
memcpy (&(multibuf[count]),&robot_fired,MAX_ROBOTS_CONTROLLED*4);
count+=(MAX_ROBOTS_CONTROLLED*4);
switch (multi_protocol)
{
case MULTI_PROTO_IPX:
net_ipx_send_naked_packet (multibuf,142,pnum);
break;
default:
Error("Protocol handling missing in multi_send_robot_controls\n");
break;
}
}
void multi_do_robot_controls(char *buf)
{
int count=2;
if (buf[1]!=Player_num)
{
Int3(); // Get Jason! Recieved a coop_sync that wasn't ours!
return;
}
memcpy (&robot_controlled,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
count+=(MAX_ROBOTS_CONTROLLED*4);
memcpy (&robot_agitation,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
count+=(MAX_ROBOTS_CONTROLLED*4);
memcpy (&robot_controlled_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
count+=(MAX_ROBOTS_CONTROLLED*4);
memcpy (&robot_last_send_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
count+=(MAX_ROBOTS_CONTROLLED*4);
memcpy (&robot_last_message_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
count+=(MAX_ROBOTS_CONTROLLED*4);
memcpy (&robot_send_pending,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
count+=(MAX_ROBOTS_CONTROLLED*4);
memcpy (&robot_fired,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
count+=(MAX_ROBOTS_CONTROLLED*4);
}
#define POWERUPADJUSTS 5
int PowerupAdjustMapping[]={11,19,39,41,44};
@ -4705,6 +4660,9 @@ void multi_send_trigger_specific (char pnum,char trig)
case MULTI_PROTO_IPX:
net_ipx_send_naked_packet(multibuf, 2, pnum);
break;
case MULTI_PROTO_UDP:
net_udp_send_mdata_direct((ubyte *)multibuf, 2, pnum, 1);
break;
default:
Error("Protocol handling missing in multi_send_trigger_specific\n");
break;
@ -4724,7 +4682,7 @@ void multi_add_lifetime_kills ()
int oldrank;
if (!Game_mode & GM_NETWORK)
if (!(Game_mode & GM_NETWORK))
return;
oldrank=GetMyNetRanking();
@ -4751,7 +4709,7 @@ void multi_add_lifetime_killed ()
int oldrank;
if (!Game_mode & GM_NETWORK)
if (!(Game_mode & GM_NETWORK))
return;
oldrank=GetMyNetRanking();
@ -4856,6 +4814,19 @@ void multi_do_play_by_play (char *buf)
/// CODE TO LOAD HOARD DATA
///
int HoardEquipped()
{
static int checked=-1;
if (checked==-1)
{
if (cfexist("hoard.ham") || cfexist("Data/hoard.ham"))
checked=1;
else
checked=0;
}
return (checked);
}
void init_bitmap(grs_bitmap *bm,int w,int h,int flags,ubyte *data)
{
@ -5179,11 +5150,10 @@ multi_process_data(char *buf, int len)
if (!Endlevel_sequence) multi_do_play_by_play(buf); break;
case MULTI_RANK:
if (!Endlevel_sequence) multi_do_ranking (buf); break;
#ifndef SHAREWARE
case MULTI_FINISH_GAME:
multi_do_finish_game(buf); break; // do this one regardless of endsequence
case MULTI_ROBOT_CONTROLS:
if (!Endlevel_sequence) multi_do_robot_controls(buf); break;
break;
case MULTI_ROBOT_CLAIM:
if (!Endlevel_sequence) multi_do_claim_robot(buf); break;
case MULTI_ROBOT_POSITION:
@ -5194,7 +5164,6 @@ multi_process_data(char *buf, int len)
if (!Endlevel_sequence) multi_do_release_robot(buf); break;
case MULTI_ROBOT_FIRE:
if (!Endlevel_sequence) multi_do_robot_fire(buf); break;
#endif
case MULTI_SCORE:
if (!Endlevel_sequence) multi_do_score(buf); break;
case MULTI_CREATE_ROBOT:

View file

@ -25,30 +25,28 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
#include "piggy.h"
#include "vers_id.h"
#include "newmenu.h"
#ifdef _WIN32
#include <winsock.h>
#include <io.h>
#include <winsock.h>
#include <io.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#endif
#ifdef IPv6
#define _sockaddr sockaddr_in6
#define _af AF_INET6
#define _pf PF_INET6
#define _sockaddr sockaddr_in6
#define _af AF_INET6
#define _pf PF_INET6
#else
#define _sockaddr sockaddr_in
#define _af AF_INET
#define _pf PF_INET
#define _sockaddr sockaddr_in
#define _af AF_INET
#define _pf PF_INET
#endif
// PROTOCOL VARIABLES AND DEFINES
extern int multi_protocol; // set and determinate used protocol
#define MULTI_PROTO_IPX 1 // IPX-type protocol (IPX, KALI)
@ -126,7 +124,7 @@ extern int multi_protocol; // set and determinate used protocol
#define MULTI_CAPTURE_BONUS 52
#define MULTI_GOT_FLAG 53
#define MULTI_DROP_FLAG 54
#define MULTI_ROBOT_CONTROLS 55
#define MULTI_ROBOT_CONTROLS 55 // unused!
#define MULTI_FINISH_GAME 56
#define MULTI_RANK 57
#define MULTI_MODEM_PING 58
@ -142,6 +140,14 @@ extern int multi_protocol; // set and determinate used protocol
#define MAX_MULTI_MESSAGE_LEN 120
#define NETGAME_ANARCHY 0
#define NETGAME_TEAM_ANARCHY 1
#define NETGAME_ROBOT_ANARCHY 2
#define NETGAME_COOPERATIVE 3
#define NETGAME_CAPTURE_FLAG 4
#define NETGAME_HOARD 5
#define NETGAME_TEAM_HOARD 6
#define NETSTAT_MENU 0
#define NETSTAT_PLAYING 1
#define NETSTAT_BROWSING 2
@ -158,6 +164,16 @@ extern int multi_protocol; // set and determinate used protocol
#define CONNECT_END_MENU 6
#define CONNECT_KMATRIX_WAITING 7 // Like CONNECT_WAITING but used especially in kmatrix.c to seperate "escaped" and "waiting"
// reasons for a packet with type PID_DUMP
#define DUMP_CLOSED 0 // no new players allowed after game started
#define DUMP_FULL 1 // player cound maxed out
#define DUMP_ENDLEVEL 2
#define DUMP_DORK 3
#define DUMP_ABORTED 4
#define DUMP_CONNECTED 5 // never used
#define DUMP_LEVEL 6
#define DUMP_KICKED 7
// Bitmask for netgame_info->AllowedItems to set allowed items in Netgame
#define NETFLAG_DOLASER 1
#define NETFLAG_DOSUPERLASER 2
@ -193,6 +209,7 @@ extern char *multi_allow_powerup_text[MULTI_ALLOW_POWERUP_MAX];
// Exported functions
extern int GetMyNetRanking();
extern void ClipRank (ubyte *rank);
int objnum_remote_to_local(int remote_obj, int owner);
int objnum_local_to_remote(int local_obj, sbyte *owner);
void map_objnum_local_to_remote(int local, int remote, int owner);
@ -236,13 +253,13 @@ void multi_send_guided_info (object *miss,char);
void multi_endlevel_score(void);
void multi_consistency_error(int reset);
void multi_prep_level(void);
int multi_level_sync(void);
int multi_endlevel(int *secret);
void multi_endlevel_poll1();
void multi_endlevel_poll2( int nitems, struct newmenu_item * menus, int * key, int citem );
void multi_endlevel_poll3( int nitems, struct newmenu_item * menus, int * key, int citem );
void multi_send_endlevel_packet();
void multi_send_endlevel_sub(int player_num);
int multi_menu_poll(void);
void multi_leave_game(void);
void multi_process_data(char *dat, int len);
@ -258,14 +275,13 @@ int multi_get_kill_list(int *plist);
void multi_new_game(void);
void multi_sort_kill_list(void);
void multi_reset_stuff(void);
void multi_send_data(char *buf, int len, int repeat);
void multi_send_data(char *buf, int len, int priority);
int get_team(int pnum);
// Exported variables
extern int PacketUrgent;
extern int Network_active;
extern int Network_status;
extern int Network_laser_gun;
extern int Network_laser_fired;
@ -274,9 +290,13 @@ extern int Network_laser_flags;
// IMPORTANT: These variables needed for player rejoining done by protocol-specific code
extern int Network_send_objects;
extern int Network_send_object_mode;
extern int Network_send_objnum;
extern int Network_rejoined;
extern int Network_new_game;
extern int Network_sending_extras;
extern int Player_joining_extras;
extern int Network_player_added;
extern int message_length[MULTI_MAX_TYPE+1];
extern char multibuf[MAX_MULTI_MESSAGE_LEN+4];
@ -329,6 +349,11 @@ extern bitmap_index multi_player_textures[MAX_NUM_NET_PLAYERS][N_PLAYER_SHIP_TEX
extern char *RankStrings[];
// Globals for protocol-bound Refuse-functions
extern char RefuseThisPlayer,WaitForRefuseAnswer,RefuseTeam,RefusePlayerName[12];
extern fix RefuseTimeLimit;
#define REFUSE_INTERVAL (F1_0*8)
#define NETGAME_FLAG_CLOSED 1
#define NETGAME_FLAG_SHOW_ID 2
#define NETGAME_FLAG_SHOW_MAP 4
@ -351,13 +376,11 @@ void change_playernum_to(int new_pnum);
#define MISSILE_ADJUST 100
#define FLARE_ADJUST 127
int HoardEquipped();
#ifdef EDITOR
void save_hoard_data(void);
#endif
enum comp_type {DOS,WIN_32,WIN_95,MAC} __pack__ ;
/*
* The Network Players structure
* Contains both IPX- and UDP-specific data with designated prefixes and general player-related data.
@ -373,16 +396,12 @@ typedef struct netplayer_info
ubyte server[4];
ubyte node[6];
ushort socket;
enum comp_type computer_type;
ubyte computer_type; // {DOS,WIN_32,WIN_95,MAC}
} ipx;
struct
{
struct _sockaddr addr; // IP address of this peer
int valid; // 1 = client connected / 2 = client ready for handshaking / 3 = client done with handshake and fully joined / 0 between clients = no connection -> relay
fix timestamp; // time of received packet - used for timeout
char hs_list[MAX_PLAYERS+4]; // list to store all handshake results for this player from already connected clients
int hstimeout; // counts the number of tries the client tried to connect - if reached 10, client put to relay if allowed
int relay; // relay packets by/to this clients over host
ubyte isyou; // This flag is set true while sending info to tell player his designated (re)join position
} udp;
} protocol;
@ -418,6 +437,7 @@ typedef struct netgame_info
{
struct _sockaddr addr; // IP address of this netgame's host
int program_iver; // IVER of program for version checking
sbyte valid; // Status of Netgame info: -1 = Failed, Wrong version; 0 = No info, yet; 1 = Success
} udp;
} protocol;
@ -438,11 +458,11 @@ typedef struct netgame_info
ubyte game_flags;
ubyte team_vector;
u_int32_t AllowedItems;
short Allow_marker_view:1;
short AlwaysLighting:1;
short ShowAllNames:1;
short BrightPlayers:1;
short InvulAppear:1;
short Allow_marker_view;
short AlwaysLighting;
short ShowAllNames;
short BrightPlayers;
short InvulAppear;
char team_name[2][CALLSIGN_LEN+1];
int locations[MAX_PLAYERS];
short kills[MAX_PLAYERS][MAX_PLAYERS];
@ -458,7 +478,7 @@ typedef struct netgame_info
int player_score[MAX_PLAYERS];
ubyte player_flags[MAX_PLAYERS];
short PacketsPerSec;
ubyte PacketLossPrevention;
ubyte PacketLossPrevention; // FIXME: IMPLEMENT ME!
} __pack__ netgame_info;

View file

@ -338,10 +338,7 @@ multi_send_claim_robot(int objnum)
s = objnum_local_to_remote(objnum, (sbyte *)&multibuf[4]);
PUT_INTEL_SHORT(multibuf+2, s);
multi_send_data(multibuf, 5, 2);
multi_send_data(multibuf, 5, 2);
multi_send_data(multibuf, 5, 2);
multi_send_data(multibuf, 5, 1);
}
void
@ -368,9 +365,7 @@ multi_send_release_robot(int objnum)
s = objnum_local_to_remote(objnum, (sbyte *)&multibuf[4]);
PUT_INTEL_SHORT(multibuf+2, s);
multi_send_data(multibuf, 5, 2);
multi_send_data(multibuf, 5, 2);
multi_send_data(multibuf, 5, 2);
multi_send_data(multibuf, 5, 1);
}
#define MIN_ROBOT_COM_GAP F1_0/12
@ -518,7 +513,7 @@ multi_send_robot_fire(int objnum, int gun_num, vms_vector *fire)
PacketUrgent = 1;
}
else
multi_send_data(multibuf, loc, 2); // Not our robot, send ASAP
multi_send_data(multibuf, loc, 1); // Not our robot, send ASAP
}
void
@ -559,7 +554,7 @@ multi_send_create_robot(int station, int objnum, int type)
map_objnum_local_to_local((short)objnum);
multi_send_data(multibuf, loc, 2);
multi_send_data(multibuf, loc, 1);
}
void
@ -638,7 +633,7 @@ multi_send_create_robot_powerups(object *del_obj)
Net_create_loc = 0;
multi_send_data(multibuf, 27, 2);
multi_send_data(multibuf, 27, 1);
}
void

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,3 @@
/* $Id: net_ipx.h,v 1.1.1.1 2006/03/17 19:56:24 zicodxx Exp $ */
/*
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
@ -14,7 +13,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
/*
*
* Prototypes for network management functions.
* Prototypes for IPX-protocol network management functions.
*
*/
@ -24,9 +23,15 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
#include "gameseq.h"
#include "multi.h"
#include "pstypes.h"
#ifdef _WIN32
#include <winsock.h>
#else
#include <netinet/in.h> /* for htons & co. */
#endif
#define NETWORK_TIMEOUT (15*F1_0) // 15 seconds disconnect timeout
#define MAX_ACTIVE_NETGAMES 12
#define IPX_TIMEOUT (15*F1_0) // 15 seconds disconnect timeout
#define IPX_MAX_NETGAMES 12
/* the following are the possible packet identificators.
* they are stored in the "type" field of the packet structs.
@ -56,14 +61,6 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
#define PID_GAME_PLAYERS 63
#define PID_NAMES_RETURN 64 // 0x40
#define NETGAME_ANARCHY 0
#define NETGAME_TEAM_ANARCHY 1
#define NETGAME_ROBOT_ANARCHY 2
#define NETGAME_COOPERATIVE 3
#define NETGAME_CAPTURE_FLAG 4
#define NETGAME_HOARD 5
#define NETGAME_TEAM_HOARD 6
/* The following are values for NetSecurityFlag */
#define NETSECURITY_OFF 0
#define NETSECURITY_WAIT_FOR_PLAYERS 1
@ -74,12 +71,12 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
* (the one that did "start netgame").
*/
typedef struct sequence_packet {
typedef struct IPX_sequence_packet {
ubyte type;
int Security;
ubyte pad1[3];
netplayer_info player;
} __pack__ sequence_packet;
} __pack__ IPX_sequence_packet;
#define NET_XDATA_SIZE 454
@ -91,7 +88,7 @@ typedef struct sequence_packet {
// shorts on even byte boundries
// ints on even byte boundries
typedef struct frame_info {
typedef struct IPX_frame_info {
ubyte type; // What type of packet
ubyte pad[3]; // Pad out length of frame_info packet
int numpackets;
@ -105,13 +102,13 @@ typedef struct frame_info {
ubyte obj_render_type;
ubyte level_num;
char data[NET_XDATA_SIZE]; // extra data to be tacked on the end
} __pack__ frame_info;
} __pack__ IPX_frame_info;
// short_frame_info is not aligned -- 01/18/96 -- MWA
// IPX_short_frame_info is not aligned -- 01/18/96 -- MWA
// won't align because of shortpos. Shortpos needs
// to stay in current form.
typedef struct short_frame_info {
typedef struct IPX_short_frame_info {
ubyte type; // What type of packet
ubyte pad[3]; // Pad out length of frame_info packet
int numpackets;
@ -121,7 +118,7 @@ typedef struct short_frame_info {
ubyte obj_render_type;
ubyte level_num;
char data[NET_XDATA_SIZE]; // extra data to be tacked on the end
} __pack__ short_frame_info;
} __pack__ IPX_short_frame_info;
typedef struct IPX_netplayer_info {
char callsign[CALLSIGN_LEN+1];
@ -139,7 +136,7 @@ typedef struct IPX_netplayer_info {
ubyte version_major;
ubyte version_minor;
enum comp_type computer_type;
ubyte computer_type;
sbyte connected;
ushort socket;
@ -252,8 +249,8 @@ void net_ipx_join_game();
void network_rejoin_game();
void net_ipx_leave_game();
int net_ipx_endlevel(int *secret);
void net_ipx_endlevel_poll2(int nitems, struct newmenu_item * menus, int * key, int citem);
void net_ipx_endlevel_poll3(int nitems, struct newmenu_item * menus, int * key, int citem);
void net_ipx_kmatrix_poll1( int nitems, newmenu_item * menus, int * key, int citem );
void net_ipx_kmatrix_poll2( int nitems, newmenu_item * menus, int * key, int citem );
int net_ipx_level_sync();
void net_ipx_send_endlevel_packet();
@ -266,8 +263,6 @@ void net_ipx_disconnect_player(int playernum);
extern void net_ipx_dump_player(ubyte * server, ubyte *node, int why);
extern void net_ipx_send_netgame_update();
extern int NetGameType;
// By putting an up-to-20-char-message into Network_message and
// setting Network_message_reciever to the player num you want to
// send it to (100 for broadcast) the next frame the player will
@ -283,7 +278,81 @@ void net_ipx_send_data(ubyte * ptr, int len, int urgent);
// returns 1 if hoard.ham available
extern int HoardEquipped();
extern void net_ipx_ping_all();
extern int IPX_Socket;
extern int IPX_active;
/* General IPX stuff - START */
#define MAX_PACKET_DATA 1500
#define MAX_DATA_SIZE 542
#define MAX_IPX_DATA 576
#define IPX_DEFAULT_SOCKET 0x5130
#define NETPROTO_IPX 1
#define NETPROTO_KALINIX 2
typedef struct IPXAddressStruct {
ubyte Network[4];
ubyte Node[6];
ubyte Socket[2];
} IPXAddress_t;
typedef struct IPXPacketStructure {
ushort Checksum;
ushort Length;
ubyte TransportControl;
ubyte PacketType;
IPXAddress_t Destination;
IPXAddress_t Source;
} IPXPacket_t;
typedef struct socket_struct {
ushort socket;
int fd;
} socket_t;
struct recv_data {
/* all network order */
ubyte src_network[4];
ubyte src_node[6];
ushort src_socket;
ushort dst_socket;
int pkt_type;
};
struct net_driver {
int (*open_socket)(socket_t *sk, int port);
void (*close_socket)(socket_t *mysock);
int (*send_packet)(socket_t *mysock, IPXPacket_t *IPXHeader, ubyte *data, int dataLen);
int (*receive_packet)(socket_t *s, char *buffer, int bufsize, struct recv_data *rec);
int (*packet_ready)(socket_t *s);
int usepacketnum;//we can save 4 bytes
int type; // type of driver (NETPROTO_*). Can be used to make driver-specific rules in other parts of the multiplayer code.
};
extern int ipxdrv_general_packet_ready(int fd);
extern void ipxdrv_get_local_target( ubyte * server, ubyte * node, ubyte * local_target );
extern int ipxdrv_set(int arg);
extern int ipxdrv_change_default_socket( ushort socket_number );
extern ubyte * ipxdrv_get_my_local_address();
extern ubyte * ipxdrv_get_my_server_address();
extern int ipxdrv_get_packet_data( ubyte * data );
extern void ipxdrv_send_broadcast_packet_data( ubyte * data, int datasize );
extern void ipxdrv_send_packet_data( ubyte * data, int datasize, ubyte *network, ubyte *address, ubyte *immediate_address );
extern void ipxdrv_send_internetwork_packet_data( ubyte * data, int datasize, ubyte * server, ubyte *address );
extern int ipxdrv_type(void);
#ifndef __APPLE__
extern struct net_driver ipxdrv_ipx;
#endif
#ifdef __LINUX__
extern struct net_driver ipxdrv_kali;
#endif
extern unsigned char MyAddress[10];
extern ubyte broadcast_addr[];
extern ubyte null_addr[];
extern u_int32_t ipx_network;
/* General IPX stuff - END */
#endif /* _NETWORK_H */

4793
main/net_udp.c Normal file

File diff suppressed because it is too large Load diff

130
main/net_udp.h Normal file
View file

@ -0,0 +1,130 @@
/*
*
* Prototypes for UDP-protocol network management functions.
*
*/
#include "multi.h"
// Exported functions
void net_udp_start_game(void);
void net_udp_manual_join_game();
int net_udp_objnum_is_past(int objnum);
void net_udp_do_frame(int force, int listen);
void net_udp_send_data( ubyte * ptr, int len, int priority );
void net_udp_leave_game();
int net_udp_endlevel(int *secret);
void net_udp_kmatrix_poll1( int nitems, newmenu_item * menus, int * key, int citem );
void net_udp_kmatrix_poll2( int nitems, newmenu_item * menus, int * key, int citem );
void net_udp_send_endlevel_packet();
void net_udp_dump_player(struct _sockaddr dump_addr, int why);
void net_udp_disconnect_player(int playernum);
int net_udp_level_sync();
void net_udp_send_mdata_direct(ubyte *data, int data_len, int pnum, int priority);
void net_udp_send_netgame_update();
// Some defines
#define UDP_PORT_DEFAULT 42424 // Our default port - easy to remember: D = 4, X = 24, X = 24
#define UDP_REQ_ID "D2XR" // ID string for a request packet
#define UDP_MAX_NETGAMES 600
#define UDP_NETGAMES_PPAGE 12 // Netgames on one page of Netlist
#define UDP_NETGAMES_PAGES 50 // Pages available on Netlist (UDP_MAX_NETGAMES/UDP_NETGAMES_PPAGE)
#define UDP_TIMEOUT (10*F1_0) // 10 seconds disconnect timeout
#define UDP_MDATA_STOR_QUEUE_SIZE 500 // Store up to 500 MDATA packets
#define UDP_OBJ_PACKETS_PER_FRAME 20
// Following are static defines for the buffer size of various packets. IF you change the packets, you must change the size, too.
#define UPKT_MAX_SIZE 1024 // Max size for a packet - just for the buffers
#define UPKT_GAME_INFO_REQ_SIZE 9
#define UPKT_SEQUENCE_SIZE 14
#define UPKT_PING_SIZE 33
#define UPKT_PONG_SIZE 6
#define UPKT_MBUF_SIZE 454
// UDP-Packet identificators (ubyte).
#define UPID_VERSION_DENY 1 // Netgame join or info has been denied due to version difference.
#define UPID_GAME_INFO_REQ 2 // Requesting all info about a netgame.
#define UPID_GAME_INFO 3 // Packet containing all info about a netgame.
#define UPID_GAME_INFO_LITE_REQ 4 // Requesting lite info about a netgame. Used for discovering games.
#define UPID_GAME_INFO_LITE 5 // Packet containing lite netgame info.
#define UPID_DUMP 6 // Packet containing why player cannot join this game.
#define UPID_ADDPLAYER 7 // Packet from Host containing info about a new player.
#define UPID_REQUEST 8 // New player says: "I want to be inside of you!" (haha, sorry I could not resist) / Packet containing request to join the game actually.
#define UPID_QUIT_JOINING 9 // Packet from a player who suddenly quits joining.
#define UPID_SYNC 10 // Packet from host containing full netgame info to sync players up.
#define UPID_OBJECT_DATA 11 // Packet from host containing object buffer.
#define UPID_PING 12 // Packet from host containing his GameTime and the Ping list. Client returns this time to host as UPID_PONG and adapts the ping list.
#define UPID_PONG 13 // Packet answer from client to UPID_PING. Contains the time the initial ping packet was sent.
#define UPID_ENDLEVEL_H 14 // Packet from Host to all Clients containing connect-states and kills information about everyone in the game.
#define UPID_ENDLEVEL_C 15 // Packet from Client to Host containing connect-state and kills information from this Client.
#define UPID_PDATA_H 16 // Packet from Host to all Clients containing all players movement data.
#define UPID_PDATA_C 17 // Packet from Client to Host containing his movement data.
#define UPID_MDATA_P0 18 // Packet containing multi buffer from a player. Priority 0 - no ACK needed.
#define UPID_MDATA_P1 19 // Packet containing multi buffer from a player. Priority 1 - ACK needed. Also contains pkt_num
#define UPID_MDATA_ACK 20 // ACK packet for UPID_MDATA_P1.
// Structure keeping lite game infos (for netlist, etc.)
typedef struct UDP_netgame_info_lite
{
struct _sockaddr game_addr;
int program_iver;
char game_name[NETGAME_NAME_LEN+1];
char mission_title[MISSION_NAME_LEN+1];
char mission_name[9];
int levelnum;
ubyte gamemode;
ubyte RefusePlayers;
ubyte difficulty;
ubyte game_status;
ubyte numplayers;
ubyte max_numplayers;
ubyte game_flags;
ubyte team_vector;
} __pack__ UDP_netgame_info_lite;
typedef struct UDP_sequence_packet
{
ubyte type;
netplayer_info player;
} __pack__ UDP_sequence_packet;
// player position packet structure
typedef struct UDP_frame_info
{
ubyte type;
ubyte Player_num;
ubyte connected;
ubyte obj_render_type;
shortpos pos;
} __pack__ UDP_frame_info;
// packet structure for multi-buffer
typedef struct UDP_mdata_info
{
ubyte type;
ubyte Player_num;
uint32_t pkt_num;
ushort mbuf_size;
ubyte mbuf[UPKT_MBUF_SIZE];
} __pack__ UDP_mdata_info;
// structure to store MDATA to maybe resend
typedef struct UDP_mdata_store
{
int used;
fix pkt_initial_timestamp; // initial timestamp to see if packet is outdated
fix pkt_timestamp[MAX_PLAYERS]; // Packet timestamp
int pkt_num; // Packet number
ubyte Player_num; // sender of this packet
ubyte player_ack[MAX_PLAYERS]; // 0 if player has not ACK'd this packet, 1 if ACK'd or not connected
ubyte data[UPKT_MBUF_SIZE]; // extra data of a packet - contains all multibuf data we don't want to loose
ushort data_size;
} __pack__ UDP_mdata_store;
// structure to keep track of MDATA packets we've already got
typedef struct UDP_mdata_recv
{
int pkt_num[UDP_MDATA_STOR_QUEUE_SIZE];
int cur_slot; // index we can use for a new pkt_num
} __pack__ UDP_mdata_recv;

View file

@ -1,658 +0,0 @@
// UDP/IP driver
// Taken inspiration from bomberclone - Thanks Steffen!
#define UDP_LEN_HOSTNAME 128
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <time.h>
#ifndef _MSC_VER
#include <sys/time.h>
#endif
#ifdef _WIN32
#include <winsock.h>
#include <io.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#endif
#include "console.h"
#include "error.h"
#include "netdrv.h"
#include "net_ipx.h"
#include "timer.h"
#include "netdrv_udp.h"
#include "key.h"
#include "text.h"
int UDP_sock = -1;
unsigned int myid=0; // My personal ID which I will get from host and will be used for IPX-Node
struct peer_list UDP_Peers[MAX_CONNECTIONS]; // The Peer list.
void udp_close_socket(socket_t *unused);
// Receive Configuration: Exchanging Peers, doing Handshakes, etc.
void udp_receive_cfg(char *text, struct _sockaddr *sAddr)
{
switch (text[4])
{
case CFG_FIRSTCONTACT_REQ:
{
int i, clientid=0;
ubyte outbuf[6];
// Check if sAddr is not used already (existing client or if client got this packet)
for (i = 1; i < MAX_CONNECTIONS; i++)
{
if (!memcmp(sAddr,(struct _sockaddr *)&UDP_Peers[i].addr,sizeof(struct _sockaddr)))
{
clientid=i;
}
}
// If we haven't found a place already...
if (!clientid)
{
for (i = 1; i < MAX_CONNECTIONS; i++) // ... find a free place in list...
{
if (!UDP_Peers[i].valid) // ... Found it!
{
clientid=i;
break;
}
}
}
if (!clientid)
return;
UDP_Peers[clientid].valid=1;
UDP_Peers[clientid].timestamp=timer_get_fixed_seconds();
memset(UDP_Peers[clientid].hs_list,0,MAX_CONNECTIONS);
UDP_Peers[clientid].hstimeout=0;
UDP_Peers[clientid].relay=0;
memcpy(&UDP_Peers[clientid].addr,sAddr,sizeof(struct _sockaddr)); // Copy address of new client to Peer list
memcpy(outbuf+0,DXXcfgid,4); // PacketCFG ID
outbuf[4]=CFG_FIRSTCONTACT_ACK; // CFG Type
outbuf[5]=clientid; // personal ID for the client
sendto (UDP_sock, outbuf, sizeof(outbuf), 0, (struct sockaddr *) sAddr, sizeof(struct _sockaddr)); // Send!
return;
}
case CFG_FIRSTCONTACT_ACK:
{
My_Seq.player.network.ipx.node[0] = MyAddress[4] = myid = text[5]; // got my ID
memcpy(&UDP_Peers[0].addr,sAddr,sizeof(struct _sockaddr)); // Add sender -> host!
UDP_Peers[0].valid=1;
UDP_Peers[0].timestamp=timer_get_fixed_seconds();
return;
}
// got signal from host to connect with a new client
case CFG_HANDSHAKE_INIT:
{
int i;
struct _sockaddr tmpAddr;
ubyte outbuf[6];
memcpy(outbuf+0,DXXcfgid,4); // PacketCFG ID
outbuf[4]=CFG_HANDSHAKE_PING; // CFG Type
outbuf[5]=myid; // my ID that will be assigned to the new client
memcpy(&tmpAddr,text+5,sizeof(struct _sockaddr));
for (i=0; i<3; i++)
sendto (UDP_sock, outbuf, sizeof(outbuf), 0, (struct sockaddr *) &tmpAddr, sizeof(struct _sockaddr)); // send!
return;
}
// Got a Handshake Ping from a connected client -> Add it to peer list and Pong back
case CFG_HANDSHAKE_PING:
{
int i;
ubyte outbuf[6];
memcpy(&UDP_Peers[(int)text[5]].addr,sAddr,sizeof(struct _sockaddr)); // Copy address of new client to Peer list
UDP_Peers[(int)text[5]].valid=1;
UDP_Peers[(int)text[5]].timestamp=timer_get_fixed_seconds();
memcpy(outbuf+0,DXXcfgid,4); // PacketCFG ID
outbuf[4]=CFG_HANDSHAKE_PONG; // CFG Type
outbuf[5]=myid; // my ID
for (i=0; i<3; i++)
sendto (UDP_sock, outbuf, sizeof(outbuf), 0, (struct sockaddr *) sAddr, sizeof(struct _sockaddr)); // send!
return;
}
// Got response from new client -> Send this to host and add new client to peer list
case CFG_HANDSHAKE_PONG:
{
int i;
ubyte outbuf[7];
memcpy(&UDP_Peers[(int)text[5]].addr,sAddr,sizeof(struct _sockaddr)); // Copy address of new client to Peer list
UDP_Peers[(int)text[5]].valid=1;
UDP_Peers[(int)text[5]].timestamp=timer_get_fixed_seconds();
memcpy(outbuf+0,DXXcfgid,4); // PacketCFG ID
outbuf[4]=CFG_HANDSHAKE_ACK; // CFG Type
outbuf[5]=myid; // my ID
outbuf[6]=text[5]; // ID of the added client
for (i=0; i<3; i++)
sendto (UDP_sock, outbuf, sizeof(outbuf), 0, (struct sockaddr *) &UDP_Peers[0].addr, sizeof(struct _sockaddr)); // send!
return;
}
// Got a message from a client about a new client -> Add hs_list info!
case CFG_HANDSHAKE_ACK:
{
UDP_Peers[(int)text[6]].hs_list[(int)text[5]]=1;
return;
}
}
return;
}
// Handshaking between clients
// Here the HOST will motivate existing clients to connect to a new one
// If all went good, client can join, if not host will relay this client if GameArg.MplIpRelay or being dumped
int udp_handshake_frame(struct _sockaddr *sAddr, char *inbuf)
{
int i,checkid=-1;
if (Network_send_objects)
return 0;//if we are currently letting someone else join, we don't know if this person can join ok.
// Find the player we want to Handshake
for (i=1; i<MAX_CONNECTIONS; i++)
{
if (!memcmp(sAddr,(struct sockaddr*)&UDP_Peers[i].addr,sizeof(struct _sockaddr)))
{
checkid=i;
UDP_Peers[checkid].valid=2;
break;
}
}
if (checkid<0)
return 0;
if (UDP_Peers[checkid].relay)
return 1;
// send Handshake init to all valid players except the new one (checkid)
for (i=1; i<MAX_CONNECTIONS; i++)
{
if (UDP_Peers[i].valid == 3 && i != checkid && !UDP_Peers[i].relay && memcmp(sAddr,(struct sockaddr*)&UDP_Peers[i].addr,sizeof(struct _sockaddr)))
{
char outbuf[6+sizeof(struct _sockaddr)];
// send request to connected clients to handshake with new client
memcpy(outbuf+0,DXXcfgid,4);
outbuf[4]=CFG_HANDSHAKE_INIT;
memcpy(outbuf+5,sAddr,sizeof(struct _sockaddr));
sendto (UDP_sock, outbuf, sizeof(outbuf), 0, (struct sockaddr *) &UDP_Peers[i].addr, sizeof(struct _sockaddr));
}
}
// check if that client is already fully joined
if (UDP_Peers[checkid].valid == 3)
return 1;
// Now check if Handshake was successful on requesting player - if not, return 0
for (i=1; i<MAX_CONNECTIONS; i++)
{
if (UDP_Peers[i].valid == 3 && memcmp(sAddr,(struct _sockaddr *)&UDP_Peers[i].addr,sizeof(struct _sockaddr)))
{
if (UDP_Peers[checkid].hs_list[i] != 1 && !UDP_Peers[i].relay)
{
if (UDP_Peers[checkid].hstimeout > 10)
{
if (GameArg.MplIpRelay)
{
con_printf(CON_NORMAL,"UDP: Relaying Client #%i over Host\n",checkid);
UDP_Peers[checkid].relay=1;
memset(UDP_Peers[checkid].hs_list,1,MAX_CONNECTIONS);
UDP_Peers[checkid].valid=3;
return 1;
}
}
UDP_Peers[checkid].hstimeout++;
return 0;
}
}
}
// Set all vals to true since this could be the first client in our list that had no need to Handshake.
// However in that case this should be true for the next client joning
memset(UDP_Peers[checkid].hs_list,1,MAX_CONNECTIONS);
UDP_Peers[checkid].valid=3;
return 1;
}
// Check if we got data from sAddr within the last 10 seconds (NETWORK_TIMEOUT). If yes, update timestamp of peer, otherwise remove it.
void udp_check_disconnect(struct _sockaddr *sAddr, char *text)
{
int i;
// Check all connections for Disconnect or Timeout.
for (i = 0; i < MAX_CONNECTIONS; i++)
{
// Find the player we got the packet from
if (!memcmp(sAddr,(struct _sockaddr *)&UDP_Peers[i].addr,sizeof(struct _sockaddr)))
{
// Update timestamp
UDP_Peers[i].timestamp=timer_get_fixed_seconds();
}
else if (UDP_Peers[i].valid && UDP_Peers[i].timestamp + NETWORK_TIMEOUT <= timer_get_fixed_seconds())
{
// Timeout!
UDP_Peers[i].valid=0;
UDP_Peers[i].timestamp=0;
memset(UDP_Peers[i].hs_list,0,MAX_CONNECTIONS);
UDP_Peers[i].hstimeout=0;
UDP_Peers[i].relay=0;
}
}
}
// Relay packets over Host
void udp_packet_relay(char *text, int len, struct _sockaddr *sAddr)
{
int i, relayid=0;
// Only host will relay
if (myid)
return;
// Never relay PING packets
if (text[0] == PID_PING_SEND || text[0] == PID_PING_RETURN)
return;
// We got an PID_PDATA_ACK packet - check if it is for me (host). If not, transfer it to designated client if sender or receiver is relay client.
if (text[0] == PID_PDATA_ACK)
{
if ((int)text[2] != Player_num && (UDP_Peers[NetPlayers.players[(int)text[1]].network.ipx.node[0]].relay || UDP_Peers[NetPlayers.players[(int)text[2]].network.ipx.node[0]].relay))
{
sendto (UDP_sock, text, len, 0, (struct sockaddr *) &UDP_Peers[NetPlayers.players[(int)text[2]].network.ipx.node[0]].addr, sizeof(struct _sockaddr));
}
return;
}
// Check if sender is a relay client and store ID if so
for (i = 1; i < MAX_CONNECTIONS; i++)
{
if (!memcmp(sAddr,(struct _sockaddr *)&UDP_Peers[i].addr,sizeof(struct _sockaddr)) && UDP_Peers[i].relay)
{
relayid=i;
}
}
if (relayid>0) // Relay packets from relay client to all others
{
for (i = 1; i < MAX_CONNECTIONS; i++)
{
if (memcmp(sAddr,(struct _sockaddr *)&UDP_Peers[i].addr,sizeof(struct _sockaddr)) && i != relayid && UDP_Peers[i].valid>1)
{
sendto (UDP_sock, text, len, 0, (struct sockaddr *) &UDP_Peers[i].addr, sizeof(struct _sockaddr));
}
}
}
else // Relay packets from normal client to relay clients
{
for (i = 1; i < MAX_CONNECTIONS; i++)
{
if (memcmp(sAddr,(struct _sockaddr *)&UDP_Peers[i].addr,sizeof(struct _sockaddr)) && UDP_Peers[i].relay)
{
sendto (UDP_sock, text, len, 0, (struct sockaddr *) &UDP_Peers[i].addr, sizeof(struct _sockaddr));
}
}
}
}
// Resolve address
int udp_dns_filladdr(char *host, int hostlen, int port, int portlen, struct _sockaddr *sAddr)
{
struct hostent *he;
#ifdef IPv6
int socktype=AF_INET6;
he = gethostbyname2 (host,socktype);
if (!he)
{
socktype=AF_INET;
he = gethostbyname2 (host,socktype);
}
if (!he)
{
con_printf(CON_URGENT,"udp_dns_filladdr (gethostbyname) failed\n");
nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not resolve address");
return -1;
}
((struct _sockaddr *) sAddr)->sin6_family = socktype; // host byte order
((struct _sockaddr *) sAddr)->sin6_port = htons (port); // short, network byte order
((struct _sockaddr *) sAddr)->sin6_flowinfo = 0;
((struct _sockaddr *) sAddr)->sin6_addr = *((struct in6_addr *) he->h_addr);
((struct _sockaddr *) sAddr)->sin6_scope_id = 0;
#else
if ((he = gethostbyname (host)) == NULL) // get the host info
{
con_printf(CON_URGENT,"udp_dns_filladdr (gethostbyname) failed\n");
nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not resolve address");
return -1;
}
((struct _sockaddr *) sAddr)->sin_family = _af; // host byte order
((struct _sockaddr *) sAddr)->sin_port = htons (port); // short, network byte order
((struct _sockaddr *) sAddr)->sin_addr = *((struct in_addr *) he->h_addr);
memset (&(((struct _sockaddr *) sAddr)->sin_zero), '\0', 8); // zero the rest of the struct
#endif
return 0;
}
// Connect to a game host - we want to play!
int UDPConnectManual(char *textaddr)
{
struct _sockaddr HostAddr;
fix start_time = 0;
ubyte node[6];
char outbuf[12], inbuf[5];
ubyte null_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// Resolve address
if (udp_dns_filladdr(textaddr, LEN_SERVERNAME, UDP_BASEPORT, LEN_PORT, &HostAddr) < 0)
{
return -1;
}
network_init();
N_players = 0;
memset(node,0,6); // Host is always on ID 0
memset(inbuf,0,5);
memset(outbuf,0,12);
start_time = timer_get_fixed_seconds();
while (!(!memcmp(inbuf+0,DXXcfgid,4) && inbuf[4] == CFG_FIRSTCONTACT_ACK)) // Yay! got ACK by this host!
{
// Cancel this with ESC
if (key_inkey()==KEY_ESC)
return 0;
// Timeout after 10 seconds
if (timer_get_fixed_seconds() >= start_time + (F1_0*10) || timer_get_fixed_seconds() < start_time)
{
nm_messagebox(TXT_ERROR,1,TXT_OK,"No response by host");
return -1;
}
// Send request to get added by host...
memcpy(outbuf+0,DXXcfgid,4);
outbuf[4]=CFG_FIRSTCONTACT_REQ;
sendto (UDP_sock, outbuf, sizeof(outbuf), 0, (struct sockaddr *) &HostAddr, sizeof(struct _sockaddr));
timer_delay(500);
// ... and wait for answer
udp_receive_packet(NULL,inbuf,6,NULL);
}
if (get_and_show_netgame_info(null_addr,node,NULL)) // show netgame info and keep connection alive!
return network_do_join_game(0); // join the game actually
else
return 0;
}
// Open socket
int udp_open_socket(socket_t *unused, int port)
{
int i;
#ifdef _WIN32
struct _sockaddr sAddr; // my address information
int reuse_on = -1;
// close stale socket
if( UDP_sock != -1 )
udp_close_socket(NULL);
memset( &sAddr, '\0', sizeof( sAddr ) );
if ((UDP_sock = socket (_af, SOCK_DGRAM, 0)) == -1) {
con_printf(CON_URGENT,"udp_open_socket: socket creation failed\n");
nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not create socket");
return -1;
}
// this is pretty annoying in win32. Not doing that will lead to
// "Could not bind name to socket" errors. It may be suitable for other
// socket implementations, too
(void)setsockopt( UDP_sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &reuse_on, sizeof( reuse_on ));
#ifdef IPv6
sAddr.sin6_family = _pf; // host byte order
sAddr.sin6_port = htons (GameArg.MplIpBasePort+UDP_BASEPORT);; // short, network byte order
sAddr.sin6_flowinfo = 0;
sAddr.sin6_addr = in6addr_any; // automatically fill with my IP
sAddr.sin6_scope_id = 0;
#else
sAddr.sin_family = _pf; // host byte order
sAddr.sin_port = htons (GameArg.MplIpBasePort+UDP_BASEPORT); // short, network byte order
sAddr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
#endif
memset (&(sAddr.sin_zero), '\0', 8); // zero the rest of the struct
if (bind (UDP_sock, (struct sockaddr *) &sAddr, sizeof (struct sockaddr)) == -1)
{
con_printf(CON_URGENT,"udp_open_socket: bind name to socket failed\n");
nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not bind name to socket");
udp_close_socket(NULL);
return -1;
}
#else
struct addrinfo hints,*res,*sres;
int err,ai_family_;
char cport[LEN_PORT];
// close stale socket
if( UDP_sock != -1 )
udp_close_socket(NULL);
memset (&hints, '\0', sizeof (struct addrinfo));
memset(cport,'\0',sizeof(char)*LEN_PORT);
hints.ai_flags = AI_PASSIVE;
hints.ai_family = _pf;
hints.ai_socktype = SOCK_DGRAM;
ai_family_ = 0;
sprintf(cport,"%i",UDP_BASEPORT+GameArg.MplIpBasePort);
if ((err = getaddrinfo (NULL, cport, &hints, &res)) == 0)
{
sres = res;
while ((ai_family_ == 0) && (sres))
{
if (sres->ai_family == _pf || _pf == PF_UNSPEC)
ai_family_ = sres->ai_family;
else
sres = sres->ai_next;
}
if (sres == NULL)
sres = res;
ai_family_ = sres->ai_family;
if (ai_family_ != _pf && _pf != PF_UNSPEC)
{
// ai_family is not identic
freeaddrinfo (res);
return -1;
}
if ((UDP_sock = socket (sres->ai_family, SOCK_DGRAM, 0)) < 0)
{
con_printf(CON_URGENT,"udp_open_socket: socket creation failed\n");
nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not create socket");
freeaddrinfo (res);
return -1;
}
if ((err = bind (UDP_sock, sres->ai_addr, sres->ai_addrlen)) < 0)
{
con_printf(CON_URGENT,"udp_open_socket: bind name to socket failed\n");
nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not bind name to socket");
udp_close_socket(NULL);
freeaddrinfo (res);
return -1;
}
freeaddrinfo (res);
}
else {
UDP_sock = -1;
con_printf(CON_URGENT,"udp_open_socket (getaddrinfo):%s\n", gai_strerror (err));
nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not get address information:\n%s",gai_strerror (err));
}
#endif
// Prepare UDP_Peers
for (i=0; i<MAX_CONNECTIONS;i++)
{
memset(&UDP_Peers[i].addr,0,sizeof(struct _sockaddr));
UDP_Peers[i].valid=0;
UDP_Peers[i].timestamp=0;
memset(UDP_Peers[i].hs_list,0,MAX_CONNECTIONS);
UDP_Peers[i].hstimeout=0;
UDP_Peers[i].relay=0;
}
myid=0;
return 0;
};
// Closes an existing udp socket
void udp_close_socket(socket_t *unused)
{
int i;
if (UDP_sock != -1)
{
#ifdef _WIN32
closesocket(UDP_sock);
#else
close (UDP_sock);
#endif
}
UDP_sock = -1;
// Prepare UDP_Peers
for (i=0; i<MAX_CONNECTIONS;i++)
{
memset(&UDP_Peers[i].addr,0,sizeof(struct _sockaddr));
UDP_Peers[i].valid=0;
UDP_Peers[i].timestamp=0;
memset(UDP_Peers[i].hs_list,0,MAX_CONNECTIONS);
UDP_Peers[i].hstimeout=0;
UDP_Peers[i].relay=0;
}
myid=0;
}
// Send text to someone
// This function get's IPXHeader as address. The first byte in this header represents the UDP_Peers ID, so sAddr can be assigned.
static int udp_send_packet(socket_t *unused, IPXPacket_t *IPXHeader, ubyte *text, int len)
{
// check if Header is in a sane range for UDP_Peers
if (IPXHeader->Destination.Node[0] >= MAX_CONNECTIONS)
return 0;
if (!UDP_Peers[IPXHeader->Destination.Node[0]].valid)
{
// PID_PDATA_ACK needs to be delivered to designated peer. If there's a relay player, Host cannot relay, as PID_PDATA_ACK is sent specifically.
// So in this case, if we encounter invalid ID while PID_PDATA_ACK, wrap this packet to Host so it can be relayed.
if (text[0] == PID_PDATA_ACK)
return sendto (UDP_sock, text, len, 0, (struct sockaddr *) &UDP_Peers[0].addr, sizeof(struct _sockaddr));
else
return 0;
}
return sendto (UDP_sock, text, len, 0, (struct sockaddr *) &UDP_Peers[IPXHeader->Destination.Node[0]].addr, sizeof(struct _sockaddr));
}
// Gets some text
// Returns 0 if nothing on there
// rd can safely be ignored here
int udp_receive_packet(socket_t *unused, char *text, int len, struct recv_data *rd)
{
unsigned int clen = sizeof (struct _sockaddr), msglen = 0;
struct _sockaddr sAddr;
if (UDP_sock == -1)
return -1;
if (udp_general_packet_ready(NULL))
{
msglen = recvfrom (UDP_sock, text, len, 0, (struct sockaddr *) &sAddr, &clen);
if (msglen < 0)
return 0;
if ((msglen >= 0) && (msglen < len))
text[msglen] = 0;
// Wrap UDP CFG packets here!
if (!memcmp(text+0,DXXcfgid,4))
{
udp_receive_cfg(text,&sAddr);
return 0;
}
// Check for Disconnect!
udp_check_disconnect(&sAddr, text);
// Seems someone wants to enter the game actually.
// If I am host, init handshakes! if not sccessful, return 0 and never process this player's request signal - cool thing, eh?
if (text[0] == PID_REQUEST && myid == 0)
if (!udp_handshake_frame(&sAddr,text))
return 0;
udp_packet_relay(text, msglen, &sAddr);
}
return msglen;
}
int udp_general_packet_ready(socket_t *unused)
{
fd_set set;
struct timeval tv;
FD_ZERO(&set);
FD_SET(UDP_sock, &set);
tv.tv_sec = tv.tv_usec = 0;
if (select(UDP_sock + 1, &set, NULL, NULL, &tv) > 0)
return 1;
else
return 0;
}
struct net_driver netdrv_udp =
{
udp_open_socket,
udp_close_socket,
udp_send_packet,
udp_receive_packet,
udp_general_packet_ready,
0, //save 4 bytes. udp/ip is completely inaccessable by the other methods, so we don't need to worry about compatibility.
NETPROTO_UDP
};

View file

@ -1,71 +0,0 @@
/* $Id: udp.h,v 1.2 2005/03/27 01:31:50 stpohle Exp $
* UDP Network */
#ifndef _UDP_H
#define _UDP_H
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <time.h>
#ifndef _MSC_VER
#include <sys/time.h>
#endif
#ifdef _WIN32
#include <winsock.h>
#include <io.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#endif
// #define IPv6 // just here for debugging - set via SConstruct
#ifdef IPv6
#define _sockaddr sockaddr_in6
#define _af AF_INET6
#define _pf PF_INET6
#else
#define _sockaddr sockaddr_in
#define _af AF_INET
#define _pf PF_INET
#endif
#define DXXcfgid "D2Rc" // identification string for UDP/IP configuration packets
#define MAX_CONNECTIONS 32 // maximum connections that can be stored in UDPPeers - as this currently bases on player node[0] this must NOT exceed ubyte!
#define LEN_SERVERNAME 41
#define LEN_PORT 6
#define UDP_BASEPORT 31017
// CFGFlags
#define CFG_FIRSTCONTACT_REQ 1 // Request to get in contact with host for the first time to show the game
#define CFG_FIRSTCONTACT_ACK 2 // Ack so client proceeds and adds host addr to it's peer list
#define CFG_HANDSHAKE_INIT 3 // Request from Host to Handshake between two clients
#define CFG_HANDSHAKE_ACK 4 // Handshake OK answer
#define CFG_HANDSHAKE_PING 5 // Contact from connected client to a new one
#define CFG_HANDSHAKE_PONG 6 // Answer from new client - Handshake successful
typedef struct peer_list
{
struct _sockaddr addr; // real address information about this peer
int valid; // 1 = client connected / 2 = client ready for handshaking / 3 = client done with handshake and fully joined / 0 between clients = no connection -> relay
fix timestamp; // time of received packet - used for timeout
char hs_list[MAX_CONNECTIONS]; // list to store all handshake results from clients assigned to this peer
int hstimeout; // counts the number of tries the client tried to connect - if reached 10, client put to relay if allowed
int relay; // relay packets by/to this clients over host
} __pack__ peer_list;
extern sequence_packet My_Seq;
extern void network_init(void);
extern int network_do_join_game();
extern int get_and_show_netgame_info(ubyte *server, ubyte *node, ubyte *net_address);
extern int udp_receive_packet(socket_t *unused, char *text, int len, struct recv_data *rd);
extern int udp_general_packet_ready(socket_t *unused);
#endif

View file

@ -1534,6 +1534,9 @@ int newdemo_read_demo_start(enum purpose_type purpose)
}
#endif
nd_read_int(&Game_mode);
Game_mode &= ~GM_NETWORK;
#ifdef NETWORK
change_playernum_to((Game_mode >> 16) & 0x7);
if (Game_mode & GM_TEAM) {
@ -2488,7 +2491,7 @@ int newdemo_read_frame_information(int rewrite)
break;
}
if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
Players[pnum].connected = 0;
Players[pnum].connected = CONNECT_DISCONNECTED;
if (!new_player) {
memcpy(Players[pnum].callsign, old_callsign, CALLSIGN_LEN+1);
Players[pnum].net_killed_total = killed_total;
@ -2497,7 +2500,7 @@ int newdemo_read_frame_information(int rewrite)
N_players--;
}
} else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
Players[pnum].connected = 1;
Players[pnum].connected = CONNECT_PLAYING;
Players[pnum].net_kills_total = 0;
Players[pnum].net_killed_total = 0;
memcpy(Players[pnum].callsign, new_callsign, CALLSIGN_LEN+1);
@ -2517,9 +2520,9 @@ int newdemo_read_frame_information(int rewrite)
break;
}
if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
Players[pnum].connected = 0;
Players[pnum].connected = CONNECT_DISCONNECTED;
else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
Players[pnum].connected = 1;
Players[pnum].connected = CONNECT_PLAYING;
break;
}
@ -2533,9 +2536,9 @@ int newdemo_read_frame_information(int rewrite)
break;
}
if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
Players[pnum].connected = 1;
Players[pnum].connected = CONNECT_PLAYING;
else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
Players[pnum].connected = 0;
Players[pnum].connected = CONNECT_DISCONNECTED;
break;
}

View file

@ -1,252 +0,0 @@
/*
* Packet-loss-prevention code for DXX-Rebirth
* This code will save the data field of a netgame packet to a queue.
* Saving is only done for urgent packets.
* Each PDATA packet will be ACK'd by the receiver.
* If all receivers submitted their ACK packets to initial sender, the packet is removed from the queue.
* If a player has not ACK'd a PDATA packet within a second, it will resend to him.
* Timeout, disconnects, or changes in player count are handled as well.
*/
#include "noloss.h"
struct pdata_noloss_store noloss_queue[NOLOSS_QUEUE_SIZE];
struct pdata_recv noloss_pdata_got[MAX_PLAYERS];
extern frame_info MySyncPack;
extern int MaxXDataSize;
extern int N_players;
// Adds a packet to our queue
// Should be called when an IMPORTANT frameinfo packet is created
void noloss_add_packet_to_queue(int urgent, int pkt_num, char *data, ushort data_size)
{
int i;
// Only proceed if this is a version-checked game
if (Netgame.protocol_version != MULTI_PROTO_D2X_VER)
return;
// Only add urgent packets
if (!urgent)
return;
for (i = 0; i < NOLOSS_QUEUE_SIZE; i++)
{
int j;
if (noloss_queue[i].used)
continue;
noloss_queue[i].used = 1;
noloss_queue[i].pkt_initial_timestamp = GameTime;
noloss_queue[i].pkt_timestamp = GameTime;
noloss_queue[i].pkt_num = pkt_num;
for (j = 0; j < MAX_PLAYERS; j++)
{
if (Players[j].connected)
noloss_queue[i].player_ack[j] = 0;
else
noloss_queue[i].player_ack[j] = 1; // Player is not connected so set to positive in case he joins
}
memcpy( &noloss_queue[i].data[0], data, data_size );
noloss_queue[i].data_size = data_size;
return;
}
con_printf(CON_DEBUG, "Noloss queue is full!\n");
}
// Send the packet stored in queue list at index to given receiver_pnum
// Called from inside noloss_process_queue()
void noloss_send_queued_packet(int queue_index)
{
short_frame_info ShortSyncPack;
int objnum = Players[Player_num].objnum;
// Update Timestamp
noloss_queue[queue_index].pkt_timestamp = GameTime;
// Copy the multibuf data to MySyncPack
memcpy( &MySyncPack.data[0],&noloss_queue[queue_index].data[0], noloss_queue[queue_index].data_size );
MySyncPack.data_size = noloss_queue[queue_index].data_size;
// The following code HEAVILY borrows from network_do_frame()
// Create a frameinfo packet
if (Netgame.ShortPackets)
{
#ifdef WORDS_BIGENDIAN
ubyte send_data[MAX_DATA_SIZE];
#endif
int i;
memset(&ShortSyncPack,0,sizeof(short_frame_info));
create_shortpos(&ShortSyncPack.thepos, Objects+objnum, 0);
ShortSyncPack.type = PID_PDATA_NOLOSS;
ShortSyncPack.playernum = Player_num;
ShortSyncPack.obj_render_type = Objects[objnum].render_type;
ShortSyncPack.level_num = Current_level_num;
ShortSyncPack.data_size = MySyncPack.data_size;
memcpy (&ShortSyncPack.data[0],&MySyncPack.data[0],MySyncPack.data_size);
MySyncPack.numpackets = INTEL_INT(noloss_queue[queue_index].pkt_num);
ShortSyncPack.numpackets = MySyncPack.numpackets;
#ifndef WORDS_BIGENDIAN
for(i=0; i<N_players; i++)
{
// Check if a player is not connected anymore so we won't send a packet and set positive
if (!noloss_queue[queue_index].player_ack[i] && !Players[i].connected)
noloss_queue[queue_index].player_ack[i] = 1;
if(Players[i].connected && (i != Player_num))
netdrv_send_packet_data((ubyte*)&ShortSyncPack, sizeof(short_frame_info) - MaxXDataSize + MySyncPack.data_size, NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node,Players[i].net_address);
}
#else
squish_short_frame_info(ShortSyncPack, send_data);
for(i=0; i<N_players; i++) {
// Check if a player is not connected anymore so we won't send a packet and set positive
if (!noloss_queue[queue_index].player_ack[i] && !Players[i].connected)
noloss_queue[queue_index].player_ack[i] = 1;
if(!noloss_queue[queue_index].player_ack[i] && Players[i].connected && (i != Player_num))
netdrv_send_packet_data((ubyte*)send_data, IPX_SHORT_INFO_SIZE-MaxXDataSize+MySyncPack.data_size, NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node,Players[i].net_address);
}
#endif
}
else // If long packets
{
int i;
MySyncPack.numpackets = noloss_queue[queue_index].pkt_num;
MySyncPack.type = PID_PDATA_NOLOSS;
MySyncPack.playernum = Player_num;
MySyncPack.obj_render_type = Objects[objnum].render_type;
MySyncPack.level_num = Current_level_num;
MySyncPack.obj_segnum = Objects[objnum].segnum;
MySyncPack.obj_pos = Objects[objnum].pos;
MySyncPack.obj_orient = Objects[objnum].orient;
MySyncPack.phys_velocity = Objects[objnum].mtype.phys_info.velocity;
MySyncPack.phys_rotvel = Objects[objnum].mtype.phys_info.rotvel;
for(i=0; i<N_players; i++)
{
// Check if a player is not connected anymore so we won't send a packet and set positive
if (!noloss_queue[queue_index].player_ack[i] && !Players[i].connected)
noloss_queue[queue_index].player_ack[i] = 1;
if(!noloss_queue[queue_index].player_ack[i] && Players[i].connected && (i != Player_num))
{
send_frameinfo_packet(&MySyncPack, NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node,Players[i].net_address);
}
}
}
MySyncPack.data_size = 0; // Start data over at 0 length.
}
// We have received a PDATA packet. Send ACK response to sender!
// ACK packet needs to contain: packet num, sender player num, receiver player num
// Call in network_process_packet() at case PID_PDATA
// Also check in our noloss_pdata_got list, if we got this packet already.
// If yes, return 0 (not valid)! If not, add this pkt_num to our list and return 1 so the pdata packet will be processed!
int noloss_validate_pdata(int pkt_num, ubyte receiver_pnum)
{
noloss_ack ack;
int i;
memset(&ack,0,sizeof(noloss_ack));
ack.type = PID_PDATA_ACK;
ack.sender_pnum = Player_num;
ack.receiver_pnum = receiver_pnum;
ack.pkt_num = pkt_num;
netdrv_send_packet_data( (ubyte *)&ack, sizeof(noloss_ack), NetPlayers.players[receiver_pnum].network.ipx.server, NetPlayers.players[receiver_pnum].network.ipx.node,Players[receiver_pnum].net_address );
for (i = 0; i < NOLOSS_QUEUE_SIZE; i++)
{
if (pkt_num == noloss_pdata_got[receiver_pnum].pkt_num[i])
return 0;
}
noloss_pdata_got[receiver_pnum].cur_slot++;
if (noloss_pdata_got[receiver_pnum].cur_slot >= NOLOSS_QUEUE_SIZE)
noloss_pdata_got[receiver_pnum].cur_slot=0;
noloss_pdata_got[receiver_pnum].pkt_num[noloss_pdata_got[receiver_pnum].cur_slot] = pkt_num;
return 1;
}
// We got an ACK by a player. Set this player slot to positive!
void noloss_got_ack(ubyte *data)
{
int i;
noloss_ack *gotack = (noloss_ack *)data;
if (gotack->receiver_pnum != Player_num)
return;
for (i = 0; i < NOLOSS_QUEUE_SIZE; i++)
{
if (gotack->pkt_num == noloss_queue[i].pkt_num)
{
noloss_queue[i].player_ack[gotack->sender_pnum] = 1;
break;
}
}
}
// Init/Free the queue. Call at start and end of a game or level.
void noloss_init_queue(void)
{
memset(&noloss_queue,0,sizeof(pdata_noloss_store)*NOLOSS_QUEUE_SIZE);
memset(&noloss_pdata_got,-1,sizeof(pdata_recv)*MAX_PLAYERS);
}
// Reset the trace list for given player when disconnect happens
void noloss_update_pdata_got(int player_num)
{
memset(&noloss_pdata_got[player_num].pkt_num,-1,sizeof(int)*NOLOSS_QUEUE_SIZE);
noloss_pdata_got[player_num].cur_slot = -1;
}
// The main queue-process function.
// 1) Check if we can remove a packet from queue (all players positive or packet too old)
// 2) Check if there are packets in queue which we need to re-send to player(s) (if packet is older than one second)
void noloss_process_queue(void)
{
int i, count = 0;
for (i = 0; i < NOLOSS_QUEUE_SIZE; i++)
{
int j, resend = 0;
if (!noloss_queue[i].used)
continue;
// Check if at least one connected player has not ACK'd the packet
for (j = 0; j < N_players; j++)
{
if (!noloss_queue[i].player_ack[j] && Players[j].connected && j != Player_num)
{
resend = 1;
}
}
// Check if we can remove a packet...
if (!resend ||
((noloss_queue[i].pkt_initial_timestamp + (F1_0*15) <= GameTime) || (GameTime < noloss_queue[i].pkt_initial_timestamp)))
{
memset(&noloss_queue[i],0,sizeof(pdata_noloss_store));
}
// ... otherwise resend if a second has passed
else if ((noloss_queue[i].pkt_timestamp + F1_0 <= GameTime) || (GameTime < noloss_queue[i].pkt_timestamp))
{
con_printf(CON_DEBUG, "Re-Sending queued packet %i\n",i);
noloss_send_queued_packet(i);
count++;
}
// Only send 5 packets from the queue by each time the queue process is called
if (count >= 5)
break;
}
}

View file

@ -1,48 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "strutil.h"
#include "pstypes.h"
#include "netpkt.h"
#include "net_ipx.h"
#include "game.h"
#include "multi.h"
#include "netpkt.h"
#include "netdrv.h"
#include "byteswap.h"
#define NOLOSS_QUEUE_SIZE 512 // Store up to 512 packets
// the structure list keeping the data we may want to resend
// this does only contain the extra data field of a PDATA packet (if that isn't enough, the whole PDATA struct info still could be added later)
typedef struct pdata_noloss_store {
int used;
fix pkt_initial_timestamp; // initial timestamp to see if packet is outdated
fix pkt_timestamp; // Packet timestamp
int pkt_num; // Packet number
ubyte player_ack[MAX_PLAYERS]; // 0 if player has not ACK'd this packet, 1 if ACK'd or not connected
char data[NET_XDATA_SIZE]; // extra data of a packet - contains all multibuf data we don't want to loose
ushort data_size;
} __pack__ pdata_noloss_store;
// ACK signal packet
typedef struct noloss_ack {
ubyte type;
ubyte sender_pnum;
ubyte receiver_pnum;
int pkt_num;
} __pack__ noloss_ack;
// keeps track of PDATA packets we've already got
typedef struct pdata_recv {
int pkt_num[NOLOSS_QUEUE_SIZE];
int cur_slot; // index we can use for a new pkt_num
} __pack__ pdata_recv;
void noloss_add_packet_to_queue(int urgent, int pkt_num, char *data, ushort data_size);
int noloss_validate_pdata(int pkt_num, ubyte receiver_pnum);
void noloss_got_ack(ubyte *data);
void noloss_init_queue(void);
void noloss_update_pdata_got(int player_num);
void noloss_process_queue(void);

View file

@ -1547,7 +1547,6 @@ void dead_player_frame(void)
#ifdef NETWORK
if (Game_mode & GM_MULTI)
{
//multi_send_position(Players[Player_num].objnum);
multi_send_player_explode(MULTI_PLAYER_EXPLODE);
}
#endif
@ -1588,7 +1587,6 @@ void dead_player_frame(void)
#ifdef NETWORK
if (Game_mode & GM_MULTI)
{
//multi_send_position(Players[Player_num].objnum);
multi_send_player_explode(MULTI_PLAYER_EXPLODE);
}
#endif

View file

@ -7,12 +7,11 @@
#ifdef D2XMICRO
#define VERSION D2XMAJOR "." D2XMINOR "." D2XMICRO
#define D2X_IVER (atoi(D2XMAJOR)*10000+atoi(D2XMINOR)*100+atoi(D2XMICRO)
#else
#define VERSION D2XMAJOR "." D2XMINOR
#define D2X_IVER (atoi(D2XMAJOR)*10000+atoi(D2XMINOR)*100)
#endif
#define D2X_IVER (atoi(D2XMAJOR)*10000+atoi(D2XMINOR)*100)
#define DESCENT_VERSION "D2X-Rebirth v" VERSION
#endif /* _VERS_ID */

View file

@ -187,9 +187,9 @@ void ReadCmdArgs(void)
GameArg.MplNoRankings = FindArg("-norankings");
GameArg.MplPlayerMessages = FindArg("-playermessages");
GameArg.MplIpxNetwork = get_str_arg("-ipxnetwork", NULL);
GameArg.MplIpBasePort = get_int_arg("-ip_baseport", 0);
GameArg.MplIpRelay = FindArg("-ip_relay");
GameArg.MplIpHostAddr = get_str_arg("-ip_hostaddr", "");
GameArg.MplUdpHostAddr = get_str_arg("-udp_hostaddr", "localhost");
GameArg.MplUdpHostPort = get_int_arg("-udp_hostport", 0);
GameArg.MplUdpMyPort = get_int_arg("-udp_myport", 0);
#ifdef EDITOR
// Editor Options