crlib: reworked dictionary to hashmap.
linkage: another fix to dynamic linkage. cpp: fixed msvc warning about placement new.
This commit is contained in:
parent
b70d2af4ab
commit
43f6a7828a
12 changed files with 291 additions and 312 deletions
|
|
@ -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;
|
||||
size_t index = getIndex (key, capacity_);
|
||||
|
||||
for (size_t i = 0; i < capacity_; ++i) {
|
||||
if (contents_[index].used && contents_[index].key == key) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename U> bool push (const K &key, U &&value) {
|
||||
operator [] (key) = cr::forward <U> (value);
|
||||
return true;
|
||||
if (++index == capacity_) {
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 () {
|
||||
for (auto object : contents_) {
|
||||
while (object != nullptr) {
|
||||
auto next = object->next;
|
||||
length_ = 0;
|
||||
|
||||
alloc.deallocate (object);
|
||||
object = next;
|
||||
for (size_t i = 0; i < capacity_; ++i) {
|
||||
contents_[i].used = false;
|
||||
}
|
||||
}
|
||||
contents_.clear ();
|
||||
buckets_.clear ();
|
||||
|
||||
reset ();
|
||||
rehash ();
|
||||
}
|
||||
|
||||
void reset () {
|
||||
contents_.resize (HashSize);
|
||||
|
||||
for (size_t i = 0; i < HashSize; ++i) {
|
||||
contents_[i] = nullptr;
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
15
inc/engine.h
15
inc/engine.h
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
||||
// 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 (game.is (GameFlags::Metamod)) {
|
||||
ensureMessages ();
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
@ -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];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue