Fixed player avoidance code.

Speedup network message handling.
This commit is contained in:
joint 2019-08-12 14:16:28 +03:00 committed by jeefo
commit 9947e41549
26 changed files with 2398 additions and 2294 deletions

View file

@ -17,11 +17,6 @@ Game::Game () {
m_startEntity = nullptr;
m_localEntity = nullptr;
resetMessages ();
for (auto &msg : m_msgBlock.regMsgs) {
msg = NetMsg::None;
}
m_precached = false;
m_isBotCommand = false;
@ -35,10 +30,6 @@ Game::Game () {
m_cvars.clear ();
}
Game::~Game () {
resetMessages ();
}
void Game::precache () {
if (m_precached) {
return;
@ -387,7 +378,7 @@ uint8 *Game::getVisibilitySet (Bot *bot, bool pvs) {
void Game::sendClientMessage (bool console, edict_t *ent, const char *message) {
// helper to sending the client message
MessageWriter (MSG_ONE, getMessageId (NetMsg::TextMsg), nullvec, ent)
MessageWriter (MSG_ONE, msgs.id (NetMsg::TextMsg), nullvec, ent)
.writeByte (console ? HUD_PRINTCONSOLE : HUD_PRINTCENTER)
.writeString (message);
}
@ -541,490 +532,6 @@ void Game::registerCvars (bool gameVars) {
}
}
void Game::processMessages (void *ptr) {
if (m_msgBlock.msg == NetMsg::None) {
return;
}
// some needed variables
static uint8 r, g, b;
static uint8 enabled;
static int damageArmor, damageTaken, damageBits;
static int killerIndex, victimIndex, playerIndex;
static int index, numPlayers;
static int state, id, clip;
static Vector damageOrigin;
static WeaponProp weaponProp;
// some widely used stuff
auto bot = bots[m_msgBlock.bot];
auto strVal = reinterpret_cast <char *> (ptr);
auto intVal = *reinterpret_cast <int *> (ptr);
auto byteVal = *reinterpret_cast <uint8 *> (ptr);
// now starts of network message execution
switch (m_msgBlock.msg) {
case NetMsg::VGUI:
// this message is sent when a VGUI menu is displayed.
if (bot != nullptr && m_msgBlock.state == 0) {
switch (intVal) {
case GuiMenu::TeamSelect:
bot->m_startAction = BotMsg::TeamSelect;
break;
case GuiMenu::TerroristSelect:
case GuiMenu::CTSelect:
bot->m_startAction = BotMsg::ClassSelect;
break;
}
}
break;
case NetMsg::ShowMenu:
// this message is sent when a text menu is displayed.
// ignore first 3 fields of message
if (m_msgBlock.state < 3 || bot == nullptr) {
break;
}
if (strcmp (strVal, "#Team_Select") == 0) {
bot->m_startAction = BotMsg::TeamSelect;
}
else if (strcmp (strVal, "#Team_Select_Spect") == 0) {
bot->m_startAction = BotMsg::TeamSelect;
}
else if (strcmp (strVal, "#IG_Team_Select_Spect") == 0) {
bot->m_startAction = BotMsg::TeamSelect;
}
else if (strcmp (strVal, "#IG_Team_Select") == 0) {
bot->m_startAction = BotMsg::TeamSelect;
}
else if (strcmp (strVal, "#IG_VIP_Team_Select") == 0) {
bot->m_startAction = BotMsg::TeamSelect;
}
else if (strcmp (strVal, "#IG_VIP_Team_Select_Spect") == 0) {
bot->m_startAction = BotMsg::TeamSelect;
}
else if (strcmp (strVal, "#Terrorist_Select") == 0) {
bot->m_startAction = BotMsg::ClassSelect;
}
else if (strcmp (strVal, "#CT_Select") == 0) {
bot->m_startAction = BotMsg::ClassSelect;
}
break;
case NetMsg::WeaponList:
// this message is sent when a client joins the game. All of the weapons are sent with the weapon ID and information about what ammo is used.
switch (m_msgBlock.state) {
case 0:
strncpy (weaponProp.classname, strVal, cr::bufsize (weaponProp.classname));
break;
case 1:
weaponProp.ammo1 = intVal; // ammo index 1
break;
case 2:
weaponProp.ammo1Max = intVal; // max ammo 1
break;
case 5:
weaponProp.slot = intVal; // slot for this weapon
break;
case 6:
weaponProp.pos = intVal; // position in slot
break;
case 7:
weaponProp.id = intVal; // weapon ID
break;
case 8:
weaponProp.flags = intVal; // flags for weapon (WTF???)
conf.setWeaponProp (weaponProp); // store away this weapon with it's ammo information...
break;
}
break;
case NetMsg::CurWeapon:
// this message is sent when a weapon is selected (either by the bot chosing a weapon or by the server auto assigning the bot a weapon). In CS it's also called when Ammo is increased/decreased
switch (m_msgBlock.state) {
case 0:
state = intVal; // state of the current weapon (WTF???)
break;
case 1:
id = intVal; // weapon ID of current weapon
break;
case 2:
clip = intVal; // ammo currently in the clip for this weapon
if (bot != nullptr && id <= 31) {
if (state != 0) {
bot->m_currentWeapon = id;
}
// ammo amount decreased ? must have fired a bullet...
if (id == bot->m_currentWeapon && bot->m_ammoInClip[id] > clip) {
bot->m_timeLastFired = timebase (); // remember the last bullet time
}
bot->m_ammoInClip[id] = clip;
}
break;
}
break;
case NetMsg::AmmoX:
// this message is sent whenever ammo amounts are adjusted (up or down). NOTE: Logging reveals that CS uses it very unreliable!
switch (m_msgBlock.state) {
case 0:
index = intVal; // ammo index (for type of ammo)
break;
case 1:
if (bot != nullptr) {
bot->m_ammo[index] = intVal; // store it away
}
break;
}
break;
case NetMsg::AmmoPickup:
// this message is sent when the bot picks up some ammo (AmmoX messages are also sent so this message is probably
// not really necessary except it allows the HUD to draw pictures of ammo that have been picked up. The bots
// don't really need pictures since they don't have any eyes anyway.
switch (m_msgBlock.state) {
case 0:
index = intVal;
break;
case 1:
if (bot != nullptr) {
bot->m_ammo[index] = intVal;
}
break;
}
break;
case NetMsg::Damage:
// this message gets sent when the bots are getting damaged.
switch (m_msgBlock.state) {
case 0:
damageArmor = intVal;
break;
case 1:
damageTaken = intVal;
break;
case 2:
damageBits = intVal;
if (bot != nullptr && (damageArmor > 0 || damageTaken > 0)) {
bot->processDamage (bot->pev->dmg_inflictor, damageTaken, damageArmor, damageBits);
}
break;
}
break;
case NetMsg::Money:
// this message gets sent when the bots money amount changes
if (bot != nullptr && m_msgBlock.state == 0) {
bot->m_moneyAmount = intVal; // amount of money
}
break;
case NetMsg::StatusIcon:
switch (m_msgBlock.state) {
case 0:
enabled = byteVal;
break;
case 1:
if (bot != nullptr) {
if (strcmp (strVal, "buyzone") == 0) {
bot->m_inBuyZone = (enabled != 0);
// try to equip in buyzone
bot->processBuyzoneEntering (BuyState::PrimaryWeapon);
}
else if (strcmp (strVal, "vipsafety") == 0) {
bot->m_inVIPZone = (enabled != 0);
}
else if (strcmp (strVal, "c4") == 0) {
bot->m_inBombZone = (enabled == 2);
}
}
break;
}
break;
case NetMsg::DeathMsg: // this message sends on death
switch (m_msgBlock.state) {
case 0:
killerIndex = intVal;
break;
case 1:
victimIndex = intVal;
break;
case 2:
if (killerIndex != 0 && killerIndex != victimIndex) {
edict_t *killer = entityOfIndex (killerIndex);
edict_t *victim = entityOfIndex (victimIndex);
if (isNullEntity (killer) || isNullEntity (victim)) {
break;
}
if (yb_radio_mode.int_ () == 2) {
// need to send congrats on well placed shot
for (const auto &notify : bots) {
if (notify->m_notKilled && killer != notify->ent () && notify->seesEntity (victim->v.origin) && getTeam (killer) == notify->m_team && getTeam (killer) != getTeam (victim)) {
if (!bots[killer]) {
notify->processChatterMessage ("#Bot_NiceShotCommander");
}
else {
notify->processChatterMessage ("#Bot_NiceShotPall");
}
break;
}
}
}
// notice nearby to victim teammates, that attacker is near
for (const auto &notify : bots) {
if (notify->m_seeEnemyTime + 2.0f < timebase () && notify->m_notKilled && notify->m_team == getTeam (victim) && util.isVisible (killer->v.origin, notify->ent ()) && isNullEntity (notify->m_enemy) && getTeam (killer) != getTeam (victim)) {
notify->m_actualReactionTime = 0.0f;
notify->m_seeEnemyTime = timebase ();
notify->m_enemy = killer;
notify->m_lastEnemy = killer;
notify->m_lastEnemyOrigin = killer->v.origin;
}
}
auto notify = bots[killer];
// is this message about a bot who killed somebody?
if (notify != nullptr) {
notify->m_lastVictim = victim;
}
else // did a human kill a bot on his team?
{
auto target = bots[victim];
if (target != nullptr) {
if (getTeam (killer) == target->m_team) {
target->m_voteKickIndex = killerIndex;
}
target->m_notKilled = false;
}
}
}
break;
}
break;
case NetMsg::ScreenFade: // this message gets sent when the screen fades (flashbang)
switch (m_msgBlock.state) {
case 3:
r = byteVal;
break;
case 4:
g = byteVal;
break;
case 5:
b = byteVal;
break;
case 6:
if (bot != nullptr && r >= 255 && g >= 255 && b >= 255 && byteVal > 170) {
bot->processBlind (byteVal);
}
break;
}
break;
case NetMsg::HLTV: // round restart in steam cs
switch (m_msgBlock.state) {
case 0:
numPlayers = intVal;
break;
case 1:
if (numPlayers == 0 && intVal == 0) {
bots.initRound ();
}
break;
}
break;
case NetMsg::TextMsg:
if (m_msgBlock.state == 1) {
if (strcmp (strVal, "#CTs_Win") == 0 ||
strcmp (strVal, "#Bomb_Defused") == 0 ||
strcmp (strVal, "#Terrorists_Win") == 0 ||
strcmp (strVal, "#Round_Draw") == 0 ||
strcmp (strVal, "#All_Hostages_Rescued") == 0 ||
strcmp (strVal, "#Target_Saved") == 0 ||
strcmp (strVal, "#Hostages_Not_Rescued") == 0 ||
strcmp (strVal, "#Terrorists_Not_Escaped") == 0 ||
strcmp (strVal, "#VIP_Not_Escaped") == 0 ||
strcmp (strVal, "#Escaping_Terrorists_Neutralized") == 0 ||
strcmp (strVal, "#VIP_Assassinated") == 0 ||
strcmp (strVal, "#VIP_Escaped") == 0 ||
strcmp (strVal, "#Terrorists_Escaped") == 0 ||
strcmp (strVal, "#CTs_PreventEscape") == 0 ||
strcmp (strVal, "#Target_Bombed") == 0 ||
strcmp (strVal, "#Game_Commencing") == 0 ||
strcmp (strVal, "#Game_will_restart_in") == 0) {
bots.setRoundOver (true);
if (strcmp (strVal, "#Game_Commencing") == 0) {
util.setNeedForWelcome (true);
}
if (strcmp (strVal, "#CTs_Win") == 0) {
bots.setLastWinner (Team::CT); // update last winner for economics
if (yb_radio_mode.int_ () == 2) {
Bot *notify = bots.findAliveBot ();
if (notify != nullptr && notify->m_notKilled) {
notify->processChatterMessage (strVal);
}
}
}
if (strcmp (strVal, "#Game_will_restart_in") == 0) {
bots.updateTeamEconomics (Team::CT, true);
bots.updateTeamEconomics (Team::Terrorist, true);
}
if (strcmp (strVal, "#Terrorists_Win") == 0) {
bots.setLastWinner (Team::Terrorist); // update last winner for economics
if (yb_radio_mode.int_ () == 2) {
Bot *notify = bots.findAliveBot ();
if (notify != nullptr && notify->m_notKilled) {
notify->processChatterMessage (strVal);
}
}
}
graph.setBombPos (true);
}
else if (!bots.isBombPlanted () && strcmp (strVal, "#Bomb_Planted") == 0) {
bots.setBombPlanted (true);
for (const auto &notify : bots) {
if (notify->m_notKilled) {
notify->clearSearchNodes ();
notify->clearTasks ();
if (yb_radio_mode.int_ () == 2 && rg.chance (55) && notify->m_team == Team::CT) {
notify->pushChatterMessage (Chatter::WhereIsTheC4);
}
}
}
graph.setBombPos ();
}
else if (bot != nullptr && strcmp (strVal, "#Switch_To_BurstFire") == 0) {
bot->m_weaponBurstMode = BurstMode::On;
}
else if (bot != nullptr && strcmp (strVal, "#Switch_To_SemiAuto") == 0) {
bot->m_weaponBurstMode = BurstMode::Off;
}
}
break;
case NetMsg::TeamInfo:
switch (m_msgBlock.state) {
case 0:
playerIndex = intVal;
break;
case 1:
if (playerIndex > 0 && playerIndex <= maxClients ()) {
int team = Team::Unassigned;
if (strVal[0] == 'U' && strVal[1] == 'N') {
team = Team::Unassigned;
}
else if (strVal[0] == 'T' && strVal[1] == 'E') {
team = Team::Terrorist;
}
else if (strVal[0] == 'C' && strVal[1] == 'T') {
team = Team::CT;
}
else if (strVal[0] == 'S' && strVal[1] == 'P') {
team = Team::Spectator;
}
auto &client = util.getClient (playerIndex - 1);
client.team2 = team;
client.team = is (GameFlags::FreeForAll) ? playerIndex : team;
}
break;
}
break;
case NetMsg::BarTime:
if (bot != nullptr && m_msgBlock.state == 0) {
if (intVal > 0) {
bot->m_hasProgressBar = true; // the progress bar on a hud
if (mapIs (MapFlags::Demolition) && bots.isBombPlanted () && bot->m_team == Team::CT) {
bots.notifyBombDefuse ();
}
}
else if (intVal == 0) {
bot->m_hasProgressBar = false; // no progress bar or disappeared
}
}
break;
case NetMsg::ItemStatus:
if (bot != nullptr && m_msgBlock.state == 0) {
bot->m_hasNVG = (intVal & ItemStatus::Nightvision) ? true : false;
bot->m_hasDefuser = (intVal & ItemStatus::DefusalKit) ? true : false;
}
break;
case NetMsg::FlashBat:
if (bot != nullptr && m_msgBlock.state == 0) {
bot->m_flashLevel = static_cast <float> (intVal);
}
break;
case NetMsg::NVGToggle:
if (bot != nullptr && m_msgBlock.state == 0) {
bot->m_usesNVG = intVal > 0;
}
break;
default:
logger.error ("Network message handler error. Call to unrecognized message id (%d).\n", m_msgBlock.msg);
}
++m_msgBlock.state; // and finally update network message state
}
bool Game::loadCSBinary () {
auto modname = getModName ();
@ -1257,82 +764,6 @@ void Game::slowFrame () {
m_slowFrame = timebase () + 1.0f;
}
void Game::beginMessage (edict_t *ent, int dest, int type) {
// store the message type in our own variables, since the GET_USER_MSG_ID () will just do a lot of strcmp()'s...
if (is (GameFlags::Metamod) && getMessageId (NetMsg::Money) == -1) {
auto setMsgId = [&] (const char *name, NetMsg id) {
setMessageId (id, GET_USER_MSG_ID (PLID, name, nullptr));
};
setMsgId ("VGUIMenu", NetMsg::VGUI);
setMsgId ("ShowMenu", NetMsg::ShowMenu);
setMsgId ("WeaponList", NetMsg::WeaponList);
setMsgId ("CurWeapon", NetMsg::CurWeapon);
setMsgId ("AmmoX", NetMsg::AmmoX);
setMsgId ("AmmoPickup", NetMsg::AmmoPickup);
setMsgId ("Damage", NetMsg::Damage);
setMsgId ("Money", NetMsg::Money);
setMsgId ("StatusIcon", NetMsg::StatusIcon);
setMsgId ("DeathMsg", NetMsg::DeathMsg);
setMsgId ("ScreenFade", NetMsg::ScreenFade);
setMsgId ("HLTV", NetMsg::HLTV);
setMsgId ("TextMsg", NetMsg::TextMsg);
setMsgId ("TeamInfo", NetMsg::TeamInfo);
setMsgId ("BarTime", NetMsg::BarTime);
setMsgId ("SendAudio", NetMsg::SendAudio);
setMsgId ("SayText", NetMsg::SayText);
setMsgId ("FlashBat", NetMsg::FlashBat);
setMsgId ("Flashlight", NetMsg::Fashlight);
setMsgId ("NVGToggle", NetMsg::NVGToggle);
setMsgId ("ItemStatus", NetMsg::ItemStatus);
if (is (GameFlags::HasBotVoice)) {
setMessageId (NetMsg::BotVoice, GET_USER_MSG_ID (PLID, "BotVoice", nullptr));
}
}
if ((!is (GameFlags::Legacy) || is (GameFlags::Xash3D)) && dest == MSG_SPEC && type == getMessageId (NetMsg::HLTV)) {
setCurrentMessageId (NetMsg::HLTV);
}
captureMessage (type, NetMsg::WeaponList);
if (!isNullEntity (ent) && !(ent->v.flags & FL_DORMANT)) {
auto bot = bots[ent];
// is this message for a bot?
if (bot != nullptr) {
setCurrentMessageOwner (bot->index ());
// message handling is done in usermsg.cpp
captureMessage (type, NetMsg::VGUI);
captureMessage (type, NetMsg::CurWeapon);
captureMessage (type, NetMsg::AmmoX);
captureMessage (type, NetMsg::AmmoPickup);
captureMessage (type, NetMsg::Damage);
captureMessage (type, NetMsg::Money);
captureMessage (type, NetMsg::StatusIcon);
captureMessage (type, NetMsg::ScreenFade);
captureMessage (type, NetMsg::BarTime);
captureMessage (type, NetMsg::TextMsg);
captureMessage (type, NetMsg::ShowMenu);
captureMessage (type, NetMsg::FlashBat);
captureMessage (type, NetMsg::NVGToggle);
captureMessage (type, NetMsg::ItemStatus);
}
}
else if (dest == MSG_ALL) {
captureMessage (type, NetMsg::TeamInfo);
captureMessage (type, NetMsg::DeathMsg);
captureMessage (type, NetMsg::TextMsg);
if (type == SVC_INTERMISSION) {
for (const auto &bot : bots) {
bot->m_notKilled = false;
}
}
}
}
void LightMeasure::initializeLightstyles () {
// this function initializes lighting information...
@ -1376,7 +807,7 @@ void LightMeasure::updateLight (int style, char *value) {
return;
}
if (util.isEmptyStr (value)){
if (strings.isEmpty (value)){
m_lightstyle[style].length = 0u;
m_lightstyle[style].map[0] = '\0';