crlib: reworked dictionary to hashmap.

linkage: another fix to dynamic linkage.
cpp: fixed msvc warning about placement new.
This commit is contained in:
dmitry 2020-06-15 22:36:11 +03:00 committed by jeefo
commit 43f6a7828a
12 changed files with 291 additions and 312 deletions

View file

@ -22,9 +22,10 @@
CR_NAMESPACE_BEGIN
// template for hashing our string
template <typename K> struct StringHash {
uint32 operator () (const K &key) const {
template <typename T> struct Hash;
template <> struct Hash <String> {
uint32 operator () (const String &key) const noexcept {
auto str = const_cast <char *> (key.chars ());
uint32 hash = 0;
@ -35,9 +36,32 @@ template <typename K> struct StringHash {
}
};
// template for hashing integers
template <typename K> struct IntHash {
uint32 operator () (K key) const {
template <> struct Hash <StringRef> {
uint32 operator () (const StringRef &key) const noexcept {
auto str = const_cast <char *> (key.chars ());
uint32 hash = 0;
while (*str++) {
hash = ((hash << 5) + hash) + *str;
}
return hash;
}
};
template <> struct Hash <const char *> {
uint32 operator () (const char *key) const noexcept {
auto str = const_cast <char *> (key);
uint32 hash = 0;
while (*str++) {
hash = ((hash << 5) + hash) + *str;
}
return hash;
}
};
template <> struct Hash <int32> {
uint32 operator () (int32 key) const noexcept {
key = ((key >> 16) ^ key) * 0x119de1f3;
key = ((key >> 16) ^ key) * 0x119de1f3;
key = (key >> 16) ^ key;
@ -46,225 +70,184 @@ template <typename K> struct IntHash {
}
};
// template for np hashing integers
template <typename K> struct IntNoHash {
uint32 operator () (K key) const {
template <typename T> struct EmptyHash {
uint32 operator () (T key) const noexcept {
return static_cast <uint32> (key);
}
};
namespace detail {
struct DictionaryList {
uint32 index;
DictionaryList *next;
};
template <typename K, typename V> struct DictionaryBucket {
uint32 hash = static_cast <uint32> (-1);
template <typename K, typename V> struct HashEntry final : DenyCopying {
public:
K key {};
V value {};
bool used { false };
public:
DictionaryBucket () = default;
~DictionaryBucket () = default;
HashEntry () = default;
~HashEntry () = default;
public:
DictionaryBucket (DictionaryBucket &&rhs) noexcept : hash (rhs.hash), key (cr::move (rhs.key)), value (cr::move (rhs.value))
HashEntry (HashEntry &&rhs) noexcept : used (rhs.used), key (cr::move (rhs.key)), value (cr::move (rhs.value))
{ }
public:
DictionaryBucket &operator = (DictionaryBucket &&rhs) noexcept {
HashEntry &operator = (HashEntry &&rhs) noexcept {
if (this != &rhs) {
key = cr::move (rhs.key);
value = cr::move (rhs.value);
hash = rhs.hash;
used = rhs.used;
}
return *this;
}
};
}
// basic dictionary
template <class K, class V, class H = StringHash <K>, size_t HashSize = 36> class Dictionary final : public DenyCopying {
template <typename K, typename V, typename H = Hash <K>> class HashMap final : public DenyCopying {
public:
using Entries = detail::HashEntry <K, V> [];
private:
using DictBucket = detail::DictionaryBucket <K, V>;
using DictList = detail::DictionaryList;
size_t capacity_ {};
size_t length_ {};
H hash_;
UniquePtr <Entries> contents_;
public:
enum : size_t {
InvalidIndex = static_cast <size_t> (-1)
};
private:
Array <DictList *> contents_;
Array <DictBucket> buckets_;
H hashFunction_;
private:
uint32 hash (const K &key) const {
return hashFunction_ (key);
explicit HashMap (const size_t capacity = 3) : capacity_ (capacity), length_ (0) {
contents_ = cr::makeUnique <Entries> (capacity);
}
size_t find (const K &key, bool allocate) {
auto hashed = hash (key);
auto pos = hashed % contents_.length ();
for (auto bucket = contents_[pos]; bucket != nullptr; bucket = bucket->next) {
if (buckets_[bucket->index].hash == hashed) {
return bucket->index;
}
}
if (allocate) {
size_t created = buckets_.length ();
buckets_.resize (created + 1);
auto allocated = alloc.allocate <DictList> ();
allocated->index = static_cast <int32> (created);
allocated->next = contents_[pos];
contents_[pos] = allocated;
buckets_[created].key = key;
buckets_[created].hash = hashed;
return created;
}
return InvalidIndex;
}
size_t findIndex (const K &key) const {
return const_cast <Dictionary *> (this)->find (key, false);
}
public:
explicit Dictionary () {
reset ();
}
Dictionary (Dictionary &&rhs) noexcept : contents_ (cr::move (rhs.contents_)), buckets_ (cr::move (rhs.buckets_)), hashFunction_ (cr::move (rhs.hashFunction_))
HashMap (HashMap &&rhs) noexcept : contents_ (cr::move (rhs.contents_)), hash_ (cr::move (rhs.hash_)), capacity_ (rhs.capacity_), length_ (rhs.length_)
{ }
~Dictionary () {
clear ();
~HashMap () = default;
private:
size_t getIndex (const K &key, size_t length) const {
return hash_ (key) % length;
}
void rehash () {
auto capacity = (capacity_ << 1);
auto contents = cr::makeUnique <Entries> (capacity);
for (size_t i = 0; i < capacity_; ++i) {
if (contents_[i].used) {
auto result = put (contents_[i].key, contents, capacity);
contents[result.second].value = cr::move (contents_[i].value);
}
}
contents_ = cr::move (contents);
capacity_ = capacity;
}
Twin <bool, size_t> put (const K &key, UniquePtr <Entries> &contents, const size_t capacity) {
size_t index = getIndex (key, capacity);
for (size_t i = 0; i < capacity; ++i) {
if (!contents[index].used) {
contents[index].key = key;
contents[index].used = true;
return { true, index };
}
if (contents[index].key == key) {
return { false, index };
}
index++;
if (index == capacity) {
index = 0;
}
}
return { false, 0 };
}
public:
bool exists (const K &key) const {
return findIndex (key) != InvalidIndex;
}
bool empty () const {
return buckets_.empty ();
return !length_;
}
size_t length () const {
return buckets_.length ();
return length_;
}
bool find (const K &key, V &value) const {
size_t index = findIndex (key);
if (index == InvalidIndex) {
bool has (const K &key) const {
if (empty ()) {
return false;
}
value = buckets_[index].value;
return true;
}
template <typename U> bool push (const K &key, U &&value) {
operator [] (key) = cr::forward <U> (value);
return true;
}
bool remove (const K &key) {
auto hashed = hash (key);
auto pos = hashed % contents_.length ();
auto *bucket = contents_[pos];
DictList *next = nullptr;
while (bucket != nullptr) {
if (buckets_[bucket->index].hash == hashed) {
if (!next) {
contents_[pos] = bucket->next;
}
else {
next->next = bucket->next;
}
buckets_.erase (bucket->index, 1);
alloc.deallocate (bucket);
bucket = nullptr;
size_t index = getIndex (key, capacity_);
for (size_t i = 0; i < capacity_; ++i) {
if (contents_[index].used && contents_[index].key == key) {
return true;
}
next = bucket;
bucket = bucket->next;
if (++index == capacity_) {
break;
}
}
return false;
}
void clear () {
for (auto object : contents_) {
while (object != nullptr) {
auto next = object->next;
void erase (const K &key) {
size_t index = getIndex (key, capacity_);
alloc.deallocate (object);
object = next;
for (size_t i = 0; i < capacity_; ++i) {
if (contents_[index].used && contents_[index].key == key) {
contents_[index].used = false;
--length_;
break;
}
if (++index == capacity_) {
break;
}
}
contents_.clear ();
buckets_.clear ();
reset ();
}
void reset () {
contents_.resize (HashSize);
void clear () {
length_ = 0;
for (size_t i = 0; i < HashSize; ++i) {
contents_[i] = nullptr;
for (size_t i = 0; i < capacity_; ++i) {
contents_[i].used = false;
}
rehash ();
}
void foreach (Lambda <void (const K &, const V &)> callback) {
for (size_t i = 0; i < capacity_; ++i) {
if (contents_[i].used) {
callback (contents_[i].key, contents_[i].value);
}
}
}
public:
V &operator [] (const K &key) {
return buckets_[find (key, true)].value;
if ((length_ << 1) > capacity_) {
rehash ();
}
auto result = put (key, contents_, capacity_);
if (result.first) {
++length_;
}
return contents_[result.second].value;
}
const V &operator [] (const K &key) const {
return buckets_[findIndex (key)].value;
}
Dictionary &operator = (Dictionary &&rhs) noexcept {
HashMap &operator = (HashMap &&rhs) noexcept {
if (this != &rhs) {
contents_ = cr::move (rhs.contents_);
buckets_ = cr::move (rhs.buckets_);
hashFunction_ = cr::move (rhs.hashFunction_);
hash_ = cr::move (rhs.hash_);
length_ = rhs.length_;
capacity_ = rhs.capacity_;
}
return *this;
}
// for range-based loops
public:
DictBucket *begin () {
return buckets_.begin ();
}
DictBucket *begin () const {
return buckets_.begin ();
}
DictBucket *end () {
return buckets_.end ();
}
DictBucket *end () const {
return buckets_.end ();
}
};
CR_NAMESPACE_END

View file

@ -97,6 +97,11 @@ CR_NAMESPACE_BEGIN
# pragma warning (disable : 11074 11075) // remarks about inlining bla-bla-bla
#endif
// msvc provides us placement new by default
#if defined (CR_CXX_MSVC)
# define __PLACEMENT_NEW_INLINE 1
#endif
CR_NAMESPACE_END
#if defined(CR_WINDOWS)

View file

@ -73,8 +73,8 @@ private:
StringArray m_logos;
StringArray m_avatars;
Dictionary <String, String, HashLangString> m_language;
Dictionary <int32, DifficultyData, IntNoHash <int32>> m_difficulty;
HashMap <String, String, HashLangString> m_language;
HashMap <int32, DifficultyData> m_difficulty;
// default tables for personality weapon preferences, overridden by weapon.cfg
SmallArray <int32> m_normalWeaponPrefs = { 0, 2, 1, 4, 5, 6, 3, 12, 10, 24, 25, 13, 11, 8, 7, 22, 23, 18, 21, 17, 19, 15, 17, 9, 14, 16 };

View file

@ -628,23 +628,10 @@ private:
# define HOOK_CAST SharedLibrary::Handle
#endif
private:
template <typename K> struct CharHash {
uint32 operator () (const char *key) const {
auto str = const_cast <char *> (key);
uint32 hash = 0;
while (*str++) {
hash = ((hash << 5) + hash) + *str;
}
return hash;
}
};
private:
SharedLibrary m_self;
SimpleHook m_dlsym;
Dictionary <const char *, SharedLibrary::Handle, CharHash <const char *>> m_exports;
HashMap <StringRef, SharedLibrary::Handle> m_exports;
public:
EntityLinkage () = default;

View file

@ -71,6 +71,7 @@ CR_DECLARE_SCOPED_ENUM (StatusIconCache,
class MessageDispatcher final : public Singleton <MessageDispatcher> {
private:
using MsgFunc = void (MessageDispatcher::*) ();
using MsgHash = Hash <int32>;
private:
struct Args {
@ -87,20 +88,22 @@ private:
};
private:
Dictionary <String, int32> m_textMsgCache; // cache strings for faster access for textmsg
Dictionary <String, int32> m_showMenuCache; // cache for the showmenu message
Dictionary <String, int32> m_statusIconCache; // cache for status icon message
Dictionary <String, int32> m_teamInfoCache; // cache for teaminfo message
HashMap <String, int32> m_textMsgCache; // cache strings for faster access for textmsg
HashMap <String, int32> m_showMenuCache; // cache for the showmenu message
HashMap <String, int32> m_statusIconCache; // cache for status icon message
HashMap <String, int32> m_teamInfoCache; // cache for teaminfo message
private:
Bot *m_bot {}; // owner of a message
NetMsg m_current {}; // ongoing message id
SmallArray <Args> m_args; // args collected from write* functions
Dictionary <String, NetMsg> m_wanted; // wanted messages
Dictionary <NetMsg, int32, IntNoHash <int32>> m_maps; // maps our message to id to engine message id
Dictionary <NetMsg, MsgFunc, IntNoHash <int32>> m_handlers; // maps our message id to handler function
HashMap <String, NetMsg> m_wanted; // wanted messages
HashMap <int32, NetMsg> m_reverseMap; // maps engine message id to our message id
HashMap <NetMsg, int32, MsgHash> m_maps; // maps our message to id to engine message id
HashMap <NetMsg, MsgFunc, MsgHash> m_handlers; // maps our message id to handler function
private:
void netMsgTextMsg ();

View file

@ -36,8 +36,8 @@ private:
SmallArray <Client> m_clients;
SmallArray <Twin <String, String>> m_tags;
Dictionary <int32, String, IntNoHash <int32>> m_weaponAlias;
Dictionary <String, int32> m_noiseCache;
HashMap <int32, String> m_weaponAlias;
HashMap <String, int32> m_noiseCache;
SimpleHook m_sendToHook;
public:

View file

@ -4938,45 +4938,45 @@ void Bot::showDebugOverlay () {
static float timeDebugUpdate = 0.0f;
static int index, goal, taskID;
static Dictionary <int32, String, IntHash <int32>> tasks;
static Dictionary <int32, String, IntHash <int32>> personalities;
static Dictionary <int32, String, IntHash <int32>> flags;
static HashMap <int32, String> tasks;
static HashMap <int32, String> personalities;
static HashMap <int32, String> flags;
if (tasks.empty ()) {
tasks.push (Task::Normal, "Normal");
tasks.push (Task::Pause, "Pause");
tasks.push (Task::MoveToPosition, "Move");
tasks.push (Task::FollowUser, "Follow");
tasks.push (Task::PickupItem, "Pickup");
tasks.push (Task::Camp, "Camp");
tasks.push (Task::PlantBomb, "PlantBomb");
tasks.push (Task::DefuseBomb, "DefuseBomb");
tasks.push (Task::Attack, "Attack");
tasks.push (Task::Hunt, "Hunt");
tasks.push (Task::SeekCover, "SeekCover");
tasks.push (Task::ThrowExplosive, "ThrowHE");
tasks.push (Task::ThrowFlashbang, "ThrowFL");
tasks.push (Task::ThrowSmoke, "ThrowSG");
tasks.push (Task::DoubleJump, "DoubleJump");
tasks.push (Task::EscapeFromBomb, "EscapeFromBomb");
tasks.push (Task::ShootBreakable, "DestroyBreakable");
tasks.push (Task::Hide, "Hide");
tasks.push (Task::Blind, "Blind");
tasks.push (Task::Spraypaint, "Spray");
tasks[Task::Normal] = "Normal";
tasks[Task::Pause] = "Pause";
tasks[Task::MoveToPosition] = "Move";
tasks[Task::FollowUser] = "Follow";
tasks[Task::PickupItem] = "Pickup";
tasks[Task::Camp] = "Camp";
tasks[Task::PlantBomb] = "PlantBomb";
tasks[Task::DefuseBomb] = "DefuseBomb";
tasks[Task::Attack] = "Attack";
tasks[Task::Hunt] = "Hunt";
tasks[Task::SeekCover] = "SeekCover";
tasks[Task::ThrowExplosive] = "ThrowHE";
tasks[Task::ThrowFlashbang] = "ThrowFL";
tasks[Task::ThrowSmoke] = "ThrowSG";
tasks[Task::DoubleJump] = "DoubleJump";
tasks[Task::EscapeFromBomb] = "EscapeFromBomb";
tasks[Task::ShootBreakable] = "DestroyBreakable";
tasks[Task::Hide] = "Hide";
tasks[Task::Blind] = "Blind";
tasks[Task::Spraypaint] = "Spray";
personalities.push (Personality::Rusher, "Rusher");
personalities.push (Personality::Normal, "Normal");
personalities.push (Personality::Careful, "Careful");
personalities[Personality::Rusher] = "Rusher";
personalities[Personality::Normal] = "Normal";
personalities[Personality::Careful] = "Careful";
flags.push (AimFlags::Nav, "Nav");
flags.push (AimFlags::Camp, "Camp");
flags.push (AimFlags::PredictPath, "Predict");
flags.push (AimFlags::LastEnemy, "LastEnemy");
flags.push (AimFlags::Entity, "Entity");
flags.push (AimFlags::Enemy, "Enemy");
flags.push (AimFlags::Grenade, "Grenade");
flags.push (AimFlags::Override, "Override");
flags.push (AimFlags::Danger, "Danger");
flags[AimFlags::Nav] = "Nav";
flags[AimFlags::Camp] = "Camp";
flags[AimFlags::PredictPath] = "Predict";
flags[AimFlags::LastEnemy] = "LastEnemy";
flags[AimFlags::Entity] = "Entity";
flags[AimFlags::Enemy] = "Enemy";
flags[AimFlags::Grenade] = "Grenade";
flags[AimFlags::Override] = "Override";
flags[AimFlags::Danger] = "Danger";
}
if (m_tasks.empty ()) {
@ -5401,11 +5401,13 @@ Vector Bot::calcThrow (const Vector &start, const Vector &stop) {
else if (time > 2.0f) {
time = 1.2f;
}
float half = time * 0.5f;
velocity = velocity * (1.0f / time);
velocity.z += gravity * time * 0.5f;
velocity.z += gravity * half;
Vector apex = start + (stop - start) * 0.5f;
apex.z += 0.5f * gravity * (time * 0.5f) * (time * 0.5f);
apex.z += 0.5f * gravity * half * half;
game.testHull (start, apex, TraceIgnore::None, head_hull, ent (), &tr);

View file

@ -495,7 +495,7 @@ void BotConfig::loadLanguageConfig () {
}
if (!lang.second.empty () && !lang.first.empty ()) {
m_language.push (lang.first.trim (), lang.second.trim ());
m_language[lang.first.trim ()] = lang.second.trim ();
}
}
else if (line.startsWith ("[TRANSLATED]") && !temp.empty ()) {
@ -756,11 +756,9 @@ const char *BotConfig::translate (StringRef input) {
if (game.isDedicated ()) {
return input.chars ();
}
static String result;
result.clear ();
if (m_language.find (input, result)) {
return result.chars ();
if (m_language.has (input)) {
return m_language[input.chars ()].chars ();
}
return input.chars (); // nothing found
}

View file

@ -127,20 +127,20 @@ int BotControl::cmdWeaponMode () {
if (!hasArg (type)) {
return BotCommandResult::BadFormat;
}
Dictionary <String, int> modes;
HashMap <String, int> modes;
modes.push ("kinfe", 1);
modes.push ("pistol", 2);
modes.push ("shotgun", 3);
modes.push ("smg", 4);
modes.push ("rifle", 5);
modes.push ("sniper", 6);
modes.push ("standard", 7);
modes["kinfe"] = 1;
modes["pistol"] = 2;
modes["shotgun"] = 3;
modes["smg"] = 4;
modes["rifle"] = 5;
modes["sniper"] = 6;
modes["standard"] = 7;
auto mode = strValue (type);
// check if selected mode exists
if (!modes.exists (mode)) {
if (!modes.has (mode)) {
return BotCommandResult::BadFormat;
}
bots.setWeaponMode (modes[mode]);
@ -276,7 +276,7 @@ int BotControl::cmdNode () {
}
// should be moved to class?
static Dictionary <String, BotCmd> commands;
static HashMap <String, BotCmd> commands;
static StringArray descriptions;
// fill only once
@ -286,7 +286,7 @@ int BotControl::cmdNode () {
auto addGraphCmd = [&] (String cmd, String format, String help, Handler handler) -> void {
BotCmd botCmd { cmd, cr::move (format), cr::move (help), cr::move (handler) };
commands.push (cmd, cr::move (botCmd));
commands[cmd] = cr::move (botCmd);
descriptions.push (cmd);
};
@ -325,7 +325,7 @@ int BotControl::cmdNode () {
addGraphCmd ("release_editor", "acquire_editor", "Releases graph editing rights.", &BotControl::cmdNodeAcquireEditor);
}
}
if (commands.exists (strValue (cmd))) {
if (commands.has (strValue (cmd))) {
auto item = commands[strValue (cmd)];
// graph have only bad format return status
@ -336,7 +336,7 @@ int BotControl::cmdNode () {
}
}
else {
if (strValue (cmd) == "help" && hasArg (cmd2) && commands.exists (strValue (cmd2))) {
if (strValue (cmd) == "help" && hasArg (cmd2) && commands.has (strValue (cmd2))) {
auto &item = commands[strValue (cmd2)];
msg ("Command: \"%s %s %s\"\nFormat: %s\nHelp: %s", m_args[root], m_args[alias], item.name, item.format, item.help);

View file

@ -1161,21 +1161,21 @@ SharedLibrary::Handle EntityLinkage::lookup (SharedLibrary::Handle module, const
if (self.handle () != module) {
return resolve (module);
}
if (m_exports.has (function)) {
return m_exports[function];
}
auto botAddr = resolve (self.handle ());
if (!botAddr) {
auto gameAddr = resolve (gamedll.handle ());
if (gameAddr) {
m_exports[function] = gameAddr;
return m_exports[function] = gameAddr;
}
}
else {
m_exports[function] = botAddr;
}
if (m_exports.exists (function)) {
return m_exports[function];
return m_exports[function] = botAddr;
}
return nullptr;
}

View file

@ -389,35 +389,35 @@ void MessageDispatcher::netMsgFlashBat () {
MessageDispatcher::MessageDispatcher () {
// register wanted message
auto pushWanted = [&] (StringRef name, NetMsg id, MsgFunc handler) -> void {
auto addWanted = [&] (StringRef name, NetMsg id, MsgFunc handler) -> void {
m_wanted[name] = id;
m_handlers[id] = handler;
};
reset ();
// we want to handle next messages
pushWanted ("TextMsg", NetMsg::TextMsg, &MessageDispatcher::netMsgTextMsg);
pushWanted ("VGUIMenu", NetMsg::VGUIMenu, &MessageDispatcher::netMsgVGUIMenu);
pushWanted ("ShowMenu", NetMsg::ShowMenu, &MessageDispatcher::netMsgShowMenu);
pushWanted ("WeaponList", NetMsg::WeaponList, &MessageDispatcher::netMsgWeaponList);
pushWanted ("CurWeapon", NetMsg::CurWeapon, &MessageDispatcher::netMsgCurWeapon);
pushWanted ("AmmoX", NetMsg::AmmoX, &MessageDispatcher::netMsgAmmoX);
pushWanted ("AmmoPickup", NetMsg::AmmoPickup, &MessageDispatcher::netMsgAmmoPickup);
pushWanted ("Damage", NetMsg::Damage, &MessageDispatcher::netMsgDamage);
pushWanted ("Money", NetMsg::Money, &MessageDispatcher::netMsgMoney);
pushWanted ("StatusIcon", NetMsg::StatusIcon, &MessageDispatcher::netMsgStatusIcon);
pushWanted ("DeathMsg", NetMsg::DeathMsg, &MessageDispatcher::netMsgDeathMsg);
pushWanted ("ScreenFade", NetMsg::ScreenFade, &MessageDispatcher::netMsgScreenFade);
pushWanted ("HLTV", NetMsg::HLTV, &MessageDispatcher::netMsgHLTV);
pushWanted ("TeamInfo", NetMsg::TeamInfo, &MessageDispatcher::netMsgTeamInfo);
pushWanted ("BarTime", NetMsg::BarTime, &MessageDispatcher::netMsgBarTime);
pushWanted ("ItemStatus", NetMsg::ItemStatus, &MessageDispatcher::netMsgItemStatus);
pushWanted ("NVGToggle", NetMsg::NVGToggle, &MessageDispatcher::netMsgNVGToggle);
pushWanted ("FlashBat", NetMsg::FlashBat, &MessageDispatcher::netMsgFlashBat);
addWanted ("TextMsg", NetMsg::TextMsg, &MessageDispatcher::netMsgTextMsg);
addWanted ("VGUIMenu", NetMsg::VGUIMenu, &MessageDispatcher::netMsgVGUIMenu);
addWanted ("ShowMenu", NetMsg::ShowMenu, &MessageDispatcher::netMsgShowMenu);
addWanted ("WeaponList", NetMsg::WeaponList, &MessageDispatcher::netMsgWeaponList);
addWanted ("CurWeapon", NetMsg::CurWeapon, &MessageDispatcher::netMsgCurWeapon);
addWanted ("AmmoX", NetMsg::AmmoX, &MessageDispatcher::netMsgAmmoX);
addWanted ("AmmoPickup", NetMsg::AmmoPickup, &MessageDispatcher::netMsgAmmoPickup);
addWanted ("Damage", NetMsg::Damage, &MessageDispatcher::netMsgDamage);
addWanted ("Money", NetMsg::Money, &MessageDispatcher::netMsgMoney);
addWanted ("StatusIcon", NetMsg::StatusIcon, &MessageDispatcher::netMsgStatusIcon);
addWanted ("DeathMsg", NetMsg::DeathMsg, &MessageDispatcher::netMsgDeathMsg);
addWanted ("ScreenFade", NetMsg::ScreenFade, &MessageDispatcher::netMsgScreenFade);
addWanted ("HLTV", NetMsg::HLTV, &MessageDispatcher::netMsgHLTV);
addWanted ("TeamInfo", NetMsg::TeamInfo, &MessageDispatcher::netMsgTeamInfo);
addWanted ("BarTime", NetMsg::BarTime, &MessageDispatcher::netMsgBarTime);
addWanted ("ItemStatus", NetMsg::ItemStatus, &MessageDispatcher::netMsgItemStatus);
addWanted ("NVGToggle", NetMsg::NVGToggle, &MessageDispatcher::netMsgNVGToggle);
addWanted ("FlashBat", NetMsg::FlashBat, &MessageDispatcher::netMsgFlashBat);
// we're need next messages IDs but we're won't handle them, so they will be removed from wanted list as soon as they get engine IDs
pushWanted ("BotVoice", NetMsg::BotVoice, nullptr);
pushWanted ("SendAudio", NetMsg::SendAudio, nullptr);
addWanted ("BotVoice", NetMsg::BotVoice, nullptr);
addWanted ("SendAudio", NetMsg::SendAudio, nullptr);
// register text msg cache
m_textMsgCache["#CTs_Win"] = TextMsgCache::NeedHandle | TextMsgCache::CounterWin;
@ -464,10 +464,12 @@ MessageDispatcher::MessageDispatcher () {
}
int32 MessageDispatcher::add (StringRef name, int32 id) {
if (!m_wanted.exists (name)) {
if (!m_wanted.has (name)) {
return id;
}
m_maps[m_wanted[name]] = id; // add message from engine regusermsg
m_reverseMap[id] = m_wanted[name]; // add message from engine regusermsg
return id;
}
@ -475,12 +477,14 @@ int32 MessageDispatcher::add (StringRef name, int32 id) {
void MessageDispatcher::start (edict_t *ent, int32 type) {
reset ();
if (game.is (GameFlags::Metamod)) {
ensureMessages ();
}
// search if we need to handle this message
for (const auto &msg : m_maps) {
if (msg.value == type && m_handlers[msg.key]) {
m_current = msg.key;
break;
}
if (m_reverseMap.has (type)) {
auto msg = m_reverseMap[type];
m_current = m_handlers[msg] ? msg : NetMsg::None;
}
// no messagem no processing
@ -513,19 +517,16 @@ void MessageDispatcher::ensureMessages () {
// this function tries to associate appropriate message ids.
// check if we're have one
if (m_maps.exists (NetMsg::Money)) {
if (m_maps.has (NetMsg::Money)) {
return;
}
// re-register our message
for (const auto &msg : m_wanted) {
add (msg.key, GET_USER_MSG_ID (PLID, msg.key.chars (), nullptr));
}
m_wanted.foreach ([&] (const String &key, const int32 &) {
add (key, GET_USER_MSG_ID (PLID, key.chars (), nullptr));
});
}
int32 MessageDispatcher::id (NetMsg msg) {
if (game.is (GameFlags::Metamod)) {
ensureMessages ();
}
return m_maps[msg];
}

View file

@ -74,38 +74,38 @@ BotSupport::BotSupport () {
m_noiseCache["doors/doorm"] = Noise::NeedHandle | Noise::Door;
// register weapon aliases
m_weaponAlias.push (Weapon::USP, "usp"); // HK USP .45 Tactical
m_weaponAlias.push (Weapon::Glock18, "glock"); // Glock18 Select Fire
m_weaponAlias.push (Weapon::Deagle, "deagle"); // Desert Eagle .50AE
m_weaponAlias.push (Weapon::P228, "p228"); // SIG P228
m_weaponAlias.push (Weapon::Elite, "elite"); // Dual Beretta 96G Elite
m_weaponAlias.push (Weapon::FiveSeven, "fn57"); // FN Five-Seven
m_weaponAlias.push (Weapon::M3, "m3"); // Benelli M3 Super90
m_weaponAlias.push (Weapon::XM1014, "xm1014"); // Benelli XM1014
m_weaponAlias.push (Weapon::MP5, "mp5"); // HK MP5-Navy
m_weaponAlias.push (Weapon::TMP, "tmp"); // Steyr Tactical Machine Pistol
m_weaponAlias.push (Weapon::P90, "p90"); // FN P90
m_weaponAlias.push (Weapon::MAC10, "mac10"); // Ingram MAC-10
m_weaponAlias.push (Weapon::UMP45, "ump45"); // HK UMP45
m_weaponAlias.push (Weapon::AK47, "ak47"); // Automat Kalashnikov AK-47
m_weaponAlias.push (Weapon::Galil, "galil"); // IMI Galil
m_weaponAlias.push (Weapon::Famas, "famas"); // GIAT FAMAS
m_weaponAlias.push (Weapon::SG552, "sg552"); // Sig SG-552 Commando
m_weaponAlias.push (Weapon::M4A1, "m4a1"); // Colt M4A1 Carbine
m_weaponAlias.push (Weapon::AUG, "aug"); // Steyr Aug
m_weaponAlias.push (Weapon::Scout, "scout"); // Steyr Scout
m_weaponAlias.push (Weapon::AWP, "awp"); // AI Arctic Warfare/Magnum
m_weaponAlias.push (Weapon::G3SG1, "g3sg1"); // HK G3/SG-1 Sniper Rifle
m_weaponAlias.push (Weapon::SG550, "sg550"); // Sig SG-550 Sniper
m_weaponAlias.push (Weapon::M249, "m249"); // FN M249 Para
m_weaponAlias.push (Weapon::Flashbang, "flash"); // Concussion Grenade
m_weaponAlias.push (Weapon::Explosive, "hegren"); // High-Explosive Grenade
m_weaponAlias.push (Weapon::Smoke, "sgren"); // Smoke Grenade
m_weaponAlias.push (Weapon::Armor, "vest"); // Kevlar Vest
m_weaponAlias.push (Weapon::ArmorHelm, "vesthelm"); // Kevlar Vest and Helmet
m_weaponAlias.push (Weapon::Defuser, "defuser"); // Defuser Kit
m_weaponAlias.push (Weapon::Shield, "shield"); // Tactical Shield
m_weaponAlias.push (Weapon::Knife, "knife"); // Knife
m_weaponAlias[Weapon::USP] = "usp"; // HK USP .45 Tactical
m_weaponAlias[Weapon::Glock18] = "glock"; // Glock18 Select Fire
m_weaponAlias[Weapon::Deagle] = "deagle"; // Desert Eagle .50AE
m_weaponAlias[Weapon::P228] = "p228"; // SIG P228
m_weaponAlias[Weapon::Elite] = "elite"; // Dual Beretta 96G Elite
m_weaponAlias[Weapon::FiveSeven] = "fn57"; // FN Five-Seven
m_weaponAlias[Weapon::M3] = "m3"; // Benelli M3 Super90
m_weaponAlias[Weapon::XM1014] = "xm1014"; // Benelli XM1014
m_weaponAlias[Weapon::MP5] = "mp5"; // HK MP5-Navy
m_weaponAlias[Weapon::TMP] = "tmp"; // Steyr Tactical Machine Pistol
m_weaponAlias[Weapon::P90] = "p90"; // FN P90
m_weaponAlias[Weapon::MAC10] = "mac10"; // Ingram MAC-10
m_weaponAlias[Weapon::UMP45] = "ump45"; // HK UMP45
m_weaponAlias[Weapon::AK47] = "ak47"; // Automat Kalashnikov AK-47
m_weaponAlias[Weapon::Galil] = "galil"; // IMI Galil
m_weaponAlias[Weapon::Famas] = "famas"; // GIAT FAMAS
m_weaponAlias[Weapon::SG552] = "sg552"; // Sig SG-552 Commando
m_weaponAlias[Weapon::M4A1] = "m4a1"; // Colt M4A1 Carbine
m_weaponAlias[Weapon::AUG] = "aug"; // Steyr Aug
m_weaponAlias[Weapon::Scout] = "scout"; // Steyr Scout
m_weaponAlias[Weapon::AWP] = "awp"; // AI Arctic Warfare/Magnum
m_weaponAlias[Weapon::G3SG1] = "g3sg1"; // HK G3/SG-1 Sniper Rifle
m_weaponAlias[Weapon::SG550] = "sg550"; // Sig SG-550 Sniper
m_weaponAlias[Weapon::M249] = "m249"; // FN M249 Para
m_weaponAlias[Weapon::Flashbang] = "flash"; // Concussion Grenade
m_weaponAlias[Weapon::Explosive] = "hegren"; // High-Explosive Grenade
m_weaponAlias[Weapon::Smoke] = "sgren"; // Smoke Grenade
m_weaponAlias[Weapon::Armor] = "vest"; // Kevlar Vest
m_weaponAlias[Weapon::ArmorHelm] = "vesthelm"; // Kevlar Vest and Helmet
m_weaponAlias[Weapon::Defuser] = "defuser"; // Defuser Kit
m_weaponAlias[Weapon::Shield] = "shield"; // Tactical Shield
m_weaponAlias[Weapon::Knife] = "knife"; // Knife
m_clients.resize (kGameMaxPlayers + 1);
}
@ -718,7 +718,7 @@ int32 BotSupport::sendTo (int socket, const void *message, size_t length, int fl
StringRef BotSupport::weaponIdToAlias (int32 id) {
StringRef none = "none";
if (m_weaponAlias.exists (id)) {
if (m_weaponAlias.has (id)) {
return m_weaponAlias[id];
}
return none;