fix: crash with hl25 structs on xash3d again
fix: %t placeholder should return damage inflictor when used in team attack section of chat fix: all arguments in bot commands are lowercased (resolves #680) bot: disable threads when engine's timescale is active bot: a little refactor for the code all over the places linkage: resolved crash due to sse alignment on ancient engines (resolves #614) utils move wave parse into crlib practice: move loading practice to thread pool build: allow to build with static linkents instead of hooking dlsym Co-Authored-By: Max <161382234+dyspose@users.noreply.github.com>
This commit is contained in:
parent
24be4479de
commit
38c45aff9a
37 changed files with 348 additions and 304 deletions
|
|
@ -1 +1 @@
|
||||||
Subproject commit fdeb120576a13457867e720d49bfd2969e10d195
|
Subproject commit 11e1a6d4c09b16ceda1f5a9d362fe35bec3f0b85
|
||||||
|
|
@ -231,8 +231,14 @@ public:
|
||||||
void collectArgs () {
|
void collectArgs () {
|
||||||
m_args.clear ();
|
m_args.clear ();
|
||||||
|
|
||||||
for (int i = 0; i < engfuncs.pfnCmd_Argc (); ++i) {
|
for (auto i = 0; i < engfuncs.pfnCmd_Argc (); ++i) {
|
||||||
m_args.emplace (String (engfuncs.pfnCmd_Argv (i)).lowercase ());
|
String arg = engfuncs.pfnCmd_Argv (i);
|
||||||
|
|
||||||
|
// only make case-insensetive command itself and first argument
|
||||||
|
if (i < 2) {
|
||||||
|
arg = arg.lowercase ();
|
||||||
|
}
|
||||||
|
m_args.emplace (arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
10
inc/engine.h
10
inc/engine.h
|
|
@ -316,27 +316,27 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets edict pointer out of entity index
|
// gets edict pointer out of entity index
|
||||||
edict_t *entityOfIndex (const int index) {
|
CR_FORCE_INLINE edict_t *entityOfIndex (const int index) {
|
||||||
return static_cast <edict_t *> (m_startEntity + index);
|
return static_cast <edict_t *> (m_startEntity + index);
|
||||||
};
|
};
|
||||||
|
|
||||||
// gets edict pointer out of entity index (player)
|
// gets edict pointer out of entity index (player)
|
||||||
edict_t *playerOfIndex (const int index) {
|
CR_FORCE_INLINE edict_t *playerOfIndex (const int index) {
|
||||||
return entityOfIndex (index) + 1;
|
return entityOfIndex (index) + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// gets edict index out of it's pointer
|
// gets edict index out of it's pointer
|
||||||
int indexOfEntity (const edict_t *ent) {
|
CR_FORCE_INLINE int indexOfEntity (const edict_t *ent) {
|
||||||
return static_cast <int> (ent - m_startEntity);
|
return static_cast <int> (ent - m_startEntity);
|
||||||
};
|
};
|
||||||
|
|
||||||
// gets edict index of it's pointer (player)
|
// gets edict index of it's pointer (player)
|
||||||
int indexOfPlayer (const edict_t *ent) {
|
CR_FORCE_INLINE int indexOfPlayer (const edict_t *ent) {
|
||||||
return indexOfEntity (ent) - 1;
|
return indexOfEntity (ent) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify entity isn't null
|
// verify entity isn't null
|
||||||
bool isNullEntity (const edict_t *ent) {
|
CR_FORCE_INLINE bool isNullEntity (const edict_t *ent) {
|
||||||
return !ent || !indexOfEntity (ent) || ent->free;
|
return !ent || !indexOfEntity (ent) || ent->free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CountdownTimer m_recalcTime {};
|
CountdownTimer m_recalcTime {};
|
||||||
|
PingBitMsg m_pbm {};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit BotFakePingManager () = default;
|
explicit BotFakePingManager () = default;
|
||||||
|
|
|
||||||
19
inc/graph.h
19
inc/graph.h
|
|
@ -189,11 +189,12 @@ public:
|
||||||
SmallArray <Path> m_paths {};
|
SmallArray <Path> m_paths {};
|
||||||
HashMap <int32_t, Array <int32_t>, EmptyHash <int32_t>> m_hashTable {};
|
HashMap <int32_t, Array <int32_t>, EmptyHash <int32_t>> m_hashTable {};
|
||||||
|
|
||||||
String m_graphAuthor {};
|
struct GraphInfo {
|
||||||
String m_graphModified {};
|
String author {};
|
||||||
|
String modified {};
|
||||||
ExtenHeader m_extenHeader {};
|
ExtenHeader exten {};
|
||||||
StorageHeader m_graphHeader {};
|
StorageHeader header {};
|
||||||
|
} m_info {};
|
||||||
|
|
||||||
edict_t *m_editor {};
|
edict_t *m_editor {};
|
||||||
|
|
||||||
|
|
@ -270,11 +271,11 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StringRef getAuthor () const {
|
StringRef getAuthor () const {
|
||||||
return m_graphAuthor;
|
return m_info.author;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef getModifiedBy () const {
|
StringRef getModifiedBy () const {
|
||||||
return m_graphModified;
|
return m_info.modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasChanged () const {
|
bool hasChanged () const {
|
||||||
|
|
@ -339,12 +340,12 @@ public:
|
||||||
|
|
||||||
// set exten header from binary storage
|
// set exten header from binary storage
|
||||||
void setExtenHeader (ExtenHeader *hdr) {
|
void setExtenHeader (ExtenHeader *hdr) {
|
||||||
memcpy (&m_extenHeader, hdr, sizeof (ExtenHeader));
|
memcpy (&m_info.exten, hdr, sizeof (ExtenHeader));
|
||||||
}
|
}
|
||||||
|
|
||||||
// set graph header from binary storage
|
// set graph header from binary storage
|
||||||
void setGraphHeader (StorageHeader *hdr) {
|
void setGraphHeader (StorageHeader *hdr) {
|
||||||
memcpy (&m_graphHeader, hdr, sizeof (StorageHeader));
|
memcpy (&m_info.header, hdr, sizeof (StorageHeader));
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets the node numbers
|
// gets the node numbers
|
||||||
|
|
|
||||||
|
|
@ -105,13 +105,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static int32_t CR_STDCALL sendTo (int socket, const void *message, size_t length, int flags, const struct sockaddr *dest, int destLength);
|
CR_FORCE_STACK_ALIGN static int32_t CR_STDCALL sendTo (int socket, const void *message, size_t length, int flags, const struct sockaddr *dest, int destLength);
|
||||||
};
|
};
|
||||||
|
|
||||||
// used for transit calls between game dll and engine without all needed functions on bot side
|
// used for transit calls between game dll and engine without all needed functions on bot side
|
||||||
class DynamicLinkerHook : public Singleton <DynamicLinkerHook> {
|
class DynamicLinkerHook : public Singleton <DynamicLinkerHook> {
|
||||||
private:
|
private:
|
||||||
#if defined (CR_WINDOWS)
|
#if defined(CR_WINDOWS)
|
||||||
# define DLSYM_FUNCTION GetProcAddress
|
# define DLSYM_FUNCTION GetProcAddress
|
||||||
# define DLCLOSE_FUNCTION FreeLibrary
|
# define DLCLOSE_FUNCTION FreeLibrary
|
||||||
#else
|
#else
|
||||||
|
|
@ -177,11 +177,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static SharedLibrary::Func CR_STDCALL lookupHandler (SharedLibrary::Handle module, const char *function) {
|
CR_FORCE_STACK_ALIGN static SharedLibrary::Func CR_STDCALL lookupHandler (SharedLibrary::Handle module, const char *function) {
|
||||||
return instance ().lookup (module, function);
|
return instance ().lookup (module, function);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CR_STDCALL closeHandler (SharedLibrary::Handle module) {
|
CR_FORCE_STACK_ALIGN static int CR_STDCALL closeHandler (SharedLibrary::Handle module) {
|
||||||
return instance ().close (module);
|
return instance ().close (module);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ public:
|
||||||
void notifyBombDefuse ();
|
void notifyBombDefuse ();
|
||||||
void execGameEntity (edict_t *ent);
|
void execGameEntity (edict_t *ent);
|
||||||
void forEach (ForEachBot handler);
|
void forEach (ForEachBot handler);
|
||||||
void erase (Bot *bot);
|
void disconnectBot (Bot *bot);
|
||||||
void handleDeath (edict_t *killer, edict_t *victim);
|
void handleDeath (edict_t *killer, edict_t *victim);
|
||||||
void setLastWinner (int winner);
|
void setLastWinner (int winner);
|
||||||
void checkBotModel (edict_t *ent, char *infobuffer);
|
void checkBotModel (edict_t *ent, char *infobuffer);
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,9 @@ public:
|
||||||
void load ();
|
void load ();
|
||||||
void save ();
|
void save ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void syncLoad ();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename U = int32_t> U getHighestDamageForTeam (int32_t team) const {
|
template <typename U = int32_t> U getHighestDamageForTeam (int32_t team) const {
|
||||||
return static_cast <U> (cr::max (1, m_teamHighestDamage[team]));
|
return static_cast <U> (cr::max (1, m_teamHighestDamage[team]));
|
||||||
|
|
|
||||||
|
|
@ -15,58 +15,59 @@
|
||||||
|
|
||||||
#include VERSION_HEADER
|
#include VERSION_HEADER
|
||||||
|
|
||||||
|
// compile time build string
|
||||||
|
#define CTS_BUILD_STR static inline constexpr StringRef
|
||||||
|
|
||||||
// simple class for bot internal information
|
// simple class for bot internal information
|
||||||
class Product final : public Singleton <Product> {
|
static constexpr class Product final {
|
||||||
public:
|
public:
|
||||||
explicit constexpr Product () = default;
|
explicit constexpr Product () = default;
|
||||||
~Product () = default;
|
~Product () = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct Build {
|
static constexpr struct BuildInfo {
|
||||||
static constexpr StringRef hash { MODULE_COMMIT_COUNT };
|
CTS_BUILD_STR hash { MODULE_COMMIT_HASH };
|
||||||
static constexpr StringRef count { MODULE_COMMIT_HASH };
|
CTS_BUILD_STR count { MODULE_COMMIT_COUNT };
|
||||||
static constexpr StringRef author { MODULE_AUTHOR };
|
CTS_BUILD_STR author { MODULE_AUTHOR };
|
||||||
static constexpr StringRef machine { MODULE_MACHINE };
|
CTS_BUILD_STR machine { MODULE_MACHINE };
|
||||||
static constexpr StringRef compiler { MODULE_COMPILER };
|
CTS_BUILD_STR compiler { MODULE_COMPILER };
|
||||||
static constexpr StringRef id { MODULE_BUILD_ID };
|
CTS_BUILD_STR id { MODULE_BUILD_ID };
|
||||||
} build {};
|
} bi {};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr StringRef name { "YaPB" };
|
CTS_BUILD_STR name { "YaPB" };
|
||||||
static constexpr StringRef nameLower { "yapb" };
|
CTS_BUILD_STR nameLower { "yapb" };
|
||||||
static constexpr StringRef year { &__DATE__[7] };
|
CTS_BUILD_STR year { &__DATE__[7] };
|
||||||
static constexpr StringRef author { "YaPB Project" };
|
CTS_BUILD_STR author { "YaPB Project" };
|
||||||
static constexpr StringRef email { "yapb@jeefo.net" };
|
CTS_BUILD_STR email { "yapb@jeefo.net" };
|
||||||
static constexpr StringRef url { "https://yapb.jeefo.net/" };
|
CTS_BUILD_STR url { "https://yapb.jeefo.net/" };
|
||||||
static constexpr StringRef download { "yapb.jeefo.net" };
|
CTS_BUILD_STR download { "yapb.jeefo.net" };
|
||||||
static constexpr StringRef upload { "yapb.jeefo.net/upload" };
|
CTS_BUILD_STR upload { "yapb.jeefo.net/upload" };
|
||||||
static constexpr StringRef httpScheme { "http" };
|
CTS_BUILD_STR httpScheme { "http" };
|
||||||
static constexpr StringRef logtag { "YB" };
|
CTS_BUILD_STR logtag { "YB" };
|
||||||
static constexpr StringRef dtime { __DATE__ " " __TIME__ };
|
CTS_BUILD_STR dtime { __DATE__ " " __TIME__ };
|
||||||
static constexpr StringRef date { __DATE__ };
|
CTS_BUILD_STR date { __DATE__ };
|
||||||
static constexpr StringRef version { MODULE_VERSION "." MODULE_COMMIT_COUNT };
|
CTS_BUILD_STR version { MODULE_VERSION "." MODULE_COMMIT_COUNT };
|
||||||
static constexpr StringRef cmdPri { "yb" };
|
CTS_BUILD_STR cmdPri { "yb" };
|
||||||
static constexpr StringRef cmdSec { "yapb" };
|
CTS_BUILD_STR cmdSec { "yapb" };
|
||||||
};
|
} product {};
|
||||||
|
|
||||||
class Folders final : public Singleton <Folders> {
|
static constexpr class Folders final {
|
||||||
public:
|
public:
|
||||||
explicit constexpr Folders () = default;
|
explicit constexpr Folders () = default;
|
||||||
~Folders () = default;
|
~Folders () = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr StringRef bot { "yapb" };
|
CTS_BUILD_STR bot { "yapb" };
|
||||||
static constexpr StringRef addons { "addons" };
|
CTS_BUILD_STR addons { "addons" };
|
||||||
static constexpr StringRef config { "conf" };
|
CTS_BUILD_STR config { "conf" };
|
||||||
static constexpr StringRef data { "data" };
|
CTS_BUILD_STR data { "data" };
|
||||||
static constexpr StringRef lang { "lang" };
|
CTS_BUILD_STR lang { "lang" };
|
||||||
static constexpr StringRef logs { "logs" };
|
CTS_BUILD_STR logs { "logs" };
|
||||||
static constexpr StringRef train { "train" };
|
CTS_BUILD_STR train { "train" };
|
||||||
static constexpr StringRef graph { "graph" };
|
CTS_BUILD_STR graph { "graph" };
|
||||||
static constexpr StringRef podbot { "pwf" };
|
CTS_BUILD_STR podbot { "pwf" };
|
||||||
static constexpr StringRef ebot { "ewp" };
|
CTS_BUILD_STR ebot { "ewp" };
|
||||||
};
|
} folders {};
|
||||||
|
|
||||||
// expose product info
|
#undef CTS_BUILD_STR
|
||||||
CR_EXPOSE_GLOBAL_SINGLETON (Product, product);
|
|
||||||
CR_EXPOSE_GLOBAL_SINGLETON (Folders, folders);
|
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !defined (BOT_STORAGE_EXPLICIT_INSTANTIATIONS)
|
#if !defined(BOT_STORAGE_EXPLICIT_INSTANTIATIONS)
|
||||||
# define BOT_STORAGE_EXPLICIT_INSTANTIATIONS
|
# define BOT_STORAGE_EXPLICIT_INSTANTIATIONS
|
||||||
# include "../src/storage.cpp"
|
# include "../src/storage.cpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ public:
|
||||||
StringRef getFakeSteamId (edict_t *ent);
|
StringRef getFakeSteamId (edict_t *ent);
|
||||||
|
|
||||||
// get's the wave length
|
// get's the wave length
|
||||||
float getWaveLength (StringRef filename);
|
float getWaveFileDuration (StringRef filename);
|
||||||
|
|
||||||
// set custom cvar descriptions
|
// set custom cvar descriptions
|
||||||
void setCustomCvarDescriptions ();
|
void setCustomCvarDescriptions ();
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
// fallback if no git or custom build
|
// fallback if no git or custom build
|
||||||
#define MODULE_COMMIT_COUNT "0"
|
#define MODULE_COMMIT_COUNT "0"
|
||||||
#define MODULE_COMMIT_HASH "0"
|
#define MODULE_COMMIT_HASH "0"
|
||||||
#define MODULE_AUTHOR "default@mail.net"
|
#define MODULE_AUTHOR "yapb-local@jeefo.net"
|
||||||
#define MODULE_MACHINE "localhost"
|
#define MODULE_MACHINE "localhost"
|
||||||
#define MODULE_COMPILER "default"
|
#define MODULE_COMPILER "default"
|
||||||
#define MODULE_VERSION "4.5"
|
#define MODULE_VERSION "4.5"
|
||||||
|
|
|
||||||
|
|
@ -617,7 +617,7 @@ public:
|
||||||
float m_preventFlashing {}; // bot turned away from flashbang
|
float m_preventFlashing {}; // bot turned away from flashbang
|
||||||
float m_blindTime {}; // time when bot is blinded
|
float m_blindTime {}; // time when bot is blinded
|
||||||
float m_blindMoveSpeed {}; // mad speeds when bot is blind
|
float m_blindMoveSpeed {}; // mad speeds when bot is blind
|
||||||
float m_blindSidemoveSpeed {}; // mad side move speeds when bot is blind
|
float m_blindSideMoveSpeed {}; // mad side move speeds when bot is blind
|
||||||
float m_fallDownTime {}; // time bot started to fall
|
float m_fallDownTime {}; // time bot started to fall
|
||||||
float m_duckForJump {}; // is bot needed to duck for double jump
|
float m_duckForJump {}; // is bot needed to duck for double jump
|
||||||
float m_baseAgressionLevel {}; // base aggression level (on initializing)
|
float m_baseAgressionLevel {}; // base aggression level (on initializing)
|
||||||
|
|
@ -720,11 +720,7 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Bot (edict_t *bot, int difficulty, int personality, int team, int skin);
|
Bot (edict_t *bot, int difficulty, int personality, int team, int skin);
|
||||||
|
~Bot () = default;
|
||||||
// need to wait until all threads will finish it's work before terminating bot object
|
|
||||||
~Bot () {
|
|
||||||
MutexScopedLock lock1 (m_pathFindLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void logic (); /// the things that can be executed while skipping frames
|
void logic (); /// the things that can be executed while skipping frames
|
||||||
|
|
|
||||||
25
meson.build
25
meson.build
|
|
@ -42,6 +42,7 @@ opt_64bit = get_option('64bit')
|
||||||
opt_native = get_option('native')
|
opt_native = get_option('native')
|
||||||
opt_winxp = get_option('winxp')
|
opt_winxp = get_option('winxp')
|
||||||
opt_nosimd = get_option('nosimd')
|
opt_nosimd = get_option('nosimd')
|
||||||
|
opt_static_linkent = get_option('static_linkent')
|
||||||
|
|
||||||
# cpp and ldflags from scratch
|
# cpp and ldflags from scratch
|
||||||
cxxflags = []
|
cxxflags = []
|
||||||
|
|
@ -143,17 +144,21 @@ if cxx == 'clang' or cxx == 'gcc'
|
||||||
]
|
]
|
||||||
|
|
||||||
if os != 'darwin' and os != 'windows' and cpu != 'aarch64' and cpu != 'arm' and not cpu.startswith('ppc')
|
if os != 'darwin' and os != 'windows' and cpu != 'aarch64' and cpu != 'arm' and not cpu.startswith('ppc')
|
||||||
cxxflags += [
|
if not opt_static_linkent
|
||||||
'-fdata-sections',
|
cxxflags += [
|
||||||
'-ffunction-sections',
|
'-fdata-sections',
|
||||||
'-fcf-protection=none',
|
'-ffunction-sections',
|
||||||
'-fno-plt'
|
'-fcf-protection=none',
|
||||||
]
|
'-fno-plt'
|
||||||
|
]
|
||||||
|
|
||||||
ldflags += [
|
ldflags += [
|
||||||
'-Wl,--version-script=' + meson.project_source_root() + '/ext/ldscripts/version.lds',
|
'-Wl,--version-script=' + meson.project_source_root() + '/ext/ldscripts/version.lds',
|
||||||
'-Wl,--gc-sections'
|
'-Wl,--gc-sections'
|
||||||
]
|
]
|
||||||
|
else
|
||||||
|
cxxflags += ['-DLINKENT_STATIC']
|
||||||
|
endif
|
||||||
|
|
||||||
if cxx == 'gcc'
|
if cxx == 'gcc'
|
||||||
cxxflags += [
|
cxxflags += [
|
||||||
|
|
|
||||||
|
|
@ -16,4 +16,7 @@ option('winxp', type : 'boolean', value : false,
|
||||||
|
|
||||||
option('nosimd', type : 'boolean', value : false,
|
option('nosimd', type : 'boolean', value : false,
|
||||||
description: 'Disables all SIMD or NEON optimizations.')
|
description: 'Disables all SIMD or NEON optimizations.')
|
||||||
|
|
||||||
|
option('static_linkent', type : 'boolean', value : false,
|
||||||
|
description: 'Use predefined entity link list, instead of hooking dlsym.')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3712,20 +3712,20 @@ void Bot::takeBlind (int alpha) {
|
||||||
|
|
||||||
if (m_difficulty <= Difficulty::Normal) {
|
if (m_difficulty <= Difficulty::Normal) {
|
||||||
m_blindMoveSpeed = 0.0f;
|
m_blindMoveSpeed = 0.0f;
|
||||||
m_blindSidemoveSpeed = 0.0f;
|
m_blindSideMoveSpeed = 0.0f;
|
||||||
m_blindButton = IN_DUCK;
|
m_blindButton = IN_DUCK;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_blindNodeIndex = findCoverNode (512.0f);
|
m_blindNodeIndex = findCoverNode (512.0f);
|
||||||
m_blindMoveSpeed = -pev->maxspeed;
|
m_blindMoveSpeed = -pev->maxspeed;
|
||||||
m_blindSidemoveSpeed = 0.0f;
|
m_blindSideMoveSpeed = 0.0f;
|
||||||
|
|
||||||
if (rg.chance (50)) {
|
if (rg.chance (50)) {
|
||||||
m_blindSidemoveSpeed = pev->maxspeed;
|
m_blindSideMoveSpeed = pev->maxspeed;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_blindSidemoveSpeed = -pev->maxspeed;
|
m_blindSideMoveSpeed = -pev->maxspeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_healthValue < 85.0f) {
|
if (m_healthValue < 85.0f) {
|
||||||
|
|
@ -3994,7 +3994,7 @@ void Bot::runMovement () {
|
||||||
// translate bot buttons
|
// translate bot buttons
|
||||||
translateInput ();
|
translateInput ();
|
||||||
|
|
||||||
engfuncs.pfnRunPlayerMove (pev->pContainingEntity,
|
engfuncs.pfnRunPlayerMove (ent (),
|
||||||
getRpmAngles (), m_moveSpeed, m_strafeSpeed,
|
getRpmAngles (), m_moveSpeed, m_strafeSpeed,
|
||||||
0.0f, static_cast <uint16_t> (pev->button), static_cast <uint8_t> (pev->impulse), msecVal);
|
0.0f, static_cast <uint16_t> (pev->button), static_cast <uint8_t> (pev->impulse), msecVal);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ void Bot::prepareChatMessage (StringRef message) {
|
||||||
m_chatBuffer = message;
|
m_chatBuffer = message;
|
||||||
|
|
||||||
// must be called before return or on the end
|
// must be called before return or on the end
|
||||||
auto finishPreparation = [&] () {
|
auto addChatErrors = [&] () {
|
||||||
if (!m_chatBuffer.empty ()) {
|
if (!m_chatBuffer.empty ()) {
|
||||||
chatlib.addChatErrors (m_chatBuffer);
|
chatlib.addChatErrors (m_chatBuffer);
|
||||||
}
|
}
|
||||||
|
|
@ -153,7 +153,7 @@ void Bot::prepareChatMessage (StringRef message) {
|
||||||
|
|
||||||
// nothing found, bail out
|
// nothing found, bail out
|
||||||
if (pos == String::InvalidIndex || pos >= message.length ()) {
|
if (pos == String::InvalidIndex || pos >= message.length ()) {
|
||||||
finishPreparation ();
|
addChatErrors ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -241,6 +241,11 @@ void Bot::prepareChatMessage (StringRef message) {
|
||||||
return humanizedName (playerIndex);
|
return humanizedName (playerIndex);
|
||||||
}
|
}
|
||||||
else if (!needsEnemy && m_team == client.team) {
|
else if (!needsEnemy && m_team == client.team) {
|
||||||
|
if (util.isPlayer (pev->dmg_inflictor)
|
||||||
|
&& game.getRealTeam (pev->dmg_inflictor) == m_team) {
|
||||||
|
|
||||||
|
return humanizedName (game.indexOfPlayer (pev->dmg_inflictor));
|
||||||
|
}
|
||||||
return humanizedName (playerIndex);
|
return humanizedName (playerIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -304,7 +309,7 @@ void Bot::prepareChatMessage (StringRef message) {
|
||||||
};
|
};
|
||||||
++replaceCounter;
|
++replaceCounter;
|
||||||
}
|
}
|
||||||
finishPreparation ();
|
addChatErrors ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::checkChatKeywords (String &reply) {
|
bool Bot::checkChatKeywords (String &reply) {
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ bool Bot::checkBodyPartsWithOffsets (edict_t *target) {
|
||||||
const auto &eyes = getEyesPos ();
|
const auto &eyes = getEyesPos ();
|
||||||
|
|
||||||
auto spot = target->v.origin;
|
auto spot = target->v.origin;
|
||||||
auto self = pev->pContainingEntity;
|
auto self = ent ();
|
||||||
|
|
||||||
// creatures can't hurt behind anything
|
// creatures can't hurt behind anything
|
||||||
const auto ignoreFlags = m_isCreature ? TraceIgnore::None : (cv_aim_trace_consider_glass ? TraceIgnore::Monsters : TraceIgnore::Everything);
|
const auto ignoreFlags = m_isCreature ? TraceIgnore::None : (cv_aim_trace_consider_glass ? TraceIgnore::Monsters : TraceIgnore::Everything);
|
||||||
|
|
@ -266,7 +266,7 @@ bool Bot::checkBodyPartsWithOffsets (edict_t *target) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::checkBodyPartsWithHitboxes (edict_t *target) {
|
bool Bot::checkBodyPartsWithHitboxes (edict_t *target) {
|
||||||
const auto self = pev->pContainingEntity;
|
const auto self = ent ();
|
||||||
const auto refresh = m_frameInterval * 1.5f;
|
const auto refresh = m_frameInterval * 1.5f;
|
||||||
|
|
||||||
TraceResult result {};
|
TraceResult result {};
|
||||||
|
|
|
||||||
|
|
@ -248,10 +248,10 @@ void BotConfig::loadChatterConfig () {
|
||||||
|
|
||||||
m_chatter.clear ();
|
m_chatter.clear ();
|
||||||
|
|
||||||
struct EventMap {
|
static constexpr struct EventMap {
|
||||||
String str;
|
StringRef name {};
|
||||||
int code;
|
int code {};
|
||||||
float repeat;
|
float repeat {};
|
||||||
} chatterEventMap[] = {
|
} chatterEventMap[] = {
|
||||||
{ "Radio_CoverMe", Radio::CoverMe, kMaxChatterRepeatInterval },
|
{ "Radio_CoverMe", Radio::CoverMe, kMaxChatterRepeatInterval },
|
||||||
{ "Radio_YouTakePoint", Radio::YouTakeThePoint, kMaxChatterRepeatInterval },
|
{ "Radio_YouTakePoint", Radio::YouTakeThePoint, kMaxChatterRepeatInterval },
|
||||||
|
|
@ -361,18 +361,21 @@ void BotConfig::loadChatterConfig () {
|
||||||
items[1].trim ("(;)");
|
items[1].trim ("(;)");
|
||||||
|
|
||||||
for (const auto &event : chatterEventMap) {
|
for (const auto &event : chatterEventMap) {
|
||||||
if (event.str == items.first ()) {
|
if (event.name == items.first ().chars ()) {
|
||||||
// this does common work of parsing comma-separated chatter line
|
// this does common work of parsing comma-separated chatter line
|
||||||
auto sentences = items[1].split (",");
|
auto sentences = items[1].split (",");
|
||||||
sentences.shuffle ();
|
sentences.shuffle ();
|
||||||
|
|
||||||
for (auto &sound : sentences) {
|
for (auto &sound : sentences) {
|
||||||
sound.trim ().trim ("\"");
|
sound.trim ().trim ("\"");
|
||||||
const auto duration = util.getWaveLength (sound.chars ());
|
const auto duration = util.getWaveFileDuration (sound.chars ());
|
||||||
|
|
||||||
if (duration > 0.0f) {
|
if (duration > 0.0f) {
|
||||||
m_chatter[event.code].emplace (cr::move (sound), event.repeat, duration);
|
m_chatter[event.code].emplace (cr::move (sound), event.repeat, duration);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
game.print ("Warning: Couldn't get duration of sound '%s.wav.", sound);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sentences.clear ();
|
sentences.clear ();
|
||||||
}
|
}
|
||||||
|
|
@ -383,7 +386,12 @@ void BotConfig::loadChatterConfig () {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cv_radio_mode.set (1);
|
cv_radio_mode.set (1);
|
||||||
game.print ("Bots chatter communication disabled.");
|
|
||||||
|
|
||||||
|
// only notify if has bot voice, but failed to open file
|
||||||
|
if (game.is (GameFlags::HasBotVoice)) {
|
||||||
|
game.print ("Bots chatter communication disabled.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -154,12 +154,12 @@ int BotControl::cmdWeaponMode () {
|
||||||
}
|
}
|
||||||
|
|
||||||
int BotControl::cmdVersion () {
|
int BotControl::cmdVersion () {
|
||||||
const auto &build = product.build;
|
constexpr auto &bi = product.bi;
|
||||||
|
|
||||||
msg ("%s v%s (ID %s)", product.name, product.version, build.id);
|
msg ("%s v%s (ID %s)", product.name, product.version, bi.id);
|
||||||
msg (" by %s (%s)", product.author, product.email);
|
msg (" by %s (%s)", product.author, product.email);
|
||||||
msg (" %s", product.url);
|
msg (" %s", product.url);
|
||||||
msg ("compiled: %s on %s with %s", product.dtime, build.machine, build.compiler);
|
msg ("compiled: %s on %s with %s", product.dtime, bi.machine, bi.compiler);
|
||||||
|
|
||||||
return BotCommandResult::Handled;
|
return BotCommandResult::Handled;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -187,17 +187,17 @@ void Game::levelInitialize (edict_t *entities, int max) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::levelShutdown () {
|
void Game::levelShutdown () {
|
||||||
// stop thread pool
|
|
||||||
worker.shutdown ();
|
|
||||||
|
|
||||||
// save collected practice on shutdown
|
// save collected practice on shutdown
|
||||||
practice.save ();
|
practice.save ();
|
||||||
|
|
||||||
|
// stop thread pool
|
||||||
|
worker.shutdown ();
|
||||||
|
|
||||||
// destroy global killer entity
|
// destroy global killer entity
|
||||||
bots.destroyKillerEntity ();
|
bots.destroyKillerEntity ();
|
||||||
|
|
||||||
// ensure players are off on xash3d
|
// ensure players are off on xash3d
|
||||||
if (game.is (GameFlags::Xash3D)) {
|
if (game.is (GameFlags::Xash3DLegacy)) {
|
||||||
bots.kickEveryone (true, false);
|
bots.kickEveryone (true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -310,7 +310,7 @@ const char *Game::getRunningModName () {
|
||||||
return name.chars ();
|
return name.chars ();
|
||||||
}
|
}
|
||||||
|
|
||||||
char engineModName[256] {};
|
char engineModName[StringBuffer::StaticBufferSize] {};
|
||||||
engfuncs.pfnGetGameDir (engineModName);
|
engfuncs.pfnGetGameDir (engineModName);
|
||||||
|
|
||||||
name = engineModName;
|
name = engineModName;
|
||||||
|
|
@ -545,7 +545,7 @@ void Game::prepareBotArgs (edict_t *ent, String str) {
|
||||||
m_botArgs.emplace (args.substr (quote, args.length () - 1).trim ("\"")); // add string with trimmed quotes
|
m_botArgs.emplace (args.substr (quote, args.length () - 1).trim ("\"")); // add string with trimmed quotes
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (auto &&arg : args.split (" ")) {
|
for (auto arg : args.split (" ")) {
|
||||||
m_botArgs.emplace (arg);
|
m_botArgs.emplace (arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -560,8 +560,8 @@ void Game::prepareBotArgs (edict_t *ent, String str) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (str.find (';', 0) != String::InvalidIndex) {
|
if (str.find (';', 0) != String::InvalidIndex) {
|
||||||
for (auto &&part : str.split (";")) {
|
for (auto part : str.split (";")) {
|
||||||
parsePartArgs (part);
|
parsePartArgs (part.trim ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -594,7 +594,7 @@ bool Game::isSoftwareRenderer () {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// and on only windows version you can use software-render game. Linux, OSX always defaults to OpenGL
|
// and on only windows version you can use software-render game. Linux, macOS always defaults to OpenGL
|
||||||
if (plat.win) {
|
if (plat.win) {
|
||||||
return plat.hasModule ("sw");
|
return plat.hasModule ("sw");
|
||||||
}
|
}
|
||||||
|
|
@ -605,7 +605,7 @@ bool Game::is25thAnniversaryUpdate () {
|
||||||
static ConVarRef sv_use_steam_networking ("sv_use_steam_networking");
|
static ConVarRef sv_use_steam_networking ("sv_use_steam_networking");
|
||||||
static ConVarRef host_hl25_extended_structs ("host_hl25_extended_structs");
|
static ConVarRef host_hl25_extended_structs ("host_hl25_extended_structs");
|
||||||
|
|
||||||
return sv_use_steam_networking.exists () || host_hl25_extended_structs.exists ();
|
return sv_use_steam_networking.exists () || host_hl25_extended_structs.value () > 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::pushConVar (StringRef name, StringRef value, StringRef info, bool bounded, float min, float max, int32_t varType, bool missingAction, StringRef regval, ConVar *self) {
|
void Game::pushConVar (StringRef name, StringRef value, StringRef info, bool bounded, float min, float max, int32_t varType, bool missingAction, StringRef regval, ConVar *self) {
|
||||||
|
|
@ -1161,7 +1161,7 @@ void Game::printBotVersion () {
|
||||||
|
|
||||||
if (is (GameFlags::Xash3D)) {
|
if (is (GameFlags::Xash3D)) {
|
||||||
if (is (GameFlags::Xash3DLegacy)) {
|
if (is (GameFlags::Xash3DLegacy)) {
|
||||||
gameVersionStr.append (" @ Xash3D (Old)");
|
gameVersionStr.append (" @ Xash3D-NG");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gameVersionStr.append (" @ Xash3D FWGS");
|
gameVersionStr.append (" @ Xash3D FWGS");
|
||||||
|
|
@ -1315,7 +1315,7 @@ void LightMeasure::animateLight () {
|
||||||
|
|
||||||
for (auto j = 0; j < MAX_LIGHTSTYLES; ++j) {
|
for (auto j = 0; j < MAX_LIGHTSTYLES; ++j) {
|
||||||
if (!m_lightstyle[j].length) {
|
if (!m_lightstyle[j].length) {
|
||||||
m_lightstyleValue[j] = 256;
|
m_lightstyleValue[j] = MAX_LIGHTSTYLEVALUE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
m_lightstyleValue[j] = static_cast <uint32_t> (m_lightstyle[j].map[index % m_lightstyle[j].length] - 'a') * 22u;
|
m_lightstyleValue[j] = static_cast <uint32_t> (m_lightstyle[j].map[index % m_lightstyle[j].length] - 'a') * 22u;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
// nice interface to handle with linkents. if ever rehlds or hlds engine will ever run on ARM or
|
// nice interface to handle with linkents. if ever rehlds or hlds engine will ever run on ARM or
|
||||||
// other platforms, and you want to run bot on it without metamod, consider enabling LINKENT_STATIC_THUNKS
|
// other platforms, and you want to run bot on it without metamod, consider enabling LINKENT_STATIC_THUNKS
|
||||||
// when compiling the bot, to get it supported.
|
// when compiling the bot, to get it supported.
|
||||||
#if defined(LINKENT_STATIC_THUNKS)
|
#if defined(LINKENT_STATIC)
|
||||||
void forwardEntity_helper (EntityProto &addr, const char *name, entvars_t *pev) {
|
void forwardEntity_helper (EntityProto &addr, const char *name, entvars_t *pev) {
|
||||||
if (!addr) {
|
if (!addr) {
|
||||||
addr = game.lib ().resolve <EntityProto> (name);
|
addr = game.lib ().resolve <EntityProto> (name);
|
||||||
|
|
|
||||||
|
|
@ -22,22 +22,21 @@ void BotFakePingManager::reset (edict_t *to) {
|
||||||
if (!hasFeature ()) {
|
if (!hasFeature ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
static PingBitMsg pbm {};
|
|
||||||
|
|
||||||
for (const auto &client : util.getClients ()) {
|
for (const auto &client : util.getClients ()) {
|
||||||
if (!(client.flags & ClientFlags::Used) || util.isFakeClient (client.ent)) {
|
if (!(client.flags & ClientFlags::Used) || util.isFakeClient (client.ent)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
pbm.start (client.ent);
|
m_pbm.start (client.ent);
|
||||||
|
|
||||||
pbm.write (1, PingBitMsg::Single);
|
m_pbm.write (1, PingBitMsg::Single);
|
||||||
pbm.write (game.indexOfPlayer (to), PingBitMsg::PlayerID);
|
m_pbm.write (game.indexOfPlayer (to), PingBitMsg::PlayerID);
|
||||||
pbm.write (0, PingBitMsg::Ping);
|
m_pbm.write (0, PingBitMsg::Ping);
|
||||||
pbm.write (0, PingBitMsg::Loss);
|
m_pbm.write (0, PingBitMsg::Loss);
|
||||||
|
|
||||||
pbm.send ();
|
m_pbm.send ();
|
||||||
}
|
}
|
||||||
pbm.flush ();
|
m_pbm.flush ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotFakePingManager::syncCalculate () {
|
void BotFakePingManager::syncCalculate () {
|
||||||
|
|
@ -107,19 +106,18 @@ void BotFakePingManager::emit (edict_t *ent) {
|
||||||
if (!util.isPlayer (ent)) {
|
if (!util.isPlayer (ent)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
static PingBitMsg pbm {};
|
|
||||||
|
|
||||||
for (const auto &bot : bots) {
|
for (const auto &bot : bots) {
|
||||||
pbm.start (ent);
|
m_pbm.start (ent);
|
||||||
|
|
||||||
pbm.write (1, PingBitMsg::Single);
|
m_pbm.write (1, PingBitMsg::Single);
|
||||||
pbm.write (bot->entindex () - 1, PingBitMsg::PlayerID);
|
m_pbm.write (bot->entindex () - 1, PingBitMsg::PlayerID);
|
||||||
pbm.write (bot->m_ping, PingBitMsg::Ping);
|
m_pbm.write (bot->m_ping, PingBitMsg::Ping);
|
||||||
pbm.write (0, PingBitMsg::Loss);
|
m_pbm.write (0, PingBitMsg::Loss);
|
||||||
|
|
||||||
pbm.send ();
|
m_pbm.send ();
|
||||||
}
|
}
|
||||||
pbm.flush ();
|
m_pbm.flush ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotFakePingManager::restartTimer () {
|
void BotFakePingManager::restartTimer () {
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,8 @@ void BotGraph::reset () {
|
||||||
m_narrowChecked = false;
|
m_narrowChecked = false;
|
||||||
m_lightChecked = false;
|
m_lightChecked = false;
|
||||||
|
|
||||||
m_graphAuthor.clear ();
|
m_info.author.clear ();
|
||||||
m_graphModified.clear ();
|
m_info.modified.clear ();
|
||||||
|
|
||||||
m_paths.clear ();
|
m_paths.clear ();
|
||||||
}
|
}
|
||||||
|
|
@ -600,7 +600,7 @@ IntArray BotGraph::getNearestInRadius (float radius, const Vector &origin, int m
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotGraph::add (int type, const Vector &pos) {
|
void BotGraph::add (int type, const Vector &pos) {
|
||||||
if (game.isNullEntity (m_editor) && !analyzer.isAnalyzing ()) {
|
if (!hasEditor () && !analyzer.isAnalyzing ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int index = kInvalidNodeIndex;
|
int index = kInvalidNodeIndex;
|
||||||
|
|
@ -610,7 +610,7 @@ void BotGraph::add (int type, const Vector &pos) {
|
||||||
Vector newOrigin = pos;
|
Vector newOrigin = pos;
|
||||||
|
|
||||||
if (newOrigin.empty ()) {
|
if (newOrigin.empty ()) {
|
||||||
if (game.isNullEntity (m_editor)) {
|
if (!hasEditor ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
newOrigin = m_editor->v.origin;
|
newOrigin = m_editor->v.origin;
|
||||||
|
|
@ -1277,21 +1277,24 @@ void BotGraph::showStats () {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotGraph::showFileInfo () {
|
void BotGraph::showFileInfo () {
|
||||||
|
const auto &info = m_info.header;
|
||||||
|
const auto &exten = m_info.exten;
|
||||||
|
|
||||||
msg ("header:");
|
msg ("header:");
|
||||||
msg (" magic: %d", m_graphHeader.magic);
|
msg (" magic: %d", info.magic);
|
||||||
msg (" version: %d", m_graphHeader.version);
|
msg (" version: %d", info.version);
|
||||||
msg (" node_count: %d", m_graphHeader.length);
|
msg (" node_count: %d", info.length);
|
||||||
msg (" compressed_size: %dkB", m_graphHeader.compressed / 1024);
|
msg (" compressed_size: %dkB", info.compressed / 1024);
|
||||||
msg (" uncompressed_size: %dkB", m_graphHeader.uncompressed / 1024);
|
msg (" uncompressed_size: %dkB", info.uncompressed / 1024);
|
||||||
msg (" options: %d", m_graphHeader.options); // display as string ?
|
msg (" options: %d", info.options); // display as string ?
|
||||||
msg (" analyzed: %s", isAnalyzed () ? conf.translate ("yes") : conf.translate ("no")); // display as string ?
|
msg (" analyzed: %s", isAnalyzed () ? conf.translate ("yes") : conf.translate ("no")); // display as string ?
|
||||||
|
|
||||||
msg ("");
|
msg ("");
|
||||||
|
|
||||||
msg ("extensions:");
|
msg ("extensions:");
|
||||||
msg (" author: %s", m_extenHeader.author);
|
msg (" author: %s", exten.author);
|
||||||
msg (" modified_by: %s", m_extenHeader.modified);
|
msg (" modified_by: %s", exten.modified);
|
||||||
msg (" bsp_size: %d", m_extenHeader.mapSize);
|
msg (" bsp_size: %d", exten.mapSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotGraph::emitNotify (int32_t sound) {
|
void BotGraph::emitNotify (int32_t sound) {
|
||||||
|
|
@ -1576,7 +1579,7 @@ void BotGraph::initNarrowPlaces () {
|
||||||
constexpr int32_t kNarrowPlacesMinGraphVersion = 2;
|
constexpr int32_t kNarrowPlacesMinGraphVersion = 2;
|
||||||
|
|
||||||
// if version 2 or higher, narrow places already initialized and saved into file
|
// if version 2 or higher, narrow places already initialized and saved into file
|
||||||
if (m_graphHeader.version >= kNarrowPlacesMinGraphVersion && !hasEditFlag (GraphEdit::On)) {
|
if (m_info.header.version >= kNarrowPlacesMinGraphVersion && !hasEditFlag (GraphEdit::On)) {
|
||||||
m_narrowChecked = true;
|
m_narrowChecked = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1747,7 +1750,7 @@ bool BotGraph::convertOldFormat () {
|
||||||
if (!m_paths.empty ()) {
|
if (!m_paths.empty ()) {
|
||||||
msg ("Converting old PWF to new format Graph.");
|
msg ("Converting old PWF to new format Graph.");
|
||||||
|
|
||||||
m_graphAuthor = header.author;
|
m_info.author = header.author;
|
||||||
|
|
||||||
// clean editor so graph will be saved with header's author
|
// clean editor so graph will be saved with header's author
|
||||||
auto editor = m_editor;
|
auto editor = m_editor;
|
||||||
|
|
@ -1774,8 +1777,8 @@ bool BotGraph::loadGraphData () {
|
||||||
ExtenHeader exten {};
|
ExtenHeader exten {};
|
||||||
int32_t outOptions = 0;
|
int32_t outOptions = 0;
|
||||||
|
|
||||||
m_graphHeader = {};
|
m_info.header = {};
|
||||||
m_extenHeader = {};
|
m_info.exten = {};
|
||||||
|
|
||||||
// re-initialize paths
|
// re-initialize paths
|
||||||
reset ();
|
reset ();
|
||||||
|
|
@ -1797,15 +1800,15 @@ bool BotGraph::loadGraphData () {
|
||||||
StringRef author = exten.author;
|
StringRef author = exten.author;
|
||||||
|
|
||||||
if ((outOptions & StorageOption::Official) || author.startsWith ("official") || author.length () < 2) {
|
if ((outOptions & StorageOption::Official) || author.startsWith ("official") || author.length () < 2) {
|
||||||
m_graphAuthor.assign (product.name);
|
m_info.author.assign (product.name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_graphAuthor.assign (author);
|
m_info.author.assign (author);
|
||||||
}
|
}
|
||||||
StringRef modified = exten.modified;
|
StringRef modified = exten.modified;
|
||||||
|
|
||||||
if (!modified.empty () && !modified.contains ("(none)")) {
|
if (!modified.empty () && !modified.contains ("(none)")) {
|
||||||
m_graphModified.assign (exten.modified);
|
m_info.modified.assign (exten.modified);
|
||||||
}
|
}
|
||||||
planner.init (); // initialize our little path planner
|
planner.init (); // initialize our little path planner
|
||||||
practice.load (); // load bots practice
|
practice.load (); // load bots practice
|
||||||
|
|
@ -1848,8 +1851,8 @@ bool BotGraph::saveGraphData () {
|
||||||
auto options = StorageOption::Graph | StorageOption::Exten;
|
auto options = StorageOption::Graph | StorageOption::Exten;
|
||||||
String editorName {};
|
String editorName {};
|
||||||
|
|
||||||
if (game.isNullEntity (m_editor) && !m_graphAuthor.empty ()) {
|
if (!hasEditor () && !m_info.author.empty ()) {
|
||||||
editorName = m_graphAuthor;
|
editorName = m_info.author;
|
||||||
|
|
||||||
if (!game.isDedicated ()) {
|
if (!game.isDedicated ()) {
|
||||||
options |= StorageOption::Recovered;
|
options |= StorageOption::Recovered;
|
||||||
|
|
@ -1874,15 +1877,15 @@ bool BotGraph::saveGraphData () {
|
||||||
ExtenHeader exten {};
|
ExtenHeader exten {};
|
||||||
|
|
||||||
// only modify the author if no author currently assigned to graph file
|
// only modify the author if no author currently assigned to graph file
|
||||||
if (m_graphAuthor.empty () || strings.isEmpty (m_extenHeader.author)) {
|
if (m_info.author.empty () || strings.isEmpty (m_info.exten.author)) {
|
||||||
strings.copy (exten.author, editorName.chars (), cr::bufsize (exten.author));
|
strings.copy (exten.author, editorName.chars (), cr::bufsize (exten.author));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
strings.copy (exten.author, m_extenHeader.author, cr::bufsize (exten.author));
|
strings.copy (exten.author, m_info.exten.author, cr::bufsize (exten.author));
|
||||||
}
|
}
|
||||||
|
|
||||||
// only update modified by, if name differs
|
// only update modified by, if name differs
|
||||||
if (m_graphAuthor != editorName && !strings.isEmpty (m_extenHeader.author)) {
|
if (m_info.author != editorName && !strings.isEmpty (m_info.exten.author)) {
|
||||||
strings.copy (exten.modified, editorName.chars (), cr::bufsize (exten.author));
|
strings.copy (exten.modified, editorName.chars (), cr::bufsize (exten.author));
|
||||||
}
|
}
|
||||||
exten.mapSize = getBspSize ();
|
exten.mapSize = getBspSize ();
|
||||||
|
|
@ -1901,8 +1904,8 @@ void BotGraph::saveOldFormat () {
|
||||||
|
|
||||||
String editorName {};
|
String editorName {};
|
||||||
|
|
||||||
if (game.isNullEntity (m_editor) && !m_graphAuthor.empty ()) {
|
if (!hasEditor () && !m_info.author.empty ()) {
|
||||||
editorName = m_graphAuthor;
|
editorName = m_info.author;
|
||||||
}
|
}
|
||||||
else if (!game.isNullEntity (m_editor)) {
|
else if (!game.isNullEntity (m_editor)) {
|
||||||
editorName = m_editor->v.netname.chars ();
|
editorName = m_editor->v.netname.chars ();
|
||||||
|
|
@ -2284,7 +2287,7 @@ void BotGraph::frame () {
|
||||||
|
|
||||||
// draw the radius circle
|
// draw the radius circle
|
||||||
Vector origin = (path.flags & NodeFlag::Crouch) ? path.origin : path.origin - Vector (0.0f, 0.0f, 18.0f);
|
Vector origin = (path.flags & NodeFlag::Crouch) ? path.origin : path.origin - Vector (0.0f, 0.0f, 18.0f);
|
||||||
static Color radiusColor { 36, 36, 255 };
|
constexpr Color radiusColor { 36, 36, 255 };
|
||||||
|
|
||||||
// if radius is nonzero, draw a full circle
|
// if radius is nonzero, draw a full circle
|
||||||
if (path.radius > 0.0f) {
|
if (path.radius > 0.0f) {
|
||||||
|
|
@ -2846,7 +2849,7 @@ const Array <int32_t> &BotGraph::getNodesInBucket (const Vector &pos) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BotGraph::isAnalyzed () const {
|
bool BotGraph::isAnalyzed () const {
|
||||||
return (m_graphHeader.options & StorageOption::Analyzed);
|
return (m_info.header.options & StorageOption::Analyzed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotGraph::eraseFromBucket (const Vector &pos, int index) {
|
void BotGraph::eraseFromBucket (const Vector &pos, int index) {
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ SharedLibrary::Func DynamicLinkerHook::lookup (SharedLibrary::Handle module, con
|
||||||
return resolve (module);
|
return resolve (module);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined (CR_WINDOWS)
|
#if defined(CR_WINDOWS)
|
||||||
if (HIWORD (function) == 0) {
|
if (HIWORD (function) == 0) {
|
||||||
return resolve (module);
|
return resolve (module);
|
||||||
}
|
}
|
||||||
|
|
@ -174,15 +174,20 @@ bool DynamicLinkerHook::needsBypass () const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynamicLinkerHook::initialize () {
|
void DynamicLinkerHook::initialize () {
|
||||||
|
#if defined(LINKENT_STATIC)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (plat.isNonX86 () || game.is (GameFlags::Metamod)) {
|
if (plat.isNonX86 () || game.is (GameFlags::Metamod)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
constexpr StringRef kKernel32Module = "kernel32.dll";
|
||||||
|
|
||||||
m_dlsym.initialize ("kernel32.dll", "GetProcAddress", DLSYM_FUNCTION);
|
m_dlsym.initialize (kKernel32Module, "GetProcAddress", DLSYM_FUNCTION);
|
||||||
m_dlsym.install (reinterpret_cast <void *> (lookupHandler), true);
|
m_dlsym.install (reinterpret_cast <void *> (lookupHandler), true);
|
||||||
|
|
||||||
if (needsBypass ()) {
|
if (needsBypass ()) {
|
||||||
m_dlclose.initialize ("kernel32.dll", "FreeLibrary", DLCLOSE_FUNCTION);
|
m_dlclose.initialize (kKernel32Module, "FreeLibrary", DLCLOSE_FUNCTION);
|
||||||
m_dlclose.install (reinterpret_cast <void *> (closeHandler), true);
|
m_dlclose.install (reinterpret_cast <void *> (closeHandler), true);
|
||||||
}
|
}
|
||||||
m_self.locate (&engfuncs);
|
m_self.locate (&engfuncs);
|
||||||
|
|
|
||||||
119
src/linkage.cpp
119
src/linkage.cpp
|
|
@ -34,7 +34,7 @@ plugin_info_t Plugin_info = {
|
||||||
|
|
||||||
// compilers can't create lambdas with vaargs, so put this one in it's own namespace
|
// compilers can't create lambdas with vaargs, so put this one in it's own namespace
|
||||||
namespace Hooks {
|
namespace Hooks {
|
||||||
void handler_engClientCommand (edict_t *ent, char const *format, ...) {
|
CR_FORCE_STACK_ALIGN void handler_engClientCommand (edict_t *ent, char const *format, ...) {
|
||||||
// this function forces the client whose player entity is ent to issue a client command.
|
// this function forces the client whose player entity is ent to issue a client command.
|
||||||
// How it works is that clients all have a argv global string in their client DLL that
|
// How it works is that clients all have a argv global string in their client DLL that
|
||||||
// stores the command string; if ever that string is filled with characters, the client DLL
|
// stores the command string; if ever that string is filled with characters, the client DLL
|
||||||
|
|
@ -99,7 +99,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
memcpy (table, &dllapi, sizeof (gamefuncs_t));
|
memcpy (table, &dllapi, sizeof (gamefuncs_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
table->pfnGameInit = [] () {
|
table->pfnGameInit = [] () CR_FORCE_STACK_ALIGN {
|
||||||
// this function is a one-time call, and appears to be the second function called in the
|
// this function is a one-time call, and appears to be the second function called in the
|
||||||
// DLL after GiveFntprsToDll() has been called. Its purpose is to tell the MOD DLL to
|
// DLL after GiveFntprsToDll() has been called. Its purpose is to tell the MOD DLL to
|
||||||
// initialize the game before the engine actually hooks into it with its video frames and
|
// initialize the game before the engine actually hooks into it with its video frames and
|
||||||
|
|
@ -121,7 +121,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
dllapi.pfnGameInit ();
|
dllapi.pfnGameInit ();
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnSpawn = [] (edict_t *ent) {
|
table->pfnSpawn = [] (edict_t *ent) CR_FORCE_STACK_ALIGN {
|
||||||
// this function asks the game DLL to spawn (i.e, give a physical existence in the virtual
|
// this function asks the game DLL to spawn (i.e, give a physical existence in the virtual
|
||||||
// world, in other words to 'display') the entity pointed to by ent in the game. The
|
// world, in other words to 'display') the entity pointed to by ent in the game. The
|
||||||
// Spawn() function is one of the functions any entity is supposed to have in the game DLL,
|
// Spawn() function is one of the functions any entity is supposed to have in the game DLL,
|
||||||
|
|
@ -141,7 +141,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnTouch = [] (edict_t *pentTouched, edict_t *pentOther) {
|
table->pfnTouch = [] (edict_t *pentTouched, edict_t *pentOther) CR_FORCE_STACK_ALIGN {
|
||||||
// this function is called when two entities' bounding boxes enter in collision. For example,
|
// this function is called when two entities' bounding boxes enter in collision. For example,
|
||||||
// when a player walks upon a gun, the player entity bounding box collides to the gun entity
|
// when a player walks upon a gun, the player entity bounding box collides to the gun entity
|
||||||
// bounding box, and the result is that this function is called. It is used by the game for
|
// bounding box, and the result is that this function is called. It is used by the game for
|
||||||
|
|
@ -170,7 +170,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
dllapi.pfnTouch (pentTouched, pentOther);
|
dllapi.pfnTouch (pentTouched, pentOther);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnClientConnect = [] (edict_t *ent, const char *name, const char *addr, char rejectReason[128]) {
|
table->pfnClientConnect = [] (edict_t *ent, const char *name, const char *addr, char rejectReason[128]) CR_FORCE_STACK_ALIGN {
|
||||||
// this function is called in order to tell the MOD DLL that a client attempts to connect the
|
// this function is called in order to tell the MOD DLL that a client attempts to connect the
|
||||||
// game. The entity pointer of this client is ent, the name under which he connects is
|
// game. The entity pointer of this client is ent, the name under which he connects is
|
||||||
// pointed to by the pszName pointer, and its IP address string is pointed by the pszAddress
|
// pointed to by the pszName pointer, and its IP address string is pointed by the pszAddress
|
||||||
|
|
@ -210,7 +210,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
return dllapi.pfnClientConnect (ent, name, addr, rejectReason);
|
return dllapi.pfnClientConnect (ent, name, addr, rejectReason);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnClientDisconnect = [] (edict_t *ent) {
|
table->pfnClientDisconnect = [] (edict_t *ent) CR_FORCE_STACK_ALIGN {
|
||||||
// this function is called whenever a client is VOLUNTARILY disconnected from the server,
|
// this function is called whenever a client is VOLUNTARILY disconnected from the server,
|
||||||
// either because the client dropped the connection, or because the server dropped him from
|
// either because the client dropped the connection, or because the server dropped him from
|
||||||
// the game (latency timeout). The effect is the freeing of a client slot on the server. Note
|
// the game (latency timeout). The effect is the freeing of a client slot on the server. Note
|
||||||
|
|
@ -224,7 +224,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
|
|
||||||
for (auto &bot : bots) {
|
for (auto &bot : bots) {
|
||||||
if (bot->pev == &ent->v) {
|
if (bot->pev == &ent->v) {
|
||||||
bots.erase (bot.get ()); // remove the bot from bots array
|
bots.disconnectBot (bot.get ()); // remove the bot from bots array
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -249,8 +249,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
dllapi.pfnClientDisconnect (ent);
|
dllapi.pfnClientDisconnect (ent);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
table->pfnClientPutInServer = [] (edict_t *ent) CR_FORCE_STACK_ALIGN {
|
||||||
table->pfnClientPutInServer = [] (edict_t *ent) {
|
|
||||||
// this function is called once a just connected client actually enters the game, after
|
// this function is called once a just connected client actually enters the game, after
|
||||||
// having downloaded and synchronized its resources with the of the server's. It's the
|
// having downloaded and synchronized its resources with the of the server's. It's the
|
||||||
// perfect place to hook for client connecting, since a client can always try to connect
|
// perfect place to hook for client connecting, since a client can always try to connect
|
||||||
|
|
@ -271,7 +270,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
dllapi.pfnClientPutInServer (ent);
|
dllapi.pfnClientPutInServer (ent);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnClientUserInfoChanged = [] (edict_t *ent, char *infobuffer) {
|
table->pfnClientUserInfoChanged = [] (edict_t *ent, char *infobuffer) CR_FORCE_STACK_ALIGN {
|
||||||
// this function is called when a player changes model, or changes team. Occasionally it
|
// this function is called when a player changes model, or changes team. Occasionally it
|
||||||
// enforces rules on these changes (for example, some MODs don't want to allow players to
|
// enforces rules on these changes (for example, some MODs don't want to allow players to
|
||||||
// change their player model). But most commonly, this function is in charge of handling
|
// change their player model). But most commonly, this function is in charge of handling
|
||||||
|
|
@ -286,7 +285,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
dllapi.pfnClientUserInfoChanged (ent, infobuffer);
|
dllapi.pfnClientUserInfoChanged (ent, infobuffer);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnClientCommand = [] (edict_t *ent) {
|
table->pfnClientCommand = [] (edict_t *ent) CR_FORCE_STACK_ALIGN {
|
||||||
// this function is called whenever the client whose player entity is ent issues a client
|
// this function is called whenever the client whose player entity is ent issues a client
|
||||||
// command. How it works is that clients all have a global string in their client DLL that
|
// command. How it works is that clients all have a global string in their client DLL that
|
||||||
// stores the command string; if ever that string is filled with characters, the client DLL
|
// stores the command string; if ever that string is filled with characters, the client DLL
|
||||||
|
|
@ -323,7 +322,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
dllapi.pfnClientCommand (ent);
|
dllapi.pfnClientCommand (ent);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnServerActivate = [] (edict_t *edictList, int edictCount, int clientMax) {
|
table->pfnServerActivate = [] (edict_t *edictList, int edictCount, int clientMax) CR_FORCE_STACK_ALIGN {
|
||||||
// this function is called when the server has fully loaded and is about to manifest itself
|
// this function is called when the server has fully loaded and is about to manifest itself
|
||||||
// on the network as such. Since a mapchange is actually a server shutdown followed by a
|
// on the network as such. Since a mapchange is actually a server shutdown followed by a
|
||||||
// restart, this function is also called when a new map is being loaded. Hence it's the
|
// restart, this function is also called when a new map is being loaded. Hence it's the
|
||||||
|
|
@ -340,7 +339,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
game.levelInitialize (edictList, edictCount);
|
game.levelInitialize (edictList, edictCount);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnServerDeactivate = [] () {
|
table->pfnServerDeactivate = [] () CR_FORCE_STACK_ALIGN {
|
||||||
// this function is called when the server is shutting down. A particular note about map
|
// this function is called when the server is shutting down. A particular note about map
|
||||||
// changes: changing the map means shutting down the server and starting a new one. Of course
|
// changes: changing the map means shutting down the server and starting a new one. Of course
|
||||||
// this process is transparent to the user, but either in single player when the hero reaches
|
// this process is transparent to the user, but either in single player when the hero reaches
|
||||||
|
|
@ -360,7 +359,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
dllapi.pfnServerDeactivate ();
|
dllapi.pfnServerDeactivate ();
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnStartFrame = [] () {
|
table->pfnStartFrame = [] () CR_FORCE_STACK_ALIGN {
|
||||||
// this function starts a video frame. It is called once per video frame by the game. If
|
// this function starts a video frame. It is called once per video frame by the game. If
|
||||||
// you run Half-Life at 90 fps, this function will then be called 90 times per second. By
|
// you run Half-Life at 90 fps, this function will then be called 90 times per second. By
|
||||||
// placing a hook on it, we have a good place to do things that should be done continuously
|
// placing a hook on it, we have a good place to do things that should be done continuously
|
||||||
|
|
@ -415,7 +414,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (game.is (GameFlags::HasFakePings) && !game.is (GameFlags::Metamod)) {
|
if (game.is (GameFlags::HasFakePings) && !game.is (GameFlags::Metamod)) {
|
||||||
table->pfnUpdateClientData = [] (const struct edict_s *player, int sendweapons, struct clientdata_s *cd) {
|
table->pfnUpdateClientData = [] (const struct edict_s *player, int sendweapons, struct clientdata_s *cd) CR_FORCE_STACK_ALIGN {
|
||||||
// this function is a synchronization tool that is used periodically by the engine to tell
|
// this function is a synchronization tool that is used periodically by the engine to tell
|
||||||
// the game DLL to send player info over the network to one of its clients when it suspects
|
// the game DLL to send player info over the network to one of its clients when it suspects
|
||||||
// that this client is desynchronizing. Early bots were using it to ask the game DLL for the
|
// that this client is desynchronizing. Early bots were using it to ask the game DLL for the
|
||||||
|
|
@ -437,7 +436,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
table->pfnPM_Move = [] (playermove_t *pm, int server) {
|
table->pfnPM_Move = [] (playermove_t *pm, int server) CR_FORCE_STACK_ALIGN {
|
||||||
// this is the player movement code clients run to predict things when the server can't update
|
// this is the player movement code clients run to predict things when the server can't update
|
||||||
// them often enough (or doesn't want to). The server runs exactly the same function for
|
// them often enough (or doesn't want to). The server runs exactly the same function for
|
||||||
// moving players. There is normally no distinction between them, else client-side prediction
|
// moving players. There is normally no distinction between them, else client-side prediction
|
||||||
|
|
@ -451,7 +450,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
dllapi.pfnPM_Move (pm, server);
|
dllapi.pfnPM_Move (pm, server);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnKeyValue = [] (edict_t *ent, KeyValueData *kvd) {
|
table->pfnKeyValue = [] (edict_t *ent, KeyValueData *kvd) CR_FORCE_STACK_ALIGN {
|
||||||
// this function is called when the game requests a pointer to some entity's keyvalue data.
|
// this function is called when the game requests a pointer to some entity's keyvalue data.
|
||||||
// The keyvalue data is held in each entity's infobuffer (basically a char buffer where each
|
// The keyvalue data is held in each entity's infobuffer (basically a char buffer where each
|
||||||
// game DLL can put the stuff it wants) under - as it says - the form of a key/value pair. A
|
// game DLL can put the stuff it wants) under - as it says - the form of a key/value pair. A
|
||||||
|
|
@ -475,7 +474,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int interfaceVersion) {
|
||||||
return HLTrue;
|
return HLTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CR_LINKAGE_C int GetEntityAPI_Post (gamefuncs_t *table, int) {
|
CR_C_LINKAGE int GetEntityAPI_Post (gamefuncs_t *table, int) {
|
||||||
// this function is called right after GiveFnptrsToDll() by the engine in the game DLL (or
|
// this function is called right after GiveFnptrsToDll() by the engine in the game DLL (or
|
||||||
// what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can
|
// what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can
|
||||||
// be called by the engine, into a memory block pointed to by the functionTable pointer
|
// be called by the engine, into a memory block pointed to by the functionTable pointer
|
||||||
|
|
@ -488,7 +487,7 @@ CR_LINKAGE_C int GetEntityAPI_Post (gamefuncs_t *table, int) {
|
||||||
|
|
||||||
plat.bzero (table, sizeof (gamefuncs_t));
|
plat.bzero (table, sizeof (gamefuncs_t));
|
||||||
|
|
||||||
table->pfnSpawn = [] (edict_t *ent) {
|
table->pfnSpawn = [] (edict_t *ent) CR_FORCE_STACK_ALIGN {
|
||||||
// this function asks the game DLL to spawn (i.e, give a physical existence in the virtual
|
// this function asks the game DLL to spawn (i.e, give a physical existence in the virtual
|
||||||
// world, in other words to 'display') the entity pointed to by ent in the game. The
|
// world, in other words to 'display') the entity pointed to by ent in the game. The
|
||||||
// Spawn() function is one of the functions any entity is supposed to have in the game DLL,
|
// Spawn() function is one of the functions any entity is supposed to have in the game DLL,
|
||||||
|
|
@ -502,7 +501,7 @@ CR_LINKAGE_C int GetEntityAPI_Post (gamefuncs_t *table, int) {
|
||||||
RETURN_META_VALUE (MRES_HANDLED, 0);
|
RETURN_META_VALUE (MRES_HANDLED, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnStartFrame = [] () {
|
table->pfnStartFrame = [] () CR_FORCE_STACK_ALIGN {
|
||||||
// this function starts a video frame. It is called once per video frame by the game. If
|
// this function starts a video frame. It is called once per video frame by the game. If
|
||||||
// you run Half-Life at 90 fps, this function will then be called 90 times per second. By
|
// you run Half-Life at 90 fps, this function will then be called 90 times per second. By
|
||||||
// placing a hook on it, we have a good place to do things that should be done continuously
|
// placing a hook on it, we have a good place to do things that should be done continuously
|
||||||
|
|
@ -515,7 +514,7 @@ CR_LINKAGE_C int GetEntityAPI_Post (gamefuncs_t *table, int) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnServerActivate = [] (edict_t *edictList, int edictCount, int) {
|
table->pfnServerActivate = [] (edict_t *edictList, int edictCount, int) CR_FORCE_STACK_ALIGN {
|
||||||
// this function is called when the server has fully loaded and is about to manifest itself
|
// this function is called when the server has fully loaded and is about to manifest itself
|
||||||
// on the network as such. Since a mapchange is actually a server shutdown followed by a
|
// on the network as such. Since a mapchange is actually a server shutdown followed by a
|
||||||
// restart, this function is also called when a new map is being loaded. Hence it's the
|
// restart, this function is also called when a new map is being loaded. Hence it's the
|
||||||
|
|
@ -531,7 +530,7 @@ CR_LINKAGE_C int GetEntityAPI_Post (gamefuncs_t *table, int) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (game.is (GameFlags::HasFakePings)) {
|
if (game.is (GameFlags::HasFakePings)) {
|
||||||
table->pfnUpdateClientData = [] (const struct edict_s *player, int, struct clientdata_s *) {
|
table->pfnUpdateClientData = [] (const struct edict_s *player, int, struct clientdata_s *) CR_FORCE_STACK_ALIGN {
|
||||||
// this function is a synchronization tool that is used periodically by the engine to tell
|
// this function is a synchronization tool that is used periodically by the engine to tell
|
||||||
// the game DLL to send player info over the network to one of its clients when it suspects
|
// the game DLL to send player info over the network to one of its clients when it suspects
|
||||||
// that this client is desynchronizing. Early bots were using it to ask the game DLL for the
|
// that this client is desynchronizing. Early bots were using it to ask the game DLL for the
|
||||||
|
|
@ -555,13 +554,13 @@ CR_LINKAGE_C int GetEntityAPI_Post (gamefuncs_t *table, int) {
|
||||||
return HLTrue;
|
return HLTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
CR_C_LINKAGE int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
if (game.is (GameFlags::Metamod)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
plat.bzero (table, sizeof (enginefuncs_t));
|
plat.bzero (table, sizeof (enginefuncs_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entlink.needsBypass () && !game.is (GameFlags::Metamod)) {
|
if (entlink.needsBypass () && !game.is (GameFlags::Metamod)) {
|
||||||
table->pfnCreateNamedEntity = [] (string_t classname) -> edict_t * {
|
table->pfnCreateNamedEntity = [] (string_t classname) CR_FORCE_STACK_ALIGN {
|
||||||
|
|
||||||
if (entlink.isPaused ()) {
|
if (entlink.isPaused ()) {
|
||||||
entlink.enable ();
|
entlink.enable ();
|
||||||
|
|
@ -572,7 +571,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.is (GameFlags::Legacy)) {
|
if (game.is (GameFlags::Legacy)) {
|
||||||
table->pfnFindEntityByString = [] (edict_t *edictStartSearchAfter, const char *field, const char *value) {
|
table->pfnFindEntityByString = [] (edict_t *edictStartSearchAfter, const char *field, const char *value) CR_FORCE_STACK_ALIGN {
|
||||||
// round starts in counter-strike 1.5
|
// round starts in counter-strike 1.5
|
||||||
if (strcmp (value, "info_map_parameters") == 0) {
|
if (strcmp (value, "info_map_parameters") == 0) {
|
||||||
bots.initRound ();
|
bots.initRound ();
|
||||||
|
|
@ -583,10 +582,22 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
}
|
}
|
||||||
return engfuncs.pfnFindEntityByString (edictStartSearchAfter, field, value);
|
return engfuncs.pfnFindEntityByString (edictStartSearchAfter, field, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
table->pfnChangeLevel = [] (char *s1, char *s2) CR_FORCE_STACK_ALIGN {
|
||||||
|
// this function gets called when server is changing a level
|
||||||
|
|
||||||
|
// kick off all the bots, needed for legacy engine versions
|
||||||
|
bots.kickEveryone (true, false);
|
||||||
|
|
||||||
|
if (game.is (GameFlags::Metamod)) {
|
||||||
|
RETURN_META (MRES_IGNORED);
|
||||||
|
}
|
||||||
|
engfuncs.pfnChangeLevel (s1, s2);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!game.is (GameFlags::Legacy)) {
|
if (!game.is (GameFlags::Legacy)) {
|
||||||
table->pfnLightStyle = [] (int style, char *val) {
|
table->pfnLightStyle = [] (int style, char *val) CR_FORCE_STACK_ALIGN {
|
||||||
// this function update lightstyle for the bots
|
// this function update lightstyle for the bots
|
||||||
|
|
||||||
illum.updateLight (style, val);
|
illum.updateLight (style, val);
|
||||||
|
|
@ -597,7 +608,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
engfuncs.pfnLightStyle (style, val);
|
engfuncs.pfnLightStyle (style, val);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnGetPlayerAuthId = [] (edict_t *e) -> const char * {
|
table->pfnGetPlayerAuthId = [] (edict_t *e) CR_FORCE_STACK_ALIGN {
|
||||||
if (bots[e]) {
|
if (bots[e]) {
|
||||||
auto authid = util.getFakeSteamId (e);
|
auto authid = util.getFakeSteamId (e);
|
||||||
|
|
||||||
|
|
@ -608,13 +619,13 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.is (GameFlags::Metamod)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META_VALUE (MRES_IGNORED, nullptr);
|
RETURN_META_VALUE (MRES_IGNORED, "");
|
||||||
}
|
}
|
||||||
return engfuncs.pfnGetPlayerAuthId (e);
|
return engfuncs.pfnGetPlayerAuthId (e);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
table->pfnEmitSound = [] (edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch) {
|
table->pfnEmitSound = [] (edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch) CR_FORCE_STACK_ALIGN {
|
||||||
// this function tells the engine that the entity pointed to by "entity", is emitting a sound
|
// this function tells the engine that the entity pointed to by "entity", is emitting a sound
|
||||||
// which fileName is "sample", at level "channel" (CHAN_VOICE, etc...), with "volume" as
|
// which fileName is "sample", at level "channel" (CHAN_VOICE, etc...), with "volume" as
|
||||||
// loudness multiplicator (normal volume VOL_NORM is 1.0), with a pitch of "pitch" (normal
|
// loudness multiplicator (normal volume VOL_NORM is 1.0), with a pitch of "pitch" (normal
|
||||||
|
|
@ -633,7 +644,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
engfuncs.pfnEmitSound (entity, channel, sample, volume, attenuation, flags, pitch);
|
engfuncs.pfnEmitSound (entity, channel, sample, volume, attenuation, flags, pitch);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnMessageBegin = [] (int msgDest, int msgType, const float *origin, edict_t *ed) {
|
table->pfnMessageBegin = [] (int msgDest, int msgType, const float *origin, edict_t *ed) CR_FORCE_STACK_ALIGN {
|
||||||
// this function called each time a message is about to sent.
|
// this function called each time a message is about to sent.
|
||||||
msgs.start (ed, msgType);
|
msgs.start (ed, msgType);
|
||||||
|
|
||||||
|
|
@ -644,7 +655,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!game.is (GameFlags::Metamod)) {
|
if (!game.is (GameFlags::Metamod)) {
|
||||||
table->pfnMessageEnd = [] () {
|
table->pfnMessageEnd = [] () CR_FORCE_STACK_ALIGN {
|
||||||
engfuncs.pfnMessageEnd ();
|
engfuncs.pfnMessageEnd ();
|
||||||
|
|
||||||
// this allows us to send messages right in handler code
|
// this allows us to send messages right in handler code
|
||||||
|
|
@ -652,7 +663,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
table->pfnWriteByte = [] (int value) {
|
table->pfnWriteByte = [] (int value) CR_FORCE_STACK_ALIGN {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
msgs.collect (value);
|
msgs.collect (value);
|
||||||
|
|
||||||
|
|
@ -662,7 +673,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
engfuncs.pfnWriteByte (value);
|
engfuncs.pfnWriteByte (value);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnWriteChar = [] (int value) {
|
table->pfnWriteChar = [] (int value) CR_FORCE_STACK_ALIGN {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
msgs.collect (value);
|
msgs.collect (value);
|
||||||
|
|
||||||
|
|
@ -672,7 +683,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
engfuncs.pfnWriteChar (value);
|
engfuncs.pfnWriteChar (value);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnWriteShort = [] (int value) {
|
table->pfnWriteShort = [] (int value) CR_FORCE_STACK_ALIGN {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
msgs.collect (value);
|
msgs.collect (value);
|
||||||
|
|
||||||
|
|
@ -682,7 +693,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
engfuncs.pfnWriteShort (value);
|
engfuncs.pfnWriteShort (value);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnWriteLong = [] (int value) {
|
table->pfnWriteLong = [] (int value) CR_FORCE_STACK_ALIGN {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
msgs.collect (value);
|
msgs.collect (value);
|
||||||
|
|
||||||
|
|
@ -692,7 +703,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
engfuncs.pfnWriteLong (value);
|
engfuncs.pfnWriteLong (value);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnWriteAngle = [] (float value) {
|
table->pfnWriteAngle = [] (float value) CR_FORCE_STACK_ALIGN {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
msgs.collect (value);
|
msgs.collect (value);
|
||||||
|
|
||||||
|
|
@ -702,7 +713,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
engfuncs.pfnWriteAngle (value);
|
engfuncs.pfnWriteAngle (value);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnWriteCoord = [] (float value) {
|
table->pfnWriteCoord = [] (float value) CR_FORCE_STACK_ALIGN {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
msgs.collect (value);
|
msgs.collect (value);
|
||||||
|
|
||||||
|
|
@ -712,7 +723,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
engfuncs.pfnWriteCoord (value);
|
engfuncs.pfnWriteCoord (value);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnWriteString = [] (const char *sz) {
|
table->pfnWriteString = [] (const char *sz) CR_FORCE_STACK_ALIGN {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
msgs.collect (sz);
|
msgs.collect (sz);
|
||||||
|
|
||||||
|
|
@ -722,7 +733,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
engfuncs.pfnWriteString (sz);
|
engfuncs.pfnWriteString (sz);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnWriteEntity = [] (int value) {
|
table->pfnWriteEntity = [] (int value) CR_FORCE_STACK_ALIGN {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
msgs.collect (value);
|
msgs.collect (value);
|
||||||
|
|
||||||
|
|
@ -736,7 +747,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
table->pfnClientCommand = Hooks::handler_engClientCommand;
|
table->pfnClientCommand = Hooks::handler_engClientCommand;
|
||||||
|
|
||||||
if (!game.is (GameFlags::Metamod)) {
|
if (!game.is (GameFlags::Metamod)) {
|
||||||
table->pfnRegUserMsg = [] (const char *name, int size) {
|
table->pfnRegUserMsg = [] (const char *name, int size) CR_FORCE_STACK_ALIGN {
|
||||||
// this function registers a "user message" by the engine side. User messages are network
|
// this function registers a "user message" by the engine side. User messages are network
|
||||||
// messages the game DLL asks the engine to send to clients. Since many MODs have completely
|
// messages the game DLL asks the engine to send to clients. Since many MODs have completely
|
||||||
// different client features (Counter-Strike has a radar and a timer, for example), network
|
// different client features (Counter-Strike has a radar and a timer, for example), network
|
||||||
|
|
@ -751,7 +762,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
table->pfnClientPrintf = [] (edict_t *ent, PRINT_TYPE printType, const char *message) {
|
table->pfnClientPrintf = [] (edict_t *ent, PRINT_TYPE printType, const char *message) CR_FORCE_STACK_ALIGN {
|
||||||
// this function prints the text message string pointed to by message by the client side of
|
// this function prints the text message string pointed to by message by the client side of
|
||||||
// the client entity pointed to by ent, in a manner depending of printType (print_console,
|
// the client entity pointed to by ent, in a manner depending of printType (print_console,
|
||||||
// print_center or print_chat). Be certain never to try to feed a bot with this function,
|
// print_center or print_chat). Be certain never to try to feed a bot with this function,
|
||||||
|
|
@ -771,7 +782,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
engfuncs.pfnClientPrintf (ent, printType, message);
|
engfuncs.pfnClientPrintf (ent, printType, message);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnCmd_Args = [] () {
|
table->pfnCmd_Args = [] () CR_FORCE_STACK_ALIGN {
|
||||||
// this function returns a pointer to the whole current client command string. Since bots
|
// this function returns a pointer to the whole current client command string. Since bots
|
||||||
// have no client DLL and we may want a bot to execute a client command, we had to implement
|
// have no client DLL and we may want a bot to execute a client command, we had to implement
|
||||||
// a argv string in the bot DLL for holding the bots' commands, and also keep track of the
|
// a argv string in the bot DLL for holding the bots' commands, and also keep track of the
|
||||||
|
|
@ -793,7 +804,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
return engfuncs.pfnCmd_Args (); // ask the client command string to the engine
|
return engfuncs.pfnCmd_Args (); // ask the client command string to the engine
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnCmd_Argv = [] (int argc) {
|
table->pfnCmd_Argv = [] (int argc) CR_FORCE_STACK_ALIGN {
|
||||||
// this function returns a pointer to a certain argument of the current client command. Since
|
// this function returns a pointer to a certain argument of the current client command. Since
|
||||||
// bots have no client DLL and we may want a bot to execute a client command, we had to
|
// bots have no client DLL and we may want a bot to execute a client command, we had to
|
||||||
// implement a argv string in the bot DLL for holding the bots' commands, and also keep
|
// implement a argv string in the bot DLL for holding the bots' commands, and also keep
|
||||||
|
|
@ -815,7 +826,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
return engfuncs.pfnCmd_Argv (argc); // ask the argument number "argc" to the engine
|
return engfuncs.pfnCmd_Argv (argc); // ask the argument number "argc" to the engine
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnCmd_Argc = [] () {
|
table->pfnCmd_Argc = [] () CR_FORCE_STACK_ALIGN {
|
||||||
// this function returns the number of arguments the current client command string has. Since
|
// this function returns the number of arguments the current client command string has. Since
|
||||||
// bots have no client DLL and we may want a bot to execute a client command, we had to
|
// bots have no client DLL and we may want a bot to execute a client command, we had to
|
||||||
// implement a argv string in the bot DLL for holding the bots' commands, and also keep
|
// implement a argv string in the bot DLL for holding the bots' commands, and also keep
|
||||||
|
|
@ -837,7 +848,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
||||||
return engfuncs.pfnCmd_Argc (); // ask the engine how many arguments there are
|
return engfuncs.pfnCmd_Argc (); // ask the engine how many arguments there are
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnSetClientMaxspeed = [] (const edict_t *ent, float newMaxspeed) {
|
table->pfnSetClientMaxspeed = [] (const edict_t *ent, float newMaxspeed) CR_FORCE_STACK_ALIGN {
|
||||||
auto bot = bots[const_cast <edict_t *> (ent)];
|
auto bot = bots[const_cast <edict_t *> (ent)];
|
||||||
|
|
||||||
// check wether it's not a bot
|
// check wether it's not a bot
|
||||||
|
|
@ -875,7 +886,7 @@ CR_EXPORT int GetNewDLLFunctions (newgamefuncs_t *table, int *interfaceVersion)
|
||||||
plat.bzero (table, sizeof (newgamefuncs_t));
|
plat.bzero (table, sizeof (newgamefuncs_t));
|
||||||
|
|
||||||
if (!game.is (GameFlags::Legacy)) {
|
if (!game.is (GameFlags::Legacy)) {
|
||||||
table->pfnOnFreeEntPrivateData = [] (edict_t *ent) {
|
table->pfnOnFreeEntPrivateData = [] (edict_t *ent) CR_FORCE_STACK_ALIGN {
|
||||||
for (auto &bot : bots) {
|
for (auto &bot : bots) {
|
||||||
if (bot->m_enemy == ent) {
|
if (bot->m_enemy == ent) {
|
||||||
bot->m_enemy = nullptr;
|
bot->m_enemy = nullptr;
|
||||||
|
|
@ -895,16 +906,16 @@ CR_EXPORT int GetNewDLLFunctions (newgamefuncs_t *table, int *interfaceVersion)
|
||||||
return HLTrue;
|
return HLTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CR_LINKAGE_C int GetEngineFunctions_Post (enginefuncs_t *table, int *) {
|
CR_C_LINKAGE int GetEngineFunctions_Post (enginefuncs_t *table, int *) {
|
||||||
plat.bzero (table, sizeof (enginefuncs_t));
|
plat.bzero (table, sizeof (enginefuncs_t));
|
||||||
|
|
||||||
table->pfnMessageEnd = [] () {
|
table->pfnMessageEnd = [] () CR_FORCE_STACK_ALIGN {
|
||||||
msgs.stop (); // this allows us to send messages right in handler code
|
msgs.stop (); // this allows us to send messages right in handler code
|
||||||
|
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
};
|
};
|
||||||
|
|
||||||
table->pfnRegUserMsg = [] (const char *name, int) {
|
table->pfnRegUserMsg = [] (const char *name, int) CR_FORCE_STACK_ALIGN {
|
||||||
// this function registers a "user message" by the engine side. User messages are network
|
// this function registers a "user message" by the engine side. User messages are network
|
||||||
// messages the game DLL asks the engine to send to clients. Since many MODs have completely
|
// messages the game DLL asks the engine to send to clients. Since many MODs have completely
|
||||||
// different client features (Counter-Strike has a radar and a timer, for example), network
|
// different client features (Counter-Strike has a radar and a timer, for example), network
|
||||||
|
|
@ -995,15 +1006,15 @@ CR_EXPORT int Meta_Detach (PLUG_LOADTIME now, PL_UNLOAD_REASON reason) {
|
||||||
gpMetaUtilFuncs->pfnLogError (PLID, "%s: plugin NOT detaching (can't unload plugin right now)", Plugin_info.name);
|
gpMetaUtilFuncs->pfnLogError (PLID, "%s: plugin NOT detaching (can't unload plugin right now)", Plugin_info.name);
|
||||||
return HLFalse; // returning FALSE prevents metamod from unloading this plugin
|
return HLFalse; // returning FALSE prevents metamod from unloading this plugin
|
||||||
}
|
}
|
||||||
// stop the worker
|
|
||||||
worker.shutdown ();
|
|
||||||
|
|
||||||
// kick all bots off this server
|
// kick all bots off this server
|
||||||
bots.kickEveryone (true);
|
bots.kickEveryone (true);
|
||||||
|
|
||||||
// save collected practice on shutdown
|
// save collected practice on shutdown
|
||||||
practice.save ();
|
practice.save ();
|
||||||
|
|
||||||
|
// stop the worker
|
||||||
|
worker.shutdown ();
|
||||||
|
|
||||||
// disable hooks
|
// disable hooks
|
||||||
fakequeries.disable ();
|
fakequeries.disable ();
|
||||||
|
|
||||||
|
|
@ -1023,13 +1034,13 @@ CR_EXPORT void Meta_Init () {
|
||||||
// games GiveFnptrsToDll is a bit tricky
|
// games GiveFnptrsToDll is a bit tricky
|
||||||
#if defined(CR_WINDOWS)
|
#if defined(CR_WINDOWS)
|
||||||
# if defined(CR_CXX_MSVC) || (defined(CR_CXX_CLANG) && !defined(CR_CXX_GCC))
|
# if defined(CR_CXX_MSVC) || (defined(CR_CXX_CLANG) && !defined(CR_CXX_GCC))
|
||||||
# if defined (CR_ARCH_X86)
|
# if defined(CR_ARCH_X32)
|
||||||
# pragma comment(linker, "/EXPORT:GiveFnptrsToDll=_GiveFnptrsToDll@8,@1")
|
# pragma comment(linker, "/EXPORT:GiveFnptrsToDll=_GiveFnptrsToDll@8,@1")
|
||||||
# endif
|
# endif
|
||||||
# pragma comment(linker, "/SECTION:.data,RW")
|
# pragma comment(linker, "/SECTION:.data,RW")
|
||||||
# endif
|
# endif
|
||||||
# if defined(CR_CXX_MSVC) && !defined(CR_ARCH_X64)
|
# if defined(CR_CXX_MSVC) && !defined(CR_ARCH_X64)
|
||||||
# define DLL_GIVEFNPTRSTODLL CR_LINKAGE_C void CR_STDCALL
|
# define DLL_GIVEFNPTRSTODLL CR_C_LINKAGE void CR_STDCALL
|
||||||
# elif defined(CR_CXX_CLANG) || defined(CR_CXX_GCC) || defined(CR_ARCH_X64)
|
# elif defined(CR_CXX_CLANG) || defined(CR_CXX_GCC) || defined(CR_ARCH_X64)
|
||||||
# define DLL_GIVEFNPTRSTODLL CR_EXPORT void CR_STDCALL
|
# define DLL_GIVEFNPTRSTODLL CR_EXPORT void CR_STDCALL
|
||||||
# endif
|
# endif
|
||||||
|
|
|
||||||
|
|
@ -1116,14 +1116,14 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
|
||||||
if (cv_show_latency.as <int> () == 1) {
|
if (cv_show_latency.as <int> () == 1) {
|
||||||
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "*bot", "1");
|
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "*bot", "1");
|
||||||
}
|
}
|
||||||
auto avatar = conf.getRandomAvatar ();
|
const auto &avatar = conf.getRandomAvatar ();
|
||||||
|
|
||||||
if (cv_show_avatars && !avatar.empty ()) {
|
if (cv_show_avatars && !avatar.empty ()) {
|
||||||
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "*sid", avatar.chars ());
|
engfuncs.pfnSetClientKeyValue (clientIndex, buffer, "*sid", avatar.chars ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char reject[256] = { 0, };
|
char reject[StringBuffer::StaticBufferSize] = { 0, };
|
||||||
MDLL_ClientConnect (bot, bot->v.netname.chars (), strings.format ("127.0.0.%d", clientIndex + 100), reject);
|
MDLL_ClientConnect (bot, bot->v.netname.chars (), strings.format ("127.0.0.%d", clientIndex + 100), reject);
|
||||||
|
|
||||||
if (!strings.isEmpty (reject)) {
|
if (!strings.isEmpty (reject)) {
|
||||||
|
|
@ -1228,7 +1228,9 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
|
||||||
m_pathWalk.init (m_planner->getMaxLength ());
|
m_pathWalk.init (m_planner->getMaxLength ());
|
||||||
|
|
||||||
// init player models parts enumerator
|
// init player models parts enumerator
|
||||||
m_hitboxEnumerator = cr::makeUnique <PlayerHitboxEnumerator> ();
|
if (cv_use_hitbox_enemy_targeting) {
|
||||||
|
m_hitboxEnumerator = cr::makeUnique <PlayerHitboxEnumerator> ();
|
||||||
|
}
|
||||||
|
|
||||||
// bot is not kicked by rotation
|
// bot is not kicked by rotation
|
||||||
m_kickedByRotation = false;
|
m_kickedByRotation = false;
|
||||||
|
|
@ -1335,21 +1337,23 @@ bool BotManager::isTeamStacked (int team) {
|
||||||
return teamCount[team] + 1 > teamCount[team == Team::CT ? Team::Terrorist : Team::CT] + limitTeams;
|
return teamCount[team] + 1 > teamCount[team == Team::CT ? Team::Terrorist : Team::CT] + limitTeams;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotManager::erase (Bot *bot) {
|
void BotManager::disconnectBot (Bot *bot) {
|
||||||
for (auto &e : m_bots) {
|
for (auto &e : m_bots) {
|
||||||
if (e.get () != bot) {
|
if (e.get () != bot) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
bot->markStale ();
|
||||||
|
|
||||||
if (!bot->m_kickedByRotation && cv_save_bots_names) {
|
if (!bot->m_kickedByRotation && cv_save_bots_names) {
|
||||||
m_saveBotNames.emplaceLast (bot->pev->netname.str ());
|
m_saveBotNames.emplaceLast (bot->pev->netname.str ());
|
||||||
}
|
}
|
||||||
bot->markStale ();
|
|
||||||
|
|
||||||
const auto index = m_bots.index (e);
|
const auto index = m_bots.index (e);
|
||||||
e.reset ();
|
e.reset ();
|
||||||
|
|
||||||
m_bots.erase (index, 1); // remove from bots array
|
m_bots.erase (index, 1); // remove from bots array
|
||||||
|
bot = nullptr;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1556,7 +1560,10 @@ void Bot::newRound () {
|
||||||
m_followWaitTime = 0.0f;
|
m_followWaitTime = 0.0f;
|
||||||
|
|
||||||
m_hostages.clear ();
|
m_hostages.clear ();
|
||||||
m_hitboxEnumerator->reset ();
|
|
||||||
|
if (cv_use_hitbox_enemy_targeting) {
|
||||||
|
m_hitboxEnumerator->reset ();
|
||||||
|
}
|
||||||
|
|
||||||
m_approachingLadderTimer.invalidate ();
|
m_approachingLadderTimer.invalidate ();
|
||||||
m_forgetLastVictimTimer.invalidate ();
|
m_forgetLastVictimTimer.invalidate ();
|
||||||
|
|
@ -1745,6 +1752,10 @@ void Bot::kick (bool silent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::markStale () {
|
void Bot::markStale () {
|
||||||
|
// wait till threads tear down
|
||||||
|
MutexScopedLock lock1 (m_pathFindLock);
|
||||||
|
MutexScopedLock lock2 (m_predictLock);
|
||||||
|
|
||||||
// switch chatter icon off
|
// switch chatter icon off
|
||||||
showChatterIcon (false, true);
|
showChatterIcon (false, true);
|
||||||
|
|
||||||
|
|
@ -2180,13 +2191,19 @@ void BotThreadWorker::shutdown () {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotThreadWorker::startup (int workers) {
|
void BotThreadWorker::startup (int workers) {
|
||||||
String disableWorkerEnv = plat.env ("YAPB_SINGLE_THREADED");
|
StringRef disableWorkerEnv = plat.env ("YAPB_SINGLE_THREADED");
|
||||||
|
|
||||||
// disable on legacy games
|
// disable on legacy games
|
||||||
const bool isLegacyGame = game.is (GameFlags::Legacy);
|
const bool isLegacyGame = game.is (GameFlags::Legacy);
|
||||||
|
|
||||||
|
// do not do any threading when timescale enabled
|
||||||
|
ConVarRef timescale ("sys_timescale");
|
||||||
|
|
||||||
// disable worker if requested via env variable or workers are disabled
|
// disable worker if requested via env variable or workers are disabled
|
||||||
if (isLegacyGame || workers == 0 || (!disableWorkerEnv.empty () && disableWorkerEnv == "1")) {
|
if (isLegacyGame
|
||||||
|
|| workers == 0
|
||||||
|
|| timescale.value () > 0
|
||||||
|
|| (!disableWorkerEnv.empty () && disableWorkerEnv == "1")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_pool = cr::makeUnique <ThreadPool> ();
|
m_pool = cr::makeUnique <ThreadPool> ();
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ CR_EXPORT IYaPBModule *GetBotAPI (int version) {
|
||||||
if (version != kYaPBModuleVersion) {
|
if (version != kYaPBModuleVersion) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
static YaPBModule botModule;
|
static YaPBModule botModule {};
|
||||||
|
|
||||||
return &botModule;
|
return &botModule;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3357,7 +3357,7 @@ edict_t *Bot::lookupButton (StringRef target, bool blindTest) {
|
||||||
const Vector &pos = game.getEntityOrigin (ent);
|
const Vector &pos = game.getEntityOrigin (ent);
|
||||||
|
|
||||||
if (!blindTest) {
|
if (!blindTest) {
|
||||||
game.testLine (pev->origin, pos, TraceIgnore::Monsters, pev->pContainingEntity, &tr);
|
game.testLine (pev->origin, pos, TraceIgnore::Monsters, this->ent (), &tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if this place safe
|
// check if this place safe
|
||||||
|
|
@ -3449,11 +3449,6 @@ void Bot::findShortestPath (int srcIndex, int destIndex) {
|
||||||
void Bot::syncFindPath (int srcIndex, int destIndex, FindPath pathType) {
|
void Bot::syncFindPath (int srcIndex, int destIndex, FindPath pathType) {
|
||||||
// this function finds a path from srcIndex to destIndex;
|
// this function finds a path from srcIndex to destIndex;
|
||||||
|
|
||||||
// stale bots shouldn't do pathfinding
|
|
||||||
if (m_isStale) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_pathFindLock.tryLock ()) {
|
if (!m_pathFindLock.tryLock ()) {
|
||||||
return; // allow only single instance of syncFindPath per-bot
|
return; // allow only single instance of syncFindPath per-bot
|
||||||
}
|
}
|
||||||
|
|
@ -3559,6 +3554,11 @@ void Bot::syncFindPath (int srcIndex, int destIndex, FindPath pathType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath::Fast */) {
|
void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath::Fast */) {
|
||||||
|
// stale bots shouldn't do pathfinding
|
||||||
|
if (m_isStale) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
worker.enqueue ([this, srcIndex, destIndex, pathType] () {
|
worker.enqueue ([this, srcIndex, destIndex, pathType] () {
|
||||||
syncFindPath (srcIndex, destIndex, pathType);
|
syncFindPath (srcIndex, destIndex, pathType);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ void BotPractice::save () {
|
||||||
bstor.save <DangerSaveRestore> (data);
|
bstor.save <DangerSaveRestore> (data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotPractice::load () {
|
void BotPractice::syncLoad () {
|
||||||
if (!graph.length ()) {
|
if (!graph.length ()) {
|
||||||
return; // no action
|
return; // no action
|
||||||
}
|
}
|
||||||
|
|
@ -182,3 +182,9 @@ void BotPractice::load () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BotPractice::load () {
|
||||||
|
worker.enqueue ([this] () {
|
||||||
|
syncLoad ();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#include <yapb.h>
|
#include <yapb.h>
|
||||||
|
|
||||||
#if defined (BOT_STORAGE_EXPLICIT_INSTANTIATIONS)
|
#if defined(BOT_STORAGE_EXPLICIT_INSTANTIATIONS)
|
||||||
|
|
||||||
template <typename U> bool BotStorage::load (SmallArray <U> &data, ExtenHeader *exten, int32_t *outOptions) {
|
template <typename U> bool BotStorage::load (SmallArray <U> &data, ExtenHeader *exten, int32_t *outOptions) {
|
||||||
auto type = guessType <U> ();
|
auto type = guessType <U> ();
|
||||||
|
|
|
||||||
|
|
@ -436,81 +436,42 @@ StringRef BotSupport::weaponIdToAlias (int32_t id) {
|
||||||
return none;
|
return none;
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper class for reading wave header
|
float BotSupport::getWaveFileDuration (StringRef filename) {
|
||||||
class WaveEndianessHelper final : public NonCopyable {
|
constexpr auto kZeroLength = 0.0f;
|
||||||
private:
|
|
||||||
#if defined (CR_ARCH_CPU_BIG_ENDIAN)
|
|
||||||
bool little { false };
|
|
||||||
#else
|
|
||||||
bool little { true };
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
using WaveHeader = WaveHelper <>::Header;
|
||||||
uint16_t read16 (uint16_t value) {
|
|
||||||
return little ? value : static_cast <uint16_t> ((value >> 8) | (value << 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t read32 (uint32_t value) {
|
|
||||||
return little ? value : (((value & 0x000000ff) << 24) | ((value & 0x0000ff00) << 8) | ((value & 0x00ff0000) >> 8) | ((value & 0xff000000) >> 24));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isWave (char *format) const {
|
|
||||||
if (little && memcmp (format, "WAVE", 4) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return *reinterpret_cast <uint32_t *> (format) == 0x57415645;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
float BotSupport::getWaveLength (StringRef filename) {
|
|
||||||
auto filePath = strings.joinPath (cv_chatter_path.as <StringRef> (), strings.format ("%s.wav", filename));
|
auto filePath = strings.joinPath (cv_chatter_path.as <StringRef> (), strings.format ("%s.wav", filename));
|
||||||
|
|
||||||
MemFile fp (filePath);
|
MemFile fp (filePath);
|
||||||
|
|
||||||
// we're got valid handle?
|
// we're got valid handle?
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
return 0.0f;
|
return kZeroLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
// else fuck with manual search
|
WaveHeader hdr {};
|
||||||
struct WavHeader {
|
static WaveHelper wh {};
|
||||||
char riff[4];
|
|
||||||
uint32_t chunkSize;
|
|
||||||
char wave[4];
|
|
||||||
char fmt[4];
|
|
||||||
uint32_t subchunk1Size;
|
|
||||||
uint16_t audioFormat;
|
|
||||||
uint16_t numChannels;
|
|
||||||
uint32_t sampleRate;
|
|
||||||
uint32_t byteRate;
|
|
||||||
uint16_t blockAlign;
|
|
||||||
uint16_t bitsPerSample;
|
|
||||||
char dataChunkId[4];
|
|
||||||
uint32_t dataChunkLength;
|
|
||||||
} header {};
|
|
||||||
|
|
||||||
static WaveEndianessHelper weh {};
|
if (fp.read (&hdr, sizeof (WaveHeader)) == 0) {
|
||||||
|
logger.error ("WAVE %s - has wrong or unsupported format.", filePath);
|
||||||
if (fp.read (&header, sizeof (WavHeader)) == 0) {
|
return kZeroLength;
|
||||||
logger.error ("Wave File %s - has wrong or unsupported format", filePath);
|
|
||||||
return 0.0f;
|
|
||||||
}
|
}
|
||||||
fp.close ();
|
fp.close ();
|
||||||
|
|
||||||
if (!weh.isWave (header.wave)) {
|
if (!wh.isWave (hdr.wave)) {
|
||||||
logger.error ("Wave File %s - has wrong wave chunk id", filePath);
|
logger.error ("WAVE %s - has wrong wave chunk id.", filePath);
|
||||||
return 0.0f;
|
return kZeroLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weh.read32 (header.dataChunkLength) == 0) {
|
if (wh.read32 <uint32_t> (hdr.dataChunkLength) == 0) {
|
||||||
logger.error ("Wave File %s - has zero length!", filePath);
|
logger.error ("WAVE %s - has zero length!.", filePath);
|
||||||
return 0.0f;
|
return kZeroLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto length = static_cast <float> (weh.read32 (header.dataChunkLength));
|
const auto length = wh.read32 <float> (hdr.dataChunkLength);
|
||||||
const auto bps = static_cast <float> (weh.read16 (header.bitsPerSample)) / 8;
|
const auto bps = wh.read16 <float> (hdr.bitsPerSample) / 8.0f;
|
||||||
const auto channels = static_cast <float> (weh.read16 (header.numChannels));
|
const auto channels = wh.read16 <float> (hdr.numChannels);
|
||||||
const auto rate = static_cast <float> (weh.read32 (header.sampleRate));
|
const auto rate = wh.read32 <float> (hdr.sampleRate);
|
||||||
|
|
||||||
return length / bps / channels / rate;
|
return length / bps / channels / rate;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -331,7 +331,7 @@ void Bot::spraypaint_ () {
|
||||||
|
|
||||||
if (getTask ()->time - 0.5f < game.time ()) {
|
if (getTask ()->time - 0.5f < game.time ()) {
|
||||||
// emit spray can sound
|
// emit spray can sound
|
||||||
engfuncs.pfnEmitSound (pev->pContainingEntity, CHAN_VOICE, "player/sprayer.wav", 1.0f, ATTN_NORM, 0, 100);
|
engfuncs.pfnEmitSound (ent (), CHAN_VOICE, "player/sprayer.wav", 1.0f, ATTN_NORM, 0, 100);
|
||||||
|
|
||||||
game.testLine (getEyesPos (), getEyesPos () + forward * 128.0f, TraceIgnore::Monsters, ent (), &tr);
|
game.testLine (getEyesPos (), getEyesPos () + forward * 128.0f, TraceIgnore::Monsters, ent (), &tr);
|
||||||
|
|
||||||
|
|
@ -594,7 +594,7 @@ void Bot::blind_ () {
|
||||||
m_blindNodeIndex = kInvalidNodeIndex;
|
m_blindNodeIndex = kInvalidNodeIndex;
|
||||||
|
|
||||||
m_blindMoveSpeed = 0.0f;
|
m_blindMoveSpeed = 0.0f;
|
||||||
m_blindSidemoveSpeed = 0.0f;
|
m_blindSideMoveSpeed = 0.0f;
|
||||||
m_blindButton = 0;
|
m_blindButton = 0;
|
||||||
|
|
||||||
m_states |= Sense::SuspectEnemy;
|
m_states |= Sense::SuspectEnemy;
|
||||||
|
|
@ -610,7 +610,7 @@ void Bot::blind_ () {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_moveSpeed = m_blindMoveSpeed;
|
m_moveSpeed = m_blindMoveSpeed;
|
||||||
m_strafeSpeed = m_blindSidemoveSpeed;
|
m_strafeSpeed = m_blindSideMoveSpeed;
|
||||||
pev->button |= m_blindButton;
|
pev->button |= m_blindButton;
|
||||||
|
|
||||||
m_states |= Sense::SuspectEnemy;
|
m_states |= Sense::SuspectEnemy;
|
||||||
|
|
|
||||||
|
|
@ -375,14 +375,19 @@ void Frustum::calculate (Planes &planes, const Vector &viewAngle, const Vector &
|
||||||
auto fc = viewOffset + forward * kMaxViewDistance;
|
auto fc = viewOffset + forward * kMaxViewDistance;
|
||||||
auto nc = viewOffset + forward * kMinViewDistance;
|
auto nc = viewOffset + forward * kMinViewDistance;
|
||||||
|
|
||||||
auto fbl = fc + (up * m_farHeight * 0.5f) - (right * m_farWidth * 0.5f);
|
auto up_half_far = up * m_farHeight * 0.5f;
|
||||||
auto fbr = fc + (up * m_farHeight * 0.5f) + (right * m_farWidth * 0.5f);
|
auto right_half_far = right * m_farWidth * 0.5f;
|
||||||
auto ftl = fc - (up * m_farHeight * 0.5f) - (right * m_farWidth * 0.5f);
|
auto up_half_near = up * m_nearHeight * 0.5f;
|
||||||
auto ftr = fc - (up * m_farHeight * 0.5f) + (right * m_farWidth * 0.5f);
|
auto right_half_near = right * m_nearWidth * 0.5f;
|
||||||
auto nbl = nc + (up * m_nearHeight * 0.5f) - (right * m_nearWidth * 0.5f);
|
|
||||||
auto nbr = nc + (up * m_nearHeight * 0.5f) + (right * m_nearWidth * 0.5f);
|
auto fbl = fc - right_half_far + up_half_far;
|
||||||
auto ntl = nc - (up * m_nearHeight * 0.5f) - (right * m_nearWidth * 0.5f);
|
auto fbr = fc + right_half_far + up_half_far;
|
||||||
auto ntr = nc - (up * m_nearHeight * 0.5f) + (right * m_nearWidth * 0.5f);
|
auto ftl = fc - right_half_far - up_half_far;
|
||||||
|
auto ftr = fc + right_half_far - up_half_far;
|
||||||
|
auto nbl = nc - right_half_near + up_half_near;
|
||||||
|
auto nbr = nc + right_half_near + up_half_near;
|
||||||
|
auto ntl = nc - right_half_near - up_half_near;
|
||||||
|
auto ntr = nc + right_half_near - up_half_near;
|
||||||
|
|
||||||
auto setPlane = [&] (PlaneSide side, const Vector &v1, const Vector &v2, const Vector &v3) {
|
auto setPlane = [&] (PlaneSide side, const Vector &v1, const Vector &v2, const Vector &v3) {
|
||||||
auto &plane = planes[static_cast <int> (side)];
|
auto &plane = planes[static_cast <int> (side)];
|
||||||
|
|
|
||||||
|
|
@ -124,14 +124,19 @@ void GraphVistable::rebuild () {
|
||||||
else {
|
else {
|
||||||
m_sliceIndex += rg (250, 400);
|
m_sliceIndex += rg (250, 400);
|
||||||
}
|
}
|
||||||
|
auto notifyProgress = [] (int value) {
|
||||||
|
game.print ("Rebuilding vistable... %d%% done.", value);
|
||||||
|
};
|
||||||
|
|
||||||
// notify host about rebuilding
|
// notify host about rebuilding
|
||||||
if (m_notifyMsgTimestamp > 0.0f && m_notifyMsgTimestamp < game.time () && end == m_length) {
|
if (m_notifyMsgTimestamp > 0.0f && m_notifyMsgTimestamp < game.time () && end == m_length) {
|
||||||
game.print ("Rebuilding vistable... %d%% done.", m_curIndex * 100 / m_length);
|
notifyProgress (m_curIndex * 100 / m_length);
|
||||||
m_notifyMsgTimestamp = game.time () + 1.0f;
|
m_notifyMsgTimestamp = game.time () + 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_curIndex == m_length && end == m_length) {
|
if (m_curIndex == m_length && end == m_length) {
|
||||||
|
notifyProgress (100);
|
||||||
|
|
||||||
m_rebuild = false;
|
m_rebuild = false;
|
||||||
m_notifyMsgTimestamp = 0.0f;
|
m_notifyMsgTimestamp = 0.0f;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@
|
||||||
<ClInclude Include="..\ext\crlib\crlib\ulz.h" />
|
<ClInclude Include="..\ext\crlib\crlib\ulz.h" />
|
||||||
<ClInclude Include="..\ext\crlib\crlib\uniqueptr.h" />
|
<ClInclude Include="..\ext\crlib\crlib\uniqueptr.h" />
|
||||||
<ClInclude Include="..\ext\crlib\crlib\vector.h" />
|
<ClInclude Include="..\ext\crlib\crlib\vector.h" />
|
||||||
|
<ClInclude Include="..\ext\crlib\crlib\wavehelper.h" />
|
||||||
<ClInclude Include="..\ext\linkage\linkage\goldsrc.h" />
|
<ClInclude Include="..\ext\linkage\linkage\goldsrc.h" />
|
||||||
<ClInclude Include="..\ext\linkage\linkage\metamod.h" />
|
<ClInclude Include="..\ext\linkage\linkage\metamod.h" />
|
||||||
<ClInclude Include="..\ext\linkage\linkage\physint.h" />
|
<ClInclude Include="..\ext\linkage\linkage\physint.h" />
|
||||||
|
|
@ -150,7 +151,7 @@
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
<UseOfMfc>false</UseOfMfc>
|
<UseOfMfc>false</UseOfMfc>
|
||||||
<PlatformToolset>ClangCL</PlatformToolset>
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<EnableASAN>false</EnableASAN>
|
<EnableASAN>false</EnableASAN>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,9 @@
|
||||||
<ClInclude Include="..\inc\fakeping.h">
|
<ClInclude Include="..\inc\fakeping.h">
|
||||||
<Filter>inc</Filter>
|
<Filter>inc</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\ext\crlib\crlib\wavehelper.h">
|
||||||
|
<Filter>inc\ext\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\src\botlib.cpp">
|
<ClCompile Include="..\src\botlib.cpp">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue