Custom.cfg (#213)

Added custom configs.

These are used for replacing some hardcoded strings inside bot code, currently custom cvar for parachute detection is available, as well as custom c4 model names.

Added editorconfig, and fixed CRLF for files (was a mix between LF & CRLF).
Fixed use-after-free sanitizer error with chatlib.
Fixed configs files loaded with memory-loader does not process last line in config files.
This commit is contained in:
jeefo 2020-12-15 15:28:58 +03:00 committed by GitHub
commit 075bff2988
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 533 additions and 404 deletions

10
.editorconfig Normal file
View file

@ -0,0 +1,10 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 3
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

View file

@ -0,0 +1,22 @@
;
; @package: YaPB
; @version: 4.2
; @author: YaPB Development Team
; @filename: yapb.cfg
;
; Custom configuration file, allow to change some hardcoded stuff in bot code.
;
;
; Custom name for C4 model, for servers that replacing C4 model with it's own.
; By default it's "c4.mdl" (the models/ path is omitted), so if you need to use
; "models/mybomb/mybomb.mdl", you should specify "mybomb/mybomb.mdl".
;
C4ModelName = c4.mdl
;
; Custon cvar name for parachute handling, there are all the different plugins that
; handles parachute (AMX Parachute, AMX Parachute Lite, etc..), you can specify needed
; cvar here.
;
AMXParachuteCvar = sv_parachute

View file

@ -1994,9 +1994,3 @@ You're launched standalone version of %s. Metamod is not installed or not enable
[TRANSLATED]
Вы запустили автономную версию %s. Metamod не установлен или не включён!
[ORIGINAL]
EndOfFile
[TRANSLATED]
EndOfFile

View file

@ -1,4 +1,4 @@
//
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2020 YaPB Project <yapb@jeefo.net>.
//

View file

@ -71,6 +71,8 @@ public:
int ch = 0;
SmallArray <char> data (255);
line.clear ();
while ((ch = get ()) != EOF && !eof ()) {
data.push (static_cast <char> (ch));
@ -78,9 +80,10 @@ public:
break;
}
}
line.assign (data.data (), data.length ());
return !eof ();
if (!data.empty ()) {
line.assign (data.data (), data.length ());
}
return !line.empty ();
}
template <typename ...Args> size_t puts (const char *fmt, Args &&...args) {
@ -282,10 +285,7 @@ public:
if (!contents_ || seek_ >= length_) {
return Eof;
}
auto ch = contents_[seek_];
++seek_;
return static_cast <char> (ch);
return static_cast <char> (contents_[seek_++]);
}
char *getString (char *buffer, size_t count) {
@ -315,16 +315,20 @@ public:
char ch;
SmallArray <char> data (255);
while ((ch = get ()) != Eof) {
line.clear ();
while ((ch = get ()) != Eof && !eof ()) {
data.push (ch);
if (ch == '\n') {
break;
}
}
line.assign (data.data (), data.length ());
return !eof ();
if (!data.empty ()) {
line.assign (data.data (), data.length ());
}
return !line.empty ();
}
size_t read (void *buffer, size_t size, size_t count = 1) {

View file

@ -111,7 +111,6 @@ CR_DECLARE_SCOPED_ENUM (HttpClientResult,
CR_NAMESPACE_BEGIN
namespace detail {
// simple http uri omitting query-string and port
@ -281,12 +280,10 @@ private:
String userAgent_ = "crlib";
HttpClientResult statusCode_ = HttpClientResult::Undefined;
int32 chunkSize_ = 4096;
bool initialized_ = false;
public:
HttpClient () {
detail::SocketInit::start ();
}
HttpClient () = default;
~HttpClient () = default;
private:
@ -333,9 +330,17 @@ private:
}
public:
void startup () {
detail::SocketInit::start ();
initialized_ = true;
}
// simple blocked download
bool downloadFile (StringRef url, StringRef localPath, int32 timeout = DefaultSocketTimeout) {
if (plat.win && !initialized_) {
plat.abort ("Sockets not initialized.");
}
if (File::exists (localPath)) {
statusCode_ = HttpClientResult::LocalFileExists;
return false;
@ -402,6 +407,10 @@ public:
}
bool uploadFile (StringRef url, StringRef localPath, const int32 timeout = DefaultSocketTimeout) {
if (plat.win && !initialized_) {
plat.abort ("Sockets not initialized.");
}
if (!File::exists (localPath)) {
statusCode_ = HttpClientResult::NoLocalFile;
return false;

View file

@ -51,6 +51,7 @@ private:
HashMap <uint32, String, Hash <int32>> m_language;
HashMap <int32, DifficultyData> m_difficulty;
HashMap <String, String> m_custom;
// default tables for personality weapon preferences, overridden by weapon.cfg
SmallArray <int32> m_normalWeaponPrefs = { 0, 2, 1, 4, 5, 6, 3, 12, 10, 24, 25, 13, 11, 8, 7, 22, 23, 18, 21, 17, 19, 15, 17, 9, 14, 16 };
@ -98,6 +99,9 @@ public:
// loads bots map-specific config
void loadMapSpecificConfig ();
// loads custom config
void loadCustomConfig ();
// sets memfile to use engine functions
void setupMemoryFiles ();
@ -119,6 +123,9 @@ public:
// translates bot message into needed language
const char *translate (StringRef input);
// display current custom values
void showCustomValues ();
private:
bool isCommentLine (StringRef line) const {
if (line.empty ()) {
@ -237,6 +244,21 @@ public:
StringRef getRandomLogoName (int index) {
return m_logos[index];
}
// get custom value
StringRef fetchCustom (StringRef name) {
if (m_custom.has (name)) {
return m_custom[name];
}
SimpleLogger::instance ().error ("Trying to fetch uknonwn custom variable: %s", name);
return "";
}
// simple accessor to c4 model name
StringRef getBombModelName () {
return fetchCustom ("C4ModelName");
}
};
// explose global

View file

@ -99,6 +99,7 @@ private:
int cmdMenu ();
int cmdList ();
int cmdCvars ();
int cmdShowCustom ();
int cmdNode ();
int cmdNodeOn ();
int cmdNodeOff ();

View file

@ -108,6 +108,10 @@ public:
// check if object inside frustum plane
bool isObjectInsidePlane (FrustumPlane &plane, const Vector &center, float height, float radius);
// checks if same model ommiting the models directory
bool isModel (const edict_t *ent, StringRef model);
public:
// re-show welcome after changelevel ?

View file

@ -14,6 +14,6 @@
#define MODULE_BUILD_MACHINE "localhost"
#define MODULE_BUILD_COMPILER "unknown"
#define MODULE_BOT_VERSION "4.1"
#define MODULE_BOT_VERSION_FILE 4,0,0,000
#define MODULE_BOT_VERSION "4.2"
#define MODULE_BOT_VERSION_FILE 4,2,0,000
#define MODULE_BOT_BUILD_ID "0:0"

View file

@ -6,25 +6,25 @@
#
project (
'yapb',
'cpp',
'yapb',
'cpp',
version: '4.1',
license: 'MIT',
version: '4.2',
license: 'MIT',
default_options: [
'buildtype=release',
'b_ndebug=if-release',
'cpp_std=c++14',
'warning_level=3',
'werror=true',
'backend=ninja',
'strip=true',
'optimization=3',
'default_library=static',
'cpp_eh=none'
],
meson_version: '>=0.48.0')
default_options: [
'buildtype=release',
'b_ndebug=if-release',
'cpp_std=c++14',
'warning_level=3',
'werror=true',
'backend=ninja',
'strip=true',
'optimization=3',
'default_library=static',
'cpp_eh=none'
],
meson_version: '>=0.48.0')
find_program ('ninja', required: true)
find_program ('git', required: true)
@ -53,9 +53,9 @@ ccflags = []
cdata = configuration_data()
if isWindows
cdata.set ('buildVersionWin', ','.join (buildVersion.split ('.')))
cdata.set ('buildVersionWin', ','.join (buildVersion.split ('.')))
else
cdata.set ('buildVersionWin', buildVersion)
cdata.set ('buildVersionWin', buildVersion)
endif
cdata.set ('commitHash', run_command ('git', 'rev-parse', '--short', 'HEAD').stdout ().strip ())
@ -71,199 +71,198 @@ configure_file (input: 'inc/version.h.in', output: 'version.build.h', configurat
ccflags += '-DVERSION_GENERATED'
if isCLang or isGCC or (isIntel and not isWindows)
ccflags += [
'-m32',
'-fno-threadsafe-statics',
'-fno-exceptions',
'-fno-rtti'
]
ccflags += [
'-m32',
'-fno-threadsafe-statics',
'-fno-exceptions',
'-fno-rtti'
]
if not isDarwin
ccflags += [
'-pedantic',
]
endif
if not isDarwin
ccflags += [
'-pedantic',
]
endif
if isOptimize
ccflags += '-msse3'
if isOptimize
ccflags += '-msse3'
if (isCLang or isGCC) and not isDarwin
ccflags += [
'-flto',
'-fdata-sections',
'-ffunction-sections'
]
if (isCLang or isGCC) and not isDarwin
ccflags += [
'-flto',
'-fdata-sections',
'-ffunction-sections'
]
if isGCC
ccflags += '-fgraphite-identity'
ldflags += '-flto-partition=none'
endif
if isGCC
ccflags += '-fgraphite-identity'
ldflags += '-flto-partition=none'
endif
ldflags += [
'-flto',
'-Wl,--version-script=../version_script.lds',
'-Wl,--gc-sections'
]
endif
endif
ldflags += [
'-flto',
'-Wl,--version-script=../version_script.lds',
'-Wl,--gc-sections'
]
endif
endif
if isLinux
ldflags += [
'-m32',
'-lm',
'-ldl'
]
endif
if isLinux
ldflags += [
'-m32',
'-lm',
'-ldl'
]
endif
endif
if isIntel and (isLinux or isDarwin)
ldflags += [
'-static-intel',
'-no-intel-extensions'
]
ldflags += [
'-static-intel',
'-no-intel-extensions'
]
endif
if isLinux or isDarwin
if isDarwin
ccflags += '-mmacosx-version-min=10.9'
ldflags += [
'-dynamiclib',
'-lstdc++',
'-mmacosx-version-min=10.9'
]
else
ldflags += '-static-libgcc'
endif
if isDarwin
ccflags += '-mmacosx-version-min=10.9'
ldflags += [
'-dynamiclib',
'-lstdc++',
'-mmacosx-version-min=10.9'
]
else
ldflags += '-static-libgcc'
endif
if not isOptimize
ccflags += [
'-g3',
'-ggdb',
'-DCR_DEBUG'
]
else
ccflags += [
'-mtune=generic',
'-msse3',
'-mfpmath=sse',
'-fno-builtin',
'-funroll-loops',
'-fomit-frame-pointer',
'-fno-stack-protector',
'-fvisibility=hidden',
'-fvisibility-inlines-hidden'
]
if not isOptimize
ccflags += [
'-g3',
'-ggdb',
'-DCR_DEBUG'
]
else
ccflags += [
'-mtune=generic',
'-msse3',
'-mfpmath=sse',
'-fno-builtin',
'-funroll-loops',
'-fomit-frame-pointer',
'-fno-stack-protector',
'-fvisibility=hidden',
'-fvisibility-inlines-hidden'
]
if isIntel
ccflags += [
'-ipo',
'-wd11076',
'-wd11074'
]
if isIntel
ccflags += [
'-ipo',
'-wd11076',
'-wd11074'
]
ldflags += [
'-cxxlib-nostd',
'-Wl,--no-undefined,-z,notext,--gc-sections',
'-ipo'
]
elif isCLang and not isDarwin
llvmLinker = find_program ('lld', required: false)
ldflags += [
'-cxxlib-nostd',
'-Wl,--no-undefined,-z,notext,--gc-sections',
'-ipo'
]
elif isCLang and not isDarwin
llvmLinker = find_program ('lld', required: false)
if llvmLinker.found() == true
ldflags += '-fuse-ld=' + llvmLinker.path ().split ('/')[-1]
ldflags += '-fuse-ld=' + llvmLinker.path ().split ('/')[-1]
endif
ldflags += [
'-nostdlib++',
'-Wunused-command-line-argument',
'-Wl,-z,notext',
'--no-undefined'
'-nostdlib++',
'-Wunused-command-line-argument',
'-Wl,-z,notext',
'--no-undefined'
]
elif isGCC and not isDarwin
elif isGCC and not isDarwin
ldflags += '-Wl,--no-undefined'
endif
endif
endif
endif
endif
if isWindows and (isVC or isIntel)
ldflags += [
'/MACHINE:X86',
'user32.lib',
'ws2_32.lib'
]
ldflags += [
'/MACHINE:X86',
'user32.lib',
'ws2_32.lib'
]
ccflags += [
'/TP'
]
ccflags += [
'/TP'
]
if isOptimize
ccflags += [
'/GL',
'/arch:SSE2',
'/GS-',
'/Ob2',
'/Oy',
'/Oi'
]
ldflags += '/LTCG'
endif
if isOptimize
ccflags += [
'/GL',
'/arch:SSE2',
'/GS-',
'/Ob2',
'/Oy',
'/Oi'
]
ldflags += '/LTCG'
endif
elif isWindows and (isCLang or isGCC)
if isCLang
ldflags += '-Wl,/MACHINE:X86'
else
ldflags += [
'-static-libgcc',
'-Wl,--kill-at'
]
endif
if isCLang
ldflags += '-Wl,/MACHINE:X86'
else
ldflags += [
'-static-libgcc',
'-Wl,--kill-at'
]
endif
ldflags += [
'-luser32',
'-lws2_32'
]
ldflags += [
'-luser32',
'-lws2_32'
]
endif
add_global_arguments (ccflags, language: 'cpp')
add_global_link_arguments (ldflags, language: 'cpp')
sources = files (
'src/android.cpp',
'src/botlib.cpp',
'src/chatlib.cpp',
'src/combat.cpp',
'src/config.cpp',
'src/control.cpp',
'src/engine.cpp',
'src/graph.cpp',
'src/linkage.cpp',
'src/manager.cpp',
'src/module.cpp',
'src/message.cpp',
'src/navigate.cpp',
'src/support.cpp'
'src/android.cpp',
'src/botlib.cpp',
'src/chatlib.cpp',
'src/combat.cpp',
'src/config.cpp',
'src/control.cpp',
'src/engine.cpp',
'src/graph.cpp',
'src/linkage.cpp',
'src/manager.cpp',
'src/module.cpp',
'src/message.cpp',
'src/navigate.cpp',
'src/support.cpp'
)
includes = include_directories ([
'.', 'inc', 'ext',
'.', 'inc', 'ext',
], is_system: true)
if isWindows and not isCLang
sources += import('windows').compile_resources (
'vc/yapb.rc',
include_directories: includes,
args: ['-DVERSION_GENERATED']
)
sources += import('windows').compile_resources (
'vc/yapb.rc',
include_directories: includes,
args: ['-DVERSION_GENERATED']
)
endif
shared_library (
meson.project_name (),
sources,
include_directories: includes,
gnu_symbol_visibility: 'hidden',
name_prefix: '')
meson.project_name (),
sources,
include_directories: includes,
gnu_symbol_visibility: 'hidden',
name_prefix: '')
run_target ('package',
command : ['python', meson.source_root() + '/package.py', '@0@.@1@'.format (buildVersion, buildCount)])

View file

@ -1,4 +1,5 @@
#
# -*- coding: utf-8 -*-#
# YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
# Copyright © 2004-2020 YaPB Project <yapb@jeefo.net>.
#
@ -14,208 +15,208 @@ import datetime, calendar
from github import Github
class BotRelease (object):
def __init__(self):
print ("Initializing Packaging")
self.workDir = os.path.join (pathlib.Path ().absolute (), 'cfg')
self.botDir = os.path.join (self.workDir, 'addons', 'yapb')
self.distDir = os.path.join (pathlib.Path ().absolute (), 'dist');
if len (sys.argv) < 2:
raise Exception('Missing required parameters.')
def __init__(self):
print ("Initializing Packaging")
self.workDir = os.path.join (pathlib.Path ().absolute (), 'cfg')
self.botDir = os.path.join (self.workDir, 'addons', 'yapb')
self.distDir = os.path.join (pathlib.Path ().absolute (), 'dist');
if len (sys.argv) < 2:
raise Exception('Missing required parameters.')
self.version = sys.argv[1]
os.makedirs (self.distDir, exist_ok=True)
self.outFileWin32 = os.path.join (self.distDir, "yapb-{}-windows.zip".format (self.version))
self.outFileLinux = os.path.join (self.distDir, "yapb-{}-linux.tar.xz".format (self.version))
self.outFileMacOS = os.path.join (self.distDir, "yapb-{}-macos.zip".format (self.version))
self.outFileWin32Setup = self.outFileWin32.replace ("zip", "exe")
self.win32SetupUrl = "https://github.com/yapb/setup/releases/latest/download/botsetup.exe"
def makeDirs (self):
dirs = [
'bin',
os.path.join ('data', 'pwf'),
os.path.join ('data', 'train'),
os.path.join ('data', 'graph'),
os.path.join ('data', 'logs')
]
for dir in dirs:
os.makedirs (os.path.join (self.botDir, dir), exist_ok=True)
def download (self, fromWhere, toFile):
http = urllib3.PoolManager (10, headers = {"user-agent": "YaPB"})
data = http.urlopen ('GET', fromWhere)
with open (toFile, "wb") as file:
file.write (data.data)
def getGraph (self, name):
file = os.path.join (self.botDir, 'data', 'graph', "{}.graph".format (name))
url = "http://graph.yapb.ru/graph/{}.graph".format (name);
if os.path.exists (file):
return
self.download (url, file)
self.version = sys.argv[1]
os.makedirs (self.distDir, exist_ok=True)
self.outFileWin32 = os.path.join (self.distDir, "yapb-{}-windows.zip".format (self.version))
self.outFileLinux = os.path.join (self.distDir, "yapb-{}-linux.tar.xz".format (self.version))
self.outFileMacOS = os.path.join (self.distDir, "yapb-{}-macos.zip".format (self.version))
self.outFileWin32Setup = self.outFileWin32.replace ("zip", "exe")
self.win32SetupUrl = "https://github.com/yapb/setup/releases/latest/download/botsetup.exe"
def makeDirs (self):
dirs = [
'bin',
os.path.join ('data', 'pwf'),
os.path.join ('data', 'train'),
os.path.join ('data', 'graph'),
os.path.join ('data', 'logs')
]
for dir in dirs:
os.makedirs (os.path.join (self.botDir, dir), exist_ok=True)
def download (self, fromWhere, toFile):
http = urllib3.PoolManager (10, headers = {"user-agent": "YaPB"})
data = http.urlopen ('GET', fromWhere)
with open (toFile, "wb") as file:
file.write (data.data)
def getGraph (self, name):
file = os.path.join (self.botDir, 'data', 'graph', "{}.graph".format (name))
url = "http://graph.yapb.ru/graph/{}.graph".format (name);
if os.path.exists (file):
return
self.download (url, file)
def getGraphs (self):
print ("Downloading graphs: ")
files = ['as_oilrig', 'cs_747', 'cs_estate', 'cs_assault', 'cs_office',
'cs_italy', 'cs_havana', 'cs_siege', 'cs_backalley', 'cs_militia',
'cs_downed_cz', 'cs_havana_cz', 'cs_italy_cz', 'cs_militia_cz',
'cs_office_cz', 'de_airstrip_cz', 'de_aztec_cz', 'de_cbble_cz',
'de_chateau_cz', 'de_corruption_cz', 'de_dust_cz', 'de_dust2_cz',
'de_fastline_cz', 'de_inferno_cz', 'de_piranesi_cz', 'de_prodigy_cz',
'de_sienna_cz', 'de_stadium_cz', 'de_tides_cz', 'de_torn_cz',
'de_truth_cz', 'de_vostok_cz', 'de_inferno', 'de_aztec', 'de_dust',
'de_dust2', 'de_torn', 'de_storm', 'de_airstrip', 'de_piranesi',
'de_prodigy', 'de_chateau', 'de_cbble', 'de_nuke', 'de_survivor',
'de_vertigo', 'de_train']
for file in files:
print (" " + file)
self.getGraph (file)
def getGraphs (self):
print ("Downloading graphs: ")
files = ['as_oilrig', 'cs_747', 'cs_estate', 'cs_assault', 'cs_office',
'cs_italy', 'cs_havana', 'cs_siege', 'cs_backalley', 'cs_militia',
'cs_downed_cz', 'cs_havana_cz', 'cs_italy_cz', 'cs_militia_cz',
'cs_office_cz', 'de_airstrip_cz', 'de_aztec_cz', 'de_cbble_cz',
'de_chateau_cz', 'de_corruption_cz', 'de_dust_cz', 'de_dust2_cz',
'de_fastline_cz', 'de_inferno_cz', 'de_piranesi_cz', 'de_prodigy_cz',
'de_sienna_cz', 'de_stadium_cz', 'de_tides_cz', 'de_torn_cz',
'de_truth_cz', 'de_vostok_cz', 'de_inferno', 'de_aztec', 'de_dust',
'de_dust2', 'de_torn', 'de_storm', 'de_airstrip', 'de_piranesi',
'de_prodigy', 'de_chateau', 'de_cbble', 'de_nuke', 'de_survivor',
'de_vertigo', 'de_train']
for file in files:
print (" " + file)
self.getGraph (file)
def unlinkBinaries (self):
libs = ['yapb.so', 'yapb.dll', 'yapb.dylib']
for lib in libs:
path = os.path.join (self.botDir, 'bin', lib)
if os.path.exists (path):
os.remove (path)
def copyBinary (self, path):
shutil.copy (path, os.path.join (self.botDir, 'bin'))
def zipDir (self, path, handle):
length = len (path) + 1
emptyDirs = []
for root, dirs, files in os.walk (path):
emptyDirs.extend ([dir for dir in dirs if os.listdir (os.path.join (root, dir)) == []])
for file in files:
filePath = os.path.join (root, file)
handle.write (filePath, filePath[length:])
for dir in emptyDirs:
dirPath = os.path.join (root, dir)
zif = zipfile.ZipInfo (dirPath[length:] + "/")
handle.writestr (zif, "")
emptyDirs = []
def unlinkBinaries (self):
libs = ['yapb.so', 'yapb.dll', 'yapb.dylib']
for lib in libs:
path = os.path.join (self.botDir, 'bin', lib)
if os.path.exists (path):
os.remove (path)
def copyBinary (self, path):
shutil.copy (path, os.path.join (self.botDir, 'bin'))
def zipDir (self, path, handle):
length = len (path) + 1
emptyDirs = []
for root, dirs, files in os.walk (path):
emptyDirs.extend ([dir for dir in dirs if os.listdir (os.path.join (root, dir)) == []])
for file in files:
filePath = os.path.join (root, file)
handle.write (filePath, filePath[length:])
for dir in emptyDirs:
dirPath = os.path.join (root, dir)
zif = zipfile.ZipInfo (dirPath[length:] + "/")
handle.writestr (zif, "")
emptyDirs = []
def generateZip (self, dir):
zipFile = zipfile.ZipFile (dir, 'w', zipfile.ZIP_DEFLATED)
zipFile.comment = bytes (self.version, encoding = "ascii")
self.zipDir (self.workDir, zipFile)
zipFile.close ()
def convertZipToTXZ (self, zip, txz):
timeshift = int ((datetime.datetime.now () - datetime.datetime.utcnow ()).total_seconds ())
with zipfile.ZipFile (zip) as zipf:
with tarfile.open (txz, 'w:xz') as tarf:
for zif in zipf.infolist ():
tif = tarfile.TarInfo (name = zif.filename)
tif.size = zif.file_size
tif.mtime = calendar.timegm (zif.date_time) - timeshift
tarf.addfile (tarinfo = tif, fileobj = zipf.open (zif.filename))
os.remove (zip)
def generateWin32 (self):
print ("Generating Win32 ZIP")
binary = os.path.join ('build_x86_win32', 'yapb.dll')
if not os.path.exists (binary):
return
self.unlinkBinaries ()
self.copyBinary (binary)
self.generateZip (self.outFileWin32)
self.download (self.win32SetupUrl, "botsetup.exe")
print ("Generating Win32 EXE")
def generateZip (self, dir):
zipFile = zipfile.ZipFile (dir, 'w', zipfile.ZIP_DEFLATED)
zipFile.comment = bytes (self.version, encoding = "ascii")
self.zipDir (self.workDir, zipFile)
zipFile.close ()
def convertZipToTXZ (self, zip, txz):
timeshift = int ((datetime.datetime.now () - datetime.datetime.utcnow ()).total_seconds ())
with zipfile.ZipFile (zip) as zipf:
with tarfile.open (txz, 'w:xz') as tarf:
for zif in zipf.infolist ():
tif = tarfile.TarInfo (name = zif.filename)
tif.size = zif.file_size
tif.mtime = calendar.timegm (zif.date_time) - timeshift
tarf.addfile (tarinfo = tif, fileobj = zipf.open (zif.filename))
os.remove (zip)
def generateWin32 (self):
print ("Generating Win32 ZIP")
binary = os.path.join ('build_x86_win32', 'yapb.dll')
if not os.path.exists (binary):
return
self.unlinkBinaries ()
self.copyBinary (binary)
self.generateZip (self.outFileWin32)
self.download (self.win32SetupUrl, "botsetup.exe")
print ("Generating Win32 EXE")
with open ("botsetup.exe", "rb") as sfx, open (self.outFileWin32, "rb") as zip, open (self.outFileWin32Setup, "wb") as exe:
exe.write (sfx.read ())
exe.write (zip.read ())
def generateLinux (self):
print ("Generating Linux TXZ")
binary = os.path.join ('build_x86_linux', 'yapb.so');
if not os.path.exists (binary):
return
self.unlinkBinaries ()
self.copyBinary (binary)
tmpFile = "tmp.zip"
self.generateZip (tmpFile)
self.convertZipToTXZ (tmpFile, self.outFileLinux)
def generateMac (self):
print ("Generating macOS ZIP")
binary = os.path.join ('build_x86_macos', 'yapb.dylib')
if not os.path.exists (binary):
return
self.unlinkBinaries ()
self.copyBinary (binary)
self.generateZip (self.outFileMacOS)
def generate (self):
self.generateWin32 ()
self.generateLinux ()
self.generateMac ()
def createRelease (self, repository, version):
print ("Creating Github Tag")
releases = [self.outFileLinux, self.outFileWin32, self.outFileMacOS, self.outFileWin32Setup]
for release in releases:
if not os.path.exists (release):
return
releaseName = "YaPB " + version
releaseMessage = repository.get_commits()[0].commit.message
releaseSha = repository.get_commits()[0].sha;
with open ("botsetup.exe", "rb") as sfx, open (self.outFileWin32, "rb") as zip, open (self.outFileWin32Setup, "wb") as exe:
exe.write (sfx.read ())
exe.write (zip.read ())
def generateLinux (self):
print ("Generating Linux TXZ")
binary = os.path.join ('build_x86_linux', 'yapb.so');
if not os.path.exists (binary):
return
self.unlinkBinaries ()
self.copyBinary (binary)
tmpFile = "tmp.zip"
self.generateZip (tmpFile)
self.convertZipToTXZ (tmpFile, self.outFileLinux)
def generateMac (self):
print ("Generating macOS ZIP")
binary = os.path.join ('build_x86_macos', 'yapb.dylib')
if not os.path.exists (binary):
return
self.unlinkBinaries ()
self.copyBinary (binary)
self.generateZip (self.outFileMacOS)
def generate (self):
self.generateWin32 ()
self.generateLinux ()
self.generateMac ()
def createRelease (self, repository, version):
print ("Creating Github Tag")
releases = [self.outFileLinux, self.outFileWin32, self.outFileMacOS, self.outFileWin32Setup]
for release in releases:
if not os.path.exists (release):
return
releaseName = "YaPB " + version
releaseMessage = repository.get_commits()[0].commit.message
releaseSha = repository.get_commits()[0].sha;
ghr = repository.create_git_tag_and_release (tag = version, tag_message = version, release_name = releaseName, release_message = releaseMessage, type='commit', object = releaseSha, draft = False)
print ("Uploading packages to Github")
for release in releases:
ghr.upload_asset( path = release, label = os.path.basename (release))
def uploadGithub (self):
gh = Github (os.environ["GITHUB_TOKEN"])
repo = gh.get_repo ("yapb/yapb")
self.createRelease (repo, self.version)
ghr = repository.create_git_tag_and_release (tag = version, tag_message = version, release_name = releaseName, release_message = releaseMessage, type='commit', object = releaseSha, draft = False)
print ("Uploading packages to Github")
for release in releases:
ghr.upload_asset( path = release, label = os.path.basename (release))
def uploadGithub (self):
gh = Github (os.environ["GITHUB_TOKEN"])
repo = gh.get_repo ("yapb/yapb")
self.createRelease (repo, self.version)
release = BotRelease ()
release.makeDirs ()

View file

@ -572,7 +572,7 @@ void Bot::updatePickups () {
allowPickup = true;
pickupType = Pickup::DefusalKit;
}
else if (strncmp ("grenade", classname, 7) == 0 && strcmp (model, "c4.mdl") == 0) {
else if (strncmp ("grenade", classname, 7) == 0 && conf.getBombModelName () == model) {
allowPickup = true;
pickupType = Pickup::PlantedC4;
}
@ -2888,7 +2888,7 @@ void Bot::checkDarkness () {
}
void Bot::checkParachute () {
static auto parachute = engfuncs.pfnCVarGetPointer ("sv_parachute");
static auto parachute = engfuncs.pfnCVarGetPointer (conf.fetchCustom ("AMXParachuteCvar").chars ());
// if no cvar or it's not enabled do not bother
if (parachute && parachute->value > 0.0f) {
@ -5460,7 +5460,7 @@ edict_t *Bot::correctGrenadeVelocity (const char *model) {
edict_t *result = nullptr;
game.searchEntities ("classname", "grenade", [&] (edict_t *ent) {
if (ent->v.owner == this->ent () && strcmp (ent->v.model.chars (9), model) == 0) {
if (ent->v.owner == this->ent () && util.isModel (ent, model)) {
result = ent;
// set the correct velocity for the grenade

View file

@ -144,7 +144,7 @@ void Bot::prepareChatMessage (StringRef message) {
}
// get the humanized name out of client
auto humanizedName = [] (int index) -> StringRef {
auto humanizedName = [] (int index) -> String {
auto ent = game.playerOfIndex (index);
if (!util.isPlayer (ent)) {
@ -157,7 +157,7 @@ void Bot::prepareChatMessage (StringRef message) {
};
// find highfrag player
auto getHighfragPlayer = [&] () -> StringRef {
auto getHighfragPlayer = [&] () -> String {
int highestFrags = -1;
int index = 0;
@ -178,7 +178,7 @@ void Bot::prepareChatMessage (StringRef message) {
};
// get roundtime
auto getRoundTime = [] () -> StringRef {
auto getRoundTime = [] () -> String {
auto roundTimeSecs = static_cast <int> (bots.getRoundEndTime () - game.time ());
String roundTime;
@ -188,12 +188,12 @@ void Bot::prepareChatMessage (StringRef message) {
};
// get bot's victim
auto getMyVictim = [&] () -> StringRef {;
auto getMyVictim = [&] () -> String {;
return humanizedName (game.indexOfPlayer (m_lastVictim));
};
// get the game name alias
auto getGameName = [] () -> StringRef {
auto getGameName = [] () -> String {
String gameName;
if (game.is (GameFlags::ConditionZero)) {
@ -216,7 +216,7 @@ void Bot::prepareChatMessage (StringRef message) {
};
// get enemy or teammate alive
auto getPlayerAlive = [&] (bool needsEnemy) -> StringRef {
auto getPlayerAlive = [&] (bool needsEnemy) -> String {
for (const auto &client : util.getClients ()) {
if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive) || client.ent == ent ()) {
continue;

View file

@ -1,6 +1,6 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright Š 2004-2020 YaPB Project <yapb@jeefo.net>.
// Copyright © 2004-2020 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
@ -28,6 +28,7 @@ void BotConfig::loadConfigs () {
loadLogosConfig ();
loadAvatarsConfig ();
loadDifficultyConfig ();
loadCustomConfig ();
}
void BotConfig::loadMainConfig (bool isFirstLoad) {
@ -614,6 +615,38 @@ void BotConfig::loadMapSpecificConfig () {
}
}
void BotConfig::loadCustomConfig () {
String line;
MemFile file;
m_custom["C4ModelName"] = "c4.mdl";
m_custom["AMXParachuteCvar"] = "sv_parachute";
// custom inititalization
if (util.openConfig ("custom.cfg", "Custom config file not found. Loading defaults.", &file)) {
m_custom.clear ();
while (file.getLine (line)) {
line.trim ();
if (isCommentLine (line)) {
continue;
}
auto values = line.split ("=");
if (values.length () != 2) {
logger.error ("Bad configuration for custom.cfg");
return;
}
auto kv = Twin <String, String> (values[0].trim (), values[1].trim ());
if (!kv.first.empty () && !kv.second.empty ()) {
m_custom[kv.first] = kv.second;
}
}
}
}
void BotConfig::loadLogosConfig () {
setupMemoryFiles ();
@ -750,6 +783,14 @@ const char *BotConfig::translate (StringRef input) {
return input.chars (); // nothing found
}
void BotConfig::showCustomValues () {
game.print ("Current values for custom config items:");
m_custom.foreach ([&](const String &key, const String &val) {
game.print (" %s = %s", key, val);
});
}
uint32 BotConfig::hashLangString (StringRef str) {
auto test = [] (const char ch) {
return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');

View file

@ -262,6 +262,14 @@ int BotControl::cmdCvars () {
return BotCommandResult::Handled;
}
int BotControl::cmdShowCustom () {
enum args { alias = 1 };
conf.showCustomValues ();
return BotCommandResult::Handled;
}
int BotControl::cmdNode () {
enum args { root, alias, cmd, cmd2 };
@ -1895,6 +1903,7 @@ BotControl::BotControl () {
m_cmds.emplace ("list/listbots", "list [noarguments]", "Lists the bots currently playing on server.", &BotControl::cmdList);
m_cmds.emplace ("graph/g/wp/wpt/waypoint", "graph [help]", "Handles graph operations.", &BotControl::cmdNode);
m_cmds.emplace ("cvars", "cvars [save|cvar]", "Display all the cvars with their descriptions.", &BotControl::cmdCvars);
m_cmds.emplace ("show_custom", "show_custom [noarguments]", "Show's the curent values from custom.cfg.", &BotControl::cmdShowCustom);
// declare the menus
createMenus ();

View file

@ -799,6 +799,9 @@ bool Game::postload () {
// set out user agent for http stuff
http.setUserAgent (strings.format ("%s/%s", product.name, product.version));
// startup the sockets
http.startup ();
// set the app name
plat.setAppName (product.name.chars ());

View file

@ -2806,9 +2806,10 @@ void BotGraph::setBombOrigin (bool reset, const Vector &pos) {
return;
}
bool wasFound = false;
auto bombModel = conf.getBombModelName ();
game.searchEntities ("classname", "grenade", [&] (edict_t *ent) {
if (strcmp (ent->v.model.chars (9), "c4.mdl") == 0) {
if (util.isModel (ent, bombModel)) {
m_bombOrigin = game.getEntityWorldOrigin (ent);
wasFound = true;

View file

@ -1628,10 +1628,13 @@ void BotManager::updateActiveGrenade () {
}
m_activeGrenades.clear (); // clear previously stored grenades
// need to ignore bomb model in active grenades...
auto bombModel = conf.getBombModelName ();
// search the map for any type of grenade
game.searchEntities ("classname", "grenade", [&] (edict_t *e) {
// do not count c4 as a grenade
if (strcmp (e->v.model.chars (9), "c4.mdl") != 0) {
if (!util.isModel (e, bombModel)) {
m_activeGrenades.push (e);
}
return EntitySearchResult::Continue; // continue iteration

View file

@ -17,7 +17,7 @@ int Bot::findBestGoal () {
int result = kInvalidNodeIndex;
game.searchEntities ("classname", "weaponbox", [&] (edict_t *ent) {
if (strcmp (ent->v.model.chars (9), "backpack.mdl") == 0) {
if (util.isModel (ent, "backpack.mdl")) {
result = graph.getNearest (game.getEntityWorldOrigin (ent));
if (graph.exists (result)) {
@ -2965,11 +2965,13 @@ int Bot::getNearestToPlantedBomb () {
if (!game.mapIs (MapFlags::Demolition)) {
return kInvalidNodeIndex; // don't search for bomb if the player is CT, or it's not defusing bomb
}
int result = kInvalidNodeIndex;
auto bombModel = conf.getBombModelName ();
auto result = kInvalidNodeIndex;
// search the bomb on the map
game.searchEntities ("classname", "grenade", [&result] (edict_t *ent) {
if (strcmp (ent->v.model.chars (9), "c4.mdl") == 0) {
game.searchEntities ("classname", "grenade", [&result, &bombModel] (edict_t *ent) {
if (util.isModel (ent, bombModel)) {
result = graph.getNearest (game.getEntityWorldOrigin (ent));
if (graph.exists (result)) {

View file

@ -687,6 +687,10 @@ bool BotSupport::isObjectInsidePlane (FrustumPlane &plane, const Vector &center,
return isPointInsidePlane (top) || isPointInsidePlane (bottom);
}
bool BotSupport::isModel (const edict_t *ent, StringRef model) {
return model == ent->v.model.chars (9);
}
int32 BotSupport::sendTo (int socket, const void *message, size_t length, int flags, const sockaddr *dest, int destLength) {
const auto send = [&] (const Twin <const uint8 *, size_t> &msg) -> int32 {
return Socket::sendto (socket, msg.first, msg.second, flags, dest, destLength);