void CCountryFlags::LoadCountryflagsIndexfile() { IOHANDLE File = Storage()->OpenFile("countryflags/index.txt", IOFLAG_READ, IStorageTW::TYPE_ALL); if(!File) { Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", "couldn't open index file"); return; } char aOrigin[128]; CLineReader LineReader; LineReader.Init(File); char *pLine; while((pLine = LineReader.Get())) { if(!str_length(pLine) || pLine[0] == '#') // skip empty lines and comments continue; str_copy(aOrigin, pLine, sizeof(aOrigin)); char *pReplacement = LineReader.Get(); if(!pReplacement) { Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", "unexpected end of index file"); break; } if(pReplacement[0] != '=' || pReplacement[1] != '=' || pReplacement[2] != ' ') { char aBuf[128]; str_format(aBuf, sizeof(aBuf), "malform replacement for index '%s'", aOrigin); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", aBuf); continue; } int CountryCode = str_toint(pReplacement+3); if(CountryCode < CODE_LB || CountryCode > CODE_UB) { char aBuf[128]; str_format(aBuf, sizeof(aBuf), "country code '%i' not within valid code range [%i..%i]", CountryCode, CODE_LB, CODE_UB); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", aBuf); continue; } // load the graphic file char aBuf[128]; CImageInfo Info; if(g_Config.m_ClLoadCountryFlags) { str_format(aBuf, sizeof(aBuf), "countryflags/%s.png", aOrigin); if(!Graphics()->LoadPNG(&Info, aBuf, IStorageTW::TYPE_ALL)) { char aMsg[128]; str_format(aMsg, sizeof(aMsg), "failed to load '%s'", aBuf); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", aMsg); continue; } } // add entry CCountryFlag CountryFlag; CountryFlag.m_CountryCode = CountryCode; str_copy(CountryFlag.m_aCountryCodeString, aOrigin, sizeof(CountryFlag.m_aCountryCodeString)); if(g_Config.m_ClLoadCountryFlags) { CountryFlag.m_Texture = Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0); mem_free(Info.m_pData); } else CountryFlag.m_Texture = -1; if(g_Config.m_Debug) { str_format(aBuf, sizeof(aBuf), "loaded country flag '%s'", aOrigin); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", aBuf); } m_aCountryFlags.add_unsorted(CountryFlag); } io_close(File); m_aCountryFlags.sort_range(); // find index of default item int DefaultIndex = 0, Index = 0; for(sorted_array<CCountryFlag>::range r = m_aCountryFlags.all(); !r.empty(); r.pop_front(), ++Index) if(r.front().m_CountryCode == -1) { DefaultIndex = Index; break; } // init LUT if(DefaultIndex != 0) for(int i = 0; i < CODE_RANGE; ++i) m_CodeIndexLUT[i] = DefaultIndex; else mem_zero(m_CodeIndexLUT, sizeof(m_CodeIndexLUT)); for(int i = 0; i < m_aCountryFlags.size(); ++i) m_CodeIndexLUT[max(0, (m_aCountryFlags[i].m_CountryCode-CODE_LB)%CODE_RANGE)] = i; }
void CGameControllerCTF::Tick() { IGameController::Tick(); if(GameServer()->m_World.m_ResetRequested || GameServer()->m_World.m_Paused) return; for(int fi = 0; fi < 2; fi++) { CFlag *F = m_apFlags[fi]; if(!F) continue; // flag hits death-tile or left the game layer, reset it if(GameServer()->Collision()->GetCollisionAt(F->m_Pos.x, F->m_Pos.y)&CCollision::COLFLAG_DEATH || F->GameLayerClipped(F->m_Pos)) { GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", "flag_return"); GameServer()->CreateSoundGlobal(SOUND_CTF_RETURN); F->Reset(); continue; } // if(F->m_pCarryingCharacter) { // update flag position F->m_Pos = F->m_pCarryingCharacter->m_Pos; if(m_apFlags[fi^1] && m_apFlags[fi^1]->m_AtStand) { if(distance(F->m_Pos, m_apFlags[fi^1]->m_Pos) < CFlag::ms_PhysSize + CCharacter::ms_PhysSize) { // CAPTURE! \o/ m_aTeamscore[fi^1] += 100; F->m_pCarryingCharacter->GetPlayer()->m_Score += 5; char aBuf[512]; str_format(aBuf, sizeof(aBuf), "flag_capture player='%d:%s'", F->m_pCarryingCharacter->GetPlayer()->GetCID(), Server()->ClientName(F->m_pCarryingCharacter->GetPlayer()->GetCID())); GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); float CaptureTime = (Server()->Tick() - F->m_GrabTick)/(float)Server()->TickSpeed(); if(CaptureTime <= 60) { str_format(aBuf, sizeof(aBuf), "The %s flag was captured by '%s' (%d.%s%d seconds)", fi ? "blue" : "red", Server()->ClientName(F->m_pCarryingCharacter->GetPlayer()->GetCID()), (int)CaptureTime%60, ((int)(CaptureTime*100)%100)<10?"0":"", (int)(CaptureTime*100)%100); } else { str_format(aBuf, sizeof(aBuf), "The %s flag was captured by '%s'", fi ? "blue" : "red", Server()->ClientName(F->m_pCarryingCharacter->GetPlayer()->GetCID())); } GameServer()->SendChat(-1, -2, aBuf); for(int i = 0; i < 2; i++) m_apFlags[i]->Reset(); GameServer()->CreateSoundGlobal(SOUND_CTF_CAPTURE); } } } else { CCharacter *apCloseCCharacters[MAX_CLIENTS]; int Num = GameServer()->m_World.FindEntities(F->m_Pos, CFlag::ms_PhysSize, (CEntity**)apCloseCCharacters, MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER); for(int i = 0; i < Num; i++) { if(!apCloseCCharacters[i]->IsAlive() || apCloseCCharacters[i]->GetPlayer()->GetTeam() == TEAM_SPECTATORS || GameServer()->Collision()->IntersectLine(F->m_Pos, apCloseCCharacters[i]->m_Pos, NULL, NULL)) continue; if(apCloseCCharacters[i]->GetPlayer()->GetTeam() == F->m_Team) { // return the flag if(!F->m_AtStand) { CCharacter *pChr = apCloseCCharacters[i]; pChr->GetPlayer()->m_Score += 1; char aBuf[256]; str_format(aBuf, sizeof(aBuf), "flag_return player='%d:%s'", pChr->GetPlayer()->GetCID(), Server()->ClientName(pChr->GetPlayer()->GetCID())); GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); GameServer()->CreateSoundGlobal(SOUND_CTF_RETURN); F->Reset(); } } else { // take the flag if(F->m_AtStand) { m_aTeamscore[fi^1]++; F->m_GrabTick = Server()->Tick(); } F->m_AtStand = 0; F->m_pCarryingCharacter = apCloseCCharacters[i]; F->m_pCarryingCharacter->GetPlayer()->m_Score += 1; char aBuf[256]; str_format(aBuf, sizeof(aBuf), "flag_grab player='%d:%s'", F->m_pCarryingCharacter->GetPlayer()->GetCID(), Server()->ClientName(F->m_pCarryingCharacter->GetPlayer()->GetCID())); GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); for(int c = 0; c < MAX_CLIENTS; c++) { CPlayer *pPlayer = GameServer()->m_apPlayers[c]; if(!pPlayer) continue; if((pPlayer->GetTeam() == TEAM_SPECTATORS || pPlayer->m_DeadSpecMode) && pPlayer->GetSpectatorID() != SPEC_FREEVIEW && GameServer()->m_apPlayers[pPlayer->GetSpectatorID()] && GameServer()->m_apPlayers[pPlayer->GetSpectatorID()]->GetTeam() == fi) GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_EN, c); else if(pPlayer->GetTeam() == fi) GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_EN, c); else GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_PL, c); } // demo record entry GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_EN, -2); break; } } if(!F->m_pCarryingCharacter && !F->m_AtStand) { if(Server()->Tick() > F->m_DropTick + Server()->TickSpeed()*30) { GameServer()->CreateSoundGlobal(SOUND_CTF_RETURN); F->Reset(); } else { F->m_Vel.y += GameServer()->m_World.m_Core.m_Tuning.m_Gravity; GameServer()->Collision()->MoveBox(&F->m_Pos, &F->m_Vel, vec2(F->ms_PhysSize, F->ms_PhysSize), 0.5f); } } } } }
static int engine_find_datadir(char *argv0) { /* 1) use provided data-dir override */ if(datadir[0]) { if(fs_is_dir(datadir)) return 0; else { dbg_msg("engine/datadir", "specified data-dir '%s' does not exist", datadir); return -1; } } /* 2) use data-dir in PWD if present */ if(fs_is_dir("data")) { strcpy(datadir, "data"); return 0; } /* 3) use compiled-in data-dir if present */ if (fs_is_dir(DATA_DIR)) { strcpy(datadir, DATA_DIR); return 0; } /* 4) check for usable path in argv[0] */ { unsigned int pos = strrchr(argv0, '/') - argv0; if (pos < sizeof(datadir)) { char basedir[sizeof(datadir)]; strncpy(basedir, argv0, pos); basedir[pos] = '\0'; str_format(datadir, sizeof(datadir), "%s/data", basedir); if (fs_is_dir(datadir)) return 0; } } #if defined(CONF_FAMILY_UNIX) /* 5) check for all default locations */ { const char *sdirs[] = { "/usr/share/teeworlds", "/usr/local/share/teeworlds" "/opt/teeworlds" }; const int sdirs_count = sizeof(sdirs) / sizeof(sdirs[0]); int i; for (i = 0; i < sdirs_count; i++) { if (fs_is_dir(sdirs[i])) { strcpy(datadir, sdirs[i]); return 0; } } } #endif /* no data-dir found */ dbg_msg("engine/datadir", "warning no data directory found"); return -1; }
int vout_snapshot_SaveImage(char **name, int *sequential, const block_t *image, vlc_object_t *object, const vout_snapshot_save_cfg_t *cfg) { /* */ char *filename; DIR *pathdir = vlc_opendir(cfg->path); if (pathdir != NULL) { /* The use specified a directory path */ closedir(pathdir); /* */ char *prefix = NULL; if (cfg->prefix_fmt) prefix = str_format(object, cfg->prefix_fmt); if (prefix) filename_sanitize(prefix); else { prefix = strdup("vlcsnap-"); if (!prefix) goto error; } if (cfg->is_sequential) { for (int num = cfg->sequence; ; num++) { struct stat st; if (asprintf(&filename, "%s" DIR_SEP "%s%05d.%s", cfg->path, prefix, num, cfg->format) < 0) { free(prefix); goto error; } if (vlc_stat(filename, &st)) { *sequential = num; break; } free(filename); } } else { struct tm curtime; time_t lcurtime = time(NULL) ; if (!localtime_r(&lcurtime, &curtime)) { const unsigned int id = (image->i_pts / 100000) & 0xFFFFFF; msg_Warn(object, "failed to get current time. Falling back to legacy snapshot naming"); if (asprintf(&filename, "%s" DIR_SEP "%s%u.%s", cfg->path, prefix, id, cfg->format) < 0) filename = NULL; } else { /* suffix with the last decimal digit in 10s of seconds resolution * FIXME gni ? */ const int id = (image->i_pts / (100*1000)) & 0xFF; char buffer[128]; if (!strftime(buffer, sizeof(buffer), "%Y-%m-%d-%Hh%Mm%Ss", &curtime)) strcpy(buffer, "error"); if (asprintf(&filename, "%s" DIR_SEP "%s%s%1u.%s", cfg->path, prefix, buffer, id, cfg->format) < 0) filename = NULL; } } free(prefix); } else { /* The user specified a full path name (including file name) */ filename = str_format(object, cfg->path); path_sanitize(filename); } if (!filename) goto error; /* Save the snapshot */ FILE *file = vlc_fopen(filename, "wb"); if (!file) { msg_Err(object, "Failed to open '%s'", filename); free(filename); goto error; } if (fwrite(image->p_buffer, image->i_buffer, 1, file) != 1) { msg_Err(object, "Failed to write to '%s'", filename); fclose(file); free(filename); goto error; } fclose(file); /* */ if (name) *name = filename; else free(filename); return VLC_SUCCESS; error: msg_Err(object, "could not save snapshot"); return VLC_EGENERIC; }
void CCharacter::Tick() { if(m_pPlayer->m_ForceBalanced) { char Buf[128]; str_format(Buf, sizeof(Buf), "You were moved to %s due to team balancing", GameServer()->m_pController->GetTeamName(m_pPlayer->GetTeam())); GameServer()->SendBroadcast(Buf, m_pPlayer->GetCID()); m_pPlayer->m_ForceBalanced = false; } m_Core.m_Input = m_Input; m_Core.Tick(true); // handle death-tiles and leaving gamelayer if(GameServer()->Collision()->GetCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y-m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH || GameServer()->Collision()->GetCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y+m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH || GameServer()->Collision()->GetCollisionAt(m_Pos.x-m_ProximityRadius/3.f, m_Pos.y-m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH || GameServer()->Collision()->GetCollisionAt(m_Pos.x-m_ProximityRadius/3.f, m_Pos.y+m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH || GameLayerClipped(m_Pos)) { Die(m_pPlayer->GetCID(), WEAPON_WORLD); } // handle Weapons HandleWeapons(); /* INFECTION MODIFICATION START ***************************************/ if(GetClass() == PLAYERCLASS_HUNTER) { if(IsGrounded()) m_AirJumpCounter = 0; if(m_Core.m_TriggeredEvents&COREEVENT_AIR_JUMP && m_AirJumpCounter < 1) { m_Core.m_Jumped &= ~2; m_AirJumpCounter++; } } if(m_pClassChooser) { if(GetClass() != PLAYERCLASS_NONE) { GameServer()->m_World.DestroyEntity(m_pClassChooser); m_pClassChooser = 0; } else { m_pClassChooser->m_Pos = m_Pos; m_pClassChooser->SetCursor(vec2(m_Input.m_TargetX, m_Input.m_TargetY)); if(m_Input.m_Fire&1) { int ccRes = m_pClassChooser->SelectClass(); if(ccRes) { GameServer()->m_World.DestroyEntity(m_pClassChooser); m_pClassChooser = 0; m_pPlayer->SetClass(ccRes); } } } } /* INFECTION MODIFICATION END *****************************************/ // Previnput m_PrevInput = m_Input; return; }
void CSqlScore::ShowRankThread(void *pUser) { lock_wait(gs_SqlLock); CSqlScoreData *pData = (CSqlScoreData *)pUser; // Connect to database if(pData->m_pSqlData->Connect()) { try { // check strings char originalName[MAX_NAME_LENGTH]; strcpy(originalName,pData->m_aName); pData->m_pSqlData->ClearString(pData->m_aName); // check sort methode char aBuf[600]; pData->m_pSqlData->m_pStatement->execute("SET @rownum := 0;"); str_format(aBuf, sizeof(aBuf), "SELECT Rank, one_rank.Name, one_rank.Time, UNIX_TIMESTAMP(CURRENT_TIMESTAMP)-UNIX_TIMESTAMP(r.Timestamp) as Ago, UNIX_TIMESTAMP(r.Timestamp) as stamp " "FROM (" "SELECT * FROM (" "SELECT @rownum := @rownum + 1 AS RANK, Name, Time " "FROM (" "SELECT Name, min(Time) as Time " "FROM %s_%s_race " "Group By Name) as all_top_times " "ORDER BY Time ASC) as all_ranks " "WHERE all_ranks.Name = '%s') as one_rank " "LEFT JOIN %s_%s_race as r " "ON one_rank.Name = r.Name && one_rank.Time = r.Time " "ORDER BY Ago ASC " "LIMIT 0,1" ";", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap,pData->m_aName, pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap); pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf); if(pData->m_pSqlData->m_pResults->rowsCount() != 1) { str_format(aBuf, sizeof(aBuf), "%s is not ranked", originalName); pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf); } else { pData->m_pSqlData->m_pResults->next(); int since = (int)pData->m_pSqlData->m_pResults->getInt("Ago"); char agoString[40]; agoTimeToString(since,agoString); float Time = (float)pData->m_pSqlData->m_pResults->getDouble("Time"); int Rank = (int)pData->m_pSqlData->m_pResults->getInt("Rank"); if(g_Config.m_SvHideScore) str_format(aBuf, sizeof(aBuf), "Your time: %d minute(s) %5.2f second(s)", (int)(Time/60), Time-((int)Time/60*60)); else str_format(aBuf, sizeof(aBuf), "%d. %s Time: %d minute(s) %5.2f second(s)", Rank, pData->m_pSqlData->m_pResults->getString("Name").c_str(), (int)(Time/60), Time-((int)Time/60*60), agoString); if(pData->m_pSqlData->m_pResults->getInt("stamp") != 0) { pData->m_pSqlData->GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf, pData->m_ClientID); str_format(aBuf, sizeof(aBuf), "Finished: %s ago", agoString); } if(pData->m_Search) strcat(aBuf, pData->m_aRequestingPlayer); pData->m_pSqlData->GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf, pData->m_ClientID); } dbg_msg("SQL", "Showing rank done"); // delete results and statement delete pData->m_pSqlData->m_pResults; delete pData->m_pSqlData->m_pStatement; } catch (sql::SQLException &e) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "MySQL Error: %s", e.what()); dbg_msg("SQL", aBuf); dbg_msg("SQL", "ERROR: Could not show rank"); } // disconnect from database pData->m_pSqlData->Disconnect();//TODO:Check if an exception is caught will this still execute ? } delete pData; lock_release(gs_SqlLock); }
void CSqlScore::ShowTimesThread(void *pUser) { lock_wait(gs_SqlLock); CSqlScoreData *pData = (CSqlScoreData *)pUser; // Connect to database if(pData->m_pSqlData->Connect()) { try { char originalName[MAX_NAME_LENGTH]; strcpy(originalName,pData->m_aName); pData->m_pSqlData->ClearString(pData->m_aName); char aBuf[512]; if(pData->m_Search) // last 5 times of a player str_format(aBuf, sizeof(aBuf), "SELECT Time, UNIX_TIMESTAMP(CURRENT_TIMESTAMP)-UNIX_TIMESTAMP(Timestamp) as Ago, UNIX_TIMESTAMP(Timestamp) as Stamp FROM %s_%s_race WHERE Name = '%s' ORDER BY Ago ASC LIMIT %d, 5;", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aName, pData->m_Num-1); else // last 5 times of server str_format(aBuf, sizeof(aBuf), "SELECT Name, Time, UNIX_TIMESTAMP(CURRENT_TIMESTAMP)-UNIX_TIMESTAMP(Timestamp) as Ago, UNIX_TIMESTAMP(Timestamp) as Stamp FROM %s_%s_race ORDER BY Ago ASC LIMIT %d, 5;", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_Num-1); pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf); // show top5 if(pData->m_pSqlData->m_pResults->rowsCount() == 0) { pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "There are no times in the specified range"); goto end; } str_format(aBuf, sizeof(aBuf), "------------ Last Times No %d - %d ------------",pData->m_Num,pData->m_Num + pData->m_pSqlData->m_pResults->rowsCount() - 1); pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf); float pTime = 0; int pSince = 0; int pStamp = 0; while(pData->m_pSqlData->m_pResults->next()) { char pAgoString[40] = "\0"; pSince = (int)pData->m_pSqlData->m_pResults->getInt("Ago"); pStamp = (int)pData->m_pSqlData->m_pResults->getInt("Stamp"); pTime = (float)pData->m_pSqlData->m_pResults->getDouble("Time"); agoTimeToString(pSince,pAgoString); if(pData->m_Search) // last 5 times of a player { if(pStamp == 0) // stamp is 00:00:00 cause it's an old entry from old times where there where no stamps yet str_format(aBuf, sizeof(aBuf), "%d min %.2f sec, don't know how long ago", (int)(pTime/60), pTime-((int)pTime/60*60)); else str_format(aBuf, sizeof(aBuf), "%s ago, %d min %.2f sec", pAgoString,(int)(pTime/60), pTime-((int)pTime/60*60)); } else // last 5 times of the server { if(pStamp == 0) // stamp is 00:00:00 cause it's an old entry from old times where there where no stamps yet str_format(aBuf, sizeof(aBuf), "%s, %d m %.2f s, don't know when", pData->m_pSqlData->m_pResults->getString("Name").c_str(), (int)(pTime/60), pTime-((int)pTime/60*60)); else str_format(aBuf, sizeof(aBuf), "%s, %s ago, %d m %.2f s", pData->m_pSqlData->m_pResults->getString("Name").c_str(), pAgoString, (int)(pTime/60), pTime-((int)pTime/60*60)); } pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf); } pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "----------------------------------------------------"); dbg_msg("SQL", "Showing times done"); // delete results and statement delete pData->m_pSqlData->m_pResults; delete pData->m_pSqlData->m_pStatement; } catch (sql::SQLException &e) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "MySQL Error: %s", e.what()); dbg_msg("SQL", aBuf); dbg_msg("SQL", "ERROR: Could not show times"); } end: // disconnect from database pData->m_pSqlData->Disconnect(); } delete pData; lock_release(gs_SqlLock); }
void CAbstractIntegerEdit::CEntry::CopyToTextBuffer() { str_format(m_aText, sizeof(m_aText), "%d", m_pIntegerEdit->GetValue()); OnTextUpdated(); }
void CGameConsole::OnRender() { CUIRect Screen = *UI()->Screen(); float ConsoleMaxHeight = Screen.h*3/5.0f; float ConsoleHeight; float Progress = (TimeNow()-(m_StateChangeEnd-m_StateChangeDuration))/float(m_StateChangeDuration); if (Progress >= 1.0f) { if (m_ConsoleState == CONSOLE_CLOSING) m_ConsoleState = CONSOLE_CLOSED; else if (m_ConsoleState == CONSOLE_OPENING) m_ConsoleState = CONSOLE_OPEN; Progress = 1.0f; } if (m_ConsoleState == CONSOLE_OPEN && g_Config.m_ClEditor) Toggle(CONSOLETYPE_LOCAL); if (m_ConsoleState == CONSOLE_CLOSED) return; if (m_ConsoleState == CONSOLE_OPEN) Input()->MouseModeAbsolute(); float ConsoleHeightScale; if (m_ConsoleState == CONSOLE_OPENING) ConsoleHeightScale = ConsoleScaleFunc(Progress); else if (m_ConsoleState == CONSOLE_CLOSING) ConsoleHeightScale = ConsoleScaleFunc(1.0f-Progress); else //if (console_state == CONSOLE_OPEN) ConsoleHeightScale = ConsoleScaleFunc(1.0f); ConsoleHeight = ConsoleHeightScale*ConsoleMaxHeight; Graphics()->MapScreen(Screen.x, Screen.y, Screen.w, Screen.h); // do console shadow Graphics()->TextureClear(); Graphics()->QuadsBegin(); IGraphics::CColorVertex Array[4] = { IGraphics::CColorVertex(0, 0,0,0, 0.5f), IGraphics::CColorVertex(1, 0,0,0, 0.5f), IGraphics::CColorVertex(2, 0,0,0, 0.0f), IGraphics::CColorVertex(3, 0,0,0, 0.0f)}; Graphics()->SetColorVertex(Array, 4); IGraphics::CQuadItem QuadItem(0, ConsoleHeight, Screen.w, 10.0f); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); // do background Graphics()->TextureSet(g_pData->m_aImages[IMAGE_CONSOLE_BG].m_Id); Graphics()->QuadsBegin(); Graphics()->SetColor(0.2f, 0.2f, 0.2f,0.9f); if(m_ConsoleType == CONSOLETYPE_REMOTE) Graphics()->SetColor(0.4f, 0.2f, 0.2f,0.9f); Graphics()->QuadsSetSubset(0,-ConsoleHeight*0.075f,Screen.w*0.075f*0.5f,0); QuadItem = IGraphics::CQuadItem(0, 0, Screen.w, ConsoleHeight); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); // do small bar shadow Graphics()->TextureClear(); Graphics()->QuadsBegin(); Array[0] = IGraphics::CColorVertex(0, 0,0,0, 0.0f); Array[1] = IGraphics::CColorVertex(1, 0,0,0, 0.0f); Array[2] = IGraphics::CColorVertex(2, 0,0,0, 0.25f); Array[3] = IGraphics::CColorVertex(3, 0,0,0, 0.25f); Graphics()->SetColorVertex(Array, 4); QuadItem = IGraphics::CQuadItem(0, ConsoleHeight-20, Screen.w, 10); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); // do the lower bar Graphics()->TextureSet(g_pData->m_aImages[IMAGE_CONSOLE_BAR].m_Id); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.9f); Graphics()->QuadsSetSubset(0,0.1f,Screen.w*0.015f,1-0.1f); QuadItem = IGraphics::CQuadItem(0,ConsoleHeight-10.0f,Screen.w,10.0f); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); ConsoleHeight -= 22.0f; CInstance *pConsole = CurrentConsole(); { float FontSize = 10.0f; float RowHeight = FontSize*1.25f; float x = 3; float y = ConsoleHeight - RowHeight - 5.0f; CRenderInfo Info; Info.m_pSelf = this; Info.m_WantedCompletion = pConsole->m_CompletionChosen; Info.m_EnumCount = 0; Info.m_Offset = pConsole->m_CompletionRenderOffset; Info.m_Width = Screen.w; Info.m_pCurrentCmd = pConsole->m_aCompletionBuffer; TextRender()->SetCursor(&Info.m_Cursor, x+Info.m_Offset, y+RowHeight+2.0f, FontSize, TEXTFLAG_RENDER); // render prompt CTextCursor Cursor; TextRender()->SetCursor(&Cursor, x, y, FontSize, TEXTFLAG_RENDER); const char *pPrompt = "> "; if(m_ConsoleType == CONSOLETYPE_REMOTE) { if(Client()->State() == IClient::STATE_ONLINE) { if(Client()->RconAuthed()) pPrompt = "rcon> "; else pPrompt = "ENTER PASSWORD> "; } else pPrompt = "NOT CONNECTED> "; } TextRender()->TextEx(&Cursor, pPrompt, -1); x = Cursor.m_X; //hide rcon password char aInputString[256]; str_copy(aInputString, pConsole->m_Input.GetString(), sizeof(aInputString)); if(m_ConsoleType == CONSOLETYPE_REMOTE && Client()->State() == IClient::STATE_ONLINE && !Client()->RconAuthed()) { for(int i = 0; i < pConsole->m_Input.GetLength(); ++i) aInputString[i] = '*'; } // render console input (wrap line) TextRender()->SetCursor(&Cursor, x, y, FontSize, 0); Cursor.m_LineWidth = Screen.w - 10.0f - x; TextRender()->TextEx(&Cursor, aInputString, pConsole->m_Input.GetCursorOffset()); TextRender()->TextEx(&Cursor, aInputString+pConsole->m_Input.GetCursorOffset(), -1); int Lines = Cursor.m_LineCount; y -= (Lines - 1) * FontSize; TextRender()->SetCursor(&Cursor, x, y, FontSize, TEXTFLAG_RENDER); Cursor.m_LineWidth = Screen.w - 10.0f - x; TextRender()->TextEx(&Cursor, aInputString, pConsole->m_Input.GetCursorOffset()); static float MarkerOffset = TextRender()->TextWidth(0, FontSize, "|", -1)/3; CTextCursor Marker = Cursor; Marker.m_X -= MarkerOffset; Marker.m_LineWidth = -1; TextRender()->TextEx(&Marker, "|", -1); TextRender()->TextEx(&Cursor, aInputString+pConsole->m_Input.GetCursorOffset(), -1); // render possible commands if(m_ConsoleType == CONSOLETYPE_LOCAL || Client()->RconAuthed()) { if(pConsole->m_Input.GetString()[0] != 0) { m_pConsole->PossibleCommands(pConsole->m_aCompletionBuffer, pConsole->m_CompletionFlagmask, m_ConsoleType != CGameConsole::CONSOLETYPE_LOCAL && Client()->RconAuthed() && Client()->UseTempRconCommands(), PossibleCommandsRenderCallback, &Info); pConsole->m_CompletionRenderOffset = Info.m_Offset; if(Info.m_EnumCount <= 0) { if(pConsole->m_IsCommand) { char aBuf[512]; str_format(aBuf, sizeof(aBuf), "Help: %s ", pConsole->m_aCommandHelp); TextRender()->TextEx(&Info.m_Cursor, aBuf, -1); TextRender()->TextColor(0.75f, 0.75f, 0.75f, 1); str_format(aBuf, sizeof(aBuf), "Syntax: %s %s", pConsole->m_aCommandName, pConsole->m_aCommandParams); TextRender()->TextEx(&Info.m_Cursor, aBuf, -1); } } } } TextRender()->TextColor(1,1,1,1); // render log (actual page, wrap lines) CInstance::CBacklogEntry *pEntry = pConsole->m_Backlog.Last(); float OffsetY = 0.0f; float LineOffset = 1.0f; for(int Page = 0; Page <= pConsole->m_BacklogActPage; ++Page, OffsetY = 0.0f) { while(pEntry) { // get y offset (calculate it if we haven't yet) if(pEntry->m_YOffset < 0.0f) { TextRender()->SetCursor(&Cursor, 0.0f, 0.0f, FontSize, 0); Cursor.m_LineWidth = Screen.w-10; TextRender()->TextEx(&Cursor, pEntry->m_aText, -1); pEntry->m_YOffset = Cursor.m_Y+Cursor.m_FontSize+LineOffset; } OffsetY += pEntry->m_YOffset; // next page when lines reach the top if(y-OffsetY <= RowHeight) break; // just render output from actual backlog page (render bottom up) if(Page == pConsole->m_BacklogActPage) { TextRender()->SetCursor(&Cursor, 0.0f, y-OffsetY, FontSize, TEXTFLAG_RENDER); Cursor.m_LineWidth = Screen.w-10.0f; TextRender()->TextEx(&Cursor, pEntry->m_aText, -1); } pEntry = pConsole->m_Backlog.Prev(pEntry); } // actual backlog page number is too high, render last available page (current checked one, render top down) if(!pEntry && Page < pConsole->m_BacklogActPage) { pConsole->m_BacklogActPage = Page; pEntry = pConsole->m_Backlog.First(); while(OffsetY > 0.0f && pEntry) { TextRender()->SetCursor(&Cursor, 0.0f, y-OffsetY, FontSize, TEXTFLAG_RENDER); Cursor.m_LineWidth = Screen.w-10.0f; TextRender()->TextEx(&Cursor, pEntry->m_aText, -1); OffsetY -= pEntry->m_YOffset; pEntry = pConsole->m_Backlog.Next(pEntry); } break; } } // render page char aBuf[128]; str_format(aBuf, sizeof(aBuf), Localize("-Page %d-"), pConsole->m_BacklogActPage+1); TextRender()->Text(0, 10.0f, 0.0f, FontSize, aBuf, -1); // render version str_format(aBuf, sizeof(aBuf), "v%s", GAME_VERSION); float Width = TextRender()->TextWidth(0, FontSize, aBuf, -1); TextRender()->Text(0, Screen.w-Width-10.0f, 0.0f, FontSize, aBuf, -1); } }
void CMenus::RenderDemoList(CUIRect MainView) { static int s_Inited = 0; if(!s_Inited) { DemolistPopulate(); DemolistOnUpdate(true); s_Inited = 1; } // delete demo if(m_DemolistDelEntry) { if(m_DemolistSelectedIndex >= 0 && !m_DemolistSelectedIsDir) { char aBuf[512]; str_format(aBuf, sizeof(aBuf), "%s/%s", m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename); if(Storage()->RemoveFile(aBuf, m_lDemos[m_DemolistSelectedIndex].m_StorageType)) { DemolistPopulate(); DemolistOnUpdate(false); } } m_DemolistDelEntry = false; } char aFooterLabel[128] = {0}; if(m_DemolistSelectedIndex >= 0) { CDemoItem *Item = &m_lDemos[m_DemolistSelectedIndex]; if(str_comp(Item->m_aFilename, "..") == 0) str_copy(aFooterLabel, Localize("Parent Folder"), sizeof(aFooterLabel)); else if(m_DemolistSelectedIsDir) str_copy(aFooterLabel, Localize("Folder"), sizeof(aFooterLabel)); else { if(!Item->m_InfosLoaded) { char aBuffer[512]; str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_aCurrentDemoFolder, Item->m_aFilename); Item->m_Valid = DemoPlayer()->GetDemoInfo(Storage(), aBuffer, Item->m_StorageType, Item->m_aMap, sizeof(Item->m_aMap)); Item->m_InfosLoaded = true; } if(!Item->m_Valid) str_copy(aFooterLabel, Localize("Invalid Demo"), sizeof(aFooterLabel)); else str_format(aFooterLabel, sizeof(aFooterLabel), "%s: %s", Localize("Map"), Item->m_aMap); } } // render background RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_ALL, 10.0f); MainView.Margin(10.0f, &MainView); CUIRect ButtonBar, RefreshRect, PlayRect, DeleteRect, FileIcon; MainView.HSplitBottom(ms_ButtonHeight+5.0f, &MainView, &ButtonBar); ButtonBar.HSplitTop(5.0f, 0, &ButtonBar); ButtonBar.VSplitRight(130.0f, &ButtonBar, &PlayRect); ButtonBar.VSplitLeft(130.0f, &RefreshRect, &ButtonBar); ButtonBar.VSplitLeft(10.0f, &DeleteRect, &ButtonBar); ButtonBar.VSplitLeft(120.0f, &DeleteRect, &ButtonBar); static int s_DemoListId = 0; static float s_ScrollValue = 0; UiDoListboxStart(&s_DemoListId, &MainView, 17.0f, Localize("Demos"), aFooterLabel, m_lDemos.size(), 1, m_DemolistSelectedIndex, s_ScrollValue); for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front()) { CListboxItem Item = UiDoListboxNextItem((void*)(&r.front())); if(Item.m_Visible) { Item.m_Rect.VSplitLeft(Item.m_Rect.h, &FileIcon, &Item.m_Rect); Item.m_Rect.VSplitLeft(5.0f, 0, &Item.m_Rect); DoButton_Icon(IMAGE_FILEICONS, r.front().m_IsDir?SPRITE_FILE_FOLDER:SPRITE_FILE_DEMO1, &FileIcon); UI()->DoLabel(&Item.m_Rect, r.front().m_aName, Item.m_Rect.h*ms_FontmodHeight, -1); } } bool Activated = false; m_DemolistSelectedIndex = UiDoListboxEnd(&s_ScrollValue, &Activated); DemolistOnUpdate(false); static int s_RefreshButton = 0; if(DoButton_Menu(&s_RefreshButton, Localize("Refresh"), 0, &RefreshRect)) { DemolistPopulate(); DemolistOnUpdate(false); } static int s_PlayButton = 0; if(DoButton_Menu(&s_PlayButton, m_DemolistSelectedIsDir?Localize("Open"):Localize("Play"), 0, &PlayRect) || Activated) { if(m_DemolistSelectedIndex >= 0) { if(m_DemolistSelectedIsDir) // folder { if(str_comp(m_lDemos[m_DemolistSelectedIndex].m_aFilename, "..") == 0) // parent folder fs_parent_dir(m_aCurrentDemoFolder); else // sub folder { char aTemp[256]; str_copy(aTemp, m_aCurrentDemoFolder, sizeof(aTemp)); str_format(m_aCurrentDemoFolder, sizeof(m_aCurrentDemoFolder), "%s/%s", aTemp, m_lDemos[m_DemolistSelectedIndex].m_aFilename); m_DemolistStorageType = m_lDemos[m_DemolistSelectedIndex].m_StorageType; } DemolistPopulate(); DemolistOnUpdate(true); } else // file { char aBuf[512]; str_format(aBuf, sizeof(aBuf), "%s/%s", m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename); const char *pError = Client()->DemoPlayer_Play(aBuf, m_lDemos[m_DemolistSelectedIndex].m_StorageType); if(pError) PopupMessage(Localize("Error"), str_comp(pError, "error loading demo") ? pError : Localize("Error loading demo"), Localize("Ok")); else { UI()->SetActiveItem(0); return; } } } } if(!m_DemolistSelectedIsDir) { static int s_DeleteButton = 0; if(DoButton_Menu(&s_DeleteButton, Localize("Delete"), 0, &DeleteRect) || m_DeletePressed) { if(m_DemolistSelectedIndex >= 0) { UI()->SetActiveItem(0); m_Popup = POPUP_DELETE_DEMO; } } } }
void CPlayer::Tick() { #ifdef CONF_DEBUG if(!g_Config.m_DbgDummies || m_ClientID < MAX_CLIENTS-g_Config.m_DbgDummies) #endif if(!Server()->ClientIngame(m_ClientID)) return; if(m_KillMe != 0) { KillCharacter(m_KillMe); m_KillMe = 0; return; } if (m_ChatScore > 0) m_ChatScore--; if (m_ForcePauseTime > 0) m_ForcePauseTime--; Server()->SetClientScore(m_ClientID, m_Score); // do latency stuff { IServer::CClientInfo Info; if(Server()->GetClientInfo(m_ClientID, &Info)) { m_Latency.m_Accum += Info.m_Latency; m_Latency.m_AccumMax = max(m_Latency.m_AccumMax, Info.m_Latency); m_Latency.m_AccumMin = min(m_Latency.m_AccumMin, Info.m_Latency); } // each second if(Server()->Tick()%Server()->TickSpeed() == 0) { m_Latency.m_Avg = m_Latency.m_Accum/Server()->TickSpeed(); m_Latency.m_Max = m_Latency.m_AccumMax; m_Latency.m_Min = m_Latency.m_AccumMin; m_Latency.m_Accum = 0; m_Latency.m_AccumMin = 1000; m_Latency.m_AccumMax = 0; } } if(((CServer *)Server())->m_NetServer.ErrorString(m_ClientID)[0]) { char aBuf[512]; str_format(aBuf, sizeof(aBuf), "'%s' would have timed out, but can use timeout protection now", Server()->ClientName(m_ClientID)); GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf); ((CServer *)(Server()))->m_NetServer.ResetErrorString(m_ClientID); } if(!GameServer()->m_World.m_Paused) { if(!m_pCharacter && m_Team == TEAM_SPECTATORS && m_SpectatorID == SPEC_FREEVIEW) m_ViewPos -= vec2(clamp(m_ViewPos.x-m_LatestActivity.m_TargetX, -500.0f, 500.0f), clamp(m_ViewPos.y-m_LatestActivity.m_TargetY, -400.0f, 400.0f)); if(!m_pCharacter && m_DieTick+Server()->TickSpeed()*3 <= Server()->Tick()) m_Spawning = true; if(m_pCharacter) { if(m_pCharacter->IsAlive()) { if(m_Paused >= PAUSED_FORCE) { if(m_ForcePauseTime == 0) m_Paused = PAUSED_NONE; ProcessPause(); } else if(m_Paused == PAUSED_PAUSED && m_NextPauseTick < Server()->Tick()) { if((!m_pCharacter->GetWeaponGot(WEAPON_NINJA) || m_pCharacter->m_FreezeTime) && m_pCharacter->IsGrounded() && m_pCharacter->m_Pos == m_pCharacter->m_PrevPos) ProcessPause(); } else if(m_NextPauseTick < Server()->Tick()) { ProcessPause(); } if(!m_Paused) m_ViewPos = m_pCharacter->m_Pos; } else if(!m_pCharacter->IsPaused()) { delete m_pCharacter; m_pCharacter = 0; } } else if(m_Spawning && !m_WeakHookSpawn) TryRespawn(); } else { ++m_DieTick; ++m_JoinTick; ++m_LastActionTick; ++m_TeamChangeTick; } m_TuneZoneOld = m_TuneZone; // determine needed tunings with viewpos int CurrentIndex = GameServer()->Collision()->GetMapIndex(m_ViewPos); m_TuneZone = GameServer()->Collision()->IsTune(CurrentIndex); if (m_TuneZone != m_TuneZoneOld) // dont send tunigs all the time { GameServer()->SendTuningParams(m_ClientID, m_TuneZone); } }
void CMenus::RenderDemoPlayer(CUIRect MainView) { const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo(); const float SeekBarHeight = 15.0f; const float ButtonbarHeight = 20.0f; const float NameBarHeight = 20.0f; const float Margins = 5.0f; float TotalHeight; if(m_MenuActive) TotalHeight = SeekBarHeight+ButtonbarHeight+NameBarHeight+Margins*3; else TotalHeight = SeekBarHeight+Margins*2; MainView.HSplitBottom(TotalHeight, 0, &MainView); MainView.VSplitLeft(250.0f, 0, &MainView); MainView.VSplitRight(250.0f, &MainView, 0); RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_T, 10.0f); MainView.Margin(5.0f, &MainView); CUIRect SeekBar, ButtonBar, NameBar; int CurrentTick = pInfo->m_CurrentTick - pInfo->m_FirstTick; int TotalTicks = pInfo->m_LastTick - pInfo->m_FirstTick; if(m_MenuActive) { MainView.HSplitTop(SeekBarHeight, &SeekBar, &ButtonBar); ButtonBar.HSplitTop(Margins, 0, &ButtonBar); ButtonBar.HSplitBottom(NameBarHeight, &ButtonBar, &NameBar); NameBar.HSplitTop(4.0f, 0, &NameBar); } else SeekBar = MainView; // do seekbar { static int s_SeekBarId = 0; void *id = &s_SeekBarId; char aBuffer[128]; RenderTools()->DrawUIRect(&SeekBar, vec4(0,0,0,0.5f), CUI::CORNER_ALL, 5.0f); float Amount = CurrentTick/(float)TotalTicks; CUIRect FilledBar = SeekBar; FilledBar.w = 10.0f + (FilledBar.w-10.0f)*Amount; RenderTools()->DrawUIRect(&FilledBar, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 5.0f); str_format(aBuffer, sizeof(aBuffer), "%d:%02d / %d:%02d", CurrentTick/SERVER_TICK_SPEED/60, (CurrentTick/SERVER_TICK_SPEED)%60, TotalTicks/SERVER_TICK_SPEED/60, (TotalTicks/SERVER_TICK_SPEED)%60); UI()->DoLabel(&SeekBar, aBuffer, SeekBar.h*0.70f, 0); // do the logic int Inside = UI()->MouseInside(&SeekBar); if(UI()->ActiveItem() == id) { if(!UI()->MouseButton(0)) UI()->SetActiveItem(0); else { static float PrevAmount = 0.0f; float Amount = (UI()->MouseX()-SeekBar.x)/(float)SeekBar.w; if(Amount > 0.0f && Amount < 1.0f && absolute(PrevAmount-Amount) >= 0.01f) { PrevAmount = Amount; m_pClient->OnReset(); m_pClient->m_SuppressEvents = true; DemoPlayer()->SetPos(Amount); m_pClient->m_SuppressEvents = false; } } } else if(UI()->HotItem() == id) { if(UI()->MouseButton(0)) UI()->SetActiveItem(id); } if(Inside) UI()->SetHotItem(id); } if(CurrentTick == TotalTicks) { DemoPlayer()->Pause(); DemoPlayer()->SetPos(0); } if(m_MenuActive) { // do buttons CUIRect Button; // combined play and pause button ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static int s_PlayPauseButton = 0; if(!pInfo->m_Paused) { if(DoButton_DemoPlayer_Sprite(&s_PlayPauseButton, SPRITE_DEMOBUTTON_PAUSE, pInfo->m_Paused, &Button)) DemoPlayer()->Pause(); } else { if(DoButton_DemoPlayer_Sprite(&s_PlayPauseButton, SPRITE_DEMOBUTTON_PLAY, !pInfo->m_Paused, &Button)) DemoPlayer()->Unpause(); } // stop button ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static int s_ResetButton = 0; if(DoButton_DemoPlayer_Sprite(&s_ResetButton, SPRITE_DEMOBUTTON_STOP, false, &Button)) { DemoPlayer()->Pause(); DemoPlayer()->SetPos(0); } // slowdown ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static int s_SlowDownButton = 0; if(DoButton_DemoPlayer_Sprite(&s_SlowDownButton, SPRITE_DEMOBUTTON_SLOWER, 0, &Button)) { if(pInfo->m_Speed > 4.0f) DemoPlayer()->SetSpeed(4.0f); else if(pInfo->m_Speed > 2.0f) DemoPlayer()->SetSpeed(2.0f); else if(pInfo->m_Speed > 1.0f) DemoPlayer()->SetSpeed(1.0f); else if(pInfo->m_Speed > 0.75f) DemoPlayer()->SetSpeed(0.75f); else if(pInfo->m_Speed > 0.5f) DemoPlayer()->SetSpeed(0.5f); else if(pInfo->m_Speed > 0.25f) DemoPlayer()->SetSpeed(0.25f); else if(pInfo->m_Speed > 0.1f) DemoPlayer()->SetSpeed(0.1f); else DemoPlayer()->SetSpeed(0.05f); } // fastforward ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static int s_FastForwardButton = 0; if(DoButton_DemoPlayer_Sprite(&s_FastForwardButton, SPRITE_DEMOBUTTON_FASTER, 0, &Button)) { if(pInfo->m_Speed < 0.1f) DemoPlayer()->SetSpeed(0.1f); else if(pInfo->m_Speed < 0.25f) DemoPlayer()->SetSpeed(0.25f); else if(pInfo->m_Speed < 0.5f) DemoPlayer()->SetSpeed(0.5f); else if(pInfo->m_Speed < 0.75f) DemoPlayer()->SetSpeed(0.75f); else if(pInfo->m_Speed < 1.0f) DemoPlayer()->SetSpeed(1.0f); else if(pInfo->m_Speed < 2.0f) DemoPlayer()->SetSpeed(2.0f); else if(pInfo->m_Speed < 4.0f) DemoPlayer()->SetSpeed(4.0f); else DemoPlayer()->SetSpeed(8.0f); } // speed meter ButtonBar.VSplitLeft(Margins*3, 0, &ButtonBar); char aBuffer[64]; if(pInfo->m_Speed >= 1.0f) str_format(aBuffer, sizeof(aBuffer), "x%.0f", pInfo->m_Speed); else str_format(aBuffer, sizeof(aBuffer), "x%.2f", pInfo->m_Speed); UI()->DoLabel(&ButtonBar, aBuffer, Button.h*0.7f, -1); // close button ButtonBar.VSplitRight(ButtonbarHeight*3, &ButtonBar, &Button); static int s_ExitButton = 0; if(DoButton_DemoPlayer(&s_ExitButton, Localize("Close"), 0, &Button)) Client()->Disconnect(); // demo name char aBuf[128]; str_format(aBuf, sizeof(aBuf), "Demofile: %s", DemoPlayer()->GetDemoName()); CTextCursor Cursor; TextRender()->SetCursor(&Cursor, NameBar.x, NameBar.y, Button.h*0.5f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = MainView.w; TextRender()->TextEx(&Cursor, aBuf, -1); } }
CConsole::CConsole(int FlagMask) { m_FlagMask = FlagMask; m_AccessLevel = ACCESS_LEVEL_ADMIN; m_pRecycleList = 0; m_TempCommands.Reset(); m_StoreCommands = true; m_paStrokeStr[0] = "0"; m_paStrokeStr[1] = "1"; m_ExecutionQueue.Reset(); m_pFirstCommand = 0; m_pFirstExec = 0; mem_zero(m_aPrintCB, sizeof(m_aPrintCB)); m_NumPrintCB = 0; m_pStorage = 0; m_pCurTick = NULL; m_pNameToIDfn = NULL; #if !defined(_MSC_VER) || _MSC_VER >= 1700 // workaround for msvc < 2012 commands.max_load_factor(0.75f); commands.reserve(512); #endif // register some basic commands Register("echo", "r", CFGFLAG_SERVER|CFGFLAG_CLIENT, Con_Echo, this, "Echo the text"); Register("+echo", "r", CFGFLAG_SERVER|CFGFLAG_CLIENT, ([] (IConsole::IResult *pResult, void *pUserData) { char aBuf[1024]; str_format(aBuf, sizeof(aBuf), "%s %s", pResult->GetString(1), pResult->GetString(0)); ((CConsole*)pUserData)->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Console", aBuf); }), this, "Echo the text"); Register("exec", "r", CFGFLAG_SERVER|CFGFLAG_CLIENT, Con_Exec, this, "Execute the specified file"); Register("toggle", "sii", CFGFLAG_SERVER|CFGFLAG_CLIENT, ConToggle, this, "Toggle config value"); Register("+toggle", "sii", CFGFLAG_CLIENT, ConToggleStroke, this, "Toggle config value via keypress"); Register("level_command", "s?i", CFGFLAG_SERVER, ConModCommandAccess, this, "Specify command accessibility"); Register("subadmin_status", "", CFGFLAG_SERVER, ConSubAdminCommandStatus, this, "List all commands which are accessible for sub admins"); Register("mod_status", "", CFGFLAG_SERVER, ConModCommandStatus, this, "List all commands which are accessible for moderators"); Register("user_status", "", CFGFLAG_SERVER, ConUserCommandStatus, this, "List all commands which are accessible for users"); Register("cmdlist", "", CFGFLAG_SERVER|CFGFLAG_CHAT, ConUserCommandStatus, this, "List all commands which are accessible for users"); Register("register_stub", "s", CFGFLAG_CLIENT|CFGFLAG_SERVER, ([](IConsole::IResult *pResult, void * pSelf) { int len = str_length(pResult->GetString(0)) + 1; char * cmdname = new char[len]; str_copy(cmdname, pResult->GetString(0), len); ((CConsole*)pSelf)->Register(cmdname, "?r", CFGFLAG_CLIENT|CFGFLAG_SERVER|CFGFLAG_CHAT, [](IConsole::IResult *, void *) {}, pSelf, "STUB"); }), this, "Register dummy command"); Register("register_alias", "sr", CFGFLAG_CLIENT|CFGFLAG_SERVER, ([](IConsole::IResult *pResult, void * pSelf) { int aliaslen = str_length(pResult->GetString(0)) + 1; char * aliasname = new char[aliaslen]; str_copy(aliasname, pResult->GetString(0), aliaslen); int cmdlen = str_length(pResult->GetString(1)) + 1; char * cmdname = new char[cmdlen]; str_copy(cmdname, pResult->GetString(1), cmdlen); ((CConsole*)pSelf)->Register(aliasname, "?r", CFGFLAG_CLIENT|CFGFLAG_SERVER, ([](IConsole::IResult *pArgs, void * pUser) { auto& info = *(std::pair<CConsole *, char *> *)pUser; if(pArgs->NumArguments()) { char aBuf[1024]; str_format(aBuf, sizeof(aBuf), "%s %s", info.second, pArgs->GetString(0)); info.first->ExecuteLine(aBuf, pArgs->m_ClientID); } else { info.first->ExecuteLine(info.second, pArgs->m_ClientID); } }), (void *)(new std::pair<CConsole *, char *>((CConsole*)pSelf, cmdname)), cmdname); }), this, "Register alias"); /*Register("commands_size", "", CFGFLAG_SERVER|CFGFLAG_CLIENT, ([](IConsole::IResult *, void * ptr) { CConsole * self = (CConsole *)ptr; char buf[128]; str_format(buf, sizeof(buf), "size: %u load: %f", self->commands.size(), self->commands.load_factor()); self->Print(IConsole::OUTPUT_LEVEL_STANDARD, "test", buf); }), this, "Total amount of commands");*/ Register("set_timer", "iir", CFGFLAG_SERVER|CFGFLAG_CLIENT, ConSetTimer, this, "Exec command after n ms (the first argument is stroke)"); Register("+set_timer", "ir", CFGFLAG_SERVER|CFGFLAG_CLIENT, ConSetTimer, this, "Exec command after n ms"); Register("set_ticktimer", "iir", CFGFLAG_SERVER|CFGFLAG_CLIENT, ConSetTickTimer, this, "Exec command after n ticks (the first argument is stroke)"); Register("+set_ticktimer", "ir", CFGFLAG_SERVER|CFGFLAG_CLIENT, ConSetTickTimer, this, "Exec command after n ticks"); // TODO: this should disappear #define MACRO_CONFIG_INT(Name,ScriptName,Def,Min,Max,Flags,Desc) \ { \ static CNumericVariableData<int> Data = { this, &g_Config.m_##Name, Min, Max }; \ Register(#ScriptName, "?i", Flags, IntVariableCommand, &Data, Desc); \ } #define MACRO_CONFIG_FLOAT(Name,ScriptName,Def,Min,Max,Flags,Desc) \ { \ static CNumericVariableData<float> Data = { this, &g_Config.m_##Name, Min, Max }; \ Register(#ScriptName, "?i", Flags, FloatVariableCommand, &Data, Desc); \ } #define MACRO_CONFIG_STR(Name,ScriptName,Len,Def,Flags,Desc) \ { \ static CStrVariableData Data = { this, g_Config.m_##Name, Len }; \ Register(#ScriptName, "?r", Flags, StrVariableCommand, &Data, Desc); \ } #include "config_variables.h" #undef MACRO_CONFIG_INT #undef MACRO_CONFIG_STR // DDRace m_Cheated = false; }
void CConsole::ExecuteLineStroked(int Stroke, const char *pStr, int ClientID) { while(pStr && *pStr) { CResult Result; Result.m_ClientID = ClientID; const char *pEnd = pStr; const char *pNextPart = 0; int InString = 0; while(*pEnd) { if(*pEnd == '"') InString ^= 1; else if(*pEnd == '\\') // escape sequences { if(pEnd[1] == '"') pEnd++; } else if(!InString) { if(*pEnd == ';') // command separator { pNextPart = pEnd+1; break; } else if(*pEnd == '#') // comment, no need to do anything more break; } pEnd++; } if(ParseStart(&Result, pStr, (pEnd-pStr) + 1) != 0) return; if(!*Result.m_pCommand) return; CCommand *pCommand = FindCommand(Result.m_pCommand, m_FlagMask); if(pCommand) { if(pCommand->GetAccessLevel() >= m_AccessLevel) { int IsStrokeCommand = 0; if(Result.m_pCommand[0] == '+') { // insert the stroke direction token Result.AddArgument(m_paStrokeStr[Stroke]); IsStrokeCommand = 1; } if(Stroke || IsStrokeCommand) { if(ParseArgs(&Result, pCommand->m_pParams)) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "Invalid arguments... Usage: %s %s", pCommand->m_pName, pCommand->m_pParams); Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf); } else if(m_StoreCommands && pCommand->m_Flags&CFGFLAG_STORE) { m_ExecutionQueue.AddEntry(); m_ExecutionQueue.m_pLast->m_pfnCommandCallback = pCommand->m_pfnCallback; m_ExecutionQueue.m_pLast->m_pCommandUserData = pCommand->m_pUserData; m_ExecutionQueue.m_pLast->m_Result = Result; } else { if(Result.GetVictim() == CResult::VICTIM_ME) Result.SetVictim(ClientID); if(pCommand->m_Flags&CMDFLAG_TEST && !g_Config.m_SvTestingCommands) return; if (Result.HasVictim()) { if (m_AccessLevel == ACCESS_LEVEL_HELPER && Result.GetVictim() != ClientID) Print(OUTPUT_LEVEL_STANDARD, "Console", "Helpers can execute commands only on their self."); else { if(Result.GetVictim() == CResult::VICTIM_ALL) { for (int i = 0; i < MAX_CLIENTS; i++) { Result.SetVictim(i); pCommand->m_pfnCallback(&Result, pCommand->m_pUserData); } } else pCommand->m_pfnCallback(&Result, pCommand->m_pUserData); } } else pCommand->m_pfnCallback(&Result, pCommand->m_pUserData); } } } else if(Stroke) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "Access for command %s denied.", Result.m_pCommand); Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf); } } else if(Stroke) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "No such command: %s.", Result.m_pCommand); Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf); } pStr = pNextPart; } }
void CHud::RenderScoreHud() { int GameFlags = m_pClient->m_Snap.m_pGameobj->m_Flags; float Whole = 300*Graphics()->ScreenAspect(); // render small score hud if(!(m_pClient->m_Snap.m_pGameobj && m_pClient->m_Snap.m_pGameobj->m_GameOver) && (GameFlags&GAMEFLAG_TEAMS)) { char aScoreTeam[2][32]; str_format(aScoreTeam[TEAM_RED], sizeof(aScoreTeam)/2, "%d", m_pClient->m_Snap.m_pGameobj->m_TeamscoreRed); str_format(aScoreTeam[TEAM_BLUE], sizeof(aScoreTeam)/2, "%d", m_pClient->m_Snap.m_pGameobj->m_TeamscoreBlue); float aScoreTeamWidth[2] = {TextRender()->TextWidth(0, 14.0f, aScoreTeam[TEAM_RED], -1), TextRender()->TextWidth(0, 14.0f, aScoreTeam[TEAM_BLUE], -1)}; float ScoreWidthMax = max(max(aScoreTeamWidth[TEAM_RED], aScoreTeamWidth[TEAM_BLUE]), TextRender()->TextWidth(0, 14.0f, "100", -1)); float Split = 3.0f; float ImageSize = GameFlags&GAMEFLAG_FLAGS ? 16.0f : Split; for(int t = 0; t < 2; t++) { // draw box Graphics()->BlendNormal(); Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); if(t == 0) Graphics()->SetColor(1.0f, 0.0f, 0.0f, 0.25f); else Graphics()->SetColor(0.0f, 0.0f, 1.0f, 0.25f); RenderTools()->DrawRoundRectExt(Whole-ScoreWidthMax-ImageSize-2*Split, 245.0f+t*20, ScoreWidthMax+ImageSize+2*Split, 18.0f, 5.0f, CUI::CORNER_L); Graphics()->QuadsEnd(); // draw score TextRender()->Text(0, Whole-ScoreWidthMax+(ScoreWidthMax-aScoreTeamWidth[t])/2-Split, 245.0f+t*20, 14.0f, aScoreTeam[t], -1); if(GameFlags&GAMEFLAG_FLAGS && m_pClient->m_Snap.m_paFlags[t]) { if(m_pClient->m_Snap.m_paFlags[t]->m_CarriedBy == -2 || (m_pClient->m_Snap.m_paFlags[t]->m_CarriedBy == -1 && ((Client()->GameTick()/10)&1))) { // draw flag Graphics()->BlendNormal(); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id); Graphics()->QuadsBegin(); RenderTools()->SelectSprite(t==0?SPRITE_FLAG_RED:SPRITE_FLAG_BLUE); IGraphics::CQuadItem QuadItem(Whole-ScoreWidthMax-ImageSize, 246.0f+t*20, ImageSize/2, ImageSize); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); } else if(m_pClient->m_Snap.m_paFlags[t]->m_CarriedBy >= 0) { // draw name of the flag holder int Id = m_pClient->m_Snap.m_paFlags[t]->m_CarriedBy%MAX_CLIENTS; const char *pName = m_pClient->m_aClients[Id].m_aName; float w = TextRender()->TextWidth(0, 10.0f, pName, -1); TextRender()->Text(0, Whole-ScoreWidthMax-ImageSize-3*Split-w, 247.0f+t*20, 10.0f, pName, -1); // draw tee of the flag holder CTeeRenderInfo Info = m_pClient->m_aClients[Id].m_RenderInfo; Info.m_Size = 18.0f; RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, EMOTE_NORMAL, vec2(1,0), vec2(Whole-ScoreWidthMax-Info.m_Size/2-Split, 246.0f+Info.m_Size/2+t*20)); } } } } }
void FindDatadir(const char *pArgv0) { // 1) use data-dir in PWD if present if(fs_is_dir("data/mapres")) { str_copy(m_aDatadir, "data", sizeof(m_aDatadir)); return; } // 2) use compiled-in data-dir if present if(fs_is_dir(DATA_DIR "/mapres")) { str_copy(m_aDatadir, DATA_DIR, sizeof(m_aDatadir)); return; } // 3) check for usable path in argv[0] { unsigned int Pos = ~0U; for(unsigned i = 0; pArgv0[i]; i++) if(pArgv0[i] == '/' || pArgv0[i] == '\\') Pos = i; if(Pos < MAX_PATH_LENGTH) { char aBaseDir[MAX_PATH_LENGTH]; str_copy(aBaseDir, pArgv0, Pos+1); str_format(m_aDatadir, sizeof(m_aDatadir), "%s/data", aBaseDir); str_append(aBaseDir, "/data/mapres", sizeof(aBaseDir)); if(fs_is_dir(aBaseDir)) return; else m_aDatadir[0] = 0; } } #if defined(CONF_FAMILY_UNIX) // 4) check for all default locations { const char *aDirs[] = { "/usr/share/teeworlds/data", "/usr/share/games/teeworlds/data", "/usr/local/share/teeworlds/data", "/usr/local/share/games/teeworlds/data", "/usr/pkg/share/teeworlds/data", "/usr/pkg/share/games/teeworlds/data", "/opt/teeworlds/data" }; const int DirsCount = sizeof(aDirs) / sizeof(aDirs[0]); int i; for (i = 0; i < DirsCount; i++) { char aBuf[128]; str_format(aBuf, sizeof(aBuf), "%s/mapres", aDirs[i]); if(fs_is_dir(aBuf)) { str_copy(m_aDatadir, aDirs[i], sizeof(m_aDatadir)); return; } } } #endif // no data-dir found dbg_msg("storage", "warning no data directory found"); }
void CChat::AddLine(int ClientID, int Team, const char *pLine) { if(ClientID != -1 && m_pClient->m_aClients[ClientID].m_aName[0] == '\0') // unknown client return; char *p = const_cast<char*>(pLine); while(*p) { pLine = p; // find line seperator and strip multiline while(*p) { if(*p++ == '\n') { *(p-1) = 0; break; } } m_CurrentLine = (m_CurrentLine+1)%MAX_LINES; m_aLines[m_CurrentLine].m_Time = time_get(); m_aLines[m_CurrentLine].m_YOffset[0] = -1.0f; m_aLines[m_CurrentLine].m_YOffset[1] = -1.0f; m_aLines[m_CurrentLine].m_ClientID = ClientID; m_aLines[m_CurrentLine].m_Team = Team; m_aLines[m_CurrentLine].m_NameColor = -2; m_aLines[m_CurrentLine].m_Highlighted = str_find_nocase(pLine, m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID].m_aName) != 0; if(ClientID == -1) // server message { str_copy(m_aLines[m_CurrentLine].m_aName, "*** ", sizeof(m_aLines[m_CurrentLine].m_aName)); str_format(m_aLines[m_CurrentLine].m_aText, sizeof(m_aLines[m_CurrentLine].m_aText), "%s", pLine); } else { if(m_pClient->m_aClients[ClientID].m_Team == TEAM_SPECTATORS) m_aLines[m_CurrentLine].m_NameColor = TEAM_SPECTATORS; if(m_pClient->m_Snap.m_pGameobj && m_pClient->m_Snap.m_pGameobj->m_Flags&GAMEFLAG_TEAMS) { if(m_pClient->m_aClients[ClientID].m_Team == TEAM_RED) m_aLines[m_CurrentLine].m_NameColor = TEAM_RED; else if(m_pClient->m_aClients[ClientID].m_Team == TEAM_BLUE) m_aLines[m_CurrentLine].m_NameColor = TEAM_BLUE; } str_copy(m_aLines[m_CurrentLine].m_aName, m_pClient->m_aClients[ClientID].m_aName, sizeof(m_aLines[m_CurrentLine].m_aName)); str_format(m_aLines[m_CurrentLine].m_aText, sizeof(m_aLines[m_CurrentLine].m_aText), ": %s", pLine); } char aBuf[1024]; str_format(aBuf, sizeof(aBuf), "%s%s", m_aLines[m_CurrentLine].m_aName, m_aLines[m_CurrentLine].m_aText); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "chat", aBuf); } // play sound if(ClientID >= 0) m_pClient->m_pSounds->Play(CSounds::CHN_GUI, SOUND_CHAT_CLIENT, 0, vec2(0,0)); else m_pClient->m_pSounds->Play(CSounds::CHN_GUI, SOUND_CHAT_SERVER, 0, vec2(0,0)); }
const char *GetPath(int Type, const char *pDir, char *pBuffer, unsigned BufferSize) { str_format(pBuffer, BufferSize, "%s%s%s", m_aaStoragePaths[Type], !m_aaStoragePaths[Type][0] ? "" : "/", pDir); return pBuffer; }
bool CSqlScore::Connect() { try { // Create connection m_pDriver = get_driver_instance(); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "tcp://%s:%d", m_pIp, m_Port); m_pConnection = m_pDriver->connect(aBuf, m_pUser, m_pPass); // Create Statement m_pStatement = m_pConnection->createStatement(); // Create database if not exists str_format(aBuf, sizeof(aBuf), "CREATE DATABASE IF NOT EXISTS %s", m_pDatabase); m_pStatement->execute(aBuf); // Connect to specific database m_pConnection->setSchema(m_pDatabase); dbg_msg("SQL", "SQL connection established"); return true; } catch (sql::SQLException &e) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "MySQL Error: %s", e.what()); dbg_msg("SQL", aBuf); dbg_msg("SQL", "ERROR: SQL connection failed"); return false; } catch (const std::exception& ex) { // ... dbg_msg("SQL", "1 %s",ex.what()); } catch (const std::string& ex) { // ... dbg_msg("SQL", "2 %s",ex.c_str()); } catch( int ) { dbg_msg("SQL", "3 %s"); } catch( float ) { dbg_msg("SQL", "4 %s"); } catch( char[] ) { dbg_msg("SQL", "5 %s"); } catch( char ) { dbg_msg("SQL", "6 %s"); } catch (...) { dbg_msg("SQL", "Unknown Error cause by the MySQL/C++ Connector, my advice compile server_debug and use it"); dbg_msg("SQL", "ERROR: SQL connection failed"); return false; } return false; }
void DEBUGHUD::render_tuning() { // render tuning debugging if(!config.dbg_tuning) return; TUNING_PARAMS standard_tuning; gfx_mapscreen(0, 0, 300*gfx_screenaspect(), 300); float y = 50.0f; int count = 0; for(int i = 0; i < gameclient.tuning.num(); i++) { char buf[128]; float current, standard; gameclient.tuning.get(i, ¤t); standard_tuning.get(i, &standard); if(standard == current) gfx_text_color(1,1,1,1.0f); else gfx_text_color(1,0.25f,0.25f,1.0f); float w; float x = 5.0f; str_format(buf, sizeof(buf), "%.2f", standard); x += 20.0f; w = gfx_text_width(0, 5, buf, -1); gfx_text(0x0, x-w, y+count*6, 5, buf, -1); str_format(buf, sizeof(buf), "%.2f", current); x += 20.0f; w = gfx_text_width(0, 5, buf, -1); gfx_text(0x0, x-w, y+count*6, 5, buf, -1); x += 5.0f; gfx_text(0x0, x, y+count*6, 5, gameclient.tuning.names[i], -1); count++; } y = y+count*6; gfx_texture_set(-1); gfx_blend_normal(); gfx_lines_begin(); float height = 50.0f; float pv = 1; for(int i = 0; i < 100; i++) { float speed = i/100.0f * 3000; float ramp = velocity_ramp(speed, gameclient.tuning.velramp_start, gameclient.tuning.velramp_range, gameclient.tuning.velramp_curvature); float rampedspeed = (speed * ramp)/1000.0f; gfx_lines_draw((i-1)*2, y+height-pv*height, i*2, y+height-rampedspeed*height); //gfx_lines_draw((i-1)*2, 200, i*2, 200); pv = rampedspeed; } gfx_lines_end(); gfx_text_color(1,1,1,1); }
void CSqlScore::agoTimeToString(int agoTime, char agoString[]) { char aBuf[20]; int times[7] = { 60 * 60 * 24 * 365 , 60 * 60 * 24 * 30 , 60 * 60 * 24 * 7, 60 * 60 * 24 , 60 * 60 , 60 , 1 }; char names[7][6] = { "year", "month", "week", "day", "hour", "min", "sec" }; int seconds = 0; char name[6]; int count = 0; int i = 0; // finding biggest match for(i = 0; i<7; i++) { seconds = times[i]; strcpy(name,names[i]); count = floor((float)agoTime/(float)seconds); if(count != 0) { break; } } if(count == 1) { str_format(aBuf, sizeof(aBuf), "%d %s", 1 , name); } else { str_format(aBuf, sizeof(aBuf), "%d %ss", count , name); } strcat(agoString,aBuf); if (i + 1 < 7) { // getting second piece now int seconds2 = times[i+1]; char name2[6]; strcpy(name2,names[i+1]); // add second piece if it's greater than 0 int count2 = floor((float)(agoTime - (seconds * count)) / (float)seconds2); if (count2 != 0) { if(count2 == 1) { str_format(aBuf, sizeof(aBuf), " and %d %s", 1 , name2); } else { str_format(aBuf, sizeof(aBuf), " and %d %ss", count2 , name2); } strcat(agoString,aBuf); } } }
void CNamePlates::RenderNameplate( const CNetObj_Character *pPrevChar, const CNetObj_Character *pPlayerChar, const CNetObj_PlayerInfo *pPlayerInfo ) { float IntraTick = Client()->IntraGameTick(); int ClientID = pPlayerInfo->m_ClientID; vec2 Position; if((!m_pClient->AntiPingPlayers() && !pPlayerInfo->m_Local) || m_pClient->m_Snap.m_SpecInfo.m_Active) { Position = mix(vec2(pPrevChar->m_X, pPrevChar->m_Y), vec2(pPlayerChar->m_X, pPlayerChar->m_Y), IntraTick); } else if(!m_pClient->AntiPingPlayers() && pPlayerInfo->m_Local) { Position = vec2(m_pClient->m_LocalCharacterPos.x, m_pClient->m_LocalCharacterPos.y); } else { Position = m_pPlayers->m_CurPredictedPos[ClientID]; } bool OtherTeam; if(m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID].m_Team == TEAM_SPECTATORS && m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW) OtherTeam = false; else if(m_pClient->m_Snap.m_SpecInfo.m_Active && m_pClient->m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW) OtherTeam = m_pClient->m_Teams.Team(pPlayerInfo->m_ClientID) != m_pClient->m_Teams.Team(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID); else OtherTeam = m_pClient->m_Teams.Team(pPlayerInfo->m_ClientID) != m_pClient->m_Teams.Team(m_pClient->m_Snap.m_LocalClientID); float FontSize = 18.0f + 20.0f * g_Config.m_ClNameplatesSize / 100.0f; float FontSizeClan = 18.0f + 20.0f * g_Config.m_ClNameplatesClanSize / 100.0f; // render name plate if(!pPlayerInfo->m_Local || g_Config.m_ClNameplatesOwn) { float a = 1; if(g_Config.m_ClNameplatesAlways == 0) a = clamp(1-powf(distance(m_pClient->m_pControls->m_TargetPos[g_Config.m_ClDummy], Position)/200.0f,16.0f), 0.0f, 1.0f); const char *pName = m_pClient->m_aClients[pPlayerInfo->m_ClientID].m_aName; if(str_comp(pName, m_aNamePlates[ClientID].m_aName) != 0 || FontSize != m_aNamePlates[ClientID].m_NameTextFontSize) { mem_copy(m_aNamePlates[ClientID].m_aName, pName, sizeof(m_aNamePlates[ClientID].m_aName)); m_aNamePlates[ClientID].m_NameTextFontSize = FontSize; m_aNamePlates[ClientID].m_NameTextWidth = TextRender()->TextWidth(0, FontSize, pName, -1); if(m_aNamePlates[ClientID].m_NameTextContainerIndex != -1) TextRender()->DeleteTextContainer(m_aNamePlates[ClientID].m_NameTextContainerIndex); CTextCursor Cursor; TextRender()->SetCursor(&Cursor, 0, 0, FontSize, TEXTFLAG_RENDER); Cursor.m_LineWidth = -1; // create nameplates at standard zoom float ScreenX0, ScreenY0, ScreenX1, ScreenY1; Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1); MapscreenToGroup(m_pClient->m_pCamera->m_Center.x, m_pClient->m_pCamera->m_Center.y, Layers()->GameGroup()); m_aNamePlates[ClientID].m_NameTextContainerIndex = TextRender()->CreateTextContainer(&Cursor, pName); Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1); } if(g_Config.m_ClNameplatesClan) { const char *pClan = m_pClient->m_aClients[ClientID].m_aClan; if(str_comp(pClan, m_aNamePlates[ClientID].m_aClanName) != 0 || FontSizeClan != m_aNamePlates[ClientID].m_ClanNameTextFontSize) { mem_copy(m_aNamePlates[ClientID].m_aClanName, pClan, sizeof(m_aNamePlates[ClientID].m_aClanName)); m_aNamePlates[ClientID].m_ClanNameTextFontSize = FontSizeClan; m_aNamePlates[ClientID].m_ClanNameTextWidth = TextRender()->TextWidth(0, FontSizeClan, pClan, -1); if(m_aNamePlates[ClientID].m_ClanNameTextContainerIndex != -1) TextRender()->DeleteTextContainer(m_aNamePlates[ClientID].m_ClanNameTextContainerIndex); CTextCursor Cursor; TextRender()->SetCursor(&Cursor, 0, 0, FontSizeClan, TEXTFLAG_RENDER); Cursor.m_LineWidth = -1; // create nameplates at standard zoom float ScreenX0, ScreenY0, ScreenX1, ScreenY1; Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1); MapscreenToGroup(m_pClient->m_pCamera->m_Center.x, m_pClient->m_pCamera->m_Center.y, Layers()->GameGroup()); m_aNamePlates[ClientID].m_ClanNameTextContainerIndex = TextRender()->CreateTextContainer(&Cursor, pClan); Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1); } } float tw = m_aNamePlates[ClientID].m_NameTextWidth; vec3 rgb = vec3(1.0f, 1.0f, 1.0f); if(g_Config.m_ClNameplatesTeamcolors && m_pClient->m_Teams.Team(ClientID)) rgb = HslToRgb(vec3(m_pClient->m_Teams.Team(ClientID) / 64.0f, 1.0f, 0.75f)); STextRenderColor TColor; STextRenderColor TOutlineColor; if(OtherTeam) { TOutlineColor.Set(0.0f, 0.0f, 0.0f, 0.2f); TColor.Set(rgb.r, rgb.g, rgb.b, g_Config.m_ClShowOthersAlpha / 100.0f); } else { TOutlineColor.Set(0.0f, 0.0f, 0.0f, 0.5f*a); TColor.Set(rgb.r, rgb.g, rgb.b, a); } if(g_Config.m_ClNameplatesTeamcolors && m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_TEAMS) { if(m_pClient->m_aClients[ClientID].m_Team == TEAM_RED) TColor.Set(1.0f, 0.5f, 0.5f, a); else if(m_pClient->m_aClients[ClientID].m_Team == TEAM_BLUE) TColor.Set(0.7f, 0.7f, 1.0f, a); } if(m_aNamePlates[ClientID].m_NameTextContainerIndex != -1) TextRender()->RenderTextContainer(m_aNamePlates[ClientID].m_NameTextContainerIndex, &TColor, &TOutlineColor, Position.x - tw / 2.0f, Position.y - FontSize - 38.0f); if(g_Config.m_ClNameplatesClan) { if(m_aNamePlates[ClientID].m_ClanNameTextContainerIndex != -1) TextRender()->RenderTextContainer(m_aNamePlates[ClientID].m_ClanNameTextContainerIndex, &TColor, &TOutlineColor, Position.x - m_aNamePlates[ClientID].m_ClanNameTextWidth / 2.0f, Position.y - FontSize - FontSizeClan - 38.0f); } if(g_Config.m_Debug) // render client id when in debug as well { char aBuf[128]; str_format(aBuf, sizeof(aBuf),"%d", pPlayerInfo->m_ClientID); float Offset = g_Config.m_ClNameplatesClan ? (FontSize * 2 + FontSizeClan) : (FontSize * 2); float tw_id = TextRender()->TextWidth(0, FontSize, aBuf, -1); TextRender()->Text(0, Position.x-tw_id/2.0f, Position.y-Offset-38.0f, 28.0f, aBuf, -1); } TextRender()->TextColor(1,1,1,1); TextRender()->TextOutlineColor(0.0f, 0.0f, 0.0f, 0.3f); } }
/* TODO: chopp up this function into smaller working parts */ int CNetServer::Recv(CNetChunk *pChunk) { while(1) { NETADDR Addr; // check for a chunk if(m_RecvUnpacker.FetchChunk(pChunk)) return 1; // TODO: empty the recvinfo int Bytes = net_udp_recv(m_Socket, &Addr, m_RecvUnpacker.m_aBuffer, NET_MAX_PACKETSIZE); // no more packets for now if(Bytes <= 0) break; if(CNetBase::UnpackPacket(m_RecvUnpacker.m_aBuffer, Bytes, &m_RecvUnpacker.m_Data) == 0) { // check if we just should drop the packet char aBuf[128]; if(NetBan() && NetBan()->IsBanned(&Addr, aBuf, sizeof(aBuf))) { // banned, reply with a message CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, aBuf, str_length(aBuf)+1); continue; } if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONNLESS) { pChunk->m_Flags = NETSENDFLAG_CONNLESS; pChunk->m_ClientID = -1; pChunk->m_Address = Addr; pChunk->m_DataSize = m_RecvUnpacker.m_Data.m_DataSize; pChunk->m_pData = m_RecvUnpacker.m_Data.m_aChunkData; return 1; } else { // TODO: check size here if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONTROL && m_RecvUnpacker.m_Data.m_aChunkData[0] == NET_CTRLMSG_CONNECT) { bool Found = false; // check if we already got this client for(int i = 0; i < MaxClients(); i++) { if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE && net_addr_comp(m_aSlots[i].m_Connection.PeerAddress(), &Addr) == 0) { Found = true; // silent ignore.. we got this client already break; } } // client that wants to connect if(!Found) { // only allow a specific number of players with the same ip NETADDR ThisAddr = Addr, OtherAddr; int FoundAddr = 1; ThisAddr.port = 0; for(int i = 0; i < MaxClients(); ++i) { if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE) continue; OtherAddr = *m_aSlots[i].m_Connection.PeerAddress(); OtherAddr.port = 0; if(!net_addr_comp(&ThisAddr, &OtherAddr)) { if(FoundAddr++ >= m_MaxClientsPerIP) { char aBuf[128]; str_format(aBuf, sizeof(aBuf), "Only %d players with the same IP are allowed", m_MaxClientsPerIP); CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, aBuf, sizeof(aBuf)); return 0; } } } for(int i = 0; i < MaxClients(); i++) { if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE) { Found = true; m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr); if(m_pfnNewClient) m_pfnNewClient(i, m_UserPtr); break; } } if(!Found) { const char FullMsg[] = "This server is full"; CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, FullMsg, sizeof(FullMsg)); } } } else { // normal packet, find matching slot for(int i = 0; i < MaxClients(); i++) { if(net_addr_comp(m_aSlots[i].m_Connection.PeerAddress(), &Addr) == 0) { if(m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr)) { if(m_RecvUnpacker.m_Data.m_DataSize) m_RecvUnpacker.Start(&Addr, &m_aSlots[i].m_Connection, i); } } } } } } } return 0; }
void mods_message(int msgtype, int client_id) { void *rawmsg = netmsg_secure_unpack(msgtype); PLAYER *p = game.players[client_id]; if(!rawmsg) { dbg_msg("server", "dropped weird message '%s' (%d), failed on '%s'", netmsg_get_name(msgtype), msgtype, netmsg_failed_on()); return; } if(msgtype == NETMSGTYPE_CL_SAY) { NETMSG_CL_SAY *msg = (NETMSG_CL_SAY *)rawmsg; int team = msg->team; if(team) team = p->team; else team = GAMECONTEXT::CHAT_ALL; if(config.sv_spamprotection && p->last_chat+time_freq() > time_get()) { if(!strcmp(msg->message, "/rank") && game.controller->is_race()) game.players[client_id]->last_chat = time_get()+time_freq()*10; else game.players[client_id]->last_chat = time_get(); } else { game.players[client_id]->last_chat = time_get(); if(!strcmp(msg->message, "/info")) { char buf[128]; str_format(buf, sizeof(buf), "DJUMP 0.32 from EliteKuchen.", RACE_VERSION); game.send_chat_target(client_id, buf); str_format(buf, sizeof(buf), "based on : Race mod %s from Rajh and Redix.", RACE_VERSION); game.send_chat_target(client_id, buf); } else if(!strncmp(msg->message, "/top5", 5) && game.controller->is_race()) { const char *pt = msg->message; int number = 0; pt += 6; while(*pt && *pt >= '0' && *pt <= '9') { number = number*10+(*pt-'0'); pt++; } if(number) ((GAMECONTROLLER_RACE*)game.controller)->score.top5_draw(client_id, number); else ((GAMECONTROLLER_RACE*)game.controller)->score.top5_draw(client_id, 0); } else if(!strncmp(msg->message, "/rank", 5) && game.controller->is_race()) { char buf[512]; const char *name = msg->message; name += 6; int pos; PLAYER_SCORE *pscore; if(!strcmp(msg->message, "/rank")) pscore = ((GAMECONTROLLER_RACE*)game.controller)->score.search_score(client_id, 1, &pos); else pscore = ((GAMECONTROLLER_RACE*)game.controller)->score.search_name(name, &pos, 1); if(pscore && pos > -1) { int punkte = pscore->points; char client_name[128]; str_format(client_name, sizeof(client_name), " (%s)", server_clientname(client_id)); str_format(buf, sizeof(buf), "%d. %s Points:%d", pos, pscore->name, punkte); if(strcmp(msg->message, "/rank")) strcat(buf, client_name); game.send_chat(-1, GAMECONTEXT::CHAT_ALL, buf); game.players[client_id]->last_chat = time_get()+time_freq()*3; return; } else if(pos == -1) str_format(buf, sizeof(buf), "Several players were found."); else str_format(buf, sizeof(buf), "%s is not ranked", strcmp(msg->message, "/rank")?name:server_clientname(client_id)); game.send_chat_target(client_id, buf); } else if(!strcmp(msg->message, "/cmdlist")) { game.send_chat_target(client_id, "---Command List---"); game.send_chat_target(client_id, "\"/info\" information about the mod"); game.send_chat_target(client_id, "\"/rank\" shows your rank"); game.send_chat_target(client_id, "\"/rank NAME\" shows the rank of a specific player"); game.send_chat_target(client_id, "\"/top5 X\" shows the top 5"); } else if(!strncmp(msg->message, "/", 1)) { game.send_chat_target(client_id, "Wrong command."); game.send_chat_target(client_id, "Say \"/cmdlist\" for list of command available."); } else game.send_chat(client_id, team, msg->message); } } else if(msgtype == NETMSGTYPE_CL_CALLVOTE) { int64 now = time_get(); if(game.vote_closetime) { game.send_chat_target(client_id, "Wait for current vote to end before calling a new one."); return; } int64 timeleft = p->last_votecall + time_freq()*60 - now; if(timeleft > 0) { char chatmsg[512] = {0}; str_format(chatmsg, sizeof(chatmsg), "You must wait %d seconds before making another vote", (timeleft/time_freq())+1); game.send_chat_target(client_id, chatmsg); return; } char chatmsg[512] = {0}; char desc[512] = {0}; char cmd[512] = {0}; NETMSG_CL_CALLVOTE *msg = (NETMSG_CL_CALLVOTE *)rawmsg; if(str_comp_nocase(msg->type, "option") == 0) { VOTEOPTION *option = voteoption_first; while(option) { if(str_comp_nocase(msg->value, option->command) == 0) { str_format(chatmsg, sizeof(chatmsg), "%s called vote to change server option '%s'", server_clientname(client_id), option->command); str_format(desc, sizeof(desc), "%s", option->command); str_format(cmd, sizeof(cmd), "%s", option->command); break; } option = option->next; } if(!option) { str_format(chatmsg, sizeof(chatmsg), "'%s' isn't an option on this server", msg->value); game.send_chat_target(client_id, chatmsg); return; } } else if(str_comp_nocase(msg->type, "kick") == 0) { if(!config.sv_vote_kick) { game.send_chat_target(client_id, "Server does not allow voting to kick players"); return; } int kick_id = atoi(msg->value); if(kick_id < 0 || kick_id >= MAX_CLIENTS || !game.players[kick_id]) { game.send_chat_target(client_id, "Invalid client id to kick"); return; } str_format(chatmsg, sizeof(chatmsg), "%s called for vote to kick '%s'", server_clientname(client_id), server_clientname(kick_id)); str_format(desc, sizeof(desc), "Kick '%s'", server_clientname(kick_id)); str_format(cmd, sizeof(cmd), "kick %d", kick_id); if (!config.sv_vote_kick_bantime) str_format(cmd, sizeof(cmd), "kick %d", kick_id); else str_format(cmd, sizeof(cmd), "ban %d %d", kick_id, config.sv_vote_kick_bantime); } if(cmd[0]) { game.send_chat(-1, GAMECONTEXT::CHAT_ALL, chatmsg); game.start_vote(desc, cmd); p->vote = 1; game.vote_creator = client_id; p->last_votecall = now; game.send_vote_status(-1); } } else if(msgtype == NETMSGTYPE_CL_VOTE) { if(!game.vote_closetime) return; if(p->vote == 0) { NETMSG_CL_VOTE *msg = (NETMSG_CL_VOTE *)rawmsg; p->vote = msg->vote; game.send_vote_status(-1); } } else if (msgtype == NETMSGTYPE_CL_SETTEAM && !game.world.paused) { NETMSG_CL_SETTEAM *msg = (NETMSG_CL_SETTEAM *)rawmsg; if(p->team == msg->team || (config.sv_spamprotection && p->last_setteam+time_freq()*3 > time_get())) return; // Switch team on given client and kill/respawn him if(game.controller->can_join_team(msg->team, client_id)) { if(game.controller->can_change_team(p, msg->team)) { p->last_setteam = time_get(); p->set_team(msg->team); (void) game.controller->check_team_balance(); } else game.send_broadcast("Teams must be balanced, please join other team", client_id); } else { char buf[128]; str_format(buf, sizeof(buf), "Only %d active players are allowed", config.sv_max_clients-config.sv_spectator_slots); game.send_broadcast(buf, client_id); } } else if (msgtype == NETMSGTYPE_CL_CHANGEINFO || msgtype == NETMSGTYPE_CL_STARTINFO) { NETMSG_CL_CHANGEINFO *msg = (NETMSG_CL_CHANGEINFO *)rawmsg; if(config.sv_spamprotection && p->last_changeinfo+time_freq()*5 > time_get()) return; p->last_changeinfo = time_get(); p->use_custom_color = msg->use_custom_color; p->color_body = msg->color_body; p->color_feet = msg->color_feet; // check for invalid chars unsigned char *name = (unsigned char *)msg->name; while (*name) { if(*name < 32) *name = ' '; name++; } // copy old name char oldname[MAX_NAME_LENGTH]; str_copy(oldname, server_clientname(client_id), MAX_NAME_LENGTH); server_setclientname(client_id, msg->name); if(msgtype == NETMSGTYPE_CL_CHANGEINFO && strcmp(oldname, server_clientname(client_id)) != 0) { char chattext[256]; str_format(chattext, sizeof(chattext), "%s changed name to %s", oldname, server_clientname(client_id)); game.send_chat(-1, GAMECONTEXT::CHAT_ALL, chattext); } // set skin str_copy(p->skin_name, msg->skin, sizeof(p->skin_name)); game.controller->on_player_info_change(p); if(msgtype == NETMSGTYPE_CL_STARTINFO) { // send vote options NETMSG_SV_VOTE_CLEAROPTIONS clearmsg; clearmsg.pack(MSGFLAG_VITAL); server_send_msg(client_id); VOTEOPTION *current = voteoption_first; while(current) { NETMSG_SV_VOTE_OPTION optionmsg; optionmsg.command = current->command; optionmsg.pack(MSGFLAG_VITAL); server_send_msg(client_id); current = current->next; } // send tuning parameters to client send_tuning_params(client_id); // NETMSG_SV_READYTOENTER m; m.pack(MSGFLAG_VITAL|MSGFLAG_FLUSH); server_send_msg(client_id); } } else if (msgtype == NETMSGTYPE_CL_EMOTICON && !game.world.paused) { NETMSG_CL_EMOTICON *msg = (NETMSG_CL_EMOTICON *)rawmsg; if(config.sv_spamprotection && p->last_emote+time_freq()*3 > time_get()) return; p->last_emote = time_get(); game.send_emoticon(client_id, msg->emoticon); } else if (msgtype == NETMSGTYPE_CL_KILL && !game.world.paused) { if(p->last_kill+time_freq()*3 > time_get()) return; p->last_kill = time_get(); p->kill_character(WEAPON_SELF); p->respawn_tick = server_tick()+server_tickspeed()*3; if(game.controller->is_race()) p->respawn_tick = server_tick(); } }
void CCharacter::TickDefered() { // advance the dummy { CWorldCore TempWorld; m_ReckoningCore.Init(&TempWorld, GameServer()->Collision()); m_ReckoningCore.Tick(false); m_ReckoningCore.Move(); m_ReckoningCore.Quantize(); } //lastsentcore vec2 StartPos = m_Core.m_Pos; vec2 StartVel = m_Core.m_Vel; bool StuckBefore = GameServer()->Collision()->TestBox(m_Core.m_Pos, vec2(28.0f, 28.0f)); m_Core.Move(); bool StuckAfterMove = GameServer()->Collision()->TestBox(m_Core.m_Pos, vec2(28.0f, 28.0f)); m_Core.Quantize(); bool StuckAfterQuant = GameServer()->Collision()->TestBox(m_Core.m_Pos, vec2(28.0f, 28.0f)); m_Pos = m_Core.m_Pos; if(!StuckBefore && (StuckAfterMove || StuckAfterQuant)) { // Hackish solution to get rid of strict-aliasing warning union { float f; unsigned u; }StartPosX, StartPosY, StartVelX, StartVelY; StartPosX.f = StartPos.x; StartPosY.f = StartPos.y; StartVelX.f = StartVel.x; StartVelY.f = StartVel.y; char aBuf[256]; str_format(aBuf, sizeof(aBuf), "STUCK!!! %d %d %d %f %f %f %f %x %x %x %x", StuckBefore, StuckAfterMove, StuckAfterQuant, StartPos.x, StartPos.y, StartVel.x, StartVel.y, StartPosX.u, StartPosY.u, StartVelX.u, StartVelY.u); GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); } int Events = m_Core.m_TriggeredEvents; int Mask = CmaskAllExceptOne(m_pPlayer->GetCID()); if(Events&COREEVENT_GROUND_JUMP) GameServer()->CreateSound(m_Pos, SOUND_PLAYER_JUMP, Mask); if(Events&COREEVENT_HOOK_ATTACH_PLAYER) GameServer()->CreateSound(m_Pos, SOUND_HOOK_ATTACH_PLAYER, CmaskAll()); if(Events&COREEVENT_HOOK_ATTACH_GROUND) GameServer()->CreateSound(m_Pos, SOUND_HOOK_ATTACH_GROUND, Mask); if(Events&COREEVENT_HOOK_HIT_NOHOOK) GameServer()->CreateSound(m_Pos, SOUND_HOOK_NOATTACH, Mask); if(m_pPlayer->GetTeam() == TEAM_SPECTATORS) { m_Pos.x = m_Input.m_TargetX; m_Pos.y = m_Input.m_TargetY; } // update the m_SendCore if needed { CNetObj_Character Predicted; CNetObj_Character Current; mem_zero(&Predicted, sizeof(Predicted)); mem_zero(&Current, sizeof(Current)); m_ReckoningCore.Write(&Predicted); m_Core.Write(&Current); // only allow dead reackoning for a top of 3 seconds if(m_ReckoningTick+Server()->TickSpeed()*3 < Server()->Tick() || mem_comp(&Predicted, &Current, sizeof(CNetObj_Character)) != 0) { m_ReckoningTick = Server()->Tick(); m_SendCore = m_Core; m_ReckoningCore = m_Core; } } }
// TODO: Ugly but works bool CUpdater::GetFile(const char *url, const char *path) { NETSOCKET Socket = invalid_socket; NETADDR HostAddress, BindAddr; mem_zero(&HostAddress, sizeof(HostAddress)); mem_zero(&BindAddr, sizeof(BindAddr)); char aNetBuff[1024]; //Lookup if(net_host_lookup(UPDATES_HOST, &HostAddress, NETTYPE_IPV4) != 0) { dbg_msg("autoupdate", "Error running host lookup"); return false; } HostAddress.port = 80; //Connect BindAddr.type = NETTYPE_IPV4; Socket = net_tcp_create(BindAddr); if(net_tcp_connect(Socket, &HostAddress) != 0) { net_tcp_close(Socket); dbg_msg("autoupdate","Error connecting to host"); return false; } //Send request str_format(aNetBuff, sizeof(aNetBuff), "GET "UPDATES_BASE_PATH"%s HTTP/1.0\r\nHost: "UPDATES_HOST"\r\n\r\n", url); net_tcp_send(Socket, aNetBuff, str_length(aNetBuff)); //read data IOHANDLE dstFile = 0; std::string NetData; int TotalRecv = 0, TotalBytes = 0, CurrentRecv = 0, enterCtrl = 0; bool isHead = true, isStatusLine = true; while ((CurrentRecv = net_tcp_recv(Socket, aNetBuff, sizeof(aNetBuff))) > 0) { for (int i=0; i<CurrentRecv ; i++) { if (isHead) { if (aNetBuff[i]=='\n') { if (++enterCtrl == 2) // Go To Body Part { dstFile = io_open(path, IOFLAG_WRITE); if (!dstFile) { net_tcp_close(Socket); dbg_msg("autoupdate","Error writing to disk"); return false; } str_copy(m_CurrentDownloadFileName, url, sizeof(m_CurrentDownloadFileName)); isHead = false; NetData.clear(); continue; } std::transform(NetData.begin(), NetData.end(), NetData.begin(), ::tolower); // Check Status if (isStatusLine) { bool isCodeOk = NetData.find("200") != std::string::npos; bool isStatusOk = NetData.find("ok") != std::string::npos; if (!isCodeOk || !isStatusOk) { net_tcp_close(Socket); dbg_msg("autoupdate","Server Host returns error code"); return false; } } isStatusLine = false; // Get File Size std::size_t fpos = std::string::npos; if ((fpos=NetData.find("content-length:")) != std::string::npos) sscanf(NetData.substr(fpos+15).c_str(), "%d", &TotalBytes); NetData.clear(); continue; } else if (aNetBuff[i]!='\r') enterCtrl=0; NetData+=aNetBuff[i]; } else // Body Part { if (TotalBytes <= 0) { io_close(dstFile); net_tcp_close(Socket); dbg_msg("autoupdate","Error receiving file"); return false; } m_CurrentDownloadProgress = (float)TotalRecv/(float)TotalBytes; io_write(dstFile, &aNetBuff[i], 1); TotalRecv++; if (TotalRecv == TotalBytes) break; } } } //Finish io_close(dstFile); net_tcp_close(Socket); return true; }
const char *engine_savepath(const char *filename, char *buffer, int max) { str_format(buffer, max, "%s/%s", application_save_path, filename); return buffer; }
static opcode_status_ty spawn(string_list_ty *args, string_ty *input, int *pid_p, string_ty *host_binding, opcode_context_ty *ocp) { size_t j; int fd; string_ty *iname; int pid; opcode_status_ty status; static char **argv; static size_t argvlen; string_list_ty cmd; sub_context_ty *scp; char *shell; trace(("spawn()\n{\n")); assert(args); /* * build the input file, if required */ status = opcode_status_error; fd = -1; iname = 0; if (input) { /* * He has given a string to be used as input to the command, * so write it out to a file, and then redirect the input. */ iname = temporary_filename(); fd = open(iname->str_text, O_RDWR | O_CREAT | O_TRUNC, 0666); if (fd < 0) fatal_intl_open(iname->str_text); if (unlink(iname->str_text)) { error_intl_unlink(iname->str_text); goto done; } if ( write(fd, input->str_text, input->str_length) < 0 || lseek(fd, 0L, SEEK_SET) ) { error_intl_write(iname->str_text); goto done; } } /* * See if there is a host_binding in effect. */ if (host_binding) { static string_ty *key; string_list_ty *slp; string_ty *s; string_ty *rcmd; string_ty *rcmdq; string_ty *result_fn; FILE *result_fp; string_ty *cwd; string_ty *script_fn; FILE *script_fp; /* * Work out the name of the remote shell command. */ if (!key) key = str_from_c("parallel_rsh"); slp = id_var_search(ocp, key); if (slp) string_list_copy_constructor(&cmd, slp); else { static string_ty *rsh; if (!rsh) rsh = str_from_c(CONF_REMOTE_SHELL); string_list_constructor(&cmd); string_list_append(&cmd, rsh); } /* * Add the name of the host. */ string_list_append(&cmd, host_binding); /* * The remote end will need to change directory to where * we are now, since it is *highly* unlikely that we are * in our home directory. */ cwd = os_curdir(); /* do not str_free this */ /* * We are going to create a small shell script contining * the command to be executed. This deals with various * weird and obscure $SHELL settings, and it also deals * with command lines so long that rsh barfs. * * Yes, there is a potential race condition here. * Between writing the script and executing it, we * could be tricked into executing something else. * Especially if there is a symlink lying in wait. */ script_fn = dot_temporary_filename(); script_fp = fopen_and_check(script_fn->str_text, "w"); /* * what shell are we using */ shell = getenv("SHELL"); if (!shell || !*shell) shell = CONF_SHELL; fprintf(script_fp, "#!%s\n", shell); /* * Now write the actual command to the script file. */ rcmd = wl2str(args, 0, args->nstrings, (char *)0); fprintf(script_fp, "%s\n", rcmd->str_text); str_free(rcmd); fflush_and_check(script_fp, script_fn->str_text); fclose_and_check(script_fp, script_fn->str_text); chmod_and_check(script_fn->str_text, 0755); /* * This is the result file. It is where the remote * command will stash its exit status. We seed it with * failure in case the rsh fails altogether. * * And, yes, there is a race conditon and we could be * lied to if they are quick. */ result_fn = dot_temporary_filename(); result_fp = fopen_and_check(result_fn->str_text, "w"); fprintf(result_fp, "42\n"); fflush_and_check(result_fp, result_fn->str_text); fclose_and_check(result_fp, result_fn->str_text); /* * Because rsh(1) always returns an exit status of zero, * we have to make other arrangements to obtain the exit * status. * * We actually need to be a more devious, so that we can * get the exit status back. Write it to a temporary * file server side, then read and remove it client side. * * This is the server side command. It gets quoted * again to protect it from the client side shell. * * We use sh explicitly, because the shell at the other * end could be csh, tcsh, or something even stranger, * and we need to guarantee the command will execute * exactly the way we need. */ rcmd = str_format ( "sh -c 'cd %s && sh %s %s/%s; echo $? > %s/%s'", cwd->str_text, (option_test(OPTION_ERROK) ? "-c" : "-ce"), cwd->str_text, script_fn->str_text, cwd->str_text, result_fn->str_text ); rcmdq = str_quote_shell(rcmd); str_free(rcmd); string_list_append(&cmd, rcmdq); str_free(rcmdq); /* * This is the rest of the server side command. * * On some systems this gives ``Text file busy'' errors, * as if the script file has yet to be released by * the kernel. Since we *aren't* executing it when the * RM command runs, I have no idea how to avoid this * (other than ignoring it with -f). Maybe this is some * kind of NFS latency? */ s = str_format ( "&& exit `cat %s;rm -f %s %s`", result_fn->str_text, result_fn->str_text, script_fn->str_text ); string_list_append(&cmd, s); str_free(s); str_free(result_fn); str_free(script_fn); /* * Because the command has a semicolon and back quotes, * we need to hand it to a shell (as alluded to above). * Assemble into a single string. */ rcmd = wl2str(&cmd, 0, cmd.nstrings, (char *)0); string_list_destructor(&cmd); /* * Build the final command to be executed. * It even cleans up after itself. */ s = str_from_c("sh"); string_list_append(&cmd, s); str_free(s); s = str_from_c("-c"); string_list_append(&cmd, s); str_free(s); string_list_append(&cmd, rcmd); str_free(rcmd); } else { /* * build the command */ if (os_execute_magic_characters_list(args)) { string_ty *str; /* * what shell are we using */ shell = getenv("SHELL"); if (!shell || !*shell) shell = CONF_SHELL; string_list_constructor(&cmd); str = str_from_c(shell); string_list_append(&cmd, str); str_free(str); if (option_test(OPTION_ERROK)) str = str_from_c("-c"); else str = str_from_c("-ce"); string_list_append(&cmd, str); str_free(str); str = wl2str(args, 0, args->nstrings - 1, (char *)0); string_list_append(&cmd, str); str_free(str); } else string_list_copy_constructor(&cmd, args); } /* * build the argv array */ if (!argv) { argvlen = cmd.nstrings + 1; argv = mem_alloc(argvlen * sizeof(char *)); } else if (argvlen < cmd.nstrings + 1) { argvlen = cmd.nstrings + 1; argv = mem_change_size(argv, argvlen * sizeof(char *)); } if (cmd.nstrings == 0) { string_list_destructor(&cmd); status = opcode_status_success; goto done; } for (j = 0; j < cmd.nstrings; ++j) argv[j] = cmd.string[j]->str_text; argv[cmd.nstrings] = 0; /* * spawn the child process */ switch (pid = fork()) { case -1: scp = sub_context_new(); sub_errno_set(scp); error_intl(scp, i18n("fork(): $errno")); sub_context_delete(scp); break; case 0: /* * child */ if (fd >= 0) { if (close(0) && errno != EBADF) { string_ty *fn0; int err; err = errno; scp = sub_context_new(); fn0 = subst_intl(scp, "standard input"); /* re-use substitution context */ sub_errno_setx(scp, err); sub_var_set_string(scp, "File_Name", fn0); fatal_intl ( scp, i18n("close $filename: $errno") ); /* NOTREACHED */ sub_context_delete(scp); str_free(fn0); } if (dup(fd) < 0) { scp = sub_context_new(); sub_errno_set(scp); fatal_intl(scp, i18n("dup(): $errno")); /* NOTREACHED */ sub_context_delete(scp); } close(fd); } if (argv[0][0] == '/') execv(argv[0], argv); else execvp(argv[0], argv); scp = sub_context_new(); sub_errno_set(scp); sub_var_set_charstar(scp, "File_Name", argv[0]); fatal_intl(scp, i18n("exec $filename: $errno")); /* NOTREACHED */ sub_context_delete(scp); default: /* * parent */ if (fd >= 0) { close(fd); fd = -1; } string_list_destructor(&cmd); status = opcode_status_wait; trace(("pid = %d;\n", pid)); *pid_p = pid; break; } done: if (fd >= 0) close(fd); if (iname) str_free(iname); trace(("return %s;\n", opcode_status_name(status))); trace(("}\n")); return status; }
void IGameController::CycleMap() { if(m_aMapWish[0] != 0) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "rotating map to %s", m_aMapWish); GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); str_copy(g_Config.m_SvMap, m_aMapWish, sizeof(g_Config.m_SvMap)); m_aMapWish[0] = 0; m_RoundCount = 0; return; } if(!str_length(g_Config.m_SvMaprotation)) return; if(m_RoundCount < g_Config.m_SvRoundsPerMap-1) { if(g_Config.m_SvRoundSwap) GameServer()->SwapTeams(); return; } // handle maprotation const char *pMapRotation = g_Config.m_SvMaprotation; const char *pCurrentMap = g_Config.m_SvMap; int CurrentMapLen = str_length(pCurrentMap); const char *pNextMap = pMapRotation; while(*pNextMap) { int WordLen = 0; while(pNextMap[WordLen] && !IsSeparator(pNextMap[WordLen])) WordLen++; if(WordLen == CurrentMapLen && str_comp_num(pNextMap, pCurrentMap, CurrentMapLen) == 0) { // map found pNextMap += CurrentMapLen; while(*pNextMap && IsSeparator(*pNextMap)) pNextMap++; break; } pNextMap++; } // restart rotation if(pNextMap[0] == 0) pNextMap = pMapRotation; // cut out the next map char aBuf[512] = {0}; for(int i = 0; i < 511; i++) { aBuf[i] = pNextMap[i]; if(IsSeparator(pNextMap[i]) || pNextMap[i] == 0) { aBuf[i] = 0; break; } } // skip spaces int i = 0; while(IsSeparator(aBuf[i])) i++; m_RoundCount = 0; char aBufMsg[256]; str_format(aBufMsg, sizeof(aBufMsg), "rotating map to %s", &aBuf[i]); GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); str_copy(g_Config.m_SvMap, &aBuf[i], sizeof(g_Config.m_SvMap)); }
void CGameClient::OnPredict() { // store the previous values so we can detect prediction errors CCharacterCore BeforePrevChar = m_PredictedPrevChar; CCharacterCore BeforeChar = m_PredictedChar; // we can't predict without our own id or own character if(m_Snap.m_LocalClientID == -1 || !m_Snap.m_aCharacters[m_Snap.m_LocalClientID].m_Active) return; // don't predict anything if we are paused if(m_Snap.m_pGameInfoObj && m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED) { if(m_Snap.m_pLocalCharacter) m_PredictedChar.Read(m_Snap.m_pLocalCharacter); if(m_Snap.m_pLocalPrevCharacter) m_PredictedPrevChar.Read(m_Snap.m_pLocalPrevCharacter); return; } // repredict character CWorldCore World; World.m_Tuning = m_Tuning; // search for players for(int i = 0; i < MAX_CLIENTS; i++) { if(!m_Snap.m_aCharacters[i].m_Active || !m_Snap.m_paPlayerInfos[i]) continue; g_GameClient.m_aClients[i].m_Predicted.Init(&World, Collision(), &m_Teams); World.m_apCharacters[i] = &g_GameClient.m_aClients[i].m_Predicted; World.m_apCharacters[i]->m_Id = m_Snap.m_paPlayerInfos[i]->m_ClientID; g_GameClient.m_aClients[i].m_Predicted.Read(&m_Snap.m_aCharacters[i].m_Cur); } // predict for(int Tick = Client()->GameTick()+1; Tick <= Client()->PredGameTick(); Tick++) { // fetch the local if(Tick == Client()->PredGameTick() && World.m_apCharacters[m_Snap.m_LocalClientID]) m_PredictedPrevChar = *World.m_apCharacters[m_Snap.m_LocalClientID]; // first calculate where everyone should move for(int c = 0; c < MAX_CLIENTS; c++) { if(!World.m_apCharacters[c]) continue; mem_zero(&World.m_apCharacters[c]->m_Input, sizeof(World.m_apCharacters[c]->m_Input)); if(m_Snap.m_LocalClientID == c) { // apply player input int *pInput = Client()->GetInput(Tick); if(pInput) World.m_apCharacters[c]->m_Input = *((CNetObj_PlayerInput*)pInput); World.m_apCharacters[c]->Tick(true); } else World.m_apCharacters[c]->Tick(false); } // move all players and quantize their data for(int c = 0; c < MAX_CLIENTS; c++) { if(!World.m_apCharacters[c]) continue; World.m_apCharacters[c]->Move(); World.m_apCharacters[c]->Quantize(); } // check if we want to trigger effects if(Tick > m_LastNewPredictedTick) { m_LastNewPredictedTick = Tick; m_NewPredictedTick = true; if(m_Snap.m_LocalClientID != -1 && World.m_apCharacters[m_Snap.m_LocalClientID]) { vec2 Pos = World.m_apCharacters[m_Snap.m_LocalClientID]->m_Pos; int Events = World.m_apCharacters[m_Snap.m_LocalClientID]->m_TriggeredEvents; if(Events&COREEVENT_GROUND_JUMP) g_GameClient.m_pSounds->PlayAndRecord(CSounds::CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, Pos); /*if(events&COREEVENT_AIR_JUMP) { GameClient.effects->air_jump(pos); GameClient.sounds->play_and_record(SOUNDS::CHN_WORLD, SOUND_PLAYER_AIRJUMP, 1.0f, pos); }*/ //if(events&COREEVENT_HOOK_LAUNCH) snd_play_random(CHN_WORLD, SOUND_HOOK_LOOP, 1.0f, pos); //if(events&COREEVENT_HOOK_ATTACH_PLAYER) snd_play_random(CHN_WORLD, SOUND_HOOK_ATTACH_PLAYER, 1.0f, pos); if(Events&COREEVENT_HOOK_ATTACH_GROUND) g_GameClient.m_pSounds->PlayAndRecord(CSounds::CHN_WORLD, SOUND_HOOK_ATTACH_GROUND, 1.0f, Pos); if(Events&COREEVENT_HOOK_HIT_NOHOOK) g_GameClient.m_pSounds->PlayAndRecord(CSounds::CHN_WORLD, SOUND_HOOK_NOATTACH, 1.0f, Pos); //if(events&COREEVENT_HOOK_RETRACT) snd_play_random(CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, pos); } } if(Tick == Client()->PredGameTick() && World.m_apCharacters[m_Snap.m_LocalClientID]) m_PredictedChar = *World.m_apCharacters[m_Snap.m_LocalClientID]; } if(g_Config.m_Debug && g_Config.m_ClPredict && m_PredictedTick == Client()->PredGameTick()) { CNetObj_CharacterCore Before = {0}, Now = {0}, BeforePrev = {0}, NowPrev = {0}; BeforeChar.Write(&Before); BeforePrevChar.Write(&BeforePrev); m_PredictedChar.Write(&Now); m_PredictedPrevChar.Write(&NowPrev); if(mem_comp(&Before, &Now, sizeof(CNetObj_CharacterCore)) != 0) { Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client", "prediction error"); for(unsigned i = 0; i < sizeof(CNetObj_CharacterCore)/sizeof(int); i++) if(((int *)&Before)[i] != ((int *)&Now)[i]) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), " %d %d %d (%d %d)", i, ((int *)&Before)[i], ((int *)&Now)[i], ((int *)&BeforePrev)[i], ((int *)&NowPrev)[i]); Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client", aBuf); } } } m_PredictedTick = Client()->PredGameTick(); }