mirror of
https://github.com/ZDoom/zduke.git
synced 2025-04-23 14:00:51 +00:00
493 lines
11 KiB
C++
493 lines
11 KiB
C++
|
// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
|
|||
|
// Ken Silverman's official web site: "http://www.advsys.net/ken"
|
|||
|
// See the included license file "BUILDLIC.TXT" for license info.
|
|||
|
|
|||
|
#include <stdio.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <string.h>
|
|||
|
#include <dos.h>
|
|||
|
#include <process.h>
|
|||
|
#include <stdarg.h>
|
|||
|
#include "pragmas.h"
|
|||
|
#include "doomtype.h"
|
|||
|
#include "multi.h"
|
|||
|
#include "m_argv.h"
|
|||
|
|
|||
|
#define BAKSIZ 16384
|
|||
|
#define SIMULATEERRORS 0
|
|||
|
#define SHOWSENDPACKETS 1
|
|||
|
#define SHOWGETPACKETS 1
|
|||
|
#define PRINTERRORS 1
|
|||
|
|
|||
|
#define updatecrc16(crc,dat) crc = (((crc<<8)&65535)^crctable[((((unsigned short)crc)>>8)&65535)^dat])
|
|||
|
|
|||
|
void initcrc ();
|
|||
|
void dosendpackets(long other);
|
|||
|
void sendpacket(long other, BYTE *bufptr, long messleng);
|
|||
|
|
|||
|
extern void I_InitNetwork (void);
|
|||
|
extern void I_NetCmd (void);
|
|||
|
|
|||
|
static long incnt[MAXPLAYERS], outcntplc[MAXPLAYERS], outcntend[MAXPLAYERS];
|
|||
|
static BYTE errorgotnum[MAXPLAYERS];
|
|||
|
static BYTE errorfixnum[MAXPLAYERS];
|
|||
|
static BYTE errorresendnum[MAXPLAYERS];
|
|||
|
#if (PRINTERRORS)
|
|||
|
static BYTE lasterrorgotnum[MAXPLAYERS];
|
|||
|
#endif
|
|||
|
|
|||
|
long crctable[256];
|
|||
|
|
|||
|
static BYTE lastpacket[576], inlastpacket = 0;
|
|||
|
static short lastpacketfrom, lastpacketleng;
|
|||
|
|
|||
|
extern volatile long totalclock; //MUST EXTERN 1 ANNOYING VARIABLE FROM GAME
|
|||
|
static long timeoutcount = 60, resendagaincount = 4, lastsendtime[MAXPLAYERS];
|
|||
|
|
|||
|
static short bakpacketptr[MAXPLAYERS][256], bakpacketlen[MAXPLAYERS][256];
|
|||
|
static BYTE bakpacketbuf[BAKSIZ];
|
|||
|
static long bakpacketplc = 0;
|
|||
|
|
|||
|
short myconnectindex, numplayers;
|
|||
|
short connecthead, connectpoint2[MAXPLAYERS];
|
|||
|
BYTE syncstate = 0;
|
|||
|
|
|||
|
extern int _argc;
|
|||
|
extern char **_argv;
|
|||
|
|
|||
|
FILE *debugfile;
|
|||
|
|
|||
|
void callcommit()
|
|||
|
{
|
|||
|
I_NetCmd ();
|
|||
|
}
|
|||
|
|
|||
|
void initmultiplayers(BYTE damultioption, BYTE dacomrateoption, BYTE dapriority)
|
|||
|
{
|
|||
|
int i;
|
|||
|
char *v;
|
|||
|
|
|||
|
I_InitNetwork ();
|
|||
|
|
|||
|
initcrc();
|
|||
|
for(i = 0; i < MAXPLAYERS; i++)
|
|||
|
{
|
|||
|
incnt[i] = 0L;
|
|||
|
outcntplc[i] = 0L;
|
|||
|
outcntend[i] = 0L;
|
|||
|
bakpacketlen[i][255] = -1;
|
|||
|
}
|
|||
|
|
|||
|
if (gcom->numplayers == 1)
|
|||
|
{
|
|||
|
delete gcom;
|
|||
|
|
|||
|
gcom = NULL;
|
|||
|
|
|||
|
numplayers = 1; myconnectindex = 0;
|
|||
|
connecthead = 0; connectpoint2[0] = -1;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
v = Args.CheckValue ("-debugfile");
|
|||
|
if (i > 0)
|
|||
|
{
|
|||
|
debugfile = fopen (v, "w");
|
|||
|
}
|
|||
|
|
|||
|
numplayers = gcom->numplayers;
|
|||
|
myconnectindex = gcom->myconnectindex;
|
|||
|
#if (SIMULATEERRORS != 0)
|
|||
|
srand(myconnectindex*24572457+345356);
|
|||
|
#endif
|
|||
|
connecthead = 0;
|
|||
|
for(i=0;i<numplayers-1;i++) connectpoint2[i] = i+1;
|
|||
|
connectpoint2[numplayers-1] = -1;
|
|||
|
|
|||
|
for(i=0;i<numplayers;i++) lastsendtime[i] = totalclock;
|
|||
|
}
|
|||
|
|
|||
|
void initcrc()
|
|||
|
{
|
|||
|
long i, j, k, a;
|
|||
|
|
|||
|
for(j=0;j<256;j++) //Calculate CRC table
|
|||
|
{
|
|||
|
k = (j<<8); a = 0;
|
|||
|
for(i=7;i>=0;i--)
|
|||
|
{
|
|||
|
if (((k^a)&0x8000) > 0)
|
|||
|
a = ((a<<1)&65535) ^ 0x1021; //0x1021 = genpoly
|
|||
|
else
|
|||
|
a = ((a<<1)&65535);
|
|||
|
k = ((k<<1)&65535);
|
|||
|
}
|
|||
|
crctable[j] = (a&65535);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void setpackettimeout(long datimeoutcount, long daresendagaincount)
|
|||
|
{
|
|||
|
long i;
|
|||
|
|
|||
|
timeoutcount = datimeoutcount;
|
|||
|
resendagaincount = daresendagaincount;
|
|||
|
for(i=0;i<numplayers;i++) lastsendtime[i] = totalclock;
|
|||
|
}
|
|||
|
|
|||
|
long getcrc(BYTE *buffer, long bufleng)
|
|||
|
{
|
|||
|
long i, j;
|
|||
|
|
|||
|
j = 0;
|
|||
|
for(i=bufleng-1;i>=0;i--) updatecrc16(j,buffer[i]);
|
|||
|
return(j&65535);
|
|||
|
}
|
|||
|
|
|||
|
void uninitmultiplayers()
|
|||
|
{
|
|||
|
if (debugfile)
|
|||
|
{
|
|||
|
fclose (debugfile);
|
|||
|
debugfile = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void sendlogon()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
void sendlogoff()
|
|||
|
{
|
|||
|
long i;
|
|||
|
BYTE tempbuf[2];
|
|||
|
|
|||
|
tempbuf[0] = 255;
|
|||
|
tempbuf[1] = (BYTE)myconnectindex;
|
|||
|
for(i=connecthead;i>=0;i=connectpoint2[i])
|
|||
|
if (i != myconnectindex)
|
|||
|
sendpacket(i,tempbuf,2L);
|
|||
|
}
|
|||
|
|
|||
|
int getoutputcirclesize()
|
|||
|
{
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
void setsocket(short newsocket)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
void sendpacket(long other, BYTE *bufptr, long messleng)
|
|||
|
{
|
|||
|
long i, j;
|
|||
|
|
|||
|
if (numplayers < 2) return;
|
|||
|
|
|||
|
i = 0;
|
|||
|
if (bakpacketlen[other][(outcntend[other]-1)&255] == messleng)
|
|||
|
{
|
|||
|
j = bakpacketptr[other][(outcntend[other]-1)&255];
|
|||
|
for(i=messleng-1;i>=0;i--)
|
|||
|
if (bakpacketbuf[(i+j)&(BAKSIZ-1)] != bufptr[i]) break;
|
|||
|
}
|
|||
|
bakpacketlen[other][outcntend[other]&255] = (short)messleng;
|
|||
|
|
|||
|
if (i < 0) //Point to last packet to save space on bakpacketbuf
|
|||
|
bakpacketptr[other][outcntend[other]&255] = (short)j;
|
|||
|
else
|
|||
|
{
|
|||
|
bakpacketptr[other][outcntend[other]&255] = (short)bakpacketplc;
|
|||
|
for(i=0;i<messleng;i++)
|
|||
|
bakpacketbuf[(bakpacketplc+i)&(BAKSIZ-1)] = bufptr[i];
|
|||
|
bakpacketplc = ((bakpacketplc+messleng)&(BAKSIZ-1));
|
|||
|
}
|
|||
|
outcntend[other]++;
|
|||
|
|
|||
|
lastsendtime[other] = totalclock;
|
|||
|
dosendpackets(other);
|
|||
|
}
|
|||
|
|
|||
|
void dosendpackets(long other)
|
|||
|
{
|
|||
|
long i, j, k, messleng;
|
|||
|
unsigned short dacrc;
|
|||
|
|
|||
|
if (outcntplc[other] == outcntend[other]) return;
|
|||
|
|
|||
|
#if (PRINTERRORS)
|
|||
|
if (errorgotnum[other] > lasterrorgotnum[other])
|
|||
|
{
|
|||
|
lasterrorgotnum[other]++;
|
|||
|
if (debugfile)
|
|||
|
fprintf(debugfile, " MeWant %ld\n",incnt[other]&255);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
if (outcntplc[other]+1 == outcntend[other])
|
|||
|
{ //Send 1 sub-packet
|
|||
|
k = 0;
|
|||
|
gcom->buffer[k++] = BYTE(outcntplc[other]&255);
|
|||
|
gcom->buffer[k++] = BYTE(errorgotnum[other]&7)+((errorresendnum[other]&7)<<3);
|
|||
|
gcom->buffer[k++] = BYTE(incnt[other]&255);
|
|||
|
|
|||
|
j = bakpacketptr[other][outcntplc[other]&255];
|
|||
|
messleng = bakpacketlen[other][outcntplc[other]&255];
|
|||
|
for(i=0;i<messleng;i++)
|
|||
|
gcom->buffer[k++] = bakpacketbuf[(i+j)&(BAKSIZ-1)];
|
|||
|
outcntplc[other]++;
|
|||
|
}
|
|||
|
else
|
|||
|
{ //Send 2 sub-packets
|
|||
|
k = 0;
|
|||
|
gcom->buffer[k++] = BYTE(outcntplc[other]&255);
|
|||
|
gcom->buffer[k++] = BYTE(errorgotnum[other]&7)+((errorresendnum[other]&7)<<3)+128;
|
|||
|
gcom->buffer[k++] = BYTE(incnt[other]&255);
|
|||
|
|
|||
|
//First half-packet
|
|||
|
j = bakpacketptr[other][outcntplc[other]&255];
|
|||
|
messleng = bakpacketlen[other][outcntplc[other]&255];
|
|||
|
gcom->buffer[k++] = (BYTE)(messleng&255);
|
|||
|
gcom->buffer[k++] = (BYTE)(messleng>>8);
|
|||
|
for(i=0;i<messleng;i++)
|
|||
|
gcom->buffer[k++] = bakpacketbuf[(i+j)&(BAKSIZ-1)];
|
|||
|
outcntplc[other]++;
|
|||
|
|
|||
|
//Second half-packet
|
|||
|
j = bakpacketptr[other][outcntplc[other]&255];
|
|||
|
messleng = bakpacketlen[other][outcntplc[other]&255];
|
|||
|
for(i=0;i<messleng;i++)
|
|||
|
gcom->buffer[k++] = bakpacketbuf[(i+j)&(BAKSIZ-1)];
|
|||
|
outcntplc[other]++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
dacrc = (unsigned short)getcrc(gcom->buffer,k);
|
|||
|
gcom->buffer[k++] = (dacrc&255);
|
|||
|
gcom->buffer[k++] = (dacrc>>8);
|
|||
|
|
|||
|
gcom->other = (short)other;
|
|||
|
gcom->numbytes = (short)k;
|
|||
|
|
|||
|
#if (SHOWSENDPACKETS)
|
|||
|
if (debugfile)
|
|||
|
{
|
|||
|
fprintf(debugfile, "Send(%ld): ",gcom->other);
|
|||
|
fprintf(debugfile, "[%3d %d-%d-%d %3d] ", gcom->buffer[0],
|
|||
|
gcom->buffer[1]>>7, (gcom->buffer[1]>>3)&7, gcom->buffer[1]&7,
|
|||
|
gcom->buffer[2]);
|
|||
|
for(i=3;i<gcom->numbytes;i++) fprintf(debugfile, "%2x ",gcom->buffer[i]);
|
|||
|
fprintf(debugfile, "\n");
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
#if (SIMULATEERRORS != 0)
|
|||
|
if (!(rand()&SIMULATEERRORS)) gcom->buffer[rand()%gcom->numbytes] = (rand()&255);
|
|||
|
if (rand()&SIMULATEERRORS)
|
|||
|
#endif
|
|||
|
{ gcom->command = 1; callcommit(); }
|
|||
|
}
|
|||
|
|
|||
|
short getpacket (short *other, BYTE *bufptr)
|
|||
|
{
|
|||
|
long i, messleng;
|
|||
|
unsigned short dacrc;
|
|||
|
|
|||
|
if (numplayers < 2) return -1;
|
|||
|
|
|||
|
for(i=connecthead;i>=0;i=connectpoint2[i])
|
|||
|
if (i != myconnectindex)
|
|||
|
{
|
|||
|
if (totalclock < lastsendtime[i]) lastsendtime[i] = totalclock;
|
|||
|
if (totalclock > lastsendtime[i]+timeoutcount)
|
|||
|
{
|
|||
|
#if (PRINTERRORS)
|
|||
|
if (debugfile)
|
|||
|
fprintf(debugfile, " TimeOut!\n");
|
|||
|
#endif
|
|||
|
errorgotnum[i] = errorfixnum[i]+1;
|
|||
|
|
|||
|
if ((outcntplc[i] == outcntend[i]) && (outcntplc[i] > 0))
|
|||
|
{ outcntplc[i]--; lastsendtime[i] = totalclock; }
|
|||
|
else
|
|||
|
lastsendtime[i] += resendagaincount;
|
|||
|
dosendpackets(i);
|
|||
|
//}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (inlastpacket != 0)
|
|||
|
{
|
|||
|
//2ND half of good double-packet
|
|||
|
inlastpacket = 0;
|
|||
|
*other = lastpacketfrom;
|
|||
|
memcpy(bufptr,lastpacket,lastpacketleng);
|
|||
|
return(lastpacketleng);
|
|||
|
}
|
|||
|
|
|||
|
retry:
|
|||
|
gcom->command = 2;
|
|||
|
callcommit();
|
|||
|
|
|||
|
#if (SHOWGETPACKETS)
|
|||
|
if (gcom->other != -1 && debugfile)
|
|||
|
{
|
|||
|
fprintf(debugfile, " Get(%ld): ",gcom->other);
|
|||
|
fprintf(debugfile, "[%3d %d-%d-%d %3d] ", gcom->buffer[0],
|
|||
|
gcom->buffer[1]>>7, (gcom->buffer[1]>>3)&7, gcom->buffer[1]&7,
|
|||
|
gcom->buffer[2]);
|
|||
|
for(i=3;i<gcom->numbytes;i++) fprintf(debugfile, "%2x ",gcom->buffer[i]);
|
|||
|
fprintf(debugfile, "\n");
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
if (gcom->other < 0) return -1;
|
|||
|
|
|||
|
messleng = gcom->numbytes;
|
|||
|
|
|||
|
// [RH] Messages shorter than this can't possibly be packets we're
|
|||
|
// interested in.
|
|||
|
if (messleng < 5)
|
|||
|
{
|
|||
|
#if PRINTERRORS
|
|||
|
if (debugfile)
|
|||
|
fprintf(debugfile, "Superfluous %d byte packet received from %d\n",
|
|||
|
messleng, gcom->other);
|
|||
|
#endif
|
|||
|
goto retry;
|
|||
|
}
|
|||
|
|
|||
|
*other = gcom->other;
|
|||
|
dacrc = ((unsigned short)gcom->buffer[messleng-2]);
|
|||
|
dacrc += (((unsigned short)gcom->buffer[messleng-1])<<8);
|
|||
|
if (dacrc != (unsigned short)getcrc(gcom->buffer,messleng-2)) //CRC check
|
|||
|
{
|
|||
|
#if (PRINTERRORS)
|
|||
|
if (debugfile)
|
|||
|
fprintf(debugfile, "%ld CRC\n",gcom->buffer[0]);
|
|||
|
#endif
|
|||
|
errorgotnum[*other] = errorfixnum[*other]+1;
|
|||
|
goto retry;
|
|||
|
}
|
|||
|
|
|||
|
while ((errorfixnum[*other]&7) != ((gcom->buffer[1]>>3)&7))
|
|||
|
errorfixnum[*other]++;
|
|||
|
|
|||
|
if ((gcom->buffer[1]&7) != (errorresendnum[*other]&7))
|
|||
|
{
|
|||
|
errorresendnum[*other]++;
|
|||
|
outcntplc[*other] = (outcntend[*other]&0xffffff00)+gcom->buffer[2];
|
|||
|
if (outcntplc[*other] > outcntend[*other]) outcntplc[*other] -= 256;
|
|||
|
}
|
|||
|
|
|||
|
if (gcom->buffer[0] != (incnt[*other]&255)) //CNT check
|
|||
|
{
|
|||
|
if (((incnt[*other]-gcom->buffer[0])&255) > 32)
|
|||
|
{
|
|||
|
errorgotnum[*other] = errorfixnum[*other]+1;
|
|||
|
#if (PRINTERRORS)
|
|||
|
if (debugfile)
|
|||
|
fprintf(debugfile, "%ld CNT\n",gcom->buffer[0]);
|
|||
|
#endif
|
|||
|
}
|
|||
|
#if (PRINTERRORS)
|
|||
|
else
|
|||
|
{
|
|||
|
if (!(gcom->buffer[1]&128)) //single else double packet
|
|||
|
{
|
|||
|
if (debugfile)
|
|||
|
fprintf(debugfile, "%ld cnt\n",gcom->buffer[0]);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (((gcom->buffer[0]+1)&255) == (incnt[*other]&255))
|
|||
|
{
|
|||
|
//GOOD! Take second half of double packet
|
|||
|
if (debugfile)
|
|||
|
fprintf(debugfile, "%ld-%ld .<2E> \n",gcom->buffer[0],(gcom->buffer[0]+1)&255);
|
|||
|
|
|||
|
messleng = ((long)gcom->buffer[3]) + (((long)gcom->buffer[4])<<8);
|
|||
|
lastpacketleng = (short)(gcom->numbytes-7-messleng);
|
|||
|
memcpy(bufptr,&gcom->buffer[messleng+5],lastpacketleng);
|
|||
|
incnt[*other]++;
|
|||
|
return(lastpacketleng);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (debugfile)
|
|||
|
fprintf(debugfile, "%ld-%ld cnt \n",gcom->buffer[0],(gcom->buffer[0]+1)&255);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
goto retry;
|
|||
|
}
|
|||
|
|
|||
|
//PACKET WAS GOOD!
|
|||
|
if ((gcom->buffer[1]&128) == 0) //Single packet
|
|||
|
{
|
|||
|
#if (PRINTERRORS)
|
|||
|
if (debugfile)
|
|||
|
fprintf(debugfile, "%ld <20> \n",gcom->buffer[0]);
|
|||
|
#endif
|
|||
|
|
|||
|
messleng = gcom->numbytes-5;
|
|||
|
|
|||
|
memcpy(bufptr,&gcom->buffer[3],messleng);
|
|||
|
|
|||
|
incnt[*other]++;
|
|||
|
return short(messleng);
|
|||
|
}
|
|||
|
|
|||
|
//Double packet
|
|||
|
#if (PRINTERRORS)
|
|||
|
if (debugfile)
|
|||
|
fprintf(debugfile, "%ld-%ld <20> \n",gcom->buffer[0],(gcom->buffer[0]+1)&255);
|
|||
|
#endif
|
|||
|
|
|||
|
messleng = ((long)gcom->buffer[3]) + (((long)gcom->buffer[4])<<8);
|
|||
|
lastpacketleng = (short)(gcom->numbytes-7-messleng);
|
|||
|
inlastpacket = 1; lastpacketfrom = *other;
|
|||
|
|
|||
|
memcpy(bufptr,&gcom->buffer[5],messleng);
|
|||
|
memcpy(lastpacket,&gcom->buffer[messleng+5],lastpacketleng);
|
|||
|
|
|||
|
incnt[*other] += 2;
|
|||
|
return short(messleng);
|
|||
|
}
|
|||
|
|
|||
|
void flushpackets()
|
|||
|
{
|
|||
|
/*long i;
|
|||
|
|
|||
|
if (numplayers < 2) return;
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
gcom->command = 2;
|
|||
|
callcommit();
|
|||
|
} while (gcom->other >= 0);
|
|||
|
|
|||
|
for(i=connecthead;i>=0;i=connectpoint2[i])
|
|||
|
{
|
|||
|
incnt[i] = 0L;
|
|||
|
outcntplc[i] = 0L;
|
|||
|
outcntend[i] = 0L;
|
|||
|
errorgotnum[i] = 0;
|
|||
|
errorfixnum[i] = 0;
|
|||
|
errorresendnum[i] = 0;
|
|||
|
lastsendtime[i] = totalclock;
|
|||
|
}*/
|
|||
|
}
|
|||
|
|
|||
|
void genericmultifunction(int other, BYTE *bufptr, int messleng, int command)
|
|||
|
{
|
|||
|
if (numplayers < 2) return;
|
|||
|
|
|||
|
gcom->command = command;
|
|||
|
gcom->numbytes = messleng < MAXPACKETSIZE ? messleng : MAXPACKETSIZE;
|
|||
|
copybuf(bufptr,gcom->buffer,(gcom->numbytes+3)>>2);
|
|||
|
gcom->other = other+1;
|
|||
|
callcommit();
|
|||
|
}
|