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

View file

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

View file

@ -73,8 +73,8 @@ private:
StringArray m_logos; StringArray m_logos;
StringArray m_avatars; StringArray m_avatars;
Dictionary <String, String, HashLangString> m_language; HashMap <String, String, HashLangString> m_language;
Dictionary <int32, DifficultyData, IntNoHash <int32>> m_difficulty; HashMap <int32, DifficultyData> m_difficulty;
// default tables for personality weapon preferences, overridden by weapon.cfg // 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 }; 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 # define HOOK_CAST SharedLibrary::Handle
#endif #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: private:
SharedLibrary m_self; SharedLibrary m_self;
SimpleHook m_dlsym; SimpleHook m_dlsym;
Dictionary <const char *, SharedLibrary::Handle, CharHash <const char *>> m_exports; HashMap <StringRef, SharedLibrary::Handle> m_exports;
public: public:
EntityLinkage () = default; EntityLinkage () = default;

View file

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

View file

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

View file

@ -4938,45 +4938,45 @@ void Bot::showDebugOverlay () {
static float timeDebugUpdate = 0.0f; static float timeDebugUpdate = 0.0f;
static int index, goal, taskID; static int index, goal, taskID;
static Dictionary <int32, String, IntHash <int32>> tasks; static HashMap <int32, String> tasks;
static Dictionary <int32, String, IntHash <int32>> personalities; static HashMap <int32, String> personalities;
static Dictionary <int32, String, IntHash <int32>> flags; static HashMap <int32, String> flags;
if (tasks.empty ()) { if (tasks.empty ()) {
tasks.push (Task::Normal, "Normal"); tasks[Task::Normal] = "Normal";
tasks.push (Task::Pause, "Pause"); tasks[Task::Pause] = "Pause";
tasks.push (Task::MoveToPosition, "Move"); tasks[Task::MoveToPosition] = "Move";
tasks.push (Task::FollowUser, "Follow"); tasks[Task::FollowUser] = "Follow";
tasks.push (Task::PickupItem, "Pickup"); tasks[Task::PickupItem] = "Pickup";
tasks.push (Task::Camp, "Camp"); tasks[Task::Camp] = "Camp";
tasks.push (Task::PlantBomb, "PlantBomb"); tasks[Task::PlantBomb] = "PlantBomb";
tasks.push (Task::DefuseBomb, "DefuseBomb"); tasks[Task::DefuseBomb] = "DefuseBomb";
tasks.push (Task::Attack, "Attack"); tasks[Task::Attack] = "Attack";
tasks.push (Task::Hunt, "Hunt"); tasks[Task::Hunt] = "Hunt";
tasks.push (Task::SeekCover, "SeekCover"); tasks[Task::SeekCover] = "SeekCover";
tasks.push (Task::ThrowExplosive, "ThrowHE"); tasks[Task::ThrowExplosive] = "ThrowHE";
tasks.push (Task::ThrowFlashbang, "ThrowFL"); tasks[Task::ThrowFlashbang] = "ThrowFL";
tasks.push (Task::ThrowSmoke, "ThrowSG"); tasks[Task::ThrowSmoke] = "ThrowSG";
tasks.push (Task::DoubleJump, "DoubleJump"); tasks[Task::DoubleJump] = "DoubleJump";
tasks.push (Task::EscapeFromBomb, "EscapeFromBomb"); tasks[Task::EscapeFromBomb] = "EscapeFromBomb";
tasks.push (Task::ShootBreakable, "DestroyBreakable"); tasks[Task::ShootBreakable] = "DestroyBreakable";
tasks.push (Task::Hide, "Hide"); tasks[Task::Hide] = "Hide";
tasks.push (Task::Blind, "Blind"); tasks[Task::Blind] = "Blind";
tasks.push (Task::Spraypaint, "Spray"); tasks[Task::Spraypaint] = "Spray";
personalities.push (Personality::Rusher, "Rusher"); personalities[Personality::Rusher] = "Rusher";
personalities.push (Personality::Normal, "Normal"); personalities[Personality::Normal] = "Normal";
personalities.push (Personality::Careful, "Careful"); personalities[Personality::Careful] = "Careful";
flags.push (AimFlags::Nav, "Nav"); flags[AimFlags::Nav] = "Nav";
flags.push (AimFlags::Camp, "Camp"); flags[AimFlags::Camp] = "Camp";
flags.push (AimFlags::PredictPath, "Predict"); flags[AimFlags::PredictPath] = "Predict";
flags.push (AimFlags::LastEnemy, "LastEnemy"); flags[AimFlags::LastEnemy] = "LastEnemy";
flags.push (AimFlags::Entity, "Entity"); flags[AimFlags::Entity] = "Entity";
flags.push (AimFlags::Enemy, "Enemy"); flags[AimFlags::Enemy] = "Enemy";
flags.push (AimFlags::Grenade, "Grenade"); flags[AimFlags::Grenade] = "Grenade";
flags.push (AimFlags::Override, "Override"); flags[AimFlags::Override] = "Override";
flags.push (AimFlags::Danger, "Danger"); flags[AimFlags::Danger] = "Danger";
} }
if (m_tasks.empty ()) { if (m_tasks.empty ()) {
@ -5401,11 +5401,13 @@ Vector Bot::calcThrow (const Vector &start, const Vector &stop) {
else if (time > 2.0f) { else if (time > 2.0f) {
time = 1.2f; time = 1.2f;
} }
float half = time * 0.5f;
velocity = velocity * (1.0f / time); velocity = velocity * (1.0f / time);
velocity.z += gravity * time * 0.5f; velocity.z += gravity * half;
Vector apex = start + (stop - start) * 0.5f; 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); 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 ()) { 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 ()) { else if (line.startsWith ("[TRANSLATED]") && !temp.empty ()) {
@ -756,11 +756,9 @@ const char *BotConfig::translate (StringRef input) {
if (game.isDedicated ()) { if (game.isDedicated ()) {
return input.chars (); return input.chars ();
} }
static String result;
result.clear ();
if (m_language.find (input, result)) { if (m_language.has (input)) {
return result.chars (); return m_language[input.chars ()].chars ();
} }
return input.chars (); // nothing found return input.chars (); // nothing found
} }

View file

@ -127,20 +127,20 @@ int BotControl::cmdWeaponMode () {
if (!hasArg (type)) { if (!hasArg (type)) {
return BotCommandResult::BadFormat; return BotCommandResult::BadFormat;
} }
Dictionary <String, int> modes; HashMap <String, int> modes;
modes.push ("kinfe", 1); modes["kinfe"] = 1;
modes.push ("pistol", 2); modes["pistol"] = 2;
modes.push ("shotgun", 3); modes["shotgun"] = 3;
modes.push ("smg", 4); modes["smg"] = 4;
modes.push ("rifle", 5); modes["rifle"] = 5;
modes.push ("sniper", 6); modes["sniper"] = 6;
modes.push ("standard", 7); modes["standard"] = 7;
auto mode = strValue (type); auto mode = strValue (type);
// check if selected mode exists // check if selected mode exists
if (!modes.exists (mode)) { if (!modes.has (mode)) {
return BotCommandResult::BadFormat; return BotCommandResult::BadFormat;
} }
bots.setWeaponMode (modes[mode]); bots.setWeaponMode (modes[mode]);
@ -276,7 +276,7 @@ int BotControl::cmdNode () {
} }
// should be moved to class? // should be moved to class?
static Dictionary <String, BotCmd> commands; static HashMap <String, BotCmd> commands;
static StringArray descriptions; static StringArray descriptions;
// fill only once // fill only once
@ -286,7 +286,7 @@ int BotControl::cmdNode () {
auto addGraphCmd = [&] (String cmd, String format, String help, Handler handler) -> void { auto addGraphCmd = [&] (String cmd, String format, String help, Handler handler) -> void {
BotCmd botCmd { cmd, cr::move (format), cr::move (help), cr::move (handler) }; 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); descriptions.push (cmd);
}; };
@ -325,7 +325,7 @@ int BotControl::cmdNode () {
addGraphCmd ("release_editor", "acquire_editor", "Releases graph editing rights.", &BotControl::cmdNodeAcquireEditor); 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)]; auto item = commands[strValue (cmd)];
// graph have only bad format return status // graph have only bad format return status
@ -336,7 +336,7 @@ int BotControl::cmdNode () {
} }
} }
else { 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)]; 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); 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) { if (self.handle () != module) {
return resolve (module); return resolve (module);
} }
if (m_exports.has (function)) {
return m_exports[function];
}
auto botAddr = resolve (self.handle ()); auto botAddr = resolve (self.handle ());
if (!botAddr) { if (!botAddr) {
auto gameAddr = resolve (gamedll.handle ()); auto gameAddr = resolve (gamedll.handle ());
if (gameAddr) { if (gameAddr) {
m_exports[function] = gameAddr; return m_exports[function] = gameAddr;
} }
} }
else { else {
m_exports[function] = botAddr; return m_exports[function] = botAddr;
}
if (m_exports.exists (function)) {
return m_exports[function];
} }
return nullptr; return nullptr;
} }

View file

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

View file

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