fix: crash when exiting linux listen server (#241)

fix: crash when loading on windows xp (#244)
build: switched to github hosted runners, and get rid of self-hosted
build: windows exe and dll is now code-signed
build: drop support for intel icc compiler
This commit is contained in:
dmitry 2021-09-08 20:09:23 +03:00
commit 1e9bc3cb5f
No known key found for this signature in database
GPG key ID: 8297CE728B7A7E37
9 changed files with 456 additions and 287 deletions

View file

@ -1,51 +1,154 @@
name: YaPB name: build
on: on:
push: push:
branches: [master] branches: [master]
paths-ignore:
- '**.md'
pull_request: pull_request:
branches: [master] types: [opened, reopened, synchronize]
release:
types: [published]
jobs: jobs:
linux: build:
name: Full Build strategy:
runs-on: self-hosted 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: steps:
- uses: actions/checkout@v2 - name: Checkout Repository
uses: actions/checkout@v2
with: with:
submodules: true
fetch-depth: 0 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 - name: Setup Meson
shell: bash
run: | run: |
meson setup build_x86_win32 --cross-file=/actions/meson/windows-msvc-32bit.txt -Db_vscrt=mt python -m pip install --upgrade meson ninja
meson setup build_x86_macos --cross-file=/actions/meson/darwin-clang-32bit.txt
CXX=clang meson setup build_x86_linux
- name: Build Bot - name: Configure Build
shell: bash
run: | run: |
ninja -C build_x86_win32 -v meson setup build
ninja -C build_x86_macos -v
ninja -C build_x86_linux -v
- name: Build Package - name: Compile Source
shell: bash run: |
env: meson compile -v -C build
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - 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: | run: |
meson setup dist meson setup dist
ninja -C dist package ninja -C dist package
env:
CS_CERTIFICATE: ${{ secrets.CS_CERTIFICATE }}
CS_CERTIFICATE_PASSWORD: ${{ secrets.CS_CERTIFICATE_PASSWORD }}
- uses: actions/upload-artifact@v2 - name: Publish Release
name: Upload Artifacts uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with: with:
name: yapb.zip files: pkg/*
path: | env:
build_x86_win32/yapb.dll GITHUB_TOKEN: ${{ secrets.API_TOKEN }}
build_x86_linux/yapb.so
build_x86_macos/yapb.dylib

View file

@ -1,5 +1,5 @@
## YaPB ## 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 ## ☉ 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. 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.

View file

@ -643,10 +643,12 @@ class EntityLinkage : public Singleton <EntityLinkage> {
private: private:
#if defined (CR_WINDOWS) #if defined (CR_WINDOWS)
# define DLSYM_FUNCTION GetProcAddress # define DLSYM_FUNCTION GetProcAddress
# define DLCLOSE_FUNCTION FreeLibrary
# define DLSYM_RETURN FARPROC # define DLSYM_RETURN FARPROC
# define DLSYM_HANDLE HMODULE # define DLSYM_HANDLE HMODULE
#else #else
# define DLSYM_FUNCTION dlsym # define DLSYM_FUNCTION dlsym
# define DLCLOSE_FUNCTION dlclose
# define DLSYM_RETURN SharedLibrary::Handle # define DLSYM_RETURN SharedLibrary::Handle
# define DLSYM_HANDLE SharedLibrary::Handle # define DLSYM_HANDLE SharedLibrary::Handle
#endif #endif
@ -655,6 +657,7 @@ private:
bool m_paused { false }; bool m_paused { false };
Detour <decltype (DLSYM_FUNCTION)> m_dlsym; Detour <decltype (DLSYM_FUNCTION)> m_dlsym;
Detour <decltype (DLCLOSE_FUNCTION)> m_dlclose;
HashMap <StringRef, DLSYM_RETURN> m_exports; HashMap <StringRef, DLSYM_RETURN> m_exports;
SharedLibrary m_self; SharedLibrary m_self;
@ -666,6 +669,15 @@ public:
void initialize (); void initialize ();
DLSYM_RETURN lookup (SharedLibrary::Handle module, const char *function); 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: public:
void callPlayerFunction (edict_t *ent) { void callPlayerFunction (edict_t *ent) {
#if defined (CR_ANDROID) && defined (CR_ARCH_ARM) #if defined (CR_ANDROID) && defined (CR_ARCH_ARM)
@ -699,16 +711,20 @@ public:
} }
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); return EntityLinkage::instance ().lookup (module, function);
} }
static int CR_STDCALL closeHandler (DLSYM_HANDLE module) {
return EntityLinkage::instance ().close (module);
}
public: public:
void clearExportTable () { void flush () {
m_exports.clear (); m_exports.clear ();
} }
bool isWorkaroundNeeded () { bool needsBypass () const {
return !plat.win && !Game::instance ().isDedicated (); return !plat.win && !Game::instance ().isDedicated ();
} }
}; };

View file

@ -9,12 +9,12 @@
// generated by meson build system // generated by meson build system
#ifndef MODULE_BUILD_HASH #ifndef MODULE_BUILD_HASH
# define MODULE_BUILD_HASH "@commitHash@" # define MODULE_BUILD_HASH "@hash@"
# define MODULE_BUILD_AUTHOR @commitAuthor@ # define MODULE_BUILD_AUTHOR @author@
# define MODULE_BUILD_COUNT "@commitCount@" # define MODULE_BUILD_COUNT "@count@"
# define MODULE_BUILD_MACHINE "@buildMachine@" # define MODULE_BUILD_MACHINE "@machine@"
# define MODULE_BUILD_COMPILER "@buildCompiler@" # define MODULE_BUILD_COMPILER "@compiler@"
# define MODULE_BOT_VERSION "@buildVersion@" # define MODULE_BOT_VERSION "@version@"
# define MODULE_BOT_VERSION_FILE @buildVersionWin@,@commitCount@ # define MODULE_BOT_VERSION_FILE @version_win@,@count@
# define MODULE_BOT_BUILD_ID "@commitCount@:@commitHash@" # define MODULE_BOT_BUILD_ID "@count@:@hash@"
#endif #endif

View file

@ -1147,12 +1147,12 @@ public:
template <typename ...Args> void issueCommand (const char *fmt, Args &&...args); template <typename ...Args> void issueCommand (const char *fmt, Args &&...args);
}; };
#include <config.h> #include "config.h"
#include <support.h> #include "support.h"
#include <message.h> #include "message.h"
#include <engine.h> #include "engine.h"
#include <manager.h> #include "manager.h"
#include <control.h> #include "control.h"
// very global convars // very global convars
extern ConVar cv_jasonmode; extern ConVar cv_jasonmode;

View file

@ -22,55 +22,59 @@ project (
'strip=true', 'strip=true',
'optimization=3', 'optimization=3',
'default_library=static', '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 ('ninja', required: true)
find_program ('git', required: true) find_program ('git', required: true)
find_program ('hostname', required: true) find_program ('hostname', required: true)
buildCompiler = meson.get_compiler ('cpp') cpp = meson.get_compiler ('cpp')
buildSystem = host_machine.system () sys = host_machine.system ()
buildVersion = meson.project_version () version = meson.project_version ()
buildCount = run_command ('git', 'rev-list', '--count', 'HEAD').stdout ().strip () count = run_command ('git', 'rev-list', '--count', 'HEAD').stdout ().strip ()
compilerId = buildCompiler.get_id () cpp_id = cpp.get_id ()
compilerVersion = buildCompiler.version () cpp_version = cpp.version ()
isOptimize = get_option ('buildtype') == 'release' or get_option ('buildtype') == 'debugoptimized' optmize = get_option ('buildtype') == 'release' or get_option ('buildtype') == 'debugoptimized'
isVC = compilerId == 'msvc' or compilerId == 'intel-cl' or compilerId == 'clang-cl'
isGCC = compilerId == 'gcc' msvc = cpp_id == 'msvc' or cpp_id == 'clang-cl'
isIntel = compilerId == 'intel' or compilerId == 'intel-cl' gcc = cpp_id == 'gcc'
isCLang = compilerId == 'clang' clang = cpp_id == 'clang'
isWindows = buildSystem == 'windows'
isLinux = buildSystem == 'linux' win32 = sys == 'windows'
isDarwin = buildSystem == 'darwin' linux = sys == 'linux'
mac = sys == 'darwin'
ldflags = [] ldflags = []
ccflags = [] ccflags = []
cdata = configuration_data() cdata = configuration_data()
if isWindows if win32
cdata.set ('buildVersionWin', ','.join (buildVersion.split ('.'))) cdata.set ('version_win', ','.join (version.split ('.')))
cdata.set ('machine', run_command ('hostname').stdout ().strip ())
else else
cdata.set ('buildVersionWin', buildVersion) cdata.set ('version_win', version)
cdata.set ('machine', run_command ('hostname', '-f').stdout ().strip ())
endif endif
cdata.set ('commitHash', run_command ('git', 'rev-parse', '--short', 'HEAD').stdout ().strip ()) cdata.set ('hash', run_command ('git', 'rev-parse', '--short', 'HEAD').stdout ().strip ())
cdata.set ('commitAuthor', run_command ('git', 'log', '--pretty="%ae"', '-1').stdout ().strip ()) cdata.set ('author', run_command ('git', 'log', '--pretty="%ae"', '-1').stdout ().strip ())
cdata.set ('commitCount', buildCount) cdata.set ('count', count)
cdata.set ('buildVersion', buildVersion) cdata.set ('version', version)
cdata.set ('buildMachine', run_command ('hostname', '-f').stdout ().strip ())
cdata.set ('buildCompiler', compilerId + ' ' + compilerVersion) cdata.set ('compiler', cpp_id + ' ' + cpp_version)
configure_file (input: 'inc/version.h.in', output: 'version.build.h', configuration: cdata) configure_file (input: 'inc/version.h.in', output: 'version.build.h', configuration: cdata)
ccflags += '-DVERSION_GENERATED' ccflags += '-DVERSION_GENERATED'
if isCLang or isGCC or (isIntel and not isWindows) if clang or gcc
ccflags += [ ccflags += [
'-m32', '-m32',
'-fno-threadsafe-statics', '-fno-threadsafe-statics',
@ -78,36 +82,32 @@ if isCLang or isGCC or (isIntel and not isWindows)
'-fno-rtti' '-fno-rtti'
] ]
if not isDarwin if not mac
ccflags += [ ccflags += [
'-pedantic', '-pedantic',
] ]
endif endif
if isOptimize if optmize
ccflags += '-msse3' if (clang or gcc) and not mac
if (isCLang or isGCC) and not isDarwin
ccflags += [ ccflags += [
'-flto', '-flto',
'-fdata-sections', '-fdata-sections',
'-ffunction-sections' '-ffunction-sections'
] ]
if isGCC if gcc
ccflags += '-fgraphite-identity' ccflags += '-fgraphite-identity'
ldflags += '-flto-partition=none' ldflags += '-flto-partition=none'
endif endif
ldflags += [ ldflags += [
'-flto', '-flto'
'-Wl,--version-script=../version_script.lds',
'-Wl,--gc-sections'
] ]
endif endif
endif endif
if isLinux if linux
ldflags += [ ldflags += [
'-m32', '-m32',
'-lm', '-lm',
@ -116,18 +116,10 @@ if isCLang or isGCC or (isIntel and not isWindows)
endif endif
endif endif
if isIntel and (isLinux or isDarwin) if linux or mac or (win32 and (gcc or clang))
ldflags += [ if mac
'-static-intel',
'-no-intel-extensions'
]
endif
if isLinux or isDarwin
if isDarwin
ccflags += '-mmacosx-version-min=10.9' ccflags += '-mmacosx-version-min=10.9'
ldflags += [ ldflags += [
'-dynamiclib',
'-lstdc++', '-lstdc++',
'-mmacosx-version-min=10.9' '-mmacosx-version-min=10.9'
] ]
@ -135,7 +127,7 @@ if isLinux or isDarwin
ldflags += '-static-libgcc' ldflags += '-static-libgcc'
endif endif
if not isOptimize if not optmize
ccflags += [ ccflags += [
'-g3', '-g3',
'-ggdb', '-ggdb',
@ -144,7 +136,7 @@ if isLinux or isDarwin
else else
ccflags += [ ccflags += [
'-mtune=generic', '-mtune=generic',
'-msse3', '-msse2',
'-mfpmath=sse', '-mfpmath=sse',
'-fno-builtin', '-fno-builtin',
'-funroll-loops', '-funroll-loops',
@ -154,38 +146,24 @@ if isLinux or isDarwin
'-fvisibility-inlines-hidden' '-fvisibility-inlines-hidden'
] ]
if isIntel if clang and not mac
ccflags += [ lld = find_program ('lld', required: false)
'-ipo',
'-wd11076',
'-wd11074'
]
ldflags += [ if lld.found () == true
'-cxxlib-nostd', ldflags += '-fuse-ld=' + lld.full_path ().split ('/')[-1]
'-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 endif
ldflags += [ ldflags += [
'-nostdlib++', '-nostdlib++',
'-Wunused-command-line-argument', '-Wunused-command-line-argument'
'-Wl,-z,notext',
'--no-undefined'
] ]
elif isGCC and not isDarwin elif gcc and not mac
ldflags += '-Wl,--no-undefined' ldflags += '-Wl,--no-undefined'
endif endif
endif endif
endif endif
if isWindows and (isVC or isIntel) if win32 and msvc
ldflags += [ ldflags += [
'/MACHINE:X86', '/MACHINE:X86',
'user32.lib', 'user32.lib',
@ -193,32 +171,34 @@ if isWindows and (isVC or isIntel)
] ]
ccflags += [ ccflags += [
'/TP' '/TP',
'/D _WIN32_WINNT=0x0501',
'/D _USING_V110_SDK71_',
'/Zc:threadSafeInit-'
] ]
if isOptimize if optmize
ccflags += [ ccflags += [
'/GL', '/GL',
'/arch:SSE2',
'/GS-', '/GS-',
'/Ob2', '/Ob2',
'/Oy', '/Oy',
'/Oi' '/Oi',
'/Ot',
'/fp:precise',
'/GF'
] ]
ldflags += '/LTCG'
endif
elif isWindows and (isCLang or isGCC)
if isCLang
ldflags += '-Wl,/MACHINE:X86'
else
ldflags += [ ldflags += [
'-static-libgcc', '/LTCG',
'-Wl,--kill-at' 'delayimp.lib',
'/DELAYLOAD:user32.dll',
'/SUBSYSTEM:WINDOWS,5.01',
] ]
endif endif
elif win32 and (clang or gcc)
ldflags += [ ldflags += [
'-Wl,--kill-at',
'-luser32', '-luser32',
'-lws2_32' '-lws2_32'
] ]
@ -228,7 +208,6 @@ add_global_arguments (ccflags, language: 'cpp')
add_global_link_arguments (ldflags, language: 'cpp') add_global_link_arguments (ldflags, language: 'cpp')
sources = files ( sources = files (
'src/android.cpp',
'src/botlib.cpp', 'src/botlib.cpp',
'src/chatlib.cpp', 'src/chatlib.cpp',
'src/combat.cpp', 'src/combat.cpp',
@ -245,10 +224,10 @@ sources = files (
) )
includes = include_directories ([ includes = include_directories ([
'.', 'inc', 'ext', '.', 'inc', 'ext', 'ext/crlib'
], is_system: true) ], is_system: true)
if isWindows and not isCLang if win32
sources += import('windows').compile_resources ( sources += import('windows').compile_resources (
'vc/yapb.rc', 'vc/yapb.rc',
include_directories: includes, include_directories: includes,
@ -260,9 +239,8 @@ shared_library (
meson.project_name (), meson.project_name (),
sources, sources,
include_directories: includes, include_directories: includes,
gnu_symbol_visibility: 'hidden', gnu_symbol_visibility: 'hidden',
name_prefix: '') name_prefix: '')
run_target ('package', run_target ('package',
command : ['python', meson.source_root() + '/package.py', '@0@.@1@'.format (buildVersion, buildCount)]) command: ['python3', meson.project_source_root () + '/package.py', '@0@.@1@'.format (version, count)])

View file

@ -6,127 +6,223 @@
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
# #
import os, sys, subprocess from genericpath import isdir
import os, sys, subprocess, base64
import locale, urllib3 import locale, urllib3
import pathlib, shutil import pathlib, shutil
import zipfile, tarfile import zipfile, tarfile
import datetime, calendar 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): class BotRelease (object):
def __init__(self): def __init__(self):
print ("Initializing Packaging") print ("Initializing Packaging")
self.workDir = os.path.join (pathlib.Path ().absolute (), 'cfg') meson_src_root_env = "MESON_SOURCE_ROOT"
self.botDir = os.path.join (self.workDir, 'addons', 'yapb')
self.distDir = os.path.join (pathlib.Path ().absolute (), 'dist'); if meson_src_root_env in os.environ:
os.chdir (os.environ.get (meson_src_root_env))
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: if len (sys.argv) < 2:
raise Exception('Missing required parameters.') raise Exception("Missing required parameters.")
self.version = sys.argv[1] self.version = sys.argv[1]
self.artifacts = 'artifacts'
os.makedirs (self.distDir, exist_ok=True) self.cs = CodeSign ("YaPB", "https://yapb.ru/")
self.outFileWin32 = os.path.join (self.distDir, "yapb-{}-windows.zip".format (self.version)) if self.cs.has ():
self.outFileLinux = os.path.join (self.distDir, "yapb-{}-linux.tar.xz".format (self.version)) print ("Code Signing Enabled")
self.outFileMacOS = os.path.join (self.distDir, "yapb-{}-macos.zip".format (self.version)) else:
print ("Code Signing Disabled")
self.outFileWin32Setup = self.outFileWin32.replace ("zip", "exe") os.makedirs (self.pkg_dir, exist_ok=True)
self.win32SetupUrl = "https://github.com/yapb/setup/releases/latest/download/botsetup.exe"
def makeDirs (self): 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"
def make_directories (self):
dirs = [ dirs = [
'bin', "bin",
os.path.join ('data', 'pwf'), os.path.join ("data", "pwf"),
os.path.join ('data', 'train'), os.path.join ("data", "train"),
os.path.join ('data', 'graph'), os.path.join ("data", "graph"),
os.path.join ('data', 'logs') os.path.join ("data", "logs")
] ]
for dir in dirs: 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"}) 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) file.write (data.data)
def getGraph (self, name): def get_graph_file (self, name):
file = os.path.join (self.botDir, 'data', 'graph', "{}.graph".format (name)) file = os.path.join (self.bot_dir, "data", "graph", "{}.graph".format (name))
url = "http://graph.yapb.ru/graph/{}.graph".format (name); url = "http://graph.yapb.ru/graph/{}.graph".format (name)
if os.path.exists (file): if os.path.exists (file):
return return
self.download (url, file) self.http_pull (url, file)
def getGraphs (self): def get_default_graphs (self):
print ("Downloading graphs: ") print ("Downloading graphs: ")
files = ['as_oilrig', 'cs_747', 'cs_estate', 'cs_assault', 'cs_office', default_list = "default.graph.txt"
'cs_italy', 'cs_havana', 'cs_siege', 'cs_backalley', 'cs_militia', self.http_pull ("http://graph.yapb.ru/DEFAULT.txt", default_list)
'cs_downed_cz', 'cs_havana_cz', 'cs_italy_cz', 'cs_militia_cz',
'cs_office_cz', 'de_airstrip_cz', 'de_aztec_cz', 'de_cbble_cz', with open (default_list) as file:
'de_chateau_cz', 'de_corruption_cz', 'de_dust_cz', 'de_dust2_cz', files = [line.rstrip () for line in file.readlines ()]
'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: for file in files:
print (" " + file) print (" " + file)
self.getGraph (file) self.get_graph_file (file)
def unlinkBinaries (self): def unlink_binaries (self):
libs = ['yapb.so', 'yapb.dll', 'yapb.dylib'] libs = ["yapb.so", "yapb.dll", "yapb.dylib"]
for lib in libs: 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): if os.path.exists (path):
os.remove (path) os.remove (path)
def copyBinary (self, path): def sign_binary (self, binary):
shutil.copy (path, os.path.join (self.botDir, 'bin')) if self.cs.has () and (binary.endswith ("dll") or binary.endswith ("exe")):
print ("Signing {}".format (binary))
self.cs.sign_file_inplace (binary)
def zipDir (self, path, handle): def copy_binary (self, binary):
dest_path = os.path.join (self.bot_dir, "bin", os.path.basename (binary))
shutil.copy (binary, dest_path)
self.sign_binary (dest_path)
def compress_directory (self, path, handle):
length = len (path) + 1 length = len (path) + 1
emptyDirs = [] empty_dirs = []
for root, dirs, files in os.walk (path): 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: for file in files:
filePath = os.path.join (root, file) file_path = os.path.join (root, file)
handle.write (filePath, filePath[length:]) handle.write (file_path, file_path[length:])
for dir in emptyDirs: for dir in empty_dirs:
dirPath = os.path.join (root, dir) dir_path = os.path.join (root, dir)
zif = zipfile.ZipInfo (dirPath[length:] + "/") zif = zipfile.ZipInfo (dir_path[length:] + "/")
handle.writestr (zif, "") handle.writestr (zif, "")
emptyDirs = [] empty_dirs = []
def generateZip (self, dir): def create_zip (self, dir):
zipFile = zipfile.ZipFile (dir, 'w', zipfile.ZIP_DEFLATED) zf = zipfile.ZipFile (dir, "w", zipfile.ZIP_DEFLATED, compresslevel=9)
zipFile.comment = bytes (self.version, encoding = "ascii") zf.comment = bytes (self.version, encoding = "ascii")
self.zipDir (self.workDir, zipFile) self.compress_directory (self.work_dir, zf)
zipFile.close () zf.close ()
def convertZipToTXZ (self, zip, txz): def convert_zip_txz (self, zip, txz):
timeshift = int ((datetime.datetime.now () - datetime.datetime.utcnow ()).total_seconds ()) timeshift = int ((datetime.datetime.now () - datetime.datetime.utcnow ()).total_seconds ())
with zipfile.ZipFile (zip) as zipf: 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 (): for zif in zipf.infolist ():
tif = tarfile.TarInfo (name = zif.filename) tif = tarfile.TarInfo (name = zif.filename)
tif.size = zif.file_size tif.size = zif.file_size
@ -136,90 +232,66 @@ class BotRelease (object):
os.remove (zip) os.remove (zip)
def generateWin32 (self): def install_binary (self, ext):
print ("Generating Win32 ZIP") lib = "yapb.{}".format (ext)
binary = os.path.join (self.artifacts, lib)
binary = os.path.join ('build_x86_win32', 'yapb.dll') if os.path.isdir (binary):
binary = os.path.join (binary, lib)
if not os.path.exists (binary): if not os.path.exists (binary):
print ("Packaging failed for {}. Skipping...", lib)
return False
self.unlink_binaries ()
self.copy_binary (binary)
return True
def create_pkg_win32 (self):
print ("Generating Win32 ZIP")
if not self.install_binary ("dll"):
return return
self.unlinkBinaries () self.create_zip (self.pkg_win32)
self.http_pull (self.pkg_win32_sfx_url, "botsetup.exe")
self.copyBinary (binary)
self.generateZip (self.outFileWin32)
self.download (self.win32SetupUrl, "botsetup.exe")
print ("Generating Win32 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 (sfx.read ())
exe.write (zip.read ()) exe.write (zip.read ())
def generateLinux (self): self.sign_binary (self.pkg_win32_sfx)
def create_pkg_linux (self):
print ("Generating Linux TXZ") print ("Generating Linux TXZ")
binary = os.path.join ('build_x86_linux', 'yapb.so'); if not self.install_binary ("so"):
if not os.path.exists (binary):
return return
self.unlinkBinaries () tmp_file = "tmp.zip"
self.copyBinary (binary)
tmpFile = "tmp.zip" self.create_zip (tmp_file)
self.convert_zip_txz (tmp_file, self.pkg_linux)
self.generateZip (tmpFile) def create_pkg_macos (self):
self.convertZipToTXZ (tmpFile, self.outFileLinux)
def generateMac (self):
print ("Generating macOS ZIP") print ("Generating macOS ZIP")
binary = os.path.join ('build_x86_macos', 'yapb.dylib') if not self.install_binary ("dylib"):
if not os.path.exists (binary):
return return
self.unlinkBinaries () self.create_zip (self.pkg_macos)
self.copyBinary (binary)
self.generateZip (self.outFileMacOS) def create_pkgs (self):
self.create_pkg_linux ()
def generate (self): self.create_pkg_win32 ()
self.generateWin32 () self.create_pkg_macos ()
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)
release = BotRelease () release = BotRelease ()
release.makeDirs () release.make_directories ()
release.getGraphs () release.get_default_graphs ()
release.generate () release.create_pkgs ()
release.uploadGithub ()

View file

@ -354,7 +354,7 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int) {
dllapi.pfnServerDeactivate (); dllapi.pfnServerDeactivate ();
// refill export table // refill export table
ents.clearExportTable (); ents.flush ();
}; };
table->pfnStartFrame = [] () { table->pfnStartFrame = [] () {
@ -500,7 +500,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
plat.bzero (table, sizeof (enginefuncs_t)); 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 * { table->pfnCreateNamedEntity = [] (int classname) -> edict_t * {
if (ents.isPaused ()) { if (ents.isPaused ()) {
@ -987,7 +987,7 @@ DLSYM_RETURN EntityLinkage::lookup (SharedLibrary::Handle module, const char *fu
return reinterpret_cast <DLSYM_RETURN> (m_dlsym (static_cast <DLSYM_HANDLE> (handle), function)); return reinterpret_cast <DLSYM_RETURN> (m_dlsym (static_cast <DLSYM_HANDLE> (handle), function));
}; };
if (ents.isWorkaroundNeeded () && !strcmp (function, "CreateInterface")) { if (ents.needsBypass () && !strcmp (function, "CreateInterface")) {
ents.setPaused (true); ents.setPaused (true);
auto ret = resolve (module); auto ret = resolve (module);
@ -1025,8 +1025,12 @@ void EntityLinkage::initialize () {
} }
m_dlsym.initialize ("kernel32.dll", "GetProcAddress", DLSYM_FUNCTION); m_dlsym.initialize ("kernel32.dll", "GetProcAddress", DLSYM_FUNCTION);
m_dlsym.install (reinterpret_cast <void *> (EntityLinkage::replacement), true); m_dlsym.install (reinterpret_cast <void *> (EntityLinkage::lookupHandler), true);
if (needsBypass ()) {
m_dlclose.initialize ("kernel32.dll", "FreeLibrary", DLCLOSE_FUNCTION);
m_dlclose.install (reinterpret_cast <void *> (EntityLinkage::closeHandler), true);
}
m_self.locate (&engfuncs); m_self.locate (&engfuncs);
} }

View file

@ -1,10 +1,6 @@
YAPB_ABI_1.0 { YAPB_ABI_1.0 {
global: global:
Meta_*; *;
GiveFnptrsToDll;
GetBotAPI;
GetEntityAPI;
GetNewDLLFunctions;
local: local:
*; *;
}; };