diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cefb884..6799538 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,51 +1,154 @@ -name: YaPB +name: build -on: - push: - branches: [master] - pull_request: +on: + push: branches: [master] + paths-ignore: + - '**.md' + + pull_request: + types: [opened, reopened, synchronize] + release: + types: [published] jobs: - linux: - name: Full Build - runs-on: self-hosted - + build: + strategy: + matrix: + include: + - os: windows-latest + bin: yapb.dll + name: windows + + - os: ubuntu-latest + bin: yapb.so + name: linux + clang: 12 + + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + steps: - - uses: actions/checkout@v2 + - name: Checkout Repository + uses: actions/checkout@v2 with: - submodules: true fetch-depth: 0 + submodules: true + + - name: Setup Windows x86 + if: startsWith (runner.os, 'windows') + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: amd64_x86 + + - name: Setup Linux x86 + if: startsWith (runner.os, 'linux') + run: | + sudo dpkg --add-architecture i386 + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + gcc-multilib g++-multilib libstdc++6 lib32stdc++6 \ + libc6-dev libc6-dev-i386 linux-libc-dev linux-libc-dev:i386 + + echo "CXX=clang-${{ matrix.clang }}" >> $GITHUB_ENV + echo "CXX_LD=lld-${{ matrix.clang }}" >> $GITHUB_ENV + + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' - name: Setup Meson - shell: bash - run: | - meson setup build_x86_win32 --cross-file=/actions/meson/windows-msvc-32bit.txt -Db_vscrt=mt - meson setup build_x86_macos --cross-file=/actions/meson/darwin-clang-32bit.txt - CXX=clang meson setup build_x86_linux - - - name: Build Bot - shell: bash run: | - ninja -C build_x86_win32 -v - ninja -C build_x86_macos -v - ninja -C build_x86_linux -v - - - name: Build Package - shell: bash - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + python -m pip install --upgrade meson ninja + + - name: Configure Build + run: | + meson setup build + + - name: Compile Source + run: | + meson compile -v -C build + + - name: Upload Artifacts + uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.bin }} + path: build/${{ matrix.bin }} + + macos: + name: macos + runs-on: ubuntu-latest + container: j4sdk/macross-x86:latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + fetch-depth: 0 + submodules: true + + - name: Configure Build + run: | + CXX_LD=/opt/osxcross/target/bin/i386-apple-darwin15-ld meson setup build --cross-file=x86-darwin + + - name: Compile Source + run: | + meson compile -v -C build + + - name: Upload Artifacts + uses: actions/upload-artifact@v2 + with: + name: yapb.dylib + path: build/yapb.dylib + + publish: + if: | + github.event_name == 'release' && + github.event.action == 'published' + + name: publish + runs-on: ubuntu-latest + needs: [build, macos] + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + with: + fetch-depth: 0 + submodules: true + + - name: Install Signing Tools + run: | + sudo apt-get update && sudo apt-get upgrade -y + sudo apt-get install -y --no-install-recommends osslsigncode + + - name: Get Artifacts + uses: actions/download-artifact@v2 + with: + path: artifacts + + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Setup Meson + run: | + python -m pip install --upgrade meson ninja urllib3 + + - name: Create Packages run: | meson setup dist ninja -C dist package - - - uses: actions/upload-artifact@v2 - name: Upload Artifacts + env: + CS_CERTIFICATE: ${{ secrets.CS_CERTIFICATE }} + CS_CERTIFICATE_PASSWORD: ${{ secrets.CS_CERTIFICATE_PASSWORD }} + + - name: Publish Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') with: - name: yapb.zip - path: | - build_x86_win32/yapb.dll - build_x86_linux/yapb.so - build_x86_macos/yapb.dylib - + files: pkg/* + env: + GITHUB_TOKEN: ${{ secrets.API_TOKEN }} diff --git a/README.md b/README.md index 2f55dd8..6b6db53 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ## YaPB -[![Latest YaPB](https://img.shields.io/github/v/release/yapb/yapb)](https://github.com/yapb/yapb/releases/latest) [![Latest YaPB](https://github.com/yapb/yapb/workflows/YaPB/badge.svg)](https://github.com/yapb/yapb/actions) [![YaPB License](https://img.shields.io/github/license/yapb/yapb)](https://github.com/yapb/yapb/blob/master/LICENSE) +[![Latest YaPB](https://img.shields.io/github/v/release/yapb/yapb)](https://github.com/yapb/yapb/releases/latest) [![Latest YaPB](https://github.com/yapb/yapb/workflows/build/badge.svg)](https://github.com/yapb/yapb/actions) [![YaPB License](https://img.shields.io/github/license/yapb/yapb)](https://github.com/yapb/yapb/blob/master/LICENSE) ## ☉ About It's a computer controlled players (bots) for the Counter-Strike b6.6 - 1.6 and Counter-Strike: Condition Zero. Bots allows you to play that games without connecting any game server or even without internet. diff --git a/inc/engine.h b/inc/engine.h index bb79fad..a41aa10 100644 --- a/inc/engine.h +++ b/inc/engine.h @@ -643,10 +643,12 @@ class EntityLinkage : public Singleton { private: #if defined (CR_WINDOWS) # define DLSYM_FUNCTION GetProcAddress +# define DLCLOSE_FUNCTION FreeLibrary # define DLSYM_RETURN FARPROC # define DLSYM_HANDLE HMODULE #else # define DLSYM_FUNCTION dlsym +# define DLCLOSE_FUNCTION dlclose # define DLSYM_RETURN SharedLibrary::Handle # define DLSYM_HANDLE SharedLibrary::Handle #endif @@ -655,6 +657,7 @@ private: bool m_paused { false }; Detour m_dlsym; + Detour m_dlclose; HashMap m_exports; SharedLibrary m_self; @@ -666,6 +669,15 @@ public: void initialize (); DLSYM_RETURN lookup (SharedLibrary::Handle module, const char *function); + int close (DLSYM_HANDLE module) { + if (m_self.handle () == module) { + disable (); + + return m_dlclose (module); + } + return m_dlclose (module); + } + public: void callPlayerFunction (edict_t *ent) { #if defined (CR_ANDROID) && defined (CR_ARCH_ARM) @@ -699,16 +711,20 @@ public: } public: - static DLSYM_RETURN CR_STDCALL replacement (SharedLibrary::Handle module, const char *function) { + static DLSYM_RETURN CR_STDCALL lookupHandler (SharedLibrary::Handle module, const char *function) { return EntityLinkage::instance ().lookup (module, function); } + static int CR_STDCALL closeHandler (DLSYM_HANDLE module) { + return EntityLinkage::instance ().close (module); + } + public: - void clearExportTable () { + void flush () { m_exports.clear (); } - bool isWorkaroundNeeded () { + bool needsBypass () const { return !plat.win && !Game::instance ().isDedicated (); } }; diff --git a/inc/version.h.in b/inc/version.h.in index c5d6c02..3a34f84 100644 --- a/inc/version.h.in +++ b/inc/version.h.in @@ -9,12 +9,12 @@ // generated by meson build system #ifndef MODULE_BUILD_HASH -# define MODULE_BUILD_HASH "@commitHash@" -# define MODULE_BUILD_AUTHOR @commitAuthor@ -# define MODULE_BUILD_COUNT "@commitCount@" -# define MODULE_BUILD_MACHINE "@buildMachine@" -# define MODULE_BUILD_COMPILER "@buildCompiler@" -# define MODULE_BOT_VERSION "@buildVersion@" -# define MODULE_BOT_VERSION_FILE @buildVersionWin@,@commitCount@ -# define MODULE_BOT_BUILD_ID "@commitCount@:@commitHash@" +# define MODULE_BUILD_HASH "@hash@" +# define MODULE_BUILD_AUTHOR @author@ +# define MODULE_BUILD_COUNT "@count@" +# define MODULE_BUILD_MACHINE "@machine@" +# define MODULE_BUILD_COMPILER "@compiler@" +# define MODULE_BOT_VERSION "@version@" +# define MODULE_BOT_VERSION_FILE @version_win@,@count@ +# define MODULE_BOT_BUILD_ID "@count@:@hash@" #endif diff --git a/inc/yapb.h b/inc/yapb.h index 41b073b..6a8a994 100644 --- a/inc/yapb.h +++ b/inc/yapb.h @@ -1147,12 +1147,12 @@ public: template void issueCommand (const char *fmt, Args &&...args); }; -#include -#include -#include -#include -#include -#include +#include "config.h" +#include "support.h" +#include "message.h" +#include "engine.h" +#include "manager.h" +#include "control.h" // very global convars extern ConVar cv_jasonmode; diff --git a/meson.build b/meson.build index a0db266..e56f69f 100644 --- a/meson.build +++ b/meson.build @@ -22,55 +22,59 @@ project ( 'strip=true', 'optimization=3', 'default_library=static', - 'cpp_eh=none' + 'cpp_eh=none', + 'b_vscrt=static_from_buildtype' ], - meson_version: '>=0.48.0') + meson_version: '>=0.56.0') find_program ('ninja', required: true) find_program ('git', required: true) find_program ('hostname', required: true) -buildCompiler = meson.get_compiler ('cpp') -buildSystem = host_machine.system () -buildVersion = meson.project_version () -buildCount = run_command ('git', 'rev-list', '--count', 'HEAD').stdout ().strip () +cpp = meson.get_compiler ('cpp') +sys = host_machine.system () +version = meson.project_version () +count = run_command ('git', 'rev-list', '--count', 'HEAD').stdout ().strip () -compilerId = buildCompiler.get_id () -compilerVersion = buildCompiler.version () +cpp_id = cpp.get_id () +cpp_version = cpp.version () -isOptimize = get_option ('buildtype') == 'release' or get_option ('buildtype') == 'debugoptimized' -isVC = compilerId == 'msvc' or compilerId == 'intel-cl' or compilerId == 'clang-cl' -isGCC = compilerId == 'gcc' -isIntel = compilerId == 'intel' or compilerId == 'intel-cl' -isCLang = compilerId == 'clang' -isWindows = buildSystem == 'windows' -isLinux = buildSystem == 'linux' -isDarwin = buildSystem == 'darwin' +optmize = get_option ('buildtype') == 'release' or get_option ('buildtype') == 'debugoptimized' + +msvc = cpp_id == 'msvc' or cpp_id == 'clang-cl' +gcc = cpp_id == 'gcc' +clang = cpp_id == 'clang' + +win32 = sys == 'windows' +linux = sys == 'linux' +mac = sys == 'darwin' ldflags = [] ccflags = [] cdata = configuration_data() -if isWindows - cdata.set ('buildVersionWin', ','.join (buildVersion.split ('.'))) +if win32 + cdata.set ('version_win', ','.join (version.split ('.'))) + cdata.set ('machine', run_command ('hostname').stdout ().strip ()) else - cdata.set ('buildVersionWin', buildVersion) + cdata.set ('version_win', version) + cdata.set ('machine', run_command ('hostname', '-f').stdout ().strip ()) endif -cdata.set ('commitHash', run_command ('git', 'rev-parse', '--short', 'HEAD').stdout ().strip ()) -cdata.set ('commitAuthor', run_command ('git', 'log', '--pretty="%ae"', '-1').stdout ().strip ()) +cdata.set ('hash', run_command ('git', 'rev-parse', '--short', 'HEAD').stdout ().strip ()) +cdata.set ('author', run_command ('git', 'log', '--pretty="%ae"', '-1').stdout ().strip ()) -cdata.set ('commitCount', buildCount) -cdata.set ('buildVersion', buildVersion) -cdata.set ('buildMachine', run_command ('hostname', '-f').stdout ().strip ()) -cdata.set ('buildCompiler', compilerId + ' ' + compilerVersion) +cdata.set ('count', count) +cdata.set ('version', version) + +cdata.set ('compiler', cpp_id + ' ' + cpp_version) configure_file (input: 'inc/version.h.in', output: 'version.build.h', configuration: cdata) ccflags += '-DVERSION_GENERATED' -if isCLang or isGCC or (isIntel and not isWindows) +if clang or gcc ccflags += [ '-m32', '-fno-threadsafe-statics', @@ -78,36 +82,32 @@ if isCLang or isGCC or (isIntel and not isWindows) '-fno-rtti' ] - if not isDarwin + if not mac ccflags += [ '-pedantic', ] endif - - if isOptimize - ccflags += '-msse3' - - if (isCLang or isGCC) and not isDarwin + + if optmize + if (clang or gcc) and not mac ccflags += [ '-flto', '-fdata-sections', '-ffunction-sections' ] - if isGCC + if gcc ccflags += '-fgraphite-identity' ldflags += '-flto-partition=none' endif ldflags += [ - '-flto', - '-Wl,--version-script=../version_script.lds', - '-Wl,--gc-sections' + '-flto' ] endif endif - if isLinux + if linux ldflags += [ '-m32', '-lm', @@ -116,18 +116,10 @@ if isCLang or isGCC or (isIntel and not isWindows) endif endif -if isIntel and (isLinux or isDarwin) - ldflags += [ - '-static-intel', - '-no-intel-extensions' - ] -endif - -if isLinux or isDarwin - if isDarwin +if linux or mac or (win32 and (gcc or clang)) + if mac ccflags += '-mmacosx-version-min=10.9' ldflags += [ - '-dynamiclib', '-lstdc++', '-mmacosx-version-min=10.9' ] @@ -135,7 +127,7 @@ if isLinux or isDarwin ldflags += '-static-libgcc' endif - if not isOptimize + if not optmize ccflags += [ '-g3', '-ggdb', @@ -144,7 +136,7 @@ if isLinux or isDarwin else ccflags += [ '-mtune=generic', - '-msse3', + '-msse2', '-mfpmath=sse', '-fno-builtin', '-funroll-loops', @@ -154,38 +146,24 @@ if isLinux or isDarwin '-fvisibility-inlines-hidden' ] - if isIntel - ccflags += [ - '-ipo', - '-wd11076', - '-wd11074' - ] + if clang and not mac + lld = 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] - endif - - ldflags += [ - '-nostdlib++', - '-Wunused-command-line-argument', - '-Wl,-z,notext', - '--no-undefined' - ] - elif isGCC and not isDarwin - ldflags += '-Wl,--no-undefined' + if lld.found () == true + ldflags += '-fuse-ld=' + lld.full_path ().split ('/')[-1] endif + + ldflags += [ + '-nostdlib++', + '-Wunused-command-line-argument' + ] + elif gcc and not mac + ldflags += '-Wl,--no-undefined' + endif endif endif -if isWindows and (isVC or isIntel) +if win32 and msvc ldflags += [ '/MACHINE:X86', 'user32.lib', @@ -193,32 +171,34 @@ if isWindows and (isVC or isIntel) ] ccflags += [ - '/TP' + '/TP', + '/D _WIN32_WINNT=0x0501', + '/D _USING_V110_SDK71_', + '/Zc:threadSafeInit-' ] - if isOptimize + if optmize ccflags += [ '/GL', - '/arch:SSE2', '/GS-', '/Ob2', '/Oy', - '/Oi' + '/Oi', + '/Ot', + '/fp:precise', + '/GF' ] - ldflags += '/LTCG' - endif - -elif isWindows and (isCLang or isGCC) - if isCLang - ldflags += '-Wl,/MACHINE:X86' - else ldflags += [ - '-static-libgcc', - '-Wl,--kill-at' - ] + '/LTCG', + 'delayimp.lib', + '/DELAYLOAD:user32.dll', + '/SUBSYSTEM:WINDOWS,5.01', + ] endif +elif win32 and (clang or gcc) ldflags += [ + '-Wl,--kill-at', '-luser32', '-lws2_32' ] @@ -228,7 +208,6 @@ 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', @@ -245,10 +224,10 @@ sources = files ( ) includes = include_directories ([ - '.', 'inc', 'ext', + '.', 'inc', 'ext', 'ext/crlib' ], is_system: true) -if isWindows and not isCLang +if win32 sources += import('windows').compile_resources ( 'vc/yapb.rc', include_directories: includes, @@ -260,9 +239,8 @@ shared_library ( 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)]) \ No newline at end of file + command: ['python3', meson.project_source_root () + '/package.py', '@0@.@1@'.format (version, count)]) \ No newline at end of file diff --git a/package.py b/package.py index 6261331..1ac2bd0 100644 --- a/package.py +++ b/package.py @@ -6,127 +6,223 @@ # SPDX-License-Identifier: MIT # -import os, sys, subprocess +from genericpath import isdir +import os, sys, subprocess, base64 import locale, urllib3 import pathlib, shutil import zipfile, tarfile import datetime, calendar -from github import Github +class CodeSign (object): + def __init__(self, product, url, verify_signature=False): + self.signing = True + + self.ossl_path = "/usr/bin/osslsigncode" + self.local_key = os.path.join (pathlib.Path ().absolute (), "key.pfx"); + + self.product = product + self.url = url + self.verify_signature = verify_signature + + if not os.path.exists (self.ossl_path): + self.signing = False + + if not "CS_CERTIFICATE" in os.environ: + self.signing = False + + if not "CS_CERTIFICATE_PASSWORD" in os.environ: + self.signing = False + + if self.signing: + self.password = os.environ.get ("CS_CERTIFICATE_PASSWORD") + + encoded = os.environ.get ("CS_CERTIFICATE") + + if len (encoded) < 64: + print ('Damaged certificate. Signing disabled.') + self.signing = False + return + + decoded = base64.b64decode (encoded) + + with open (self.local_key, "wb") as key: + key.write (decoded) + + def has(self): + return self.signing + + def sign_file_inplace (self, filename): + signed_filename = filename + ".signed" + sign = [] + + sign.append (self.ossl_path) + sign.append ("sign") + sign.append ("-pkcs12") + sign.append (self.local_key) + sign.append ("-pass") + sign.append (self.password) + sign.append ("-n") + sign.append (self.product) + sign.append ("-i") + sign.append (self.url) + sign.append ("-h") + sign.append ("sha256") + sign.append ("-t") + sign.append ("http://timestamp.sectigo.com") + sign.append ("-in") + sign.append (filename) + sign.append ("-out") + sign.append (signed_filename) + + result = subprocess.run (sign, capture_output=True, text=True) + + if result.returncode == 0: + os.unlink (filename) + shutil.move (signed_filename, filename) + + print ("Signing result: {}".format (result.stdout)) + + if self.verify_signature: + verify = [] + verify.append (self.ossl_path) + verify.append ("verify") + verify.append (filename) + + verify = subprocess.run (verify, capture_output=True, text=True) + print (verify.stdout) + + else: + print (result.stdout) + class BotRelease (object): def __init__(self): print ("Initializing Packaging") + + meson_src_root_env = "MESON_SOURCE_ROOT" + + if meson_src_root_env in os.environ: + os.chdir (os.environ.get (meson_src_root_env)) - 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'); + self.work_dir = os.path.join (pathlib.Path ().absolute (), "cfg") + self.bot_dir = os.path.join (self.work_dir, "addons", "yapb") + self.pkg_dir = os.path.join (pathlib.Path ().absolute (), "pkg") if len (sys.argv) < 2: - raise Exception('Missing required parameters.') + raise Exception("Missing required parameters.") self.version = sys.argv[1] + self.artifacts = 'artifacts' + + self.cs = CodeSign ("YaPB", "https://yapb.ru/") + + if self.cs.has (): + print ("Code Signing Enabled") + else: + print ("Code Signing Disabled") + + os.makedirs (self.pkg_dir, exist_ok=True) - os.makedirs (self.distDir, exist_ok=True) + self.pkg_win32 = os.path.join (self.pkg_dir, "yapb-{}-windows.zip".format (self.version)) + self.pkg_linux = os.path.join (self.pkg_dir, "yapb-{}-linux.tar.xz".format (self.version)) + self.pkg_macos = os.path.join (self.pkg_dir, "yapb-{}-macos.zip".format (self.version)) + + self.pkg_win32_sfx = self.pkg_win32.replace ("zip", "exe") + self.pkg_win32_sfx_url = "https://github.com/yapb/setup/releases/latest/download/botsetup.exe" - 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): + def make_directories (self): dirs = [ - 'bin', - os.path.join ('data', 'pwf'), - os.path.join ('data', 'train'), - os.path.join ('data', 'graph'), - os.path.join ('data', 'logs') + "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) + os.makedirs (os.path.join (self.bot_dir, dir), exist_ok=True) - def download (self, fromWhere, toFile): + def http_pull (self, url, local_file): http = urllib3.PoolManager (10, headers = {"user-agent": "YaPB"}) - data = http.urlopen ('GET', fromWhere) + data = http.urlopen ("GET", url) - with open (toFile, "wb") as file: + with open (local_file, "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); + def get_graph_file (self, name): + file = os.path.join (self.bot_dir, "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.http_pull (url, file) - def getGraphs (self): + def get_default_graphs (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'] + default_list = "default.graph.txt" + self.http_pull ("http://graph.yapb.ru/DEFAULT.txt", default_list) + + with open (default_list) as file: + files = [line.rstrip () for line in file.readlines ()] for file in files: print (" " + file) - self.getGraph (file) + self.get_graph_file (file) - def unlinkBinaries (self): - libs = ['yapb.so', 'yapb.dll', 'yapb.dylib'] + def unlink_binaries (self): + libs = ["yapb.so", "yapb.dll", "yapb.dylib"] for lib in libs: - path = os.path.join (self.botDir, 'bin', lib) + path = os.path.join (self.bot_dir, "bin", lib) if os.path.exists (path): os.remove (path) - - def copyBinary (self, path): - shutil.copy (path, os.path.join (self.botDir, 'bin')) + + def sign_binary (self, binary): + if self.cs.has () and (binary.endswith ("dll") or binary.endswith ("exe")): + print ("Signing {}".format (binary)) + self.cs.sign_file_inplace (binary) + + def copy_binary (self, binary): + dest_path = os.path.join (self.bot_dir, "bin", os.path.basename (binary)) + shutil.copy (binary, dest_path) - def zipDir (self, path, handle): + self.sign_binary (dest_path) + + def compress_directory (self, path, handle): length = len (path) + 1 - emptyDirs = [] + empty_dirs = [] for root, dirs, files in os.walk (path): - emptyDirs.extend ([dir for dir in dirs if os.listdir (os.path.join (root, dir)) == []]) + empty_dirs.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:]) + file_path = os.path.join (root, file) + handle.write (file_path, file_path[length:]) - for dir in emptyDirs: - dirPath = os.path.join (root, dir) + for dir in empty_dirs: + dir_path = os.path.join (root, dir) - zif = zipfile.ZipInfo (dirPath[length:] + "/") + zif = zipfile.ZipInfo (dir_path[length:] + "/") handle.writestr (zif, "") - emptyDirs = [] + empty_dirs = [] - def generateZip (self, dir): - zipFile = zipfile.ZipFile (dir, 'w', zipfile.ZIP_DEFLATED) - zipFile.comment = bytes (self.version, encoding = "ascii") + def create_zip (self, dir): + zf = zipfile.ZipFile (dir, "w", zipfile.ZIP_DEFLATED, compresslevel=9) + zf.comment = bytes (self.version, encoding = "ascii") - self.zipDir (self.workDir, zipFile) - zipFile.close () + self.compress_directory (self.work_dir, zf) + zf.close () - def convertZipToTXZ (self, zip, txz): + def convert_zip_txz (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: + with tarfile.open (txz, "w:xz") as tarf: for zif in zipf.infolist (): tif = tarfile.TarInfo (name = zif.filename) tif.size = zif.file_size @@ -135,91 +231,67 @@ class BotRelease (object): 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') + + def install_binary (self, ext): + lib = "yapb.{}".format (ext) + binary = os.path.join (self.artifacts, lib) + + if os.path.isdir (binary): + binary = os.path.join (binary, lib) if not os.path.exists (binary): - return + print ("Packaging failed for {}. Skipping...", lib) + return False - self.unlinkBinaries () + self.unlink_binaries () + self.copy_binary (binary) + + return True - self.copyBinary (binary) - self.generateZip (self.outFileWin32) + def create_pkg_win32 (self): + print ("Generating Win32 ZIP") - self.download (self.win32SetupUrl, "botsetup.exe") + if not self.install_binary ("dll"): + return + + self.create_zip (self.pkg_win32) + self.http_pull (self.pkg_win32_sfx_url, "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: + with open ("botsetup.exe", "rb") as sfx, open (self.pkg_win32, "rb") as zip, open (self.pkg_win32_sfx, "wb") as exe: exe.write (sfx.read ()) exe.write (zip.read ()) + + self.sign_binary (self.pkg_win32_sfx) - def generateLinux (self): + def create_pkg_linux (self): print ("Generating Linux TXZ") - binary = os.path.join ('build_x86_linux', 'yapb.so'); - - if not os.path.exists (binary): + if not self.install_binary ("so"): return - - self.unlinkBinaries () - self.copyBinary (binary) - tmpFile = "tmp.zip" + tmp_file = "tmp.zip" - self.generateZip (tmpFile) - self.convertZipToTXZ (tmpFile, self.outFileLinux) - - def generateMac (self): + self.create_zip (tmp_file) + self.convert_zip_txz (tmp_file, self.pkg_linux) + + def create_pkg_macos (self): print ("Generating macOS ZIP") - binary = os.path.join ('build_x86_macos', 'yapb.dylib') - - if not os.path.exists (binary): + if not self.install_binary ("dylib"): return - - self.unlinkBinaries () - self.copyBinary (binary) - self.generateZip (self.outFileMacOS) + self.create_zip (self.pkg_macos) - 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; + def create_pkgs (self): + self.create_pkg_linux () + self.create_pkg_win32 () + self.create_pkg_macos () - 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 () -release.getGraphs () -release.generate () -release.uploadGithub () +release.make_directories () +release.get_default_graphs () +release.create_pkgs () + diff --git a/src/linkage.cpp b/src/linkage.cpp index b0d85cc..6915be1 100644 --- a/src/linkage.cpp +++ b/src/linkage.cpp @@ -354,7 +354,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int) { dllapi.pfnServerDeactivate (); // refill export table - ents.clearExportTable (); + ents.flush (); }; table->pfnStartFrame = [] () { @@ -500,7 +500,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) { plat.bzero (table, sizeof (enginefuncs_t)); } - if (ents.isWorkaroundNeeded () && !game.is (GameFlags::Metamod)) { + if (ents.needsBypass () && !game.is (GameFlags::Metamod)) { table->pfnCreateNamedEntity = [] (int classname) -> edict_t * { if (ents.isPaused ()) { @@ -987,7 +987,7 @@ DLSYM_RETURN EntityLinkage::lookup (SharedLibrary::Handle module, const char *fu return reinterpret_cast (m_dlsym (static_cast (handle), function)); }; - if (ents.isWorkaroundNeeded () && !strcmp (function, "CreateInterface")) { + if (ents.needsBypass () && !strcmp (function, "CreateInterface")) { ents.setPaused (true); auto ret = resolve (module); @@ -1025,8 +1025,12 @@ void EntityLinkage::initialize () { } m_dlsym.initialize ("kernel32.dll", "GetProcAddress", DLSYM_FUNCTION); - m_dlsym.install (reinterpret_cast (EntityLinkage::replacement), true); + m_dlsym.install (reinterpret_cast (EntityLinkage::lookupHandler), true); + if (needsBypass ()) { + m_dlclose.initialize ("kernel32.dll", "FreeLibrary", DLCLOSE_FUNCTION); + m_dlclose.install (reinterpret_cast (EntityLinkage::closeHandler), true); + } m_self.locate (&engfuncs); } diff --git a/version_script.lds b/version_script.lds index 0f0065f..dadb05b 100644 --- a/version_script.lds +++ b/version_script.lds @@ -1,10 +1,6 @@ YAPB_ABI_1.0 { global: - Meta_*; - GiveFnptrsToDll; - GetBotAPI; - GetEntityAPI; - GetNewDLLFunctions; + *; local: *; -}; \ No newline at end of file +};