void appStrcatn(char *dst, int count, const char *src) { char *p = strchr(dst, 0); int maxLen = count - (p - dst); if (maxLen > 1) appStrncpyz(p, src, maxLen); }
void appMakeDirectory(const char *dirname) { if (!dirname[0]) return; // Win32 and Unix: there is no API to create directory chains // so - we will create "a", then "a/b", then "a/b/c" char Name[256]; appStrncpyz(Name, dirname, ARRAY_COUNT(Name)); appNormalizeFilename(Name); for (char *s = Name; /* empty */ ; s++) { char c = *s; if (c != '/' && c != 0) continue; *s = 0; // temporarily cut rest of path // here: path delimiter or end of string if (Name[0] != '.' || Name[1] != 0) // do not create "." #if _WIN32 _mkdir(Name); #else mkdir(Name, S_IRWXU); #endif if (!c) break; // end of string *s = '/'; // restore string (c == '/') } }
void appSetRootDirectory(const char *dir, bool recurse) { guard(appSetRootDirectory); if (dir[0] == 0) dir = "."; // using dir="" will cause scanning of "/dir1", "/dir2" etc (i.e. drive root) appStrncpyz(RootDirectory, dir, ARRAY_COUNT(RootDirectory)); ScanGameDirectory(RootDirectory, recurse); appPrintf("Found %d game files (%d skipped)\n", GNumGameFiles, GNumForeignFiles); #if PRINT_HASH_DISTRIBUTION PrintHashDistribution(); #endif unguardf("dir=%s", dir); }
void appMakeDirectoryForFile(const char *filename) { char Name[256]; appStrncpyz(Name, filename, ARRAY_COUNT(Name)); appNormalizeFilename(Name); char *s = strrchr(Name, '/'); if (s) { *s = 0; appMakeDirectory(Name); } }
unsigned appGetFileType(const char *filename) { char Name[256]; appStrncpyz(Name, filename, ARRAY_COUNT(Name)); appNormalizeFilename(Name); struct stat buf; if (stat(filename, &buf) == -1) return 0; // no such file/dir if (S_ISDIR(buf.st_mode)) return FS_DIR; else if (S_ISREG(buf.st_mode)) return FS_FILE; return 0; // just in case ... (may be, win32 have other file types?) }
static void Field_Draw(menuField_t *f) { int i; char tempbuffer[128]; // draw caption if (f->name) Menu_DrawStringR2L(f->x + f->parent->x + LCOLUMN_OFFSET, f->y + f->parent->y, va(S_GREEN"%s", f->name)); int x = f->x + f->parent->x; int y = f->y + f->parent->y; // draw border #if 1 RE_DrawChar(x + CHAR_WIDTH * 2, y - CHAR_HEIGHT/2, 18); // left RE_DrawChar(x + CHAR_WIDTH * 2, y + CHAR_HEIGHT/2, 24); RE_DrawChar(x + (f->visible_length + 3) * CHAR_WIDTH, y - CHAR_HEIGHT/2, 20); // right RE_DrawChar(x + (f->visible_length + 3) * CHAR_WIDTH, y + CHAR_HEIGHT/2, 26); for (i = 0; i < f->visible_length; i++) { RE_DrawChar(x + (i + 3) * CHAR_WIDTH, y - CHAR_HEIGHT/2, 19); // top RE_DrawChar(x + (i + 3) * CHAR_WIDTH, y + CHAR_HEIGHT/2, 25); // bottom } #else RE_Fill(x + CHAR_WIDTH * 2, y - CHAR_HEIGHT / 2, (f->visible_length + 2) * CHAR_WIDTH, CHAR_HEIGHT * 2, RGBA(1, 0, 0, 0.2)); #endif // perform string drawing without text coloring appStrncpyz(tempbuffer, f->buffer + f->visible_offset, max(f->visible_length, sizeof(tempbuffer))); const char *s = tempbuffer; int x1 = x + 3 * CHAR_WIDTH; while (char c = *s++) { RE_DrawChar(x1, y, c); x1 += CHAR_WIDTH; } if (f->parent->ItemAtCursor() == f) { int offset = (f->visible_offset) ? f->visible_length : f->cursor; // show cursor RE_DrawChar(x + (offset + 3) * CHAR_WIDTH, y, ((cls.realtime >> 8) & 1) ? 11 : ' '); }
//?? TODO: may be pass "Ext" here void appFindGameFiles(const char *Filename, TArray<const CGameFileInfo*>& Files) { guard(appFindGameFiles); if (!appContainsWildcard(Filename)) { const CGameFileInfo* File = appFindGameFile(Filename); if (File) Files.Add(File); return; } // here we're working with wildcard and should iterate over all files char buf[MAX_PACKAGE_PATH]; appStrncpyz(buf, Filename, ARRAY_COUNT(buf)); // replace backslashes bool containsPath = false; for (char* s = buf; *s; s++) { char c = *s; if (c == '\\') { *s = '/'; containsPath = true; } else if (c == '/') { containsPath = true; } } FindPackageWildcardData findData; findData.WildcardContainsPath = containsPath; findData.Wildcard = buf; appEnumGameFiles(FindPackageWildcardCallback, findData); CopyArray(Files, findData.FoundFiles); unguardf("wildcard=%s", Filename); }
const CGameFileInfo *appFindGameFile(const char *Filename, const char *Ext) { guard(appFindGameFile); #if UNREAL3 bool findStartupPackage = (strcmp(Filename, GStartupPackage) == 0); if (findStartupPackage) return GStartupPackageInfo; #endif char buf[MAX_PACKAGE_PATH]; appStrncpyz(buf, Filename, ARRAY_COUNT(buf)); // replace backslashes const char* ShortFilename = buf; for (char* s = buf; *s; s++) { char c = *s; if (c == '\\') *s = '/'; if (*s == '/') ShortFilename = s + 1; } if (Ext) { // extension is provided assert(!strchr(buf, '.')); } else { // check for extension in filename char *s = strrchr(buf, '.'); if (s) { Ext = s + 1; // remember extension *s = 0; // cut extension } } int nameLen = strlen(ShortFilename); int hash = GetHashForFileName(buf); #ifdef DEBUG_HASH_NAME printf("--> Loading %s (%s, len=%d)\n", buf, ShortFilename, nameLen); #endif CGameFileInfo* bestMatch = NULL; int bestMatchWeight = -1; for (CGameFileInfo* info = GGameFileHash[hash]; info; info = info->HashNext) { #ifdef DEBUG_HASH_NAME printf("----> verify %s\n", info->RelativeName); #endif if (info->Extension - 1 - info->ShortFilename != nameLen) // info->Extension points to char after '.' { // printf("-----> wrong length %d\n", info->Extension - info->ShortFilename); continue; // different filename length } // verify extension if (Ext) { if (stricmp(info->Extension, Ext) != 0) continue; } else { // Ext = NULL => should be any package extension if (!info->IsPackage) continue; } // verify a filename if (strnicmp(info->ShortFilename, ShortFilename, nameLen) != 0) continue; // if (info->ShortFilename[nameLen] != '.') -- verified before extension comparison // continue; // Short filename matched, now compare path before the filename. // Assume 'ShortFilename' is part of 'buf' and 'info->ShortFilename' is part of 'info->RelativeName'. int matchWeight = 0; const char *s = ShortFilename; const char *d = info->ShortFilename; while (--s >= buf && --d >= info->RelativeName) { if (*s != *d) break; matchWeight++; } // printf("--> matched: %s (weight=%d)\n", info->RelativeName, matchWeight); if (matchWeight > bestMatchWeight) { // printf("---> better match\n"); bestMatch = info; bestMatchWeight = matchWeight; } } return bestMatch; unguardf("name=%s ext=%s", Filename, Ext); }
void appSetRootDirectory2(const char *filename) { char buf[MAX_PACKAGE_PATH], buf2[MAX_PACKAGE_PATH]; appStrncpyz(buf, filename, ARRAY_COUNT(buf)); char *s; // replace slashes for (s = buf; *s; s++) if (*s == '\\') *s = '/'; // cut filename s = strrchr(buf, '/'); *s = 0; // make a copy for fallback strcpy(buf2, buf); FString root; int detected = 0; // weigth; 0 = not detected root = buf; // analyze path const char *pCooked = NULL; for (int i = 0; i < 8; i++) { // find deepest directory name s = strrchr(buf, '/'); if (!s) break; *s++ = 0; bool found = false; if (i == 0) { for (int j = 0; j < ARRAY_COUNT(KnownDirs2); j++) if (!stricmp(KnownDirs2[j], s)) { found = true; break; } } if (found) { if (detected < 1) { detected = 1; root = buf; } } pCooked = appStristr(s, "Cooked"); if (pCooked || appStristr(s, "Content")) { s[-1] = '/'; // put it back if (detected < 2) { detected = 2; root = buf; break; } } } appPrintf("Detected game root %s%s", *root, (detected == false) ? " (no recurse)" : ""); // detect platform if (GForcePlatform == PLATFORM_UNKNOWN && pCooked) { pCooked += 6; // skip "Cooked" string if (!strnicmp(pCooked, "PS3", 3)) GForcePlatform = PLATFORM_PS3; else if (!strnicmp(pCooked, "Xenon", 5)) GForcePlatform = PLATFORM_XBOX360; else if (!strnicmp(pCooked, "IPhone", 6)) GForcePlatform = PLATFORM_IOS; if (GForcePlatform != PLATFORM_UNKNOWN) { static const char *PlatformNames[] = { "", "PC", "XBox360", "PS3", "iPhone", "Android", }; staticAssert(ARRAY_COUNT(PlatformNames) == PLATFORM_COUNT, Verify_PlatformNames); appPrintf("; platform %s", PlatformNames[GForcePlatform]); } } // scan root directory appPrintf("\n"); appSetRootDirectory(*root, detected); }
static bool RegisterGameFile(const char *FullName, FVirtualFileSystem* parentVfs = NULL) { guard(RegisterGameFile); // printf("..file %s\n", FullName); // return false when MAX_GAME_FILES if (GNumGameFiles >= ARRAY_COUNT(GameFiles)) return false; if (!parentVfs) // no nested VFSs { const char* ext = strrchr(FullName, '.'); if (ext) { guard(MountVFS); ext++; FVirtualFileSystem* vfs = NULL; FArchive* reader = NULL; #if SUPPORT_ANDROID if (!stricmp(ext, "obb")) { GForcePlatform = PLATFORM_ANDROID; reader = new FFileReader(FullName); if (!reader) return true; reader->Game = GAME_UE3; vfs = new FObbVFS(); } #endif // SUPPORT_ANDROID #if UNREAL4 if (!stricmp(ext, "pak")) { reader = new FFileReader(FullName); if (!reader) return true; reader->Game = GAME_UE4; vfs = new FPakVFS(); //!! detect game by file name } #endif // UNREAL4 //!! process other VFS types here if (vfs) { assert(reader); // read VF directory if (!vfs->AttachReader(reader)) { // something goes wrong delete vfs; delete reader; return true; } // add game files int NumVFSFiles = vfs->NumFiles(); for (int i = 0; i < NumVFSFiles; i++) { if (!RegisterGameFile(vfs->FileName(i), vfs)) return false; } return true; } unguard; } } bool IsPackage; if (FindExtension(FullName, ARRAY_ARG(PackageExtensions))) { IsPackage = true; } else { #if HAS_SUPORT_FILES if (!FindExtension(FullName, ARRAY_ARG(KnownExtensions))) #endif { // perhaps this file was exported by our tool - skip it if (FindExtension(FullName, ARRAY_ARG(SkipExtensions))) return true; // unknown file type if (++GNumForeignFiles >= MAX_FOREIGN_FILES) appError("Too much unknown files - bad root directory (%s)?", RootDirectory); return true; } IsPackage = false; } // create entry CGameFileInfo *info = new CGameFileInfo; GameFiles[GNumGameFiles++] = info; info->IsPackage = IsPackage; info->FileSystem = parentVfs; if (IsPackage) GNumPackageFiles++; if (!parentVfs) { // regular file FILE* f = fopen(FullName, "rb"); if (f) { fseek(f, 0, SEEK_END); info->SizeInKb = (ftell(f) + 512) / 1024; fclose(f); } else { info->SizeInKb = 0; } // cut RootDirectory from filename const char *s = FullName + strlen(RootDirectory) + 1; assert(s[-1] == '/'); appStrncpyz(info->RelativeName, s, ARRAY_COUNT(info->RelativeName)); } else { // file in virtual file system info->SizeInKb = parentVfs->GetFileSize(FullName); appStrncpyz(info->RelativeName, FullName, ARRAY_COUNT(info->RelativeName)); } // find filename const char* s = strrchr(info->RelativeName, '/'); if (s) s++; else s = info->RelativeName; info->ShortFilename = s; // find extension s = strrchr(info->ShortFilename, '.'); if (s) s++; info->Extension = s; // printf(".. -> %s (pkg=%d)\n", info->ShortFilename, info->IsPackage); #if UNREAL3 if (info->IsPackage && (strnicmp(info->ShortFilename, "startup", 7) == 0)) { // Register a startup package // possible name variants: // - startup // - startup_int // - startup_* int startupWeight = 0; if (info->ShortFilename[7] == '.') startupWeight = 30; // "startup.upk" else if (strnicmp(info->ShortFilename+7, "_int.", 5) == 0) startupWeight = 20; // "startup_int.upk" else if (strnicmp(info->ShortFilename+7, "_loc_int.", 9) == 0) startupWeight = 20; // "startup_int.upk" else if (info->ShortFilename[7] == '_') startupWeight = 1; // non-int locale, lower priority - use if when other is not detected if (startupWeight > GStartupPackageInfoWeight) { GStartupPackageInfoWeight = startupWeight; GStartupPackageInfo = info; } } #endif // UNREAL3 // insert CGameFileInfo into hash table int hash = GetHashForFileName(info->ShortFilename); info->HashNext = GGameFileHash[hash]; GGameFileHash[hash] = info; return true; unguardf("%s", FullName); }
static bool ReadXprFile(const CGameFileInfo *file) { guard(ReadXprFile); FArchive *Ar = appCreateFileReader(file); int Tag, FileLen, DataStart, DataCount; *Ar << Tag << FileLen << DataStart << DataCount; //?? "XPR0" - xpr variant with a single object (texture) inside if (Tag != BYTES4('X','P','R','1')) { #if XPR_DEBUG appPrintf("Unknown XPR tag in %s\n", file->RelativeName); #endif delete Ar; return true; } #if XPR_DEBUG appPrintf("Scanning %s ...\n", file->RelativeName); #endif XprInfo *Info = new(xprFiles) XprInfo; Info->File = file; Info->DataStart = DataStart; // read filelist int i; for (i = 0; i < DataCount; i++) { int NameOffset, DataOffset; *Ar << NameOffset << DataOffset; int savePos = Ar->Tell(); Ar->Seek(NameOffset + 12); // read name char c, buf[256]; int n = 0; while (true) { *Ar << c; if (n < ARRAY_COUNT(buf)) buf[n++] = c; if (!c) break; } buf[ARRAY_COUNT(buf)-1] = 0; // just in case // create item XprEntry *Entry = new(Info->Items) XprEntry; appStrncpyz(Entry->Name, buf, ARRAY_COUNT(Entry->Name)); Entry->DataOffset = DataOffset + 12; assert(Entry->DataOffset < DataStart); // seek back Ar->Seek(savePos); // setup size of previous item if (i >= 1) { XprEntry *PrevEntry = &Info->Items[i - 1]; PrevEntry->DataSize = Entry->DataOffset - PrevEntry->DataOffset; } // setup size of the last item if (i == DataCount - 1) Entry->DataSize = DataStart - Entry->DataOffset; } // scan data // data block is either embedded in this block or followed after DataStart position for (i = 0; i < DataCount; i++) { XprEntry *Entry = &Info->Items[i]; #if XPR_DEBUG // appPrintf(" %08X [%08X] %s\n", Entry->DataOffset, Entry->DataSize, Entry->Name); #endif Ar->Seek(Entry->DataOffset); int id; *Ar << id; switch (id) { case 0x80020001: // header is 4 dwords + immediately followed data Entry->DataOffset += 4 * 4; Entry->DataSize -= 4 * 4; break; case 0x00040001: // header is 5 dwords + external data { int pos; *Ar << pos; Entry->DataOffset = DataStart + pos; } break; case 0x00020001: // header is 4 dwords + external data { int d1, d2, pos; *Ar << d1 << d2 << pos; Entry->DataOffset = DataStart + pos; } break; default: // header is 2 dwords - offset and size + external data { int pos; *Ar << pos; Entry->DataOffset = DataStart + pos; } break; } } // setup sizes of blocks placed after DataStart (not embedded into file list) for (i = 0; i < DataCount; i++) { XprEntry *Entry = &Info->Items[i]; if (Entry->DataOffset < DataStart) continue; // embedded data // Entry points to a data block placed after DataStart position // we should find a next block int NextPos = FileLen; for (int j = i + 1; j < DataCount; j++) { XprEntry *NextEntry = &Info->Items[j]; if (NextEntry->DataOffset < DataStart) continue; // embedded data NextPos = NextEntry->DataOffset; break; } Entry->DataSize = NextPos - Entry->DataOffset; } #if XPR_DEBUG for (i = 0; i < DataCount; i++) { XprEntry *Entry = &Info->Items[i]; appPrintf(" %3d %08X [%08X] .. %08X %s\n", i, Entry->DataOffset, Entry->DataSize, Entry->DataOffset + Entry->DataSize, Entry->Name); } #endif delete Ar; return true; unguardf("%s", file->RelativeName); }
FString ShowFileSelectionDialog( bool bIsSaveDialog, UIBaseDialog* ParentDialog, const FString& InitialFilename, const FString& InitialDirectory, const FString& Title, const TArray<FString>& Filters) { OPENFILENAME ofn; memset(&ofn, 0, sizeof(ofn)); char szPathName[1024]; appStrncpyz(szPathName, *InitialFilename, ARRAY_COUNT(szPathName)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = ParentDialog->GetWnd(); ofn.lpstrFile = szPathName; ofn.nMaxFile = ARRAY_COUNT(szPathName); // Build filters string. It consists of null-terminated strings concatenated // into single buffer. Ends with extra null character. FStaticString<1024> filterBuf; for (int i = 0; i < Filters.Num(); i++) { const char* s = *Filters[i]; const char* s2 = strchr(s, '|'); if (s2) { int delimRSize = Filters[i].Len() - int(s2 - s); filterBuf += s; filterBuf[filterBuf.Len() - delimRSize] = 0; filterBuf.AppendChar(0); } else { filterBuf += s; filterBuf.AppendChar(0); filterBuf += s; filterBuf.AppendChar(0); } } // Add "all files" filter, and finish it with extra null character. filterBuf += "All Files (*.*)"; filterBuf.AppendChar(0); filterBuf += "*.*"; filterBuf.AppendChar(0); filterBuf.AppendChar(0); ofn.lpstrFilter = *filterBuf; if (!InitialDirectory.IsEmpty()) { ofn.lpstrInitialDir = *InitialDirectory; } if (!Title.IsEmpty()) { ofn.lpstrTitle = *Title; } ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLESIZING | OFN_EXPLORER; if (bIsSaveDialog) { ofn.Flags |= OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT | OFN_NOVALIDATE; } else { ofn.Flags |= OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; } int bSuccess = (bIsSaveDialog) ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn); if (bSuccess) { return szPathName; } else { return ""; } }
// Mask variants: // 1) * - any file // 2) *.* - any file // 3) *rest - name ends with "rest" (for example, ".ext") // 4) start* - name starts with "start" // 4) text - name equals "text" // Comparision is case-sensitive, when ignoreCase == false (default) // A few masks can be separated with ',' bool appMatchWildcard(const char *name, const char *mask, bool ignoreCase) { guard(appMatchWildcard); if (!name[0] && !mask[0]) return true; // empty strings matched char NameCopy[1024], MaskCopy[1024]; if (ignoreCase) { appStrncpylwr(NameCopy, name, ARRAY_COUNT(NameCopy)); appStrncpylwr(MaskCopy, mask, ARRAY_COUNT(MaskCopy)); } else { appStrncpyz(NameCopy, name, ARRAY_COUNT(NameCopy)); appStrncpyz(MaskCopy, mask, ARRAY_COUNT(MaskCopy)); } int namelen = strlen(NameCopy); // can use TStringSplitter here const char *next; for (mask = MaskCopy; mask; mask = next) { // find next wildcard (comma-separated) next = strchr(mask, ','); int masklen; if (next) { masklen = next - mask; next++; // skip ',' } else masklen = strlen(mask); if (!masklen) { // used something like "mask1,,mask3" (2nd mask is empty) //?? appPrintf("appMatchWildcard: skip empty mask in \"%s\"\n", mask); continue; } // check for a trivial wildcard if (mask[0] == '*') { if (masklen == 1 || (masklen == 3 && mask[1] == '.' && mask[2] == '*')) return true; // "*" or "*.*" -- any name valid } // "*text*" mask if (masklen >= 3 && mask[0] == '*' && mask[masklen-1] == '*') { int i; mask++; masklen -= 2; for (i = 0; i <= namelen - masklen; i++) if (!memcmp(&NameCopy[i], mask, masklen)) return true; } else { // "*text" or "text*" mask const char *suff = strchr(mask, '*'); if (next && suff >= next) suff = NULL; // suff can be in next wildcard if (suff) { int preflen = suff - mask; int sufflen = masklen - preflen - 1; suff++; if (namelen < preflen + sufflen) continue; // name is not long enough if (preflen && memcmp(NameCopy, mask, preflen)) continue; // different prefix if (sufflen && memcmp(NameCopy + namelen - sufflen, suff, sufflen)) continue; // different suffix return true; } // exact match ("text") if (namelen == masklen && !memcmp(NameCopy, mask, namelen)) return true; } } return false; unguard; }
/* ================== cDirectConnect A connection request that did not come from the master ================== */ static void cDirectConnect(int argc, char **argv) { int i; netadr_t adr = net_from; Com_DPrintf("SVC_DirectConnect()\n"); int version = atoi(argv[1]); if (version != PROTOCOL_VERSION) { Netchan_OutOfBandPrint(NS_SERVER, adr, "print\nServer is version %4.2f.\n", VERSION); Com_DPrintf(" rejected connect from version %d\n", version); return; } int port = atoi(argv[2]); int challenge = atoi(argv[3]); // get userinfo char userinfo[MAX_INFO_STRING]; appStrncpyz(userinfo, argv[4], sizeof(userinfo)); // force the IP key/value pair to be in userinfo (for game-side IP filters) Info_SetValueForKey(userinfo, "ip", NET_AdrToString(&net_from)); // attractloop servers are ONLY for local clients if (sv.attractloop) { if (!NET_IsLocalAddress(&adr)) { appPrintf("Remote connect in attract loop. Ignored.\n"); Netchan_OutOfBandPrint(NS_SERVER, adr, "print\nConnection refused.\n"); return; } } // see if the challenge is valid if (!NET_IsLocalAddress(&adr)) { for (i = 0; i < MAX_CHALLENGES; i++) if (NET_CompareBaseAdr(&net_from, &svs.challenges[i].adr)) { if (challenge == svs.challenges[i].challenge) break; // good Netchan_OutOfBandPrint(NS_SERVER, adr, "print\nBad challenge.\n"); return; } if (i == MAX_CHALLENGES) { Netchan_OutOfBandPrint(NS_SERVER, adr, "print\nNo challenge for address.\n"); return; } } client_t temp, *cl; memset(&temp, 0, sizeof(client_t)); client_t *newcl = NULL; // if there is already a slot for this ip, reuse it for (i = 0, cl = svs.clients; i < sv_maxclients->integer; i++,cl++) { if (cl->state == cs_free) continue; if (NET_CompareBaseAdr(&adr, &cl->netchan.remote_address) && (cl->netchan.port == port || adr.port == cl->netchan.remote_address.port)) { if (!NET_IsLocalAddress(&adr) && (svs.realtime - cl->lastconnect) < (sv_reconnect_limit->integer * 1000)) { Com_DPrintf("%s:reconnect rejected : too soon\n", NET_AdrToString(&adr)); return; } appPrintf("%s:reconnect\n", NET_AdrToString(&adr)); newcl = cl; break; } } // find a client slot if (!newcl) { for (i = 0, cl = svs.clients; i < sv_maxclients->integer; i++,cl++) if (cl->state == cs_free) { newcl = cl; break; } } if (!newcl) { Netchan_OutOfBandPrint(NS_SERVER, adr, "print\nServer is full.\n"); Com_DPrintf("Rejected a connection.\n"); return; } // build a new connection // accept the new client // this is the only place a client_t is ever initialized *newcl = temp; sv_client = newcl; int edictnum = (newcl-svs.clients)+1; edict_t *ent = EDICT_NUM(edictnum); newcl->edict = ent; newcl->challenge = challenge; // save challenge for checksumming // get the game a chance to reject this connection or modify the userinfo qboolean result; guardGame(ge.ClientConnect); result = ge->ClientConnect(ent, userinfo); unguardGame; if (!result) { if (*Info_ValueForKey(userinfo, "rejmsg")) Netchan_OutOfBandPrint(NS_SERVER, adr, "print\n%s\nConnection refused.\n", Info_ValueForKey(userinfo, "rejmsg")); else Netchan_OutOfBandPrint(NS_SERVER, adr, "print\nConnection refused.\n" ); Com_DPrintf("Game rejected a connection.\n"); return; } // parse some info from the info strings newcl->Userinfo = userinfo; SV_UserinfoChanged(newcl); // check if client trying to connect with a new protocol newcl->newprotocol = !strcmp(argv [5], NEW_PROTOCOL_ID) && sv_extProtocol->integer; // send the connect packet to the client if (newcl->newprotocol) { int ver = atoi(argv[6]); if (ver != NEW_PROTOCOL_VERSION) { //?? we may also perform extended protocol checking by adding "[cl_]extprotocol" to userinfo Com_DPrintf("Client used extended protocol %d != "STR(NEW_PROTOCOL_VERSION)"\n", ver); if (ver < NEW_PROTOCOL_VERSION) Netchan_OutOfBandPrint(NS_SERVER, adr, "print\n" S_YELLOW"Server provides newer version of extended protocol\nPlease upgrade your client\n" ); newcl->newprotocol = false; } } if (newcl->newprotocol) { Com_DPrintf("Connecting client using extended protocol\n"); Netchan_OutOfBandPrint(NS_SERVER, adr, "client_connect "NEW_PROTOCOL_ID" "STR(NEW_PROTOCOL_VERSION)); } else Netchan_OutOfBandPrint(NS_SERVER, adr, "client_connect"); newcl->netchan.Setup(NS_SERVER, adr, port); newcl->maxPacketSize = cl->newprotocol ? MAX_MSGLEN : MAX_MSGLEN_OLD; newcl->state = cs_connected; newcl->datagram.Init(newcl->datagram_buf, sizeof(newcl->datagram_buf)); newcl->datagram.allowoverflow = true; newcl->lastmessage = svs.realtime; // don't timeout newcl->lastconnect = svs.realtime; }
char *Sys_ConsoleInput() { guard(Sys_ConsoleInput); #if !NO_DEDICATED if (console_drawInput) { // display input line Win32Log.WriteChar(']'); if (console_textlen) { console_text[console_textlen] = 0; Win32Log.WriteStr(console_text); } console_drawInput = false; } while (true) { DWORD numevents, numread; GetNumberOfConsoleInputEvents(hConInput, &numevents); if (numevents <= 0) break; INPUT_RECORD rec; ReadConsoleInput(hConInput, &rec, 1, &numread); if (rec.EventType == KEY_EVENT && rec.Event.KeyEvent.bKeyDown) { int ch = rec.Event.KeyEvent.uChar.AsciiChar; switch (ch) { case '\r': // ENTER Win32Log.WriteStr("\r\n"); console_drawInput = true; if (console_textlen) { console_textlen = 0; return console_text; } break; case '\b': // BACKSPACE if (console_textlen) { console_text[--console_textlen] = 0; Win32Log.WriteStr("\b \b"); } break; case '\t': // TAB { appSprintf(ARRAY_ARG(editLine), "]%s", console_text); CompleteCommand(); const char *s = editLine; if (s[0] == ']') s++; if (s[0] == '/') s++; int len = strlen(s); if (len > 0) { console_textlen = min(len, sizeof(console_text)-2); appStrncpyz(console_text, s, console_textlen+1); Win32Log.EraseInput(); console_drawInput = true; // next time ... } } break; case '\x1B': // ESC Win32Log.EraseInput(); console_textlen = 0; console_text[0] = 0; break; default: if (ch >= ' ') { if (console_textlen < sizeof(console_text)-2) { Win32Log.WriteChar(ch); console_text[console_textlen++] = ch; console_text[console_textlen] = 0; } } // else // appPrintf("%2X\n",ch); break; } } } #endif return NULL; unguard; }