www.pudn.com > BUILD Engine 08012001.zip > mmulti.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. * This file has been modified from Ken Silverman's original release */ #include#include #include #include #include "platform.h" #include "pragmas.h" #define MAXPLAYERS 16 #define BAKSIZ 16384 #define SIMULATEERRORS 0 #define SHOWSENDPACKETS 0 #define SHOWGETPACKETS 0 #define PRINTERRORS 0 #define updatecrc16(crc,dat) crc = (((crc<<8)&65535)^crctable[((((unsigned short)crc)>>8)&65535)^dat]) static long incnt[MAXPLAYERS], outcntplc[MAXPLAYERS], outcntend[MAXPLAYERS]; static char errorgotnum[MAXPLAYERS]; static char errorfixnum[MAXPLAYERS]; static char errorresendnum[MAXPLAYERS]; #if (PRINTERRORS) static char lasterrorgotnum[MAXPLAYERS]; #endif long crctable[256]; static char lastpacket[576], inlastpacket = 0; static short lastpacketfrom, lastpacketleng; extern 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 char bakpacketbuf[BAKSIZ]; static long bakpacketplc = 0; short myconnectindex, numplayers; short connecthead, connectpoint2[MAXPLAYERS]; char syncstate = 0; extern int _argc; extern char **_argv; #define MAXPACKETSIZE 2048 typedef struct { short intnum; /* communication between Game and the driver */ short command; /* 1-send, 2-get */ short other; /* dest for send, set by get (-1 = no packet) */ short numbytes; short myconnectindex; short numplayers; short gametype; /* gametype: 1-serial,2-modem,3-net */ short filler; char buffer[MAXPACKETSIZE]; long longcalladdress; } gcomtype; static gcomtype *gcom; #ifdef PLATFORM_DOS static union REGS regs; #pragma aux longcall =\ "call eax",\ parm [eax] #endif void callcommit(void) { #ifdef PLATFORM_DOS if (gcom->intnum&0xff00) longcall(gcom->longcalladdress); else int386(gcom->intnum,®s,®s); #else fprintf (stderr, "%s, line %d; callcommit() called\n", __FILE__, __LINE__); #endif } void initcrc(void) { 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); } } long getcrc(char *buffer, short bufleng) { long i, j; j = 0; for(i=bufleng-1;i>=0;i--) updatecrc16(j,buffer[i]); return(j&65535); } void initmultiplayers(char damultioption, char dacomrateoption, char dapriority) { long i; char *parm, delims[4] = {'\\','-','/','\0'}; initcrc(); for(i=0;i 0;i--) if ((parm = strtok(_argv[i],&delims[0])) != NULL) if (!stricmp("net",parm)) break; if (i == 0) { numplayers = 1; myconnectindex = 0; connecthead = 0; connectpoint2[0] = -1; return; } gcom = (gcomtype *)atol(_argv[i+1]); numplayers = gcom->numplayers; myconnectindex = gcom->myconnectindex-1; #if (SIMULATEERRORS != 0) srand(myconnectindex*24572457+345356); #endif connecthead = 0; for(i=0;i lasterrorgotnum[other]) { lasterrorgotnum[other]++; printf(" MeWant %ld",incnt[other]&255); } #endif if (outcntplc[other]+1 == outcntend[other]) { /* Send 1 sub-packet */ k = 0; gcom->buffer[k++] = (outcntplc[other]&255); gcom->buffer[k++] = (errorgotnum[other]&7)+((errorresendnum[other]&7)<<3); gcom->buffer[k++] = (incnt[other]&255); j = bakpacketptr[other][outcntplc[other]&255]; messleng = bakpacketlen[other][outcntplc[other]&255]; for(i=0;i buffer[k++] = bakpacketbuf[(i+j)&(BAKSIZ-1)]; outcntplc[other]++; } else { /* Send 2 sub-packets */ k = 0; gcom->buffer[k++] = (outcntplc[other]&255); gcom->buffer[k++] = (errorgotnum[other]&7)+((errorresendnum[other]&7)<<3)+128; gcom->buffer[k++] = (incnt[other]&255); /* First half-packet */ j = bakpacketptr[other][outcntplc[other]&255]; messleng = bakpacketlen[other][outcntplc[other]&255]; gcom->buffer[k++] = (char)(messleng&255); gcom->buffer[k++] = (char)(messleng>>8); for(i=0;i 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 buffer[k++] = bakpacketbuf[(i+j)&(BAKSIZ-1)]; outcntplc[other]++; } dacrc = getcrc(gcom->buffer,k); gcom->buffer[k++] = (dacrc&255); gcom->buffer[k++] = (dacrc>>8); gcom->other = other+1; gcom->numbytes = k; #if (SHOWSENDPACKETS) printf("Send(%ld): ",gcom->other); for(i=0;i numbytes;i++) printf("%2x ",gcom->buffer[i]); printf("\n"); #endif #if (SIMULATEERRORS != 0) if (!(rand()&SIMULATEERRORS)) gcom->buffer[rand()%gcom->numbytes] = (rand()&255); if (rand()&SIMULATEERRORS) #endif { gcom->command = 1; callcommit(); } } void sendpacket(long other, char *bufptr, long messleng) { long i = 0; long j = 0; 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] = messleng; if (i < 0) /* Point to last packet to save space on bakpacketbuf */ bakpacketptr[other][outcntend[other]&255] = j; else { bakpacketptr[other][outcntend[other]&255] = bakpacketplc; for(i=0;i =0;i=connectpoint2[i]) if (i != myconnectindex) sendpacket(i,tempbuf,2L); } int getoutputcirclesize(void) { return(0); } void setsocket(short newsocket) { } short getpacket (short *other, char *bufptr) { long i, messleng; unsigned short dacrc; if (numplayers < 2) return(0); 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) printf(" TimeOut!"); #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); } gcom->command = 2; callcommit(); #if (SHOWGETPACKETS) if (gcom->other != -1) { printf(" Get(%ld): ",gcom->other); for(i=0;i numbytes;i++) printf("%2x ",gcom->buffer[i]); printf("\n"); } #endif if (gcom->other < 0) return(0); *other = gcom->other-1; messleng = gcom->numbytes; dacrc = ((unsigned short)gcom->buffer[messleng-2]); dacrc += (((unsigned short)gcom->buffer[messleng-1])<<8); if (dacrc != getcrc(gcom->buffer,messleng-2)) /* CRC check */ { #if (PRINTERRORS) printf("\n%ld CRC",gcom->buffer[0]); #endif errorgotnum[*other] = errorfixnum[*other]+1; return(0); } 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) printf("\n%ld CNT",gcom->buffer[0]); #endif } #if (PRINTERRORS) else { if (!(gcom->buffer[1]&128)) /* single else double packet */ printf("\n%ld cnt",gcom->buffer[0]); else { if (((gcom->buffer[0]+1)&255) == (incnt[*other]&255)) { /* GOOD! Take second half of double packet */ #if (PRINTERRORS) printf("\n%ld-%ld .û ",gcom->buffer[0],(gcom->buffer[0]+1)&255); #endif messleng = ((long)gcom->buffer[3]) + (((long)gcom->buffer[4])<<8); lastpacketleng = gcom->numbytes-7-messleng; memcpy(bufptr,&gcom->buffer[messleng+5],lastpacketleng); incnt[*other]++; return(lastpacketleng); } else printf("\n%ld-%ld cnt ",gcom->buffer[0],(gcom->buffer[0]+1)&255); } } #endif return(0); } /* PACKET WAS GOOD! */ if ((gcom->buffer[1]&128) == 0) /* Single packet */ { #if (PRINTERRORS) printf("\n%ld û ",gcom->buffer[0]); #endif messleng = gcom->numbytes-5; memcpy(bufptr,&gcom->buffer[3],messleng); incnt[*other]++; return(messleng); } /* Double packet */ #if (PRINTERRORS) printf("\n%ld-%ld ûû ",gcom->buffer[0],(gcom->buffer[0]+1)&255); #endif messleng = ((long)gcom->buffer[3]) + (((long)gcom->buffer[4])<<8); lastpacketleng = 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(messleng); } void flushpackets() { #if 0 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; } #endif } void genericmultifunction(long other, char *bufptr, long messleng, long command) { if (numplayers < 2) return; gcom->command = command; gcom->numbytes = min(messleng,MAXPACKETSIZE); copybuf(bufptr,gcom->buffer,(gcom->numbytes+3)>>2); gcom->other = other+1; callcommit(); } /* end of mmulti.c ... */