static void _Datagram_SearchForHosts (qboolean xmit) { int ret; int n; int i; struct qsockaddr readaddr; struct qsockaddr myaddr; int control; dfunc.GetSocketAddr (dfunc.controlSock, &myaddr); if (xmit) { SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREQ_SERVER_INFO); MSG_WriteString(&net_message, "QUAKE"); MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize); SZ_Clear(&net_message); } while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0) { if (ret < sizeof(int)) continue; net_message.cursize = ret; // don't answer our own query if (dfunc.AddrCompare(&readaddr, &myaddr) >= 0) continue; // is the cache full? if (hostCacheCount == HOSTCACHESIZE) continue; MSG_BeginReading (); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) continue; if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) continue; if ((control & NETFLAG_LENGTH_MASK) != ret) continue; if (MSG_ReadByte() != CCREP_SERVER_INFO) continue; dfunc.GetAddrFromName(MSG_ReadString(), &readaddr); // search the cache for this server for (n = 0; n < hostCacheCount; n++) if (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0) break; // is it already there? if (n < hostCacheCount) continue; // add it hostCacheCount++; Q_strcpy(hostcache[n].name, MSG_ReadString()); Q_strcpy(hostcache[n].map, MSG_ReadString()); hostcache[n].users = MSG_ReadByte(); hostcache[n].maxusers = MSG_ReadByte(); if (MSG_ReadByte() != NET_PROTOCOL_VERSION) { Q_strcpy(hostcache[n].cname, hostcache[n].name); hostcache[n].cname[14] = 0; Q_strcpy(hostcache[n].name, "*"); Q_strcat(hostcache[n].name, hostcache[n].cname); } Q_memcpy(&hostcache[n].addr, &readaddr, sizeof(struct qsockaddr)); hostcache[n].driver = net_driverlevel; hostcache[n].ldriver = net_landriverlevel; Q_strcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr)); // check for a name conflict for (i = 0; i < hostCacheCount; i++) { if (i == n) continue; if (Q_strcasecmp (hostcache[n].name, hostcache[i].name) == 0) { i = Q_strlen(hostcache[n].name); if (i < 15 && hostcache[n].name[i-1] > '8') { hostcache[n].name[i] = '0'; hostcache[n].name[i+1] = 0; } else hostcache[n].name[i-1]++; i = -1; } } } }
static qsocket_t *_Datagram_Connect (char *host) { struct qsockaddr sendaddr; struct qsockaddr readaddr; qsocket_t *sock; int newsock; int ret; int reps; double start_time; int control; char *reason; // see if we can resolve the host name if (dfunc.GetAddrFromName(host, &sendaddr) == -1) return NULL; newsock = dfunc.OpenSocket (0); if (newsock == -1) return NULL; sock = NET_NewQSocket (); if (sock == NULL) goto ErrorReturn2; sock->socket = newsock; sock->landriver = net_landriverlevel; // connect to the host if (dfunc.Connect (newsock, &sendaddr) == -1) goto ErrorReturn; // send the connection request Con_Printf("trying...\n"); SCR_UpdateScreen (); start_time = net_time; for (reps = 0; reps < 3; reps++) { SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREQ_CONNECT); MSG_WriteString(&net_message, "QUAKE"); MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (newsock, net_message.data, net_message.cursize, &sendaddr); SZ_Clear(&net_message); do { ret = dfunc.Read (newsock, net_message.data, net_message.maxsize, &readaddr); // if we got something, validate it if (ret > 0) { // is it from the right place? if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0) { #ifdef DEBUG Con_Printf("wrong reply address\n"); Con_Printf("Expected: %s\n", StrAddr (&sendaddr)); Con_Printf("Received: %s\n", StrAddr (&readaddr)); SCR_UpdateScreen (); #endif ret = 0; continue; } if (ret < sizeof(int)) { ret = 0; continue; } net_message.cursize = ret; MSG_BeginReading (); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) { ret = 0; continue; } if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) { ret = 0; continue; } if ((control & NETFLAG_LENGTH_MASK) != ret) { ret = 0; continue; } } } while (ret == 0 && (SetNetTime() - start_time) < 2.5); if (ret) break; Con_Printf("still trying...\n"); SCR_UpdateScreen (); start_time = SetNetTime(); } if (ret == 0) { reason = "No Response"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } if (ret == -1) { reason = "Network Error"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } ret = MSG_ReadByte(); if (ret == CCREP_REJECT) { reason = MSG_ReadString(); Con_Printf(reason); Q_strncpy(m_return_reason, reason, 31); goto ErrorReturn; } if (ret == CCREP_ACCEPT) { Q_memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr)); dfunc.SetSocketPort (&sock->addr, MSG_ReadLong()); } else { reason = "Bad Response"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } dfunc.GetNameFromAddr (&sendaddr, sock->address); Con_Printf ("Connection accepted\n"); sock->lastMessageTime = SetNetTime(); // switch the connection to the specified address if (dfunc.Connect (newsock, &sock->addr) == -1) { reason = "Connect to Game failed"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } m_return_onerror = false; return sock; ErrorReturn: NET_FreeQSocket(sock); ErrorReturn2: dfunc.CloseSocket(newsock); if (m_return_onerror) { key_dest = key_menu; m_state = m_return_state; m_return_onerror = false; } return NULL; }
void FPNGTexture::MakeTexture () { FileReader *lump; if (SourceLump >= 0) { lump = new FWadLump(Wads.OpenLumpNum(SourceLump)); } else { lump = new FileReader(SourceFile.GetChars()); } Pixels = new BYTE[Width*Height]; if (StartOfIDAT == 0) { memset (Pixels, 0x99, Width*Height); } else { DWORD len, id; lump->Seek (StartOfIDAT, SEEK_SET); lump->Read(&len, 4); lump->Read(&id, 4); if (ColorType == 0 || ColorType == 3) /* Grayscale and paletted */ { M_ReadIDAT (lump, Pixels, Width, Height, Width, BitDepth, ColorType, Interlace, BigLong((unsigned int)len)); if (Width == Height) { if (PaletteMap != NULL) { FlipSquareBlockRemap (Pixels, Width, Height, PaletteMap); } else { FlipSquareBlock (Pixels, Width, Height); } } else { BYTE *newpix = new BYTE[Width*Height]; if (PaletteMap != NULL) { FlipNonSquareBlockRemap (newpix, Pixels, Width, Height, Width, PaletteMap); } else { FlipNonSquareBlock (newpix, Pixels, Width, Height, Width); } BYTE *oldpix = Pixels; Pixels = newpix; delete[] oldpix; } } else /* RGB and/or Alpha present */ { int bytesPerPixel = ColorType == 2 ? 3 : ColorType == 4 ? 2 : 4; BYTE *tempix = new BYTE[Width * Height * bytesPerPixel]; BYTE *in, *out; int x, y, pitch, backstep; M_ReadIDAT (lump, tempix, Width, Height, Width*bytesPerPixel, BitDepth, ColorType, Interlace, BigLong((unsigned int)len)); in = tempix; out = Pixels; // Convert from source format to paletted, column-major. // Formats with alpha maps are reduced to only 1 bit of alpha. switch (ColorType) { case 2: // RGB pitch = Width * 3; backstep = Height * pitch - 3; for (x = Width; x > 0; --x) { for (y = Height; y > 0; --y) { if (!HaveTrans) { *out++ = RGB32k.RGB[in[0]>>3][in[1]>>3][in[2]>>3]; } else { if (in[0] == NonPaletteTrans[0] && in[1] == NonPaletteTrans[1] && in[2] == NonPaletteTrans[2]) { *out++ = 0; } else { *out++ = RGB32k.RGB[in[0]>>3][in[1]>>3][in[2]>>3]; } } in += pitch; } in -= backstep; } break; case 4: // Grayscale + Alpha pitch = Width * 2; backstep = Height * pitch - 2; if (PaletteMap != NULL) { for (x = Width; x > 0; --x) { for (y = Height; y > 0; --y) { *out++ = in[1] < 128 ? 0 : PaletteMap[in[0]]; in += pitch; } in -= backstep; } } else { for (x = Width; x > 0; --x) { for (y = Height; y > 0; --y) { *out++ = in[1] < 128 ? 0 : in[0]; in += pitch; } in -= backstep; } } break; case 6: // RGB + Alpha pitch = Width * 4; backstep = Height * pitch - 4; for (x = Width; x > 0; --x) { for (y = Height; y > 0; --y) { *out++ = in[3] < 128 ? 0 : RGB32k.RGB[in[0]>>3][in[1]>>3][in[2]>>3]; in += pitch; } in -= backstep; } break; } delete[] tempix; }
//----------------------------------------------------------------------------- // Reads the PSD file into the specified buffer //----------------------------------------------------------------------------- bool PSDReadFileRGBA8888( CUtlBuffer &buf, Bitmap_t &bitmap ) { PSDHeader_t header; buf.Get( &header, sizeof(header) ); if ( BigLong( header.m_nSignature ) != PSD_SIGNATURE ) return false; if ( BigShort( header.m_nVersion ) != 1 ) return false; if ( BigShort( header.m_nDepth ) != 8 ) return false; PSDMode_t mode = (PSDMode_t)BigShort( header.m_nMode ); int nChannelsCount = BigShort( header.m_nChannels ); if ( mode == MODE_MULTICHANNEL || mode == MODE_LAB ) return false; switch ( mode ) { case MODE_RGBA: if ( nChannelsCount < 3 ) return false; break; case MODE_GREYSCALE: case MODE_PALETTIZED: if ( nChannelsCount != 1 && nChannelsCount != 2 ) return false; break; case MODE_CMYK: if ( nChannelsCount < 4 ) return false; break; default: Warning( "Unsupported PSD color mode!\n" ); return false; } int nWidth = BigLong( header.m_nColumns ); int nHeight = BigLong( header.m_nRows ); // Skip parts of memory we don't care about int nColorModeSize = BigLong( buf.GetUnsignedInt() ); Assert( nColorModeSize % 3 == 0 ); unsigned char *pPaletteBits = (unsigned char*)_alloca( nColorModeSize ); PSDPalette_t palette; palette.m_pRed = palette.m_pGreen = palette.m_pBlue = 0; if ( nColorModeSize ) { int nPaletteSize = nColorModeSize / 3; buf.Get( pPaletteBits, nColorModeSize ); palette.m_pRed = pPaletteBits; palette.m_pGreen = palette.m_pRed + nPaletteSize; palette.m_pBlue = palette.m_pGreen + nPaletteSize; } int nImageResourcesSize = BigLong( buf.GetUnsignedInt() ); buf.SeekGet( CUtlBuffer::SEEK_CURRENT, nImageResourcesSize ); int nLayersSize = BigLong( buf.GetUnsignedInt() ); buf.SeekGet( CUtlBuffer::SEEK_CURRENT, nLayersSize ); unsigned short nCompressionType = BigShort( buf.GetShort() ); bitmap.Init( nWidth, nHeight, IMAGE_FORMAT_RGBA8888 ); bool bSecondPassCMYKA = ( nChannelsCount > 4 && mode == MODE_CMYK ); if ( nCompressionType == 0 ) { PSDReadUncompressedChannels( buf, ( nChannelsCount > 4 ) ? 4 : nChannelsCount, mode, palette, bitmap ); } else { // Skip the data that indicates the length of each compressed row in bytes // NOTE: There are two bytes per row per channel unsigned int nLineLengthData = sizeof(unsigned short) * bitmap.m_nHeight * nChannelsCount; buf.SeekGet( CUtlBuffer::SEEK_CURRENT, nLineLengthData ); PSDReadCompressedChannels( buf, ( nChannelsCount > 4 ) ? 4 : nChannelsCount, mode, palette, bitmap ); } // Read the alpha in a second pass for CMYKA if ( bSecondPassCMYKA ) { if ( nCompressionType == 0 ) { PSDReadUncompressedChannels( buf, 1, MODE_COUNT, palette, bitmap ); } else { PSDReadCompressedChannels( buf, 1, MODE_COUNT, palette, bitmap ); } } return true; }
void TRI_LoadPolysets( const char *filename, polyset_t **ppPSET, int *numpsets ) { FILE *input; float start; char name[256], tex[256]; int i, count, magic, pset = 0; triangle_t *ptri; polyset_t *pPSET; int iLevel; int exitpattern; float t; t = -FLOAT_START; *((unsigned char *)&exitpattern + 0) = *((unsigned char *)&t + 3); *((unsigned char *)&exitpattern + 1) = *((unsigned char *)&t + 2); *((unsigned char *)&exitpattern + 2) = *((unsigned char *)&t + 1); *((unsigned char *)&exitpattern + 3) = *((unsigned char *)&t + 0); if ((input = fopen(filename, "rb")) == 0) Error ("reader: could not open file '%s'", filename); iLevel = 0; fread(&magic, sizeof(int), 1, input); if (BigLong(magic) != MAGIC) Error ("%s is not a Alias object separated triangle file, magic number is wrong.", filename); pPSET = calloc( 1, POLYSET_MAXPOLYSETS * sizeof( polyset_t ) ); ptri = calloc( 1, POLYSET_MAXTRIANGLES * sizeof( triangle_t ) ); *ppPSET = pPSET; while (feof(input) == 0) { if (fread(&start, sizeof(float), 1, input) < 1) break; *(int *)&start = BigLong(*(int *)&start); if (*(int *)&start != exitpattern) { if (start == FLOAT_START) { /* Start of an object or group of objects. */ i = -1; do { /* There are probably better ways to read a string from */ /* a file, but this does allow you to do error checking */ /* (which I'm not doing) on a per character basis. */ ++i; fread( &(name[i]), sizeof( char ), 1, input); } while( name[i] != '\0' ); if ( i != 0 ) strncpy( pPSET[pset].name, name, sizeof( pPSET[pset].name ) - 1 ); else strcpy( pPSET[pset].name , "(unnamed)" ); strlwr( pPSET[pset].name ); // indent(); // fprintf(stdout,"OBJECT START: %s\n",name); fread( &count, sizeof(int), 1, input); count = BigLong(count); ++iLevel; if (count != 0) { // indent(); // fprintf(stdout,"NUMBER OF TRIANGLES: %d\n",count); i = -1; do { ++i; fread( &(tex[i]), sizeof( char ), 1, input); } while( tex[i] != '\0' ); /* if ( i != 0 ) strncpy( pPSET[pset].texname, tex, sizeof( pPSET[pset].texname ) - 1 ); else strcpy( pPSET[pset].texname, "(unnamed)" ); strlwr( pPSET[pset].texname ); */ // indent(); // fprintf(stdout," Object texture name: '%s'\n",tex); } /* Else (count == 0) this is the start of a group, and */ /* no texture name is present. */ } else if (start == FLOAT_END) { /* End of an object or group. Yes, the name should be */ /* obvious from context, but it is in here just to be */ /* safe and to provide a little extra information for */ /* those who do not wish to write a recursive reader. */ /* Mea culpa. */ --iLevel; i = -1; do { ++i; fread( &(name[i]), sizeof( char ), 1, input); } while( name[i] != '\0' ); if ( i != 0 ) strncpy( pPSET[pset].name, name, sizeof( pPSET[pset].name ) - 1 ); else strcpy( pPSET[pset].name , "(unnamed)" ); strlwr( pPSET[pset].name ); // indent(); // fprintf(stdout,"OBJECT END: %s\n",name); continue; } } // // read the triangles // if ( count > 0 ) { pPSET[pset].triangles = ptri; ReadPolysetGeometry( pPSET[0].triangles, input, count, ptri ); ptri += count; pPSET[pset].numtriangles = count; if ( ++pset >= POLYSET_MAXPOLYSETS ) { Error ("Error: too many polysets; increase POLYSET_MAXPOLYSETS\n"); } } } *numpsets = pset; fclose (input); }
FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, const FString &filename, int width, int height, BYTE depth, BYTE colortype, BYTE interlace) : FTexture(NULL, lumpnum), SourceFile(filename), Pixels(0), Spans(0), BitDepth(depth), ColorType(colortype), Interlace(interlace), HaveTrans(false), PaletteMap(0), PaletteSize(0), StartOfIDAT(0) { union { DWORD palette[256]; BYTE pngpal[256][3]; } p; BYTE trans[256]; DWORD len, id; int i; UseType = TEX_MiscPatch; LeftOffset = 0; TopOffset = 0; bMasked = false; Width = width; Height = height; CalcBitSize (); memset(trans, 255, 256); // Parse pre-IDAT chunks. I skip the CRCs. Is that bad? lump.Seek(33, SEEK_SET); lump.Read(&len, 4); lump.Read(&id, 4); while (id != MAKE_ID('I','D','A','T') && id != MAKE_ID('I','E','N','D')) { len = BigLong((unsigned int)len); switch (id) { default: lump.Seek (len, SEEK_CUR); break; case MAKE_ID('g','r','A','b'): // This is like GRAB found in an ILBM, except coordinates use 4 bytes { DWORD hotx, hoty; int ihotx, ihoty; lump.Read(&hotx, 4); lump.Read(&hoty, 4); ihotx = BigLong((int)hotx); ihoty = BigLong((int)hoty); if (ihotx < -32768 || ihotx > 32767) { Printf ("X-Offset for PNG texture %s is bad: %d (0x%08x)\n", Wads.GetLumpFullName (lumpnum), ihotx, ihotx); ihotx = 0; } if (ihoty < -32768 || ihoty > 32767) { Printf ("Y-Offset for PNG texture %s is bad: %d (0x%08x)\n", Wads.GetLumpFullName (lumpnum), ihoty, ihoty); ihoty = 0; } LeftOffset = ihotx; TopOffset = ihoty; } break; case MAKE_ID('P','L','T','E'): PaletteSize = MIN<int> (len / 3, 256); lump.Read (p.pngpal, PaletteSize * 3); if (PaletteSize * 3 != (int)len) { lump.Seek (len - PaletteSize * 3, SEEK_CUR); } for (i = PaletteSize - 1; i >= 0; --i) { p.palette[i] = MAKERGB(p.pngpal[i][0], p.pngpal[i][1], p.pngpal[i][2]); } break; case MAKE_ID('t','R','N','S'): lump.Read (trans, len); HaveTrans = true; // Save for colortype 2 NonPaletteTrans[0] = WORD(trans[0] * 256 + trans[1]); NonPaletteTrans[1] = WORD(trans[2] * 256 + trans[3]); NonPaletteTrans[2] = WORD(trans[4] * 256 + trans[5]); break; case MAKE_ID('a','l','P','h'): bAlphaTexture = true; bMasked = true; break; } lump.Seek(4, SEEK_CUR); // Skip CRC lump.Read(&len, 4); id = MAKE_ID('I','E','N','D'); lump.Read(&id, 4); } StartOfIDAT = lump.Tell() - 8; switch (colortype) { case 4: // Grayscale + Alpha bMasked = true; // intentional fall-through case 0: // Grayscale if (!bAlphaTexture) { if (colortype == 0 && HaveTrans && NonPaletteTrans[0] < 256) { bMasked = true; PaletteSize = 256; PaletteMap = new BYTE[256]; memcpy (PaletteMap, GrayMap, 256); PaletteMap[NonPaletteTrans[0]] = 0; } else { PaletteMap = GrayMap; } } break; case 3: // Paletted PaletteMap = new BYTE[PaletteSize]; GPalette.MakeRemap (p.palette, PaletteMap, trans, PaletteSize); for (i = 0; i < PaletteSize; ++i) { if (trans[i] == 0) { bMasked = true; PaletteMap[i] = 0; } } break; case 6: // RGB + Alpha bMasked = true; break; case 2: // RGB bMasked = HaveTrans; break; } }
static qsocket_t *_Datagram_CheckNewConnections (void) { struct qsockaddr clientaddr; struct qsockaddr newaddr; int newsock; int acceptsock; qsocket_t *sock; qsocket_t *s; int len; int command; int control; int ret; acceptsock = dfunc.CheckNewConnections(); if (acceptsock == -1) return NULL; SZ_Clear(&net_message); len = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr); if (len < sizeof(int)) return NULL; net_message.cursize = len; MSG_BeginReading (); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) return NULL; if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) return NULL; if ((control & NETFLAG_LENGTH_MASK) != len) return NULL; command = MSG_ReadByte(); if (command == CCREQ_SERVER_INFO) { if (strcmp(MSG_ReadString(), "QUAKE") != 0) return NULL; SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_SERVER_INFO); dfunc.GetSocketAddr(acceptsock, &newaddr); MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr)); MSG_WriteString(&net_message, hostname->string); MSG_WriteString(&net_message, sv.name); MSG_WriteByte(&net_message, net_activeconnections); MSG_WriteByte(&net_message, svs.maxclients); MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } if (command == CCREQ_PLAYER_INFO) { int playerNumber; int activeNumber; int clientNumber; client_t *client; playerNumber = MSG_ReadByte(); activeNumber = -1; for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++) { if (client->active) { activeNumber++; if (activeNumber == playerNumber) break; } } if (clientNumber == svs.maxclients) return NULL; SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_PLAYER_INFO); MSG_WriteByte(&net_message, playerNumber); MSG_WriteString(&net_message, client->name); MSG_WriteLong(&net_message, client->colors); MSG_WriteLong(&net_message, (int)client->edict->v.frags); MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime)); MSG_WriteString(&net_message, client->netconnection->address); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } if (command == CCREQ_RULE_INFO) { char *prevCvarName; cvar_t *var; // find the search start location prevCvarName = MSG_ReadString(); if (*prevCvarName) { var = Cvar_FindVar (prevCvarName); if (!var) return NULL; var = var->next; } else var = cvar_list; // 2001-09-18 New cvar system by Maddes // search for the next server cvar while (var) { if (var->flags & CVAR_SERVERINFO) // 2001-09-18 New cvar system by Maddes break; var = var->next; } // send the response SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_RULE_INFO); if (var) { MSG_WriteString(&net_message, var->name); MSG_WriteString(&net_message, var->string); } *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } if (command != CCREQ_CONNECT) return NULL; if (strcmp(MSG_ReadString(), "QUAKE") != 0) return NULL; if (MSG_ReadByte() != NET_PROTOCOL_VERSION) { SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_REJECT); MSG_WriteString(&net_message, "Incompatible version.\n"); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } #ifdef BAN_TEST // check for a ban if (clientaddr.sa_family == AF_INET) { unsigned long testAddr; testAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr; if ((testAddr & banMask) == banAddr) { SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_REJECT); MSG_WriteString(&net_message, "You have been banned.\n"); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } } #endif // see if this guy is already connected for (s = net_activeSockets; s; s = s->next) { if (s->driver != net_driverlevel) continue; ret = dfunc.AddrCompare(&clientaddr, &s->addr); if (ret >= 0) { // is this a duplicate connection reqeust? if (ret == 0 && net_time - s->connecttime < 2.0) { // yes, so send a duplicate reply SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_ACCEPT); dfunc.GetSocketAddr(s->socket, &newaddr); MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr)); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } // it's somebody coming back in from a crash/disconnect // so close the old qsocket and let their retry get them back in NET_Close(s); return NULL; } } // allocate a QSocket sock = NET_NewQSocket (); if (sock == NULL) { // no room; try to let him know SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_REJECT); MSG_WriteString(&net_message, "Server is full.\n"); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } // allocate a network socket newsock = dfunc.OpenSocket(0); if (newsock == -1) { NET_FreeQSocket(sock); return NULL; } // connect to the client if (dfunc.Connect (newsock, &clientaddr) == -1) { dfunc.CloseSocket(newsock); NET_FreeQSocket(sock); return NULL; } // everything is allocated, just fill in the details sock->socket = newsock; sock->landriver = net_landriverlevel; sock->addr = clientaddr; strcpy(sock->address, dfunc.AddrToString(&clientaddr)); // send him back the info about the server connection he has been allocated SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_ACCEPT); dfunc.GetSocketAddr(newsock, &newaddr); MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr)); // MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr)); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return sock; }
static void LoadTRI(FILE *input, triangle_t **triList, int *triangleCount) { int i, j, k; char text[256]; int count; int magic; tf_triangle tri; triangle_t *ptri; int exitpattern; float t; union { float _f; int _i; } start; t = -FLOAT_START; *((unsigned char *)&exitpattern + 0) = *((unsigned char *)&t + 3); *((unsigned char *)&exitpattern + 1) = *((unsigned char *)&t + 2); *((unsigned char *)&exitpattern + 2) = *((unsigned char *)&t + 1); *((unsigned char *)&exitpattern + 3) = *((unsigned char *)&t + 0); fread(&magic, sizeof(int), 1, input); if (BigLong(magic) != TRI_MAGIC) { COM_Error("Bad .TRI file: %s\n", InputFileName); } ptri = (triangle_t *) SafeMalloc(MAXTRIANGLES * sizeof(triangle_t)); *triList = ptri; count = 0; // make static analyzers happy while (feof(input) == 0) { fread(&start._f, sizeof(float), 1, input); start._i = BigLong(start._i); if (start._i != exitpattern) { if (start._f == FLOAT_START) { // Start of an object or group of objects i = -1; do { ++i; fread(&(text[i]), sizeof(char), 1, input); } while (text[i] != '\0'); //fprintf(stdout,"OBJECT START: %s\n", text); fread(&count, sizeof(int), 1, input); count = BigLong(count); if (count != 0) { //fprintf(stdout,"NUMBER OF TRIANGLES: %d\n", count); i = -1; do { ++i; fread(&(text[i]), sizeof( char ), 1, input); } while (text[i] != '\0'); //fprintf(stdout," Object texture name: '%s'\n", text); } } else if (start._f == FLOAT_END) { i = -1; do { ++i; fread(&(text[i]), sizeof(char), 1, input); } while (text[i] != '\0'); //fprintf(stdout,"OBJECT END: %s\n", text); continue; } } // Read the triangles for (i = 0; i < count; ++i) { fread(&tri, sizeof(tf_triangle), 1, input); ByteSwapTri(&tri); for (j = 0; j < 3; j++) { for (k = 0; k < 3; k++) { ptri->verts[j][k] = tri.pt[j].p.v[k]; } } /* printf("Face %i:\n v0: %f, %f, %f\n v1: %f, %f, %f\n" " v2: %f, %f, %f\n", i, ptri->verts[0][0], ptri->verts[0][1], ptri->verts[0][2], ptri->verts[1][0], ptri->verts[1][1], ptri->verts[1][2], ptri->verts[2][0], ptri->verts[2][1], ptri->verts[2][2]); */ ptri++; if ((ptri - *triList) >= MAXTRIANGLES) { COM_Error("Error: too many triangles; increase MAXTRIANGLES\n"); } } } *triangleCount = ptri - *triList; }
void netadr_t::SetIP(uint unIP) { *((uint*)ip) = BigLong( unIP ); }
//----------------------------------------------------------------------------- // Load the bsp file //----------------------------------------------------------------------------- bool LoadBSPFile( const char* pFilename, void **ppBSPBuffer, int *pBSPSize ) { CByteswap byteSwap; *ppBSPBuffer = NULL; *pBSPSize = 0; FILE *fp = fopen( pFilename, "rb" ); if ( fp ) { fseek( fp, 0, SEEK_END ); int size = ftell( fp ); fseek( fp, 0, SEEK_SET ); *ppBSPBuffer = malloc( size ); if ( !*ppBSPBuffer ) { Warning( "Failed to alloc %d bytes\n", size ); goto cleanUp; } *pBSPSize = size; fread( *ppBSPBuffer, size, 1, fp ); fclose( fp ); } else { if ( !g_bQuiet ) { Warning( "Missing %s\n", pFilename ); } goto cleanUp; } dheader_t *pBSPHeader = (dheader_t *)*ppBSPBuffer; if ( pBSPHeader->ident != IDBSPHEADER ) { if ( pBSPHeader->ident != BigLong( IDBSPHEADER ) ) { if ( !g_bQuiet ) { Warning( "BSP %s has bad id: got %d, expected %d\n", pFilename, pBSPHeader->ident, IDBSPHEADER ); } goto cleanUp; } else { // bsp is for 360, swap the header byteSwap.ActivateByteSwapping( true ); byteSwap.SwapFieldsToTargetEndian( pBSPHeader ); } } if ( pBSPHeader->version < MINBSPVERSION || pBSPHeader->version > BSPVERSION ) { if ( !g_bQuiet ) { Warning( "BSP %s has bad version: got %d, expected %d\n", pFilename, pBSPHeader->version, BSPVERSION ); } goto cleanUp; } // sucess return true; cleanUp: if ( *ppBSPBuffer ) { free( *ppBSPBuffer ); *ppBSPBuffer = NULL; } return false; }
void LoadTriangleList( char *filename, triangle_t **pptri, int *numtriangles ){ FILE *input; float start; char name[256], tex[256]; int i, count, magic; tf_triangle tri; triangle_t *ptri; int iLevel; int exitpattern; float t; t = -FLOAT_START; *( (unsigned char *)&exitpattern + 0 ) = *( (unsigned char *)&t + 3 ); *( (unsigned char *)&exitpattern + 1 ) = *( (unsigned char *)&t + 2 ); *( (unsigned char *)&exitpattern + 2 ) = *( (unsigned char *)&t + 1 ); *( (unsigned char *)&exitpattern + 3 ) = *( (unsigned char *)&t + 0 ); if ( ( input = fopen( filename, "rb" ) ) == 0 ) { Error( "reader: could not open file '%s'", filename ); } iLevel = 0; fread( &magic, sizeof( int ), 1, input ); if ( BigLong( magic ) != MAGIC ) { Error( "%s is not a Alias object separated triangle file, magic number is wrong.", filename ); } ptri = malloc( MAXTRIANGLES * sizeof( triangle_t ) ); *pptri = ptri; while ( feof( input ) == 0 ) { if ( fread( &start, sizeof( float ), 1, input ) < 1 ) { break; } *(int *)&start = BigLong( *(int *)&start ); if ( *(int *)&start != exitpattern ) { if ( start == FLOAT_START ) { /* Start of an object or group of objects. */ i = -1; do { /* There are probably better ways to read a string from */ /* a file, but this does allow you to do error checking */ /* (which I'm not doing) on a per character basis. */ ++i; fread( &( name[i] ), sizeof( char ), 1, input ); } while ( name[i] != '\0' ); // indent(); // fprintf(stdout,"OBJECT START: %s\n",name); fread( &count, sizeof( int ), 1, input ); count = BigLong( count ); ++iLevel; if ( count != 0 ) { // indent(); // fprintf(stdout,"NUMBER OF TRIANGLES: %d\n",count); i = -1; do { ++i; fread( &( tex[i] ), sizeof( char ), 1, input ); } while ( tex[i] != '\0' ); // indent(); // fprintf(stdout," Object texture name: '%s'\n",tex); } /* Else (count == 0) this is the start of a group, and */ /* no texture name is present. */ } else if ( start == FLOAT_END ) { /* End of an object or group. Yes, the name should be */ /* obvious from context, but it is in here just to be */ /* safe and to provide a little extra information for */ /* those who do not wish to write a recursive reader. */ /* Mia culpa. */ --iLevel; i = -1; do { ++i; fread( &( name[i] ), sizeof( char ), 1, input ); } while ( name[i] != '\0' ); // indent(); // fprintf(stdout,"OBJECT END: %s\n",name); continue; } } // // read the triangles // for ( i = 0; i < count; ++i ) { int j; fread( &tri, sizeof( tf_triangle ), 1, input ); ByteSwapTri( &tri ); for ( j = 0 ; j < 3 ; j++ ) { int k; for ( k = 0 ; k < 3 ; k++ ) { ptri->verts[j][k] = tri.pt[j].p.v[k]; } } ptri++; if ( ( ptri - *pptri ) >= MAXTRIANGLES ) { Error( "Error: too many triangles; increase MAXTRIANGLES\n" ); } } } *numtriangles = ptri - *pptri; fclose( input ); }
static void Test2_Poll(void) { struct qsockaddr clientaddr; int control; int len; char name[256]; char value[256]; net_landriverlevel = test2Driver; name[0] = 0; len = dfunc.Read(test2Socket, net_message.data, net_message.maxsize, &clientaddr); if (len < sizeof(int)) { goto Reschedule; } net_message.cursize = len; MSG_BeginReading(); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) { goto Error; } if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) { goto Error; } if ((control & NETFLAG_LENGTH_MASK) != len) { goto Error; } if (MSG_ReadByte() != CCREP_RULE_INFO) { goto Error; } Q_strcpy(name, MSG_ReadString()); if (name[0] == 0) { goto Done; } Q_strcpy(value, MSG_ReadString()); Con_Printf("%-16.16s %-16.16s\n", name, value); SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREQ_RULE_INFO); MSG_WriteString(&net_message, name); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write(test2Socket, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); Reschedule: SchedulePollProcedure(&test2PollProcedure, 0.05); return; Error: Con_Printf("Unexpected repsonse to Rule Info request\n"); Done: dfunc.CloseSocket(test2Socket); test2InProgress = false; return; }
static void Test2_f (void) { const char *host; int n; struct qsockaddr sendaddr; if (test2InProgress) return; host = Strip_Port (Cmd_Argv(1)); if (host && hostCacheCount) { for (n = 0; n < hostCacheCount; n++) { if (q_strcasecmp (host, hostcache[n].name) == 0) { if (hostcache[n].driver != myDriverLevel) continue; net_landriverlevel = hostcache[n].ldriver; Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr)); break; } } if (n < hostCacheCount) goto JustDoIt; } for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) { if (!net_landrivers[net_landriverlevel].initialized) continue; // see if we can resolve the host name if (dfunc.GetAddrFromName(host, &sendaddr) != -1) break; } if (net_landriverlevel == net_numlandrivers) { Con_Printf("Could not resolve %s\n", host); return; } JustDoIt: test2Socket = dfunc.Open_Socket(0); if (test2Socket == INVALID_SOCKET) return; test2InProgress = true; test2Driver = net_landriverlevel; SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREQ_RULE_INFO); MSG_WriteString(&net_message, ""); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (test2Socket, net_message.data, net_message.cursize, &sendaddr); SZ_Clear(&net_message); SchedulePollProcedure(&test2PollProcedure, 0.05); }
int Datagram_GetMessage (qsocket_t *sock) { unsigned int length; unsigned int flags; int ret = 0; struct qsockaddr readaddr; unsigned int sequence; unsigned int count; if (!sock->canSend) if ((net_time - sock->lastSendTime) > 1.0) ReSendMessage (sock); while(1) { length = sfunc.Read (sock->socket, (byte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr); // if ((rand() & 255) > 220) // continue; if (length == 0) break; if (length == -1) { Con_Printf("Read error\n"); return -1; } if (sfunc.AddrCompare(&readaddr, &sock->addr) != 0) { #ifdef DEBUG Con_DPrintf("Forged packet received\n"); Con_DPrintf("Expected: %s\n", StrAddr (&sock->addr)); Con_DPrintf("Received: %s\n", StrAddr (&readaddr)); #endif continue; } if (length < NET_HEADERSIZE) { shortPacketCount++; continue; } length = BigLong(packetBuffer.length); flags = length & (~NETFLAG_LENGTH_MASK); length &= NETFLAG_LENGTH_MASK; // ProQuake extra protection if (length > NET_DATAGRAMSIZE) { Con_Printf ("\002Datagram_GetMessage: "); Con_Printf ("excessive datagram length (%d, max = %d)\n", length, NET_DATAGRAMSIZE); return -1; } if (flags & NETFLAG_CTL) continue; sequence = BigLong(packetBuffer.sequence); packetsReceived++; if (flags & NETFLAG_UNRELIABLE) { if (sequence < sock->unreliableReceiveSequence) { Con_DPrintf("Got a stale datagram\n"); ret = 0; break; } if (sequence != sock->unreliableReceiveSequence) { count = sequence - sock->unreliableReceiveSequence; droppedDatagrams += count; Con_DPrintf("Dropped %u datagram(s)\n", count); } sock->unreliableReceiveSequence = sequence + 1; length -= NET_HEADERSIZE; SZ_Clear (&net_message); SZ_Write (&net_message, packetBuffer.data, length); ret = 2; break; } if (flags & NETFLAG_ACK) { if (sequence != (sock->sendSequence - 1)) { Con_DPrintf("Stale ACK received\n"); continue; } if (sequence == sock->ackSequence) { sock->ackSequence++; if (sock->ackSequence != sock->sendSequence) Con_DPrintf("ack sequencing error\n"); } else { Con_DPrintf("Duplicate ACK received\n"); continue; } sock->sendMessageLength -= MAX_DATAGRAM2; if (sock->sendMessageLength > 0) { Q_memcpy(sock->sendMessage, sock->sendMessage+MAX_DATAGRAM2, sock->sendMessageLength); sock->sendNext = true; } else { sock->sendMessageLength = 0; sock->canSend = true; } continue; } if (flags & NETFLAG_DATA) { packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK); packetBuffer.sequence = BigLong(sequence); sfunc.Write (sock->socket, (byte *)&packetBuffer, NET_HEADERSIZE, &readaddr); if (sequence != sock->receiveSequence) { receivedDuplicateCount++; continue; } sock->receiveSequence++; length -= NET_HEADERSIZE; if (flags & NETFLAG_EOM) { SZ_Clear(&net_message); SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength); SZ_Write(&net_message, packetBuffer.data, length); sock->receiveMessageLength = 0; ret = 1; break; } Q_memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length); sock->receiveMessageLength += length; continue; } } if (sock->sendNext) SendMessageNext (sock); return ret; }
int FPNGTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) { // Parse pre-IDAT chunks. I skip the CRCs. Is that bad? PalEntry pe[256]; DWORD len, id; FileReader *lump; static char bpp[] = {1, 0, 3, 1, 2, 0, 4}; int pixwidth = Width * bpp[ColorType]; int transpal = false; if (SourceLump >= 0) { lump = new FWadLump(Wads.OpenLumpNum(SourceLump)); } else { lump = new FileReader(SourceFile.GetChars()); } lump->Seek(33, SEEK_SET); for(int i = 0; i < 256; i++) // default to a gray map pe[i] = PalEntry(255,i,i,i); lump->Read(&len, 4); lump->Read(&id, 4); while (id != MAKE_ID('I','D','A','T') && id != MAKE_ID('I','E','N','D')) { len = BigLong((unsigned int)len); switch (id) { default: lump->Seek (len, SEEK_CUR); break; case MAKE_ID('P','L','T','E'): for(int i = 0; i < PaletteSize; i++) { (*lump) >> pe[i].r >> pe[i].g >> pe[i].b; } break; case MAKE_ID('t','R','N','S'): for(DWORD i = 0; i < len; i++) { (*lump) >> pe[i].a; if (pe[i].a != 0 && pe[i].a != 255) transpal = true; } break; } lump->Seek(4, SEEK_CUR); // Skip CRC lump->Read(&len, 4); id = MAKE_ID('I','E','N','D'); lump->Read(&id, 4); } BYTE * Pixels = new BYTE[pixwidth * Height]; lump->Seek (StartOfIDAT, SEEK_SET); lump->Read(&len, 4); lump->Read(&id, 4); M_ReadIDAT (lump, Pixels, Width, Height, pixwidth, BitDepth, ColorType, Interlace, BigLong((unsigned int)len)); delete lump; switch (ColorType) { case 0: case 3: bmp->CopyPixelData(x, y, Pixels, Width, Height, 1, Width, rotate, pe, inf); break; case 2: bmp->CopyPixelDataRGB(x, y, Pixels, Width, Height, 3, pixwidth, rotate, CF_RGB, inf); break; case 4: bmp->CopyPixelDataRGB(x, y, Pixels, Width, Height, 2, pixwidth, rotate, CF_IA, inf); transpal = -1; break; case 6: bmp->CopyPixelDataRGB(x, y, Pixels, Width, Height, 4, pixwidth, rotate, CF_RGBA, inf); transpal = -1; break; default: break; } delete[] Pixels; return transpal; }
static void Test_f (void) { char *host; int n; int max = MAX_SCOREBOARD; struct qsockaddr sendaddr; if (testInProgress) return; host = Cmd_Argv (1); if (host && hostCacheCount) { for (n = 0; n < hostCacheCount; n++) if (Q_strcasecmp (host, hostcache[n].name) == 0) { if (hostcache[n].driver != myDriverLevel) continue; net_landriverlevel = hostcache[n].ldriver; max = hostcache[n].maxusers; Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr)); break; } if (n < hostCacheCount) goto JustDoIt; } for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) { if (!net_landrivers[net_landriverlevel].initialized) continue; // see if we can resolve the host name if (dfunc.GetAddrFromName(host, &sendaddr) != -1) break; } if (net_landriverlevel == net_numlandrivers) return; JustDoIt: testSocket = dfunc.OpenSocket(0); if (testSocket == -1) return; testInProgress = true; testPollCount = 20; testDriver = net_landriverlevel; for (n = 0; n < max; n++) { SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREQ_PLAYER_INFO); MSG_WriteByte(&net_message, n); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write (testSocket, net_message.data, net_message.cursize, &sendaddr); } SZ_Clear(&net_message); SchedulePollProcedure(&testPollProcedure, 0.1); }
//----------------------------------------------------------------------------- // A Scene image file contains all the compiled .XCD //----------------------------------------------------------------------------- bool CSceneImage::CreateSceneImageFile( CUtlBuffer &targetBuffer, char const *pchModPath, bool bLittleEndian, bool bQuiet, ISceneCompileStatus *pStatus ) { CUtlVector<fileList_t> vcdFileList; CUtlSymbolTable vcdSymbolTable( 0, 32, true ); Msg( "\n" ); // get all the VCD files according to the seacrh paths char searchPaths[512]; g_pFullFileSystem->GetSearchPath( "GAME", false, searchPaths, sizeof( searchPaths ) ); char *pPath = strtok( searchPaths, ";" ); while ( pPath ) { int currentCount = vcdFileList.Count(); char szPath[MAX_PATH]; V_ComposeFileName( pPath, "scenes/*.vcd", szPath, sizeof( szPath ) ); scriptlib->FindFiles( szPath, true, vcdFileList ); Msg( "Scenes: Searching '%s' - Found %d scenes.\n", szPath, vcdFileList.Count() - currentCount ); pPath = strtok( NULL, ";" ); } if ( !vcdFileList.Count() ) { Msg( "Scenes: No Scene Files found!\n" ); return false; } // iterate and convert all the VCD files bool bGameIsTF = V_stristr( pchModPath, "\\tf" ) != NULL; for ( int i=0; i<vcdFileList.Count(); i++ ) { const char *pFilename = vcdFileList[i].fileName.String(); const char *pSceneName = V_stristr( pFilename, "scenes\\" ); if ( !pSceneName ) { continue; } if ( !bLittleEndian && bGameIsTF && V_stristr( pSceneName, "high\\" ) ) { continue; } // process files in order they would be found in search paths // i.e. skipping later processed files that match an earlier conversion UtlSymId_t symbol = vcdSymbolTable.Find( pSceneName ); if ( symbol == UTL_INVAL_SYMBOL ) { vcdSymbolTable.AddString( pSceneName ); pStatus->UpdateStatus( pFilename, bQuiet, i, vcdFileList.Count() ); if ( !CreateTargetFile_VCD( pFilename, "", false, bLittleEndian ) ) { Error( "CreateSceneImageFile: Failed on '%s' conversion!\n", pFilename ); } } } if ( !g_SceneFiles.Count() ) { // nothing to do return true; } Msg( "Scenes: Finalizing %d unique scenes.\n", g_SceneFiles.Count() ); // get the string pool CUtlVector< unsigned int > stringOffsets; CUtlBuffer stringPool; g_ChoreoStringPool.GetTableAndPool( stringOffsets, stringPool ); if ( !bQuiet ) { Msg( "Scenes: String Table: %d bytes\n", stringOffsets.Count() * sizeof( int ) ); Msg( "Scenes: String Pool: %d bytes\n", stringPool.TellMaxPut() ); } // first header, then lookup table, then string pool blob int stringPoolStart = sizeof( SceneImageHeader_t ) + stringOffsets.Count() * sizeof( int ); // then directory int sceneEntryStart = stringPoolStart + stringPool.TellMaxPut(); // then variable sized summaries int sceneSummaryStart = sceneEntryStart + g_SceneFiles.Count() * sizeof( SceneImageEntry_t ); // then variable sized compiled binary scene data int sceneDataStart = 0; // construct header SceneImageHeader_t imageHeader = { 0 }; imageHeader.nId = SCENE_IMAGE_ID; imageHeader.nVersion = SCENE_IMAGE_VERSION; imageHeader.nNumScenes = g_SceneFiles.Count(); imageHeader.nNumStrings = stringOffsets.Count(); imageHeader.nSceneEntryOffset = sceneEntryStart; if ( !bLittleEndian ) { imageHeader.nId = BigLong( imageHeader.nId ); imageHeader.nVersion = BigLong( imageHeader.nVersion ); imageHeader.nNumScenes = BigLong( imageHeader.nNumScenes ); imageHeader.nNumStrings = BigLong( imageHeader.nNumStrings ); imageHeader.nSceneEntryOffset = BigLong( imageHeader.nSceneEntryOffset ); } targetBuffer.Put( &imageHeader, sizeof( imageHeader ) ); // header is immediately followed by string table and pool for ( int i = 0; i < stringOffsets.Count(); i++ ) { unsigned int offset = stringPoolStart + stringOffsets[i]; if ( !bLittleEndian ) { offset = BigLong( offset ); } targetBuffer.PutInt( offset ); } Assert( stringPoolStart == targetBuffer.TellMaxPut() ); targetBuffer.Put( stringPool.Base(), stringPool.TellMaxPut() ); // construct directory CUtlSortVector< SceneImageEntry_t, CSceneImageEntryLessFunc > imageDirectory; imageDirectory.EnsureCapacity( g_SceneFiles.Count() ); // build directory // directory is linear sorted by filename checksum for later binary search for ( int i = 0; i < g_SceneFiles.Count(); i++ ) { SceneImageEntry_t imageEntry = { 0 }; // name needs to be normalized for determinstic later CRC name calc // calc crc based on scenes\anydir\anyscene.vcd char szCleanName[MAX_PATH]; V_strncpy( szCleanName, g_SceneFiles[i].fileName.String(), sizeof( szCleanName ) ); V_strlower( szCleanName ); V_FixSlashes( szCleanName ); char *pName = V_stristr( szCleanName, "scenes\\" ); if ( !pName ) { // must have scenes\ in filename Error( "CreateSceneImageFile: Unexpected lack of scenes prefix on %s\n", g_SceneFiles[i].fileName.String() ); } CRC32_t crcFilename = CRC32_ProcessSingleBuffer( pName, strlen( pName ) ); imageEntry.crcFilename = crcFilename; // temp store an index to its file, fixup later, necessary to access post sort imageEntry.nDataOffset = i; if ( imageDirectory.Find( imageEntry ) != imageDirectory.InvalidIndex() ) { // filename checksums must be unique or runtime binary search would be bogus Error( "CreateSceneImageFile: Unexpected filename checksum collision!\n" ); } imageDirectory.Insert( imageEntry ); } // determine sort order and start of data after dynamic summaries CUtlVector< int > writeOrder; writeOrder.EnsureCapacity( g_SceneFiles.Count() ); sceneDataStart = sceneSummaryStart; for ( int i = 0; i < imageDirectory.Count(); i++ ) { // reclaim offset, indicates write order of scene file int iScene = imageDirectory[i].nDataOffset; writeOrder.AddToTail( iScene ); // march past each variable sized summary to determine start of scene data int numSounds = g_SceneFiles[iScene].soundList.Count(); sceneDataStart += sizeof( SceneImageSummary_t ) + ( numSounds - 1 ) * sizeof( int ); } // finalize and write directory Assert( sceneEntryStart == targetBuffer.TellMaxPut() ); int nSummaryOffset = sceneSummaryStart; int nDataOffset = sceneDataStart; for ( int i = 0; i < imageDirectory.Count(); i++ ) { int iScene = writeOrder[i]; imageDirectory[i].nDataOffset = nDataOffset; imageDirectory[i].nDataLength = g_SceneFiles[iScene].compiledBuffer.TellMaxPut(); imageDirectory[i].nSceneSummaryOffset = nSummaryOffset; if ( !bLittleEndian ) { imageDirectory[i].crcFilename = BigLong( imageDirectory[i].crcFilename ); imageDirectory[i].nDataOffset = BigLong( imageDirectory[i].nDataOffset ); imageDirectory[i].nDataLength = BigLong( imageDirectory[i].nDataLength ); imageDirectory[i].nSceneSummaryOffset = BigLong( imageDirectory[i].nSceneSummaryOffset ); } targetBuffer.Put( &imageDirectory[i], sizeof( SceneImageEntry_t ) ); int numSounds = g_SceneFiles[iScene].soundList.Count(); nSummaryOffset += sizeof( SceneImageSummary_t ) + (numSounds - 1) * sizeof( int ); nDataOffset += g_SceneFiles[iScene].compiledBuffer.TellMaxPut(); } // finalize and write summaries Assert( sceneSummaryStart == targetBuffer.TellMaxPut() ); for ( int i = 0; i < imageDirectory.Count(); i++ ) { int iScene = writeOrder[i]; int msecs = g_SceneFiles[iScene].msecs; int soundCount = g_SceneFiles[iScene].soundList.Count(); if ( !bLittleEndian ) { msecs = BigLong( msecs ); soundCount = BigLong( soundCount ); } targetBuffer.PutInt( msecs ); targetBuffer.PutInt( soundCount ); for ( int j = 0; j < g_SceneFiles[iScene].soundList.Count(); j++ ) { int soundId = g_SceneFiles[iScene].soundList[j]; if ( !bLittleEndian ) { soundId = BigLong( soundId ); } targetBuffer.PutInt( soundId ); } } // finalize and write data Assert( sceneDataStart == targetBuffer.TellMaxPut() ); for ( int i = 0; i < imageDirectory.Count(); i++ ) { int iScene = writeOrder[i]; targetBuffer.Put( g_SceneFiles[iScene].compiledBuffer.Base(), g_SceneFiles[iScene].compiledBuffer.TellMaxPut() ); } if ( !bQuiet ) { Msg( "Scenes: Final size: %.2f MB\n", targetBuffer.TellMaxPut() / (1024.0f * 1024.0f ) ); } // cleanup g_SceneFiles.Purge(); return true; }