bool SendServerMessage(const std::string &body, PeerBitSet peers) { auto session = Blam::Network::GetActiveSession(); if (!session || !session->IsEstablished() || !session->IsHost()) return false; ChatMessage message(ChatMessageType::Server, body); return BroadcastMessage(session, session->MembershipInfo.LocalPeerIndex, &message, peers); }
bool SendTeamMessage(const std::string &body) { auto session = Blam::Network::GetActiveSession(); if (!session || !session->IsEstablished() || !session->HasTeams()) return false; ChatMessage message(ChatMessageType::Team, body); return SendClientMessage(session, message); }
QueryError OnScoreboard(const rapidjson::Value &p_Args, std::string *p_Result) { auto session = Blam::Network::GetActiveSession(); if (!session || !session->IsEstablished()) { *p_Result = "Cannot get scoreboard data when there is not an active session."; return QueryError_BadQuery; } *p_Result = Web::Ui::WebScoreboard::getScoreboard(); return QueryError_Ok; }
bool CClientSession::Close() { CMessageBase* pAck = NULL; if( IsEstablished() ){ CMessageBase msg; msg.Init( NCM_CLOSESESSION, GetAddr(), GetServAddr() ); m_pClntProxy->SendMessage( &msg ); pAck = WaitForMessage(NCF_ACK|NCM_CLOSESESSION); SetState( CSS_CLOSED ); } m_pClntProxy->CloseChannel( this ); CMessageTrash trash( pAck ); return pAck!=NULL && pAck->IsSucceeded(); }
//Should keep the script kiddies away. //TODO: Replace with a better check BOOL CALLBACK AntiTrainer(HWND hwnd, LPARAM lParam) { char title[80]; GetWindowText(hwnd, title, sizeof(title)); if (strcmp(title, "Halo Online Trainer") == 0) { auto session = Blam::Network::GetActiveSession(); if (session && session->IsEstablished() && !session->IsHost()) { MessageBox(NULL, "Detected Halo Online Trainer!\nOnly hosts are allowed to use a trainer!", "AntiCheat", MB_OK); //Tell the user what they did wrong. Modules::CommandMap::Instance().ExecuteCommand("exit"); //exit game } } return TRUE; }
QueryError OnMapVariantInfo(const rapidjson::Value &p_Args, std::string *p_Result) { // Get the map variant session parameter auto session = Blam::Network::GetActiveSession(); if (!session || !session->IsEstablished()) { *p_Result = "Not available: A game session is not active"; return QueryError_NotAvailable; } auto mapVariant = reinterpret_cast<uint8_t*>(session->Parameters.MapVariant.Get()); if (!mapVariant) { *p_Result = "Not available: Map variant data is not available"; return QueryError_NotAvailable; } // Get values out of it auto name = Utils::String::ThinString(reinterpret_cast<const wchar_t*>(mapVariant + 0x8)); auto description = reinterpret_cast<const char*>(mapVariant + 0x28); auto author = reinterpret_cast<const char*>(mapVariant + 0xA8); auto mapId = *reinterpret_cast<uint32_t*>(mapVariant + 0x100); // Build a JSON response rapidjson::StringBuffer buffer; rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); writer.StartObject(); writer.Key("name"); writer.String(name.c_str()); writer.Key("description"); writer.String(description); writer.Key("author"); writer.String(author); writer.Key("mapId"); writer.Int64(mapId); writer.EndObject(); *p_Result = buffer.GetString(); return QueryError_Ok; }
QueryError OnSessionInfo(const rapidjson::Value &p_Args, std::string *p_Result) { rapidjson::StringBuffer buffer; rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); writer.StartObject(); auto session = Blam::Network::GetActiveSession(); if (!session || !session->IsEstablished()) { writer.Key("established"); writer.Bool(false); writer.Key("hasTeams"); writer.Bool(false); writer.Key("isHost"); writer.Bool(false); } else { writer.Key("established"); writer.Bool(true); writer.Key("hasTeams"); writer.Bool(session->HasTeams()); writer.Key("isHost"); writer.Bool(session->IsHost()); } writer.Key("mapName"); writer.String((char*)Pointer(0x22AB018)(0x1A4)); writer.EndObject(); *p_Result = buffer.GetString(); return QueryError_Ok; }
QueryError OnStats(const rapidjson::Value &p_Args, std::string *p_Result) { auto name = p_Args.FindMember("playerName"); if (name == p_Args.MemberEnd() || !name->value.IsString()) { *p_Result = "Bad query: A \"playerName\" argument is required and must be a string"; return QueryError_BadQuery; } auto session = Blam::Network::GetActiveSession(); if (!session || !session->IsEstablished()) { *p_Result = "Cannot get stat data when there is not an active session."; return QueryError_BadQuery; } int playerIdx = session->MembershipInfo.FindFirstPlayer(); while (playerIdx != -1) { auto player = session->MembershipInfo.PlayerSessions[playerIdx]; if (strcmp(Utils::String::ThinString(player.Properties.DisplayName).c_str(), name->value.GetString()) == 0) { rapidjson::StringBuffer buffer; rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); auto playerStats = Blam::Players::GetStats(playerIdx); auto pvpStats = Blam::Players::GetPVPStats(playerIdx); writer.StartObject(); writer.Key("playerkilledplayer"); writer.StartArray(); for (int i = 0; i < 16; i++) { if (pvpStats.StatsAgainstEachPlayer[i].Kills > 0) { auto p = session->MembershipInfo.PlayerSessions[i]; writer.StartObject(); writer.Key("PlayerName"); writer.String(Utils::String::ThinString(p.Properties.DisplayName).c_str()); writer.Key("Kills"); writer.Int(pvpStats.StatsAgainstEachPlayer[i].Kills); writer.EndObject(); } } writer.EndArray(); writer.Key("playerkilledby"); writer.StartArray(); for (int i = 0; i < 16; i++) { if (pvpStats.StatsAgainstEachPlayer[i].KilledBy > 0) { auto p = session->MembershipInfo.PlayerSessions[i]; writer.StartObject(); writer.Key("PlayerName"); writer.String(Utils::String::ThinString(p.Properties.DisplayName).c_str()); writer.Key("Kills"); writer.Int(pvpStats.StatsAgainstEachPlayer[i].KilledBy); writer.EndObject(); } } writer.EndArray(); writer.Key("medals"); writer.StartObject(); for (int medal = 0; medal < Blam::Tags::Objects::MedalType::MedalCount; medal++) { writer.Key(Blam::Tags::Objects::MedalTypeNames[medal].c_str()); writer.Int(playerStats.Medals[medal]); } writer.EndObject(); writer.Key("weapons"); writer.StartObject(); for (int weapon = 0; weapon < Blam::Tags::Objects::DamageReportingType::DamageCount; weapon++) { writer.Key(Blam::Tags::Objects::DamageReportingTypeNames[weapon].c_str()); writer.StartObject(); auto wep = playerStats.WeaponStats[weapon]; writer.Key("BetrayalsWith"); writer.Int(wep.BetrayalsWith); writer.Key("HeadshotsWith"); writer.Int(wep.HeadshotsWith); writer.Key("KilledBy"); writer.Int(wep.KilledBy); writer.Key("Kills"); writer.Int(wep.Kills); writer.Key("SuicidesWith"); writer.Int(wep.SuicidesWith); writer.EndObject(); } writer.EndObject(); writer.EndObject(); *p_Result = buffer.GetString(); return QueryError_Ok; } playerIdx = session->MembershipInfo.FindNextPlayer(playerIdx); } *p_Result = "Could not find player."; return QueryError_BadQuery; }
QueryError OnGameVariantInfo(const rapidjson::Value &p_Args, std::string *p_Result) { // Get the game variant session parameter auto session = Blam::Network::GetActiveSession(); if (!session || !session->IsEstablished()) { *p_Result = "Not available: A game session is not active"; return QueryError_NotAvailable; } auto gameVariant = session->Parameters.GameVariant.Get(); if (!gameVariant) { *p_Result = "Not available: Game variant data is not available"; return QueryError_NotAvailable; } // Get values out of it auto mode = gameVariant->GameType; auto name = Utils::String::ThinString(gameVariant->Name); auto description = gameVariant->Description; auto author = gameVariant->Author; auto teams = (gameVariant->TeamGame & 1) != 0; auto timeLimit = gameVariant->RoundTimeLimit; auto rounds = gameVariant->NumberOfRounds; // The score-to-win value location varies depending on gametype auto scoreToWin = -1; auto rawGameVariant = reinterpret_cast<uint8_t*>(gameVariant); switch (gameVariant->GameType) { case Blam::GameType::Slayer: scoreToWin = *reinterpret_cast<int16_t*>(rawGameVariant + 0x1D4); break; case Blam::GameType::Oddball: scoreToWin = *reinterpret_cast<int16_t*>(rawGameVariant + 0x1D8); break; case Blam::GameType::KOTH: scoreToWin = *reinterpret_cast<int16_t*>(rawGameVariant + 0x1D8); break; case Blam::GameType::CTF: scoreToWin = *reinterpret_cast<int16_t*>(rawGameVariant + 0x1DC); break; case Blam::GameType::Assault: scoreToWin = *reinterpret_cast<int16_t*>(rawGameVariant + 0x1DC); break; case Blam::GameType::Juggernaut: scoreToWin = *reinterpret_cast<int16_t*>(rawGameVariant + 0x1D4); break; case Blam::GameType::VIP: scoreToWin = *reinterpret_cast<int16_t*>(rawGameVariant + 0x1D4); break; } // Build a JSON response rapidjson::StringBuffer buffer; rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); writer.StartObject(); writer.Key("mode"); writer.Int(mode); writer.Key("name"); writer.String(name.c_str()); writer.Key("description"); writer.String(description); writer.Key("author"); writer.String(author); writer.Key("teams"); writer.Bool(teams); writer.Key("timeLimit"); writer.Int(timeLimit); writer.Key("rounds"); writer.Int(rounds); writer.Key("scoreToWin"); writer.Int(scoreToWin); writer.EndObject(); *p_Result = buffer.GetString(); return QueryError_Ok; }
bool CommandMap::ExecuteCommandWithStatus(std::string command, bool isUserInput, std::string *output) { *output = ""; int numArgs = 0; auto args = CommandLineToArgvA((PCHAR)command.c_str(), &numArgs); if (numArgs <= 0) { *output = "Invalid input"; return false; } auto cmd = FindCommand(args[0]); if (!cmd || (isUserInput && cmd->Flags & eCommandFlagsInternal)) { *output = "Command/Variable not found"; return false; } if ((cmd->Flags & eCommandFlagsRunOnMainMenu) && !ElDorito::Instance().GameHasMenuShown) { queuedCommands.push_back(command); *output = "Command queued until mainmenu shows"; return true; } // Host-only commands if (cmd->Flags & eCommandFlagsCheat || cmd->Flags & eCommandFlagsHostOnly) { auto session = Blam::Network::GetActiveSession(); if (session && session->IsEstablished() && !session->IsHost()) { *output = "Only a player hosting a game can use this command"; return false; } } std::vector<std::string> argsVect; if (numArgs > 1) for (int i = 1; i < numArgs; i++) argsVect.push_back(args[i]); if (cmd->Type == eCommandTypeCommand && cmd->Flags == eCommandFlagsArgsNoParse) { argsVect.clear(); if (numArgs >= 2) argsVect.push_back(command.substr(std::strlen(args[0]) + 1)); //push unparsed arguments after the command return cmd->UpdateEvent(argsVect, *output); } if (cmd->Type == eCommandTypeCommand) return cmd->UpdateEvent(argsVect, *output); // if it's a command call it and return if (numArgs <= 1) { *output = cmd->ValueString; return true; } std::string previousValue; auto updateRet = SetVariable(cmd, argsVect[0], previousValue); switch (updateRet) { case eVariableSetReturnValueError: *output = "Command/variable not found"; return false; case eVariableSetReturnValueInvalidArgument: *output = "Invalid value"; return false; case eVariableSetReturnValueOutOfRange: if (cmd->Type == eCommandTypeVariableInt) *output = "Value " + argsVect[0] + " out of range [" + std::to_string(cmd->ValueIntMin) + ".." + std::to_string(cmd->ValueIntMax) + "]"; else if (cmd->Type == eCommandTypeVariableInt64) *output = "Value " + argsVect[0] + " out of range [" + std::to_string(cmd->ValueInt64Min) + ".." + std::to_string(cmd->ValueInt64Max) + "]"; else if (cmd->Type == eCommandTypeVariableFloat) *output = "Value " + argsVect[0] + " out of range [" + std::to_string(cmd->ValueFloatMin) + ".." + std::to_string(cmd->ValueFloatMax) + "]"; else *output = "Value " + argsVect[0] + " out of range [this shouldn't be happening!]"; return false; } if (!cmd->UpdateEvent) { *output = previousValue + " -> " + cmd->ValueString; // no update event, so we'll just return with what we set the value to return true; } auto ret = cmd->UpdateEvent(argsVect, *output); if (!ret) // error, revert the variable this->SetVariable(cmd, previousValue, std::string()); if (output->length() <= 0) *output = previousValue + " -> " + cmd->ValueString; return ret; }