Compare commits
	
		
			17 Commits
		
	
	
		
			1.11-fork-
			...
			1.10-fork
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 178202a5b3 | ||
|  | 60f3268236 | ||
|  | 64b3c8fbd8 | ||
|  | 4c4629fca7 | ||
|  | 8749877c62 | ||
|  | 102b01c626 | ||
|  | 8e07790997 | ||
|  | a701408c71 | ||
|  | 2d0fff79a8 | ||
|  | 9da44d67f1 | ||
|  | 1847f5e2dc | ||
|  | 0dd3361050 | ||
|  | 11d12aad11 | ||
|  | 8ac0c18674 | ||
|  | a0b8153f4b | ||
|  | a363587be9 | ||
|  | fdcce81a41 | 
							
								
								
									
										98
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										98
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @ -1,98 +0,0 @@ | ||||
| name: Continuous Integration | ||||
| on:  | ||||
|   push: | ||||
|     branches: | ||||
|      - master | ||||
|      - '[0-9]+.[0-9]+-dev' | ||||
|   pull_request: | ||||
|     branches: | ||||
|      - master | ||||
|      - '[0-9]+.[0-9]+-dev' | ||||
| jobs: | ||||
|   test: | ||||
|     strategy: | ||||
|       matrix: | ||||
|         os: [ubuntu-18.04, ubuntu-latest, windows-latest] | ||||
|         include: | ||||
|           - os: windows-latest | ||||
|             os_short: win | ||||
|             compiler_cc: msvc | ||||
|           - os: ubuntu-latest | ||||
|             os_short: linux | ||||
|             compiler_cc: clang | ||||
|             compiler_cxx: clang++ | ||||
|           - os: ubuntu-18.04 | ||||
|             os_short: linux | ||||
|             compiler_cc: clang-8 | ||||
|             compiler_cxx: clang++-8 | ||||
|       fail-fast: false | ||||
|     runs-on: ${{ matrix.os }} | ||||
|     name: ${{ matrix.os_short }}-${{ matrix.compiler_cc }} | ||||
|     env: | ||||
|       SDKS: '["episode1","css","tf2","l4d2","csgo"]' | ||||
|       ARCH: x86,x86_64 | ||||
|       DEPENDENCIES_FOLDER: dependencies | ||||
|       DEPENDENCIES_ROOT: ${{ github.workspace }}/dependencies | ||||
|       MYSQL_VERSION: '5.5' | ||||
|       MMSOURCE_VERSION: '1.10' | ||||
|     steps: | ||||
|       - uses: actions/checkout@v2 | ||||
|         with: | ||||
|           submodules: recursive | ||||
|           path: sourcemod | ||||
| 
 | ||||
|       - name: Cache dependencies | ||||
|         uses: actions/cache@v2 | ||||
|         env: | ||||
|           cache-name: hl2sdk-mysql-mmsource | ||||
|         with: | ||||
|           path: ${{ env.DEPENDENCIES_ROOT }} | ||||
|           key: ${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-mmsource${{ env.MMSOURCE_VERSION }}-${{ join(fromJSON(env.SDKS), '') }} | ||||
|           restore-keys: | | ||||
|             ${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-mmsource${{ env.MMSOURCE_VERSION }}- | ||||
|             ${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}- | ||||
| 
 | ||||
|       # Setup Python for AMBuild | ||||
|       - uses: actions/setup-python@v2 | ||||
|         name: Setup Python 3.8 | ||||
|         with: | ||||
|           python-version: 3.8 | ||||
|       - name: Install Python dependencies | ||||
|         run: | | ||||
|           python -m pip install --upgrade pip setuptools wheel | ||||
| 
 | ||||
|       - name: Install dependencies | ||||
|         shell: bash | ||||
|         run: | | ||||
|           mkdir -p ${{ env.DEPENDENCIES_FOLDER }} | ||||
|           cd ${{ env.DEPENDENCIES_FOLDER }} | ||||
| 
 | ||||
|           # Satisfy checkout-deps requirement for a "sourcemod" folder. | ||||
|           mkdir -p sourcemod | ||||
|           ../sourcemod/tools/checkout-deps.sh -s ${{ join(fromJSON(env.SDKS)) }} | ||||
| 
 | ||||
|       - name: Install Linux dependencies | ||||
|         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 lib32z1-dev ${{ matrix.compiler_cc }} | ||||
| 
 | ||||
|       - name: Select clang compiler | ||||
|         if: startsWith(runner.os, 'Linux') | ||||
|         run: | | ||||
|           echo "CC=${{ matrix.compiler_cc }}" >> $GITHUB_ENV | ||||
|           echo "CXX=${{ matrix.compiler_cxx }}" >> $GITHUB_ENV | ||||
|           ${{ matrix.compiler_cc }} --version | ||||
|           ${{ matrix.compiler_cxx }} --version | ||||
| 
 | ||||
|       - name: Build | ||||
|         working-directory: sourcemod | ||||
|         run: | | ||||
|           mkdir build | ||||
|           cd build | ||||
|           python ../configure.py --enable-optimize --sdks=${{ join(fromJSON(env.SDKS)) }} --targets=${{ env.ARCH }} --mms-path=${{ env.DEPENDENCIES_ROOT }}/mmsource-${{ env.MMSOURCE_VERSION }} --hl2sdk-root=${{ env.DEPENDENCIES_ROOT }} --mysql-path=${{ env.DEPENDENCIES_ROOT }}/mysql-${{ env.MYSQL_VERSION }} --mysql64-path=${{ env.DEPENDENCIES_ROOT }}/mysql-${{ env.MYSQL_VERSION }}-x86_64 | ||||
|           ambuild | ||||
							
								
								
									
										79
									
								
								.github/workflows/scripting.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										79
									
								
								.github/workflows/scripting.yml
									
									
									
									
										vendored
									
									
								
							| @ -1,79 +0,0 @@ | ||||
| name: SourcePawn scripting | ||||
| on:  | ||||
|   push: | ||||
|     branches: | ||||
|       - master | ||||
|       - '[0-9]+.[0-9]+-dev' | ||||
|     paths: | ||||
|       - 'plugins/include/*' | ||||
|       - 'sourcepawn/**' | ||||
|   workflow_dispatch: | ||||
|   schedule: | ||||
|     - cron: '53 05 01 */3 *' # Artifacts expire every 3 months | ||||
| jobs: | ||||
|   build: | ||||
|     strategy: | ||||
|       matrix: | ||||
|         os: [ubuntu-latest, windows-latest, macos-latest] | ||||
|         include: | ||||
|           - os: ubuntu-latest | ||||
|             os_short: linux | ||||
|           - os: windows-latest | ||||
|             os_short: win | ||||
|           - os: macos-latest | ||||
|             os_short: mac | ||||
|       fail-fast: false | ||||
|     runs-on: ${{ matrix.os }} | ||||
|     env: | ||||
|       ARCH: x86,x86_64 | ||||
|     steps: | ||||
|       - uses: actions/checkout@v2 | ||||
|         with: | ||||
|           submodules: recursive | ||||
| 
 | ||||
|       # Setup Python for AMBuild | ||||
|       - uses: actions/setup-python@v2 | ||||
|         name: Setup Python 3.8 | ||||
|         with: | ||||
|           python-version: 3.8 | ||||
|       - name: Install AMBuild | ||||
|         run: | | ||||
|           python -m pip install --upgrade pip setuptools wheel | ||||
|           pip install git+https://github.com/alliedmodders/ambuild | ||||
| 
 | ||||
|       - name: Build only for x64 on macOS | ||||
|         if: startsWith(runner.os, 'macOS') | ||||
|         run: echo "ARCH=x86_64" >> $GITHUB_ENV | ||||
| 
 | ||||
|       - name: Install Linux dependencies | ||||
|         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 lib32z1-dev ${{ matrix.compiler_cc }} | ||||
| 
 | ||||
|       - name: Select clang compiler | ||||
|         if: startsWith(runner.os, 'Linux') || startsWith(runner.os, 'macOS') | ||||
|         run: | | ||||
|           echo "CC=clang" >> $GITHUB_ENV | ||||
|           echo "CXX=clang++" >> $GITHUB_ENV | ||||
|           clang --version | ||||
|           clang++ --version | ||||
| 
 | ||||
|       - name: Build | ||||
|         shell: bash | ||||
|         run: | | ||||
|           mkdir build | ||||
|           cd build | ||||
|           python ../configure.py --enable-optimize --scripting-only --targets=${{ env.ARCH }} | ||||
|           ambuild | ||||
|           echo "SM_VERSION=$(cat ../product.version)" >> $GITHUB_ENV | ||||
| 
 | ||||
|       - name: Archive tooling | ||||
|         uses: actions/upload-artifact@v2 | ||||
|         with: | ||||
|           name: sourcemod-tooling-${{ env.SM_VERSION }}-${{ matrix.os_short }} | ||||
|           path: build/package | ||||
							
								
								
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -28,7 +28,7 @@ LIB-Debug/ | ||||
| [Tt]humbs.db | ||||
| 
 | ||||
| # AMBuild build directories | ||||
| build*/ | ||||
| build/ | ||||
| obj-*/ | ||||
| *~ | ||||
| *.rej | ||||
| @ -36,7 +36,3 @@ obj-*/ | ||||
| *.smx | ||||
| *.swp | ||||
| *.gdb_history | ||||
| objdir | ||||
| 
 | ||||
| .vs/* | ||||
| .vscode/* | ||||
							
								
								
									
										4
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @ -1,8 +1,6 @@ | ||||
| [submodule "public/amtl"] | ||||
| 	path = public/amtl | ||||
| 	url = https://github.com/alliedmodders/amtl | ||||
| 	shallow = true | ||||
| [submodule "sourcepawn"] | ||||
| 	path = sourcepawn | ||||
| 	url = https://github.com/alliedmodders/sourcepawn | ||||
| 	shallow = true | ||||
| 	url = https://github.com/BotoX/sourcepawn.git | ||||
|  | ||||
							
								
								
									
										146
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										146
									
								
								.travis.yml
									
									
									
									
									
								
							| @ -1,86 +1,118 @@ | ||||
| git: | ||||
|   depth: 3 | ||||
| 
 | ||||
| sudo: false | ||||
| language: cpp | ||||
| os: linux | ||||
| dist: xenial | ||||
| dist: trusty | ||||
| addons: | ||||
|   apt: | ||||
|     sources: | ||||
|       - ubuntu-toolchain-r-test | ||||
|       - llvm-toolchain-trusty-3.9 | ||||
|       - llvm-toolchain-trusty-4.0 | ||||
|       - llvm-toolchain-trusty-5.0 | ||||
|     packages: | ||||
|       - lib32stdc++6 | ||||
|       - lib32z1-dev | ||||
|       - libc6-dev-i386 | ||||
|       - linux-libc-dev | ||||
|       - g++-multilib | ||||
| #      - clang-3.6 | ||||
| #      - clang-3.8 | ||||
| #      - clang-4.0 | ||||
| #      - clang-5.0 | ||||
| #      - g++-6 | ||||
| #      - g++-6-multilib | ||||
|       - clang-3.9 | ||||
|       - g++-4.8-multilib | ||||
|       - g++-4.8 | ||||
|       - g++-4.9-multilib | ||||
|       - g++-4.9 | ||||
|       - g++-5-multilib | ||||
|       - g++-5 | ||||
|       - g++-7-multilib | ||||
|       - g++-7 | ||||
|     cache: | ||||
|       directories: | ||||
|         - ../mysql-5.0 | ||||
| env: | ||||
|  - MATRIX_EVAL="CC=clang-3.9 && CXX=clang++-3.9" | ||||
|  - MATRIX_EVAL="CC=gcc-4.8 && CXX=g++-4.8" | ||||
|  - MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9" | ||||
|  - MATRIX_EVAL="CC=gcc-5 && CXX=g++-5" | ||||
|  - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" | ||||
| 
 | ||||
| jobs: | ||||
| matrix: | ||||
|   fast_finish: true | ||||
|   include: | ||||
|     - os: linux | ||||
|       dist: trusty | ||||
|       sudo: false | ||||
|       language: cpp | ||||
|       addons: | ||||
|         apt: | ||||
|           sources: | ||||
|             - ubuntu-toolchain-r-test | ||||
|           packages: ['clang-3.8', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-4.9-multilib', 'python3-pip'] | ||||
|       env: | ||||
|         - MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8" | ||||
|         - SDKS=episode1,css,tf2,l4d2,csgo | ||||
|         - MODE=optimize | ||||
|         - ARCH=x86,x86_64 | ||||
|           packages: ['clang-3.6', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib'] | ||||
|         cache: | ||||
|           directories: ['../mysql-5.0'] | ||||
|       env: ['MATRIX_EVAL="CC=clang-3.6 && CXX=clang++-3.6"'] | ||||
| 
 | ||||
|     - os: linux | ||||
|       dist: trusty | ||||
|       sudo: false | ||||
|       language: cpp | ||||
|       addons: | ||||
|         apt: | ||||
|           sources: | ||||
|             - ubuntu-toolchain-r-test | ||||
|           packages: ['clang-3.4', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-4.9-multilib', 'python3-pip'] | ||||
|       env: | ||||
|         - MATRIX_EVAL="CC=clang && CXX=clang++" | ||||
|         - SDKS=episode1,css,tf2,l4d2,csgo | ||||
|         - MODE=optimize | ||||
|         - ARCH=x86,x86_64 | ||||
|           packages: ['clang-3.8', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib'] | ||||
|         cache: | ||||
|           directories: ['../mysql-5.0'] | ||||
|       env: ['MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8"'] | ||||
| 
 | ||||
|     - os: osx | ||||
|       osx_image: xcode7.2 | ||||
|       language: cpp | ||||
|       env: | ||||
|         - MATRIX_EVAL="CC=clang && CXX=clang++" | ||||
|         - SDKS=episode1,css,tf2,l4d2,csgo | ||||
|         - MODE=optimize | ||||
|         - ARCH=x86_64,x86 | ||||
| 
 | ||||
|     # # This is a faster test for the latest g++. | ||||
|     # - os: linux | ||||
|     #   dist: bionic | ||||
|     #   sudo: false | ||||
|     #   language: cpp | ||||
|     #   addons: | ||||
|     #     apt: | ||||
|     #       packages: ['lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-multilib', 'g++'] | ||||
|     #     cache: | ||||
|     #       directories: ['../mysql-5.0'] | ||||
|     #   env: | ||||
|     #     - MATRIX_EVAL="CC=gcc && CXX=g++" | ||||
|     #     - SDKS=csgo | ||||
|     #     # GCC currently fails in opt builds trying to inline stuff in sqlite3.c. | ||||
|     #     - MODE=debug | ||||
| 
 | ||||
|     # This is a faster test for the latest clang. | ||||
|     - os: linux | ||||
|       dist: bionic | ||||
|       sudo: false | ||||
|       language: cpp | ||||
|       addons: | ||||
|         apt: | ||||
|           packages: ['lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-multilib', 'clang'] | ||||
|       env: | ||||
|         - MATRIX_EVAL="CC=clang && CXX=clang++" | ||||
|         - SDKS=csgo | ||||
|         - MODE=optimize | ||||
|         - ARCH=x86 | ||||
|           sources: ['llvm-toolchain-trusty-4.0'] | ||||
|           packages: ['clang-4.0', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib'] | ||||
|         cache: | ||||
|           directories: ['../mysql-5.0'] | ||||
|       env: ['MATRIX_EVAL="CC=clang-4.0 && CXX=clang++-4.0"'] | ||||
| 
 | ||||
|     - os: linux | ||||
|       sudo: false | ||||
|       language: cpp | ||||
|       addons: | ||||
|         apt: | ||||
|           sources: ['llvm-toolchain-trusty-5.0'] | ||||
|           packages: ['clang-5.0', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib'] | ||||
|         cache: | ||||
|           directories: ['../mysql-5.0'] | ||||
|       env: ['MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0"'] | ||||
| 
 | ||||
|     - os: linux | ||||
|       sudo: false | ||||
|       language: cpp | ||||
|       addons: | ||||
|         apt: | ||||
|           sources: ['ubuntu-toolchain-r-test'] | ||||
|           packages: ['g++-6', 'g++-6-multilib', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib'] | ||||
|         cache: | ||||
|           directories: ['../mysql-5.0'] | ||||
|       env: ['MATRIX_EVAL="CC=gcc-6 && CXX=g++-6"'] | ||||
| 
 | ||||
|   allow_failures: | ||||
|     - env: MATRIX_EVAL="CC=clang-3.7 && CXX=clang++-3.7" | ||||
|     - env: MATRIX_EVAL="CC=clang-3.9 && CXX=clang++-3.9" | ||||
|     - env: MATRIX_EVAL="CC=gcc-4.8 && CXX=g++-4.8" | ||||
|     - env: MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9" | ||||
|     - env: MATRIX_EVAL="CC=gcc-5 && CXX=g++-5" | ||||
|     - env: MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" | ||||
| 
 | ||||
| 
 | ||||
| before_script: | ||||
|   - CHECKOUT_DIR=$PWD && cd .. && $CHECKOUT_DIR/tools/checkout-deps.sh -s ${SDKS} && cd $CHECKOUT_DIR | ||||
|   - CHECKOUT_DIR=$PWD && cd .. && $CHECKOUT_DIR/tools/checkout-deps.sh && cd $CHECKOUT_DIR | ||||
| script: | ||||
|   - mkdir build && cd build | ||||
|   - PATH="~/.local/bin:$PATH" | ||||
|   - eval "${MATRIX_EVAL}" | ||||
|   - eval "${CC} --version" | ||||
|   - eval "${CXX} --version" | ||||
|   - python3 ../configure.py --enable-${MODE} --sdks=${SDKS} --targets=${ARCH} | ||||
|   - python ../configure.py --enable-optimize --sdks=episode1,css,tf2,l4d2,csgo,dota | ||||
|   - ambuild | ||||
|  | ||||
							
								
								
									
										459
									
								
								AMBuildScript
									
									
									
									
									
								
							
							
						
						
									
										459
									
								
								AMBuildScript
									
									
									
									
									
								
							| @ -1,8 +1,5 @@ | ||||
| # vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: | ||||
| import collections | ||||
| import os, sys | ||||
| import subprocess | ||||
| import traceback | ||||
| 
 | ||||
| class SDK(object): | ||||
|   def __init__(self, sdk, ext, aDef, name, platform, dir): | ||||
| @ -22,33 +19,23 @@ class SDK(object): | ||||
|     else: | ||||
|       self.platformSpec = platform | ||||
| 
 | ||||
|   def shouldBuild(self, targets): | ||||
|     for cxx in targets: | ||||
|       if cxx.target.platform in self.platformSpec: | ||||
|         if cxx.target.arch in self.platformSpec[cxx.target.platform]: | ||||
|           return True | ||||
|   def shouldBuild(self, target, archs): | ||||
|     if target.platform not in self.platformSpec: | ||||
|       return False | ||||
|     if not len([i for i in self.platformSpec[target.platform] if i in archs]): | ||||
|       return False | ||||
|     return True | ||||
| 
 | ||||
| WinOnly = ['windows'] | ||||
| WinLinux = ['windows', 'linux'] | ||||
| WinLinuxMac = ['windows', 'linux', 'mac'] | ||||
| Blade = { | ||||
|   'windows': ['x86', 'x86_64'], | ||||
|   'linux': ['x86_64'], | ||||
|   'mac': ['x86_64'] | ||||
| } | ||||
| CSGO = { | ||||
|   'windows': ['x86'], | ||||
|   'linux': ['x86', 'x86_64'], | ||||
|   'mac': ['x86_64'] | ||||
| } | ||||
| Mock = { | ||||
|   'windows': ['x86', 'x86_64'], | ||||
|   'linux': ['x86', 'x86_64'], | ||||
|   'mac': ['x86_64'] | ||||
|   'linux': ['x86', 'x64'], | ||||
|   'mac': ['x64'] | ||||
| } | ||||
| 
 | ||||
| SDKMap = { | ||||
| PossibleSDKs = { | ||||
|   'episode1':  SDK('HL2SDK', '2.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'), | ||||
|   'ep2':  SDK('HL2SDKOB', '2.ep2', '3', 'ORANGEBOX', WinLinux, 'orangebox'), | ||||
|   'css':  SDK('HL2SDKCSS', '2.css', '6', 'CSS', WinLinuxMac, 'css'), | ||||
| @ -65,19 +52,13 @@ SDKMap = { | ||||
|   'eye':  SDK('HL2SDK-EYE', '2.eye', '5', 'EYE', WinOnly, 'eye'), | ||||
|   'csgo': SDK('HL2SDKCSGO', '2.csgo', '21', 'CSGO', CSGO, 'csgo'), | ||||
|   'portal2':  SDK('HL2SDKPORTAL2', '2.portal2', '17', 'PORTAL2', [], 'portal2'), | ||||
|   'blade':  SDK('HL2SDKBLADE', '2.blade', '18', 'BLADE', Blade, 'blade'), | ||||
|   'blade':  SDK('HL2SDKBLADE', '2.blade', '18', 'BLADE', WinLinux, 'blade'), | ||||
|   'insurgency':  SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'), | ||||
|   'contagion':  SDK('HL2SDKCONTAGION', '2.contagion', '14', 'CONTAGION', WinOnly, 'contagion'), | ||||
|   'bms':  SDK('HL2SDKBMS', '2.bms', '10', 'BMS', WinLinux, 'bms'), | ||||
|   'doi':  SDK('HL2SDKDOI', '2.doi', '20', 'DOI', WinLinuxMac, 'doi'), | ||||
|   'mock': SDK('HL2SDK-MOCK', '2.mock', '999', 'MOCK', Mock, 'mock'), | ||||
| } | ||||
| 
 | ||||
| # Stable sorting for command equivalence in AMBuild. | ||||
| PossibleSDKs = collections.OrderedDict() | ||||
| for key in sorted(SDKMap.keys()): | ||||
|     PossibleSDKs[key] = SDKMap[key] | ||||
| 
 | ||||
| def ResolveEnvPath(env, folder): | ||||
|   if env in os.environ: | ||||
|     path = os.environ[env] | ||||
| @ -99,19 +80,32 @@ def ResolveEnvPath(env, folder): | ||||
| def Normalize(path): | ||||
|   return os.path.abspath(os.path.normpath(path)) | ||||
|    | ||||
| def SetArchFlags(compiler): | ||||
| def SetArchFlags(compiler, arch, platform): | ||||
|   if compiler.behavior == 'gcc': | ||||
|     if compiler.target.arch == 'x86_64': | ||||
|       compiler.cflags += ['-fPIC'] | ||||
|     if arch == 'x86': | ||||
|       compiler.cflags += ['-m32'] | ||||
|       compiler.linkflags += ['-m32'] | ||||
|       if platform == 'mac': | ||||
|         compiler.linkflags += ['-arch', 'i386'] | ||||
|     elif arch == 'x64': | ||||
|       compiler.cflags += ['-m64', '-fPIC'] | ||||
|       compiler.linkflags += ['-m64'] | ||||
|       if platform == 'mac': | ||||
|         compiler.linkflags += ['-arch', 'x86_64'] | ||||
|   elif compiler.like('msvc'): | ||||
|     if compiler.target.arch == 'x86_64': | ||||
|       compiler.defines += ['WIN64'] | ||||
|     if builder.target.arch == 'x86': | ||||
|       compiler.linkflags += ['/MACHINE:X86'] | ||||
|     elif builder.target.arch == 'x64': | ||||
|       compiler.linkflags += ['/MACHINE:X64'] | ||||
| 
 | ||||
| def AppendArchSuffix(binary, name, arch): | ||||
|   if arch == 'x64': | ||||
|     binary.localFolder = name + '.x64' | ||||
| 
 | ||||
| class SMConfig(object): | ||||
|   def __init__(self): | ||||
|     self.sdks = {} | ||||
|     self.binaries = [] | ||||
|     self.spvm = [] | ||||
|     self.extensions = [] | ||||
|     self.generated_headers = None | ||||
|     self.mms_root = None | ||||
| @ -120,32 +114,7 @@ class SMConfig(object): | ||||
|     self.spcomp_bins = None | ||||
|     self.smx_files = {} | ||||
|     self.versionlib = None | ||||
|     self.all_targets = [] | ||||
|     self.target_archs = set() | ||||
|     self.enable_asan = getattr(builder.options, 'enable_asan', False) | ||||
|     self.asan_libs = {} | ||||
| 
 | ||||
|     if builder.options.targets: | ||||
|       target_archs = builder.options.targets.split(',') | ||||
|     else: | ||||
|       target_archs = ['x86'] | ||||
|       if builder.backend != 'amb2': | ||||
|         target_archs.append('x86_64') | ||||
| 
 | ||||
|     for arch in target_archs: | ||||
|         try: | ||||
|             cxx = builder.DetectCxx(target_arch = arch) | ||||
|             self.target_archs.add(cxx.target.arch) | ||||
|         except Exception as e: | ||||
|             # Error if archs were manually overridden. | ||||
|             if builder.options.targets: | ||||
|                 raise | ||||
|             print('Skipping target {}: {}'.format(arch, e)) | ||||
|             continue | ||||
|         self.all_targets.append(cxx) | ||||
| 
 | ||||
|     if not self.all_targets: | ||||
|         raise Exception('No suitable C/C++ compiler was found.') | ||||
|     self.archs = builder.target.arch.replace('x86_64', 'x64').split(',') | ||||
| 
 | ||||
|   def use_auto_versioning(self): | ||||
|     if builder.backend != 'amb2': | ||||
| @ -174,33 +143,31 @@ class SMConfig(object): | ||||
| 
 | ||||
|   def detectSDKs(self): | ||||
|     sdk_list = builder.options.sdks.split(',') | ||||
|     use_none = sdk_list[0] == 'none' | ||||
|     use_all = sdk_list[0] == 'all' | ||||
|     use_present = sdk_list[0] == 'present' | ||||
| 
 | ||||
|     for sdk_name in PossibleSDKs: | ||||
|       sdk = PossibleSDKs[sdk_name] | ||||
|       if sdk.shouldBuild(self.all_targets): | ||||
|       if sdk.shouldBuild(builder.target, self.archs): | ||||
|         if builder.options.hl2sdk_root: | ||||
|           sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder) | ||||
|         else: | ||||
|           sdk_path = ResolveEnvPath(sdk.envvar, sdk.folder) | ||||
|         if sdk_path is None or not os.path.isdir(sdk_path): | ||||
|           if (use_all and sdk_name != 'mock') or sdk_name in sdk_list: | ||||
|           if use_all or sdk_name in sdk_list: | ||||
|             raise Exception('Could not find a valid path for {0}'.format(sdk.envvar)) | ||||
|           continue | ||||
|         if use_all or use_present or sdk_name in sdk_list: | ||||
|           sdk.path = Normalize(sdk_path) | ||||
|           self.sdks[sdk_name] = sdk | ||||
| 
 | ||||
|     if len(self.sdks) < 1 and len(sdk_list) and not use_none: | ||||
|       raise Exception('No applicable SDKs were found, nothing to do') | ||||
|     if len(self.sdks) < 1 and len(sdk_list): | ||||
|       raise Exception('No SDKs were found that build on {0}-{1}, nothing to do.'.format( | ||||
|         builder.target.platform, builder.target.arch)) | ||||
| 
 | ||||
|     if builder.options.mms_path: | ||||
|       self.mms_root = builder.options.mms_path | ||||
|     else: | ||||
|       self.mms_root = ResolveEnvPath('MMSOURCE111', 'mmsource-1.11') | ||||
|       if not self.mms_root: | ||||
|       self.mms_root = ResolveEnvPath('MMSOURCE110', 'mmsource-1.10') | ||||
|       if not self.mms_root: | ||||
|         self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source') | ||||
| @ -212,7 +179,6 @@ class SMConfig(object): | ||||
|     self.mms_root = Normalize(self.mms_root) | ||||
| 
 | ||||
|     if builder.options.hasMySql: | ||||
|       if 'x86' in self.target_archs: | ||||
|       if builder.options.mysql_path: | ||||
|         self.mysql_root['x86'] = builder.options.mysql_path | ||||
|       else: | ||||
| @ -221,40 +187,32 @@ class SMConfig(object): | ||||
|           if self.mysql_root['x86']: | ||||
|             break | ||||
|       if not self.mysql_root['x86'] or not os.path.isdir(self.mysql_root['x86']): | ||||
|           raise Exception('Could not find a path to MySQL. Configure with --no-mysql to disable it.') | ||||
|         raise Exception('Could not find a path to MySQL!') | ||||
|       self.mysql_root['x86'] = Normalize(self.mysql_root['x86']) | ||||
| 
 | ||||
|       if 'x86_64' in self.target_archs: | ||||
|       # For now, ignore 64-bit MySQL on Windows | ||||
|       if 'x64' in self.archs and builder.target.platform != 'windows': | ||||
|         if builder.options.mysql64_path: | ||||
|           self.mysql_root['x86_64'] = builder.options.mysql64_path | ||||
|           self.mysql_root['x64'] = builder.options.mysql64_path | ||||
|         else: | ||||
|           for i in range(10): | ||||
|             self.mysql_root['x86_64'] = ResolveEnvPath('MYSQL55_64', 'mysql-5.' + str(i) + '-x86_64') | ||||
|             if self.mysql_root['x86_64']: | ||||
|             self.mysql_root['x64'] = ResolveEnvPath('MYSQL55_64', 'mysql-5.' + str(i) + '-x86_64') | ||||
|             if self.mysql_root['x64']: | ||||
|               break | ||||
|         if not self.mysql_root['x86_64'] or not os.path.isdir(self.mysql_root['x86_64']): | ||||
|         if not self.mysql_root['x64'] or not os.path.isdir(self.mysql_root['x64']): | ||||
|           raise Exception('Could not find a path to 64-bit MySQL!') | ||||
|         self.mysql_root['x86_64'] = Normalize(self.mysql_root['x86_64']) | ||||
|         self.mysql_root['x64'] = Normalize(self.mysql_root['x64']) | ||||
| 
 | ||||
|   def configure(self): | ||||
|     builder.AddConfigureFile('pushbuild.txt') | ||||
|      | ||||
|     if not set(self.target_archs).issubset(['x86', 'x86_64']): | ||||
|       raise Exception('Unknown target architecture: {0}'.format(self.target_archs)) | ||||
|     if not set(self.archs).issubset(['x86', 'x64']): | ||||
|       raise Exception('Unknown target architecture: {0}'.format(builder.target.arch)) | ||||
| 
 | ||||
|     for cxx in self.all_targets: | ||||
|         self.configure_cxx(cxx) | ||||
|     cxx = builder.DetectCxx() | ||||
|      | ||||
|   def configure_cxx(self, cxx): | ||||
|     if cxx.family == 'msvc': | ||||
|       if cxx.version < 1900: | ||||
|         raise Exception('Only MSVC 2015 and later are supported, c++14 support is required.') | ||||
|     if cxx.family == 'gcc': | ||||
|       if cxx.version < 'gcc-4.9': | ||||
|         raise Exception('Only GCC versions 4.9 or greater are supported, c++14 support is required.') | ||||
|     if cxx.family == 'clang': | ||||
|       if cxx.version < 'clang-3.4': | ||||
|         raise Exception('Only clang versions 3.4 or greater are supported, c++14 support is required.') | ||||
|     if cxx.like('msvc') and len(self.archs) > 1: | ||||
|       raise Exception('Building multiple archs with MSVC is not currently supported') | ||||
| 
 | ||||
|     if cxx.like('gcc'): | ||||
|       self.configure_gcc(cxx) | ||||
| @ -270,11 +228,11 @@ class SMConfig(object): | ||||
|       cxx.defines += ['DEBUG', '_DEBUG'] | ||||
| 
 | ||||
|     # Platform-specifics | ||||
|     if cxx.target.platform == 'linux': | ||||
|     if builder.target.platform == 'linux': | ||||
|       self.configure_linux(cxx) | ||||
|     elif cxx.target.platform == 'mac': | ||||
|     elif builder.target.platform == 'mac': | ||||
|       self.configure_mac(cxx) | ||||
|     elif cxx.target.platform == 'windows': | ||||
|     elif builder.target.platform == 'windows': | ||||
|       self.configure_windows(cxx) | ||||
| 
 | ||||
|     # Finish up. | ||||
| @ -312,13 +270,9 @@ class SMConfig(object): | ||||
|       '-msse', | ||||
|       '-fvisibility=hidden', | ||||
|     ] | ||||
| 
 | ||||
|     if cxx.version == 'apple-clang-6.0' or cxx.version == 'clang-3.4': | ||||
|       cxx.cxxflags += ['-std=c++1y'] | ||||
|     else: | ||||
|       cxx.cxxflags += ['-std=c++14'] | ||||
| 
 | ||||
|     cxx.cxxflags += [ | ||||
|       '-std=c++11', | ||||
|       '-fno-exceptions', | ||||
|       '-fno-threadsafe-statics', | ||||
|       '-Wno-non-virtual-dtor', | ||||
|       '-Wno-overloaded-virtual', | ||||
| @ -327,11 +281,11 @@ class SMConfig(object): | ||||
| 
 | ||||
|     have_gcc = cxx.family == 'gcc' | ||||
|     have_clang = cxx.family == 'clang' | ||||
|     if cxx.version >= 'clang-3.9' or cxx.version == 'clang-3.4' or cxx.version > 'apple-clang-6.0': | ||||
|     if cxx.version >= 'clang-3.9': | ||||
|       cxx.cxxflags += ['-Wno-expansion-to-defined'] | ||||
|     if cxx.version == 'clang-3.9' or cxx.version == 'apple-clang-8.0': | ||||
|       cxx.cflags += ['-Wno-varargs'] | ||||
|     if cxx.version >= 'clang-3.4' or cxx.version >= 'apple-clang-7.0': | ||||
|     if cxx.version >= 'clang-3.6' or cxx.version >= 'apple-clang-7.0': | ||||
|       cxx.cxxflags += ['-Wno-inconsistent-missing-override'] | ||||
|     if cxx.version >= 'clang-2.9' or cxx.version >= 'apple-clang-3.0': | ||||
|       cxx.cxxflags += ['-Wno-null-dereference'] | ||||
| @ -351,35 +305,14 @@ class SMConfig(object): | ||||
|         cxx.cxxflags += ['-Wno-deprecated'] | ||||
|       cxx.cflags += ['-Wno-sometimes-uninitialized'] | ||||
| 
 | ||||
|     if self.enable_asan: | ||||
|       if not have_clang: | ||||
|         raise Exception('--enable-asan only supported when using Clang') | ||||
|       self.configure_asan(cxx) | ||||
| 
 | ||||
|     # Work around SDK warnings. | ||||
|     if cxx.version >= 'clang-10.0' or cxx.version >= 'apple-clang-12.0': | ||||
|         cxx.cflags += [ | ||||
|             '-Wno-implicit-int-float-conversion', | ||||
|             '-Wno-tautological-overlap-compare', | ||||
|         ] | ||||
| 
 | ||||
|     if have_gcc: | ||||
|       cxx.cflags += ['-mfpmath=sse'] | ||||
|       cxx.cflags += ['-Wno-maybe-uninitialized'] | ||||
| 
 | ||||
|     if builder.options.opt == '1': | ||||
|       if self.enable_asan: | ||||
|         cxx.cflags += ['-O1'] | ||||
|       else: | ||||
|       cxx.cflags += ['-O3'] | ||||
| 
 | ||||
|     # Don't omit the frame pointer. | ||||
|     cxx.cflags += ['-fno-omit-frame-pointer'] | ||||
| 
 | ||||
|   def configure_msvc(self, cxx): | ||||
|     if self.enable_asan: | ||||
|       raise Exception('--enable-asan only supported when using Clang') | ||||
| 
 | ||||
|     if builder.options.debug == '1': | ||||
|       cxx.cflags += ['/MTd'] | ||||
|       cxx.linkflags += ['/NODEFAULTLIB:libcmt'] | ||||
| @ -425,29 +358,6 @@ class SMConfig(object): | ||||
|     # Don't omit the frame pointer. | ||||
|     cxx.cflags += ['/Oy-'] | ||||
| 
 | ||||
|   def configure_asan(self, cxx): | ||||
|     if cxx.target.platform != 'linux': | ||||
|       raise Exception('--enable-asan only supported on Linux') | ||||
|     cxx.cflags += ['-fsanitize=address'] | ||||
|     cxx.linkflags += ['-fsanitize=address'] | ||||
|     if cxx.target.arch == 'x86': | ||||
|       libclang_rt = 'libclang_rt.asan-i386.so' | ||||
|     else: | ||||
|       libclang_rt = 'libclang_rt.asan-x86_64.so' | ||||
| 
 | ||||
|     try: | ||||
|       argv = cxx.cxx_argv + ['--print-file-name', libclang_rt] | ||||
|       output = subprocess.check_output(argv) | ||||
|       output = output.decode('utf-8') | ||||
|       output = output.strip() | ||||
|     except: | ||||
|       raise Exception('Could not find {}'.format(libclang_rt)) | ||||
| 
 | ||||
|     print('ASAN library for {}: {}'.format(cxx.target.arch, output)) | ||||
|     print('You will need to LD_PRELOAD this into srcds.') | ||||
| 
 | ||||
|     self.asan_libs[cxx.target.arch] = os.path.dirname(output) | ||||
| 
 | ||||
|   def configure_linux(self, cxx): | ||||
|     cxx.defines += ['_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64'] | ||||
|     cxx.linkflags += ['-lm'] | ||||
| @ -455,33 +365,22 @@ class SMConfig(object): | ||||
|       cxx.linkflags += ['-static-libgcc'] | ||||
|     elif cxx.family == 'clang': | ||||
|       cxx.linkflags += ['-lgcc_eh'] | ||||
|     cxx.linkflags += ['-static-libstdc++'] | ||||
| 
 | ||||
|   def configure_mac(self, cxx): | ||||
|     cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL'] | ||||
|     cxx.cflags += ['-mmacosx-version-min=10.7'] | ||||
|     cxx.cflags += ['-mmacosx-version-min=10.5'] | ||||
|     cxx.linkflags += [ | ||||
|       '-mmacosx-version-min=10.7', | ||||
|       '-stdlib=libc++', | ||||
|       '-lc++', | ||||
|       '-mmacosx-version-min=10.5', | ||||
|       '-lstdc++', | ||||
|       '-stdlib=libstdc++', | ||||
|     ] | ||||
|     cxx.cxxflags += ['-stdlib=libc++'] | ||||
|     cxx.cxxflags += ['-stdlib=libstdc++'] | ||||
| 
 | ||||
|   def configure_windows(self, cxx): | ||||
|     cxx.defines += ['WIN32', '_WINDOWS'] | ||||
| 
 | ||||
|   def add_libamtl(self): | ||||
|     # Add libamtl. | ||||
|     self.libamtl = {} | ||||
|     for cxx in self.all_targets: | ||||
|       def get_configure_fn(cxx): | ||||
|         return lambda builder, name: self.StaticLibrary(builder, cxx, name) | ||||
|       extra_vars = {'Configure': get_configure_fn(cxx)} | ||||
|       libamtl = builder.Build('public/amtl/amtl/AMBuilder', extra_vars) | ||||
|       self.libamtl[cxx.target.arch] = libamtl.binary | ||||
| 
 | ||||
|   def AddVersioning(self, binary): | ||||
|     if binary.compiler.target.platform == 'windows': | ||||
|   def AddVersioning(self, binary, arch): | ||||
|     if builder.target.platform == 'windows': | ||||
|       binary.sources += ['version.rc'] | ||||
|       binary.compiler.rcdefines += [ | ||||
|         'BINARY_NAME="{0}"'.format(binary.outputFile), | ||||
| @ -489,38 +388,31 @@ class SMConfig(object): | ||||
|       ] | ||||
|       if self.use_auto_versioning(): | ||||
|         binary.compiler.rcdefines += ['SM_GENERATED_BUILD'] | ||||
|     elif binary.compiler.target.platform == 'mac': | ||||
|     elif builder.target.platform == 'mac': | ||||
|       if binary.type == 'library': | ||||
|         binary.compiler.postlink += [ | ||||
|           '-compatibility_version', '1.0.0', | ||||
|           '-current_version', self.productVersion | ||||
|         ] | ||||
|     if self.use_auto_versioning(): | ||||
|       binary.compiler.postlink += [self.versionlib[binary.compiler.target.arch]] | ||||
|       binary.compiler.linkflags += [self.versionlib[arch]] | ||||
|       binary.compiler.sourcedeps += SM.generated_headers | ||||
|     return binary | ||||
|      | ||||
|   def LibraryBuilder(self, compiler, name): | ||||
|   def LibraryBuilder(self, compiler, name, arch): | ||||
|     binary = compiler.Library(name) | ||||
|     self.AddVersioning(binary) | ||||
|     AppendArchSuffix(binary, name, arch) | ||||
|     self.AddVersioning(binary, arch) | ||||
|     if binary.compiler.like('msvc'): | ||||
|       binary.compiler.linkflags += ['/SUBSYSTEM:WINDOWS'] | ||||
| 
 | ||||
|     # Dumb clang behavior means we have to manually find libclang_rt. | ||||
|     if self.enable_asan: | ||||
|       binary.compiler.linkflags += [ | ||||
|         '-shared-libsan', | ||||
|         '-Wl,-rpath={}'.format(self.asan_libs[binary.compiler.target.arch]), | ||||
|       ] | ||||
|     return binary | ||||
| 
 | ||||
|   def ProgramBuilder(self, compiler, name): | ||||
|   def ProgramBuilder(self, compiler, name, arch): | ||||
|     binary = compiler.Program(name) | ||||
|     self.AddVersioning(binary) | ||||
|     AppendArchSuffix(binary, name, arch) | ||||
|     self.AddVersioning(binary, arch) | ||||
|     if '-static-libgcc' in binary.compiler.linkflags: | ||||
|       binary.compiler.linkflags.remove('-static-libgcc') | ||||
|     if self.enable_asan: | ||||
|       binary.compiler.linkflags.append('-static-libsan') | ||||
|     if '-lgcc_eh' in binary.compiler.linkflags: | ||||
|       binary.compiler.linkflags.remove('-lgcc_eh') | ||||
|     if binary.compiler.like('gcc'): | ||||
| @ -529,23 +421,25 @@ class SMConfig(object): | ||||
|       binary.compiler.linkflags += ['/SUBSYSTEM:CONSOLE'] | ||||
|     return binary | ||||
|      | ||||
|   def StaticLibraryBuilder(self, compiler, name): | ||||
|     return compiler.StaticLibrary(name) | ||||
|   def StaticLibraryBuilder(self, compiler, name, arch): | ||||
|     binary = compiler.StaticLibrary(name) | ||||
|     AppendArchSuffix(binary, name, arch) | ||||
|     return binary; | ||||
| 
 | ||||
|   def Library(self, context, compiler, name): | ||||
|     compiler = compiler.clone() | ||||
|     SetArchFlags(compiler) | ||||
|     return self.LibraryBuilder(compiler, name) | ||||
|   def Library(self, context, name, arch): | ||||
|     compiler = context.cxx.clone() | ||||
|     SetArchFlags(compiler, arch, builder.target.platform) | ||||
|     return self.LibraryBuilder(compiler, name, arch) | ||||
| 
 | ||||
|   def Program(self, context, compiler, name): | ||||
|     compiler = compiler.clone() | ||||
|     SetArchFlags(compiler) | ||||
|     return self.ProgramBuilder(compiler, name) | ||||
|   def Program(self, context, name, arch): | ||||
|     compiler = context.cxx.clone() | ||||
|     SetArchFlags(compiler, arch, builder.target.platform) | ||||
|     return self.ProgramBuilder(compiler, name, arch) | ||||
|      | ||||
|   def StaticLibrary(self, context, compiler, name): | ||||
|     compiler = compiler.clone() | ||||
|     SetArchFlags(compiler) | ||||
|     return self.StaticLibraryBuilder(compiler, name) | ||||
|   def StaticLibrary(self, context, name, arch): | ||||
|     compiler = context.cxx.clone() | ||||
|     SetArchFlags(compiler, arch, builder.target.platform) | ||||
|     return self.StaticLibraryBuilder(compiler, name, arch) | ||||
| 
 | ||||
|   def ConfigureForExtension(self, context, compiler): | ||||
|     compiler.cxxincludes += [ | ||||
| @ -558,15 +452,15 @@ class SMConfig(object): | ||||
|     ] | ||||
|     return compiler | ||||
| 
 | ||||
|   def ExtLibrary(self, context, compiler, name): | ||||
|     binary = self.Library(context, compiler, name) | ||||
|     SetArchFlags(compiler) | ||||
|   def ExtLibrary(self, context, name, arch): | ||||
|     binary = self.Library(context, name, arch) | ||||
|     self.ConfigureForExtension(context, binary.compiler) | ||||
|     return binary | ||||
| 
 | ||||
|   def ConfigureForHL2(self, context, binary, sdk): | ||||
|   def ConfigureForHL2(self, binary, sdk, arch): | ||||
|     compiler = binary.compiler | ||||
|     SetArchFlags(compiler) | ||||
|      | ||||
|     SetArchFlags(compiler, arch, builder.target.platform) | ||||
| 
 | ||||
|     compiler.cxxincludes += [ | ||||
|       os.path.join(self.mms_root, 'core'), | ||||
| @ -603,16 +497,13 @@ class SMConfig(object): | ||||
|       compiler.defines.remove('_vsnprintf=vsnprintf') | ||||
| 
 | ||||
|     if compiler.like('msvc'): | ||||
|       compiler.defines += ['COMPILER_MSVC'] | ||||
|       if compiler.target.arch == 'x86': | ||||
|         compiler.defines += ['COMPILER_MSVC32'] | ||||
|       elif compiler.target.arch == 'x86_64': | ||||
|         compiler.defines += ['COMPILER_MSVC64'] | ||||
|       compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32'] | ||||
|       if compiler.version >= 1900: | ||||
|         compiler.linkflags += ['legacy_stdio_definitions.lib'] | ||||
|     else: | ||||
|       compiler.defines += ['COMPILER_GCC'] | ||||
| 
 | ||||
|     if compiler.target.arch == 'x86_64': | ||||
|     if arch == 'x64': | ||||
|       compiler.defines += ['X64BITS', 'PLATFORM_64BITS'] | ||||
| 
 | ||||
|     # For everything after Swarm, this needs to be defined for entity networking | ||||
| @ -621,142 +512,107 @@ class SMConfig(object): | ||||
|       compiler.defines += ['NETWORK_VARS_ENABLED'] | ||||
| 
 | ||||
|     if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2']: | ||||
|       if compiler.target.platform in ['linux', 'mac']: | ||||
|       if builder.target.platform in ['linux', 'mac']: | ||||
|         compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE'] | ||||
| 
 | ||||
|     if compiler.target.platform == 'linux': | ||||
|       if sdk.name in ['csgo', 'blade']: | ||||
|         compiler.linkflags.remove('-static-libstdc++') | ||||
|     if sdk.name == 'csgo' and builder.target.platform == 'linux': | ||||
|       compiler.linkflags += ['-lstdc++'] | ||||
|       compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0'] | ||||
|     elif compiler.target.platform == 'mac': | ||||
|       if sdk.name in ['csgo']: | ||||
|         # Switch libc++ to libstdc++ for protobuf linkage. | ||||
|         compiler.cxxflags.remove('-stdlib=libc++') | ||||
|         compiler.linkflags.remove('-stdlib=libc++') | ||||
|         compiler.linkflags.remove('-lc++') | ||||
| 
 | ||||
|         compiler.cxxflags += ['-stdlib=libstdc++'] | ||||
|         compiler.linkflags += ['-stdlib=libstdc++'] | ||||
|         compiler.linkflags += ['-lstdc++'] | ||||
| 
 | ||||
|         if 'c++1y' in compiler.cxxflags: | ||||
|           compiler.cxxflags.remove('-std=c++1y') | ||||
|           compiler.cxxflags += ['-std=c++11'] | ||||
|         elif 'c++14' in compiler.cxxflags: | ||||
|           compiler.cxxflags.remove('-std=c++14') | ||||
|           compiler.cxxflags += ['-std=c++11'] | ||||
| 
 | ||||
|     for path in paths: | ||||
|       compiler.cxxincludes += [os.path.join(sdk.path, *path)] | ||||
| 
 | ||||
|     if compiler.target.platform == 'linux': | ||||
|     if builder.target.platform == 'linux': | ||||
|       if sdk.name == 'episode1': | ||||
|         lib_folder = os.path.join(sdk.path, 'linux_sdk') | ||||
|       elif sdk.name in ['sdk2013', 'bms']: | ||||
|         lib_folder = os.path.join(sdk.path, 'lib', 'public', 'linux32') | ||||
|       elif compiler.target.arch == 'x86_64': | ||||
|       elif arch == 'x64': | ||||
|         lib_folder = os.path.join(sdk.path, 'lib', 'linux64') | ||||
|       else: | ||||
|         lib_folder = os.path.join(sdk.path, 'lib', 'linux') | ||||
|     elif compiler.target.platform == 'mac': | ||||
|     elif builder.target.platform == 'mac': | ||||
|       if sdk.name in ['sdk2013', 'bms']: | ||||
|         lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32') | ||||
|       elif compiler.target.arch == 'x86_64': | ||||
|       elif arch == 'x64': | ||||
|         lib_folder = os.path.join(sdk.path, 'lib', 'osx64') | ||||
|       else: | ||||
|         lib_folder = os.path.join(sdk.path, 'lib', 'mac') | ||||
| 
 | ||||
|     if compiler.target.platform in ['linux', 'mac']: | ||||
|       if sdk.name in ['sdk2013', 'bms'] or compiler.target.arch == 'x86_64': | ||||
|     if builder.target.platform in ['linux', 'mac']: | ||||
|       if sdk.name in ['sdk2013', 'bms'] or arch == 'x64': | ||||
|         compiler.postlink += [ | ||||
|           os.path.join(lib_folder, 'tier1.a'), | ||||
|           os.path.join(lib_folder, 'mathlib.a') | ||||
|           compiler.Dep(os.path.join(lib_folder, 'tier1.a')), | ||||
|           compiler.Dep(os.path.join(lib_folder, 'mathlib.a')) | ||||
|         ] | ||||
|       else: | ||||
|         compiler.postlink += [ | ||||
|           os.path.join(lib_folder, 'tier1_i486.a'), | ||||
|           os.path.join(lib_folder, 'mathlib_i486.a') | ||||
|           compiler.Dep(os.path.join(lib_folder, 'tier1_i486.a')), | ||||
|           compiler.Dep(os.path.join(lib_folder, 'mathlib_i486.a')) | ||||
|         ] | ||||
| 
 | ||||
|       if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']: | ||||
|         if compiler.target.arch == 'x86_64': | ||||
|           compiler.postlink += [os.path.join(lib_folder, 'interfaces.a')] | ||||
|         if arch == 'x64': | ||||
|           compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces.a'))] | ||||
|         else: | ||||
|           compiler.postlink += [os.path.join(lib_folder, 'interfaces_i486.a')] | ||||
|           compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces_i486.a'))] | ||||
| 
 | ||||
|     dynamic_libs = [] | ||||
|     if compiler.target.platform == 'linux': | ||||
|     if builder.target.platform == 'linux': | ||||
|       if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2', 'insurgency', 'doi']: | ||||
|         dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so'] | ||||
|       elif compiler.target.arch == 'x86_64' and sdk.name in ['csgo', 'mock']: | ||||
|       elif arch == 'x64' and sdk.name == 'csgo': | ||||
|         dynamic_libs = ['libtier0_client.so', 'libvstdlib_client.so'] | ||||
|       elif sdk.name in ['l4d', 'blade', 'insurgency', 'doi', 'csgo']: | ||||
|         dynamic_libs = ['libtier0.so', 'libvstdlib.so'] | ||||
|       else: | ||||
|         dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so'] | ||||
|     elif compiler.target.platform == 'mac': | ||||
|     elif builder.target.platform == 'mac': | ||||
|       compiler.linkflags.append('-liconv') | ||||
|       dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib'] | ||||
|     elif compiler.target.platform == 'windows': | ||||
|     elif builder.target.platform == 'windows': | ||||
|       libs = ['tier0', 'tier1', 'vstdlib', 'mathlib'] | ||||
|       if sdk.name in ['swarm', 'blade', 'insurgency', 'doi', 'csgo']: | ||||
|         libs.append('interfaces') | ||||
|       for lib in libs: | ||||
|         if compiler.target.arch == 'x86': | ||||
|         lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib' | ||||
|         elif compiler.target.arch == 'x86_64': | ||||
|           lib_path = os.path.join(sdk.path, 'lib', 'public', 'win64', lib) + '.lib' | ||||
|         compiler.linkflags.append(lib_path) | ||||
|         compiler.linkflags.append(compiler.Dep(lib_path)) | ||||
| 
 | ||||
|     for library in dynamic_libs: | ||||
|       source_path = os.path.join(lib_folder, library) | ||||
|       output_path = os.path.join(binary.localFolder, library) | ||||
| 
 | ||||
|       # Ensure the output path exists. | ||||
|       context.AddFolder(binary.localFolder) | ||||
|       output = context.AddSymlink(source_path, output_path) | ||||
|       def make_linker(source_path, output_path): | ||||
|         def link(context, binary): | ||||
|           cmd_node, (output,) = context.AddSymlink(source_path, output_path) | ||||
|           return output | ||||
|         return link | ||||
| 
 | ||||
|       compiler.weaklinkdeps += [output] | ||||
|       compiler.linkflags[0:0] = [library] | ||||
|       linker = make_linker(source_path, output_path) | ||||
|       compiler.linkflags[0:0] = [compiler.Dep(library, linker)] | ||||
| 
 | ||||
|     return binary | ||||
| 
 | ||||
|   def HL2Library(self, context, compiler, name, sdk): | ||||
|     binary = self.Library(context, compiler, name) | ||||
|   def HL2Library(self, context, name, sdk, arch): | ||||
|     binary = self.Library(context, name, arch) | ||||
|     self.ConfigureForExtension(context, binary.compiler) | ||||
|     return self.ConfigureForHL2(context, binary, sdk) | ||||
|     return self.ConfigureForHL2(binary, sdk, arch) | ||||
| 
 | ||||
|   def HL2Config(self, project, context, compiler, name, sdk): | ||||
|     binary = project.Configure(compiler, name, | ||||
|                                '{0} - {1} {2}'.format(self.tag, sdk.name, compiler.target.arch)) | ||||
|     self.AddVersioning(binary) | ||||
|     return self.ConfigureForHL2(context, binary, sdk) | ||||
|   def HL2Project(self, context, name): | ||||
|     project = context.cxx.LibraryProject(name) | ||||
|     self.ConfigureForExtension(context, project.compiler) | ||||
|     return project | ||||
| 
 | ||||
|   def HL2ExtConfig(self, project, context, compiler, name, sdk): | ||||
|     binary = project.Configure(compiler, name, | ||||
|                                '{0} - {1} {2}'.format(self.tag, sdk.name, compiler.target.arch)) | ||||
|     self.AddVersioning(binary) | ||||
|     self.ConfigureForHL2(context, binary, sdk) | ||||
|     self.ConfigureForExtension(context, binary.compiler) | ||||
|     return binary | ||||
| 
 | ||||
| if getattr(builder, 'target', None) is not None: | ||||
|     sys.stderr.write("Your output folder was configured for AMBuild 2.1, and SourceMod is now\n") | ||||
|     sys.stderr.write("configured to use AMBuild 2.2. Please remove your output folder and\n") | ||||
|     sys.stderr.write("reconfigure to continue.\n") | ||||
|     os._exit(1) | ||||
|   def HL2Config(self, project, name, sdk, arch): | ||||
|     binary = project.Configure(name, '{0} - {1}'.format(self.tag, sdk.name)) | ||||
|     AppendArchSuffix(binary, name, arch) | ||||
|     self.AddVersioning(binary, arch) | ||||
|     return self.ConfigureForHL2(binary, sdk, arch) | ||||
| 
 | ||||
| SM = SMConfig() | ||||
| SM.detectProductVersion() | ||||
| if not getattr(builder.options, 'scripting_only', False): | ||||
|   SM.detectSDKs() | ||||
| SM.detectSDKs() | ||||
| SM.configure() | ||||
| SM.add_libamtl() | ||||
| 
 | ||||
| # This will clone the list and each cxx object as we recurse, preventing child | ||||
| # scripts from messing up global state. | ||||
| builder.targets = builder.CloneableList(SM.all_targets) | ||||
| 
 | ||||
| if SM.use_auto_versioning(): | ||||
|   SM.generated_headers = builder.Build( | ||||
| @ -768,53 +624,23 @@ if SM.use_auto_versioning(): | ||||
|     { 'SM': SM } | ||||
|   ) | ||||
| 
 | ||||
| class SPRoot(object): | ||||
|   # SourcePawn's build scripts are always one-offs, and attach the current target | ||||
|   # to the builder, so we have to provide a shim to our StaticLibrary() method. | ||||
|   def StaticLibrary(self, builder, name): | ||||
|     return SM.StaticLibrary(builder, builder.cxx, name) | ||||
|   def Program(self, builder, name): | ||||
|     return SM.Program(builder, builder.cxx, name) | ||||
|   def Library(self, builder, name): | ||||
|     return SM.Library(builder, builder.cxx, name) | ||||
| 
 | ||||
|   @property | ||||
|   def targets(self): | ||||
|     return SM.all_targets | ||||
| 
 | ||||
|   @property | ||||
|   def libamtl(self): | ||||
|     return SM.libamtl | ||||
| 
 | ||||
| SP_build_parts = ['core'] | ||||
| if getattr(builder.options, 'scripting_only', False): | ||||
|   SP_build_parts = ['spcomp'] | ||||
| 
 | ||||
| # Build SourcePawn externally. | ||||
| SP = builder.Build('sourcepawn/AMBuildScript', { | ||||
|   'external_root': SPRoot(), | ||||
|   'external_root': SM, | ||||
|   'external_amtl': os.path.join(builder.sourcePath, 'public', 'amtl'), | ||||
|   'external_build': SP_build_parts, | ||||
|   'external_build': ['core'], | ||||
| }) | ||||
| if len(SP.spcomp) > 1: | ||||
|   SM.spcomp = SP.spcomp['x86'] | ||||
| else: | ||||
|   SM.spcomp = SP.spcomp[list(SP.spcomp.keys())[0]] | ||||
| SM.spcomp_bins = list(SP.spcomp.values()) | ||||
| 
 | ||||
| if not getattr(builder.options, 'scripting_only', False): | ||||
|   for cxx in SM.all_targets: | ||||
|     SM.spvm += [ | ||||
|       SP.libsourcepawn[cxx.target.arch] | ||||
| for arch in SM.archs: | ||||
|   SM.binaries += [ | ||||
|      SP.libsourcepawn[arch] | ||||
|   ] | ||||
| 
 | ||||
| if getattr(builder.options, 'scripting_only', False): | ||||
|   BuildScripts = [ | ||||
|     'tools/buildbot/PackageHelpers', | ||||
|     'tools/buildbot/ToolsPackageScript', | ||||
|   ] | ||||
| else: | ||||
|   BuildScripts = [ | ||||
| BuildScripts = [ | ||||
|   'loader/AMBuilder', | ||||
|   'core/AMBuilder', | ||||
|   'core/logic/AMBuilder', | ||||
| @ -822,10 +648,8 @@ else: | ||||
|   'extensions/clientprefs/AMBuilder', | ||||
|   'extensions/curl/AMBuilder', | ||||
|   'extensions/cstrike/AMBuilder', | ||||
|     'extensions/dhooks/AMBuilder', | ||||
|   'extensions/geoip/AMBuilder', | ||||
|   'extensions/mysql/AMBuilder', | ||||
|     'extensions/pgsql/AMBuilder', | ||||
|   'extensions/regex/AMBuilder', | ||||
|   'extensions/sdkhooks/AMBuilder', | ||||
|   'extensions/sdktools/AMBuilder', | ||||
| @ -833,12 +657,11 @@ else: | ||||
|   'extensions/tf2/AMBuilder', | ||||
|   'extensions/topmenus/AMBuilder', | ||||
|   'extensions/updater/AMBuilder', | ||||
|   ] | ||||
| ] | ||||
| 
 | ||||
|   if builder.backend == 'amb2': | ||||
| if builder.backend == 'amb2': | ||||
|   BuildScripts += [ | ||||
|     'plugins/AMBuilder', | ||||
|       'tools/buildbot/PackageHelpers', | ||||
|     'tools/buildbot/PackageScript', | ||||
|   ] | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										17
									
								
								appveyor.yml
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								appveyor.yml
									
									
									
									
									
								
							| @ -1,17 +0,0 @@ | ||||
| version: 1.0.{build} | ||||
| image: Visual Studio 2015 | ||||
| clone_folder: c:/projects/sourcemod | ||||
| clone_depth: 1 | ||||
| install: | ||||
| - cmd: set PATH=C:\Python38;C:\Python38\Scripts;%PATH% | ||||
| - cmd: git submodule update --init --recursive | ||||
| - cmd: git pull --recurse-submodules | ||||
| - cmd: cd .. | ||||
| - ps: sourcemod/tools/checkout-deps.ps1 -SDKs episode1,css,tf2,l4d2,csgo | ||||
| - cmd: cd sourcemod | ||||
| build_script: | ||||
| - cmd: call "%VS140COMNTOOLS%/vsvars32.bat" | ||||
| - cmd: mkdir build | ||||
| - cmd: cd build | ||||
| - cmd: python.exe ../configure.py --enable-optimize --no-mysql --sdks=episode1,css,tf2,l4d2,csgo | ||||
| - cmd: ambuild | ||||
| @ -67,7 +67,7 @@ struct DatabaseInfo; | ||||
| class IPlayerInfoBridge; | ||||
| class ICommandArgs; | ||||
| 
 | ||||
| typedef ke::Function<bool(int client, const ICommandArgs*)> CommandFunc; | ||||
| typedef ke::Lambda<bool(int client, const ICommandArgs*)> CommandFunc; | ||||
| 
 | ||||
| class CoreProvider | ||||
| { | ||||
| @ -115,8 +115,6 @@ public: | ||||
| 	virtual void ConsolePrint(const char *fmt, ...) = 0; | ||||
| 	virtual void ConsolePrintVa(const char *fmt, va_list ap) = 0; | ||||
| 
 | ||||
| 	virtual void FormatSourceBinaryName(const char *basename, char *buffer, size_t maxlength) = 0; | ||||
| 
 | ||||
| 	// Game engine helper functions.
 | ||||
| 	virtual bool IsClientConVarQueryingSupported() = 0; | ||||
| 	virtual int QueryClientConVar(int client, const char *cvar) = 0; | ||||
|  | ||||
| @ -73,9 +73,6 @@ struct sm_logic_t | ||||
| 	void            (*FreeCellArray)(ICellArray *arr); | ||||
| 	void *			(*FromPseudoAddress)(uint32_t pseudoAddr); | ||||
| 	uint32_t		(*ToPseudoAddress)(void *addr); | ||||
| 	void			(*SetEntityLumpWritable)(bool writable); | ||||
| 	bool			(*ParseEntityLumpString)(const char *entityString, int &status, size_t &position); | ||||
| 	const char *	(*GetEntityLumpString)(); | ||||
| 	IScriptManager	*scripts; | ||||
| 	IShareSys		*sharesys; | ||||
| 	IExtensionSys	*extsys; | ||||
|  | ||||
| @ -145,15 +145,5 @@ | ||||
| 	 * Disable this option at your own risk. | ||||
| 	 */ | ||||
| 	"FollowCSGOServerGuidelines"	"yes" | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Controls whether the SourcePawn runtime will generate additional metadata about | ||||
| 	 * JIT-compiled functions for performance profiling or debugging purposes. | ||||
| 	 * | ||||
| 	 * "none"    - Don't generate any additional JIT metadata | ||||
| 	 * "default" - Generate basic perf metadata (on Linux) and delete it automatically on quit | ||||
| 	 * "perf"    - Generate basic perf metadata (Linux only - function names) | ||||
| 	 * "jitdump" - Generate extended perf metadata (Linux only - function names, bytecode, and source information) | ||||
| 	 */ | ||||
| 	"JITMetadata"	"default" | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								configs/geoip/GeoIP.dat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								configs/geoip/GeoIP.dat
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -1,41 +0,0 @@ | ||||
| CREATE TABLE IF NOT EXISTS sm_cookies | ||||
| ( | ||||
| 	id serial, | ||||
| 	name varchar(30) NOT NULL UNIQUE, | ||||
| 	description varchar(255), | ||||
| 	access INTEGER, | ||||
| 	PRIMARY KEY (id) | ||||
| ); | ||||
| 
 | ||||
| CREATE TABLE IF NOT EXISTS sm_cookie_cache | ||||
| ( | ||||
| 	player varchar(65) NOT NULL, | ||||
| 	cookie_id int NOT NULL, | ||||
| 	value varchar(100), | ||||
| 	timestamp int NOT NULL, | ||||
| 	PRIMARY KEY (player, cookie_id) | ||||
| ); | ||||
| 
 | ||||
| CREATE LANGUAGE plpgsql; | ||||
| 
 | ||||
| CREATE OR REPLACE FUNCTION add_or_update_cookie(in_player VARCHAR(65), in_cookie INT, in_value VARCHAR(100), in_time INT) RETURNS VOID AS | ||||
| $$ | ||||
| BEGIN | ||||
|   LOOP | ||||
|     -- first try to update the it. | ||||
|     UPDATE sm_cookie_cache SET value = in_value, timestamp = in_time WHERE player = in_player AND cookie_id = in_cookie; | ||||
|     IF found THEN | ||||
|       RETURN; | ||||
|     END IF; | ||||
|     -- not there, so try to insert. | ||||
|     -- if someone else inserts the same key concurrently, we could get a unique-key failure. | ||||
|     BEGIN | ||||
|       INSERT INTO sm_cookie_cache (player, cookie_id, value, timestamp) VALUES (in_player, in_cookie, in_value, in_time); | ||||
|       RETURN; | ||||
|     EXCEPTION WHEN unique_violation THEN | ||||
|       -- do nothing...  loop again, and we'll update. | ||||
|     END; | ||||
|   END LOOP; | ||||
| END; | ||||
| $$ | ||||
| LANGUAGE plpgsql; | ||||
| @ -1,65 +0,0 @@ | ||||
| CREATE TABLE sm_admins ( | ||||
|   id serial, | ||||
|   authtype varchar(6) NOT NULL, | ||||
|   CHECK (authtype in ('steam', 'name', 'ip')), | ||||
|   identity varchar(65) NOT NULL, | ||||
|   password varchar(65), | ||||
|   flags varchar(30) NOT NULL, | ||||
|   name varchar(65) NOT NULL, | ||||
|   immunity int NOT NULL, | ||||
|   PRIMARY KEY (id) | ||||
| ); | ||||
| 
 | ||||
| CREATE TABLE sm_groups ( | ||||
|   id serial, | ||||
|   flags varchar(30) NOT NULL, | ||||
|   name varchar(120) NOT NULL, | ||||
|   immunity_level int NOT NULL, | ||||
|   PRIMARY KEY (id) | ||||
| ); | ||||
| 
 | ||||
| CREATE TABLE sm_group_immunity ( | ||||
|   group_id int NOT NULL, | ||||
|   other_id int NOT NULL, | ||||
|   FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE, | ||||
|   FOREIGN KEY (other_id) REFERENCES sm_groups(id) ON DELETE CASCADE, | ||||
|   PRIMARY KEY (group_id, other_id) | ||||
| ); | ||||
| 
 | ||||
| CREATE TABLE sm_group_overrides ( | ||||
|   group_id int NOT NULL, | ||||
|   FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE, | ||||
|   type varchar(10) NOT NULL, | ||||
|   CHECK (type in ('command', 'group')), | ||||
|   name varchar(32) NOT NULL, | ||||
|   access varchar(5) NOT NULL, | ||||
|   CHECK (access in ('allow', 'deny')), | ||||
|   PRIMARY KEY (group_id, type, name) | ||||
| ); | ||||
| 
 | ||||
| CREATE TABLE sm_overrides ( | ||||
|   type varchar(10) NOT NULL, | ||||
|   CHECK (type in ('command', 'group')), | ||||
|   name varchar(32) NOT NULL, | ||||
|   flags varchar(30) NOT NULL, | ||||
|   PRIMARY KEY (type,name) | ||||
| ); | ||||
| 
 | ||||
| CREATE TABLE sm_admins_groups ( | ||||
|   admin_id int NOT NULL, | ||||
|   group_id int NOT NULL, | ||||
|   FOREIGN KEY (admin_id) REFERENCES sm_admins(id) ON DELETE CASCADE, | ||||
|   FOREIGN KEY (group_id) REFERENCES sm_groups(id) ON DELETE CASCADE, | ||||
|   inherit_order int NOT NULL, | ||||
|   PRIMARY KEY (admin_id, group_id) | ||||
| ); | ||||
| 
 | ||||
| -- side note, this is pgsql module, sm_config will not exist if the above stuff exists... and it's being left to the admin | ||||
| -- to figure out if it exists. | ||||
| CREATE TABLE sm_config ( | ||||
|   cfg_key varchar(32) NOT NULL, | ||||
|   cfg_value varchar(255) NOT NULL, | ||||
|   PRIMARY KEY (cfg_key) | ||||
| ); | ||||
| 
 | ||||
| INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409'); | ||||
							
								
								
									
										41
									
								
								configure.py
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								configure.py
									
									
									
									
									
								
							| @ -12,38 +12,31 @@ except: | ||||
| 		sys.stderr.write('http://www.alliedmods.net/ambuild\n') | ||||
| 	sys.exit(1) | ||||
| 
 | ||||
| # Hack to show a decent upgrade message, which wasn't done until 2.2. | ||||
| ambuild_version = getattr(run, 'CURRENT_API', '2.1') | ||||
| if ambuild_version.startswith('2.1'): | ||||
|   sys.stderr.write("AMBuild 2.2 or higher is required; please update\n") | ||||
|   sys.exit(1) | ||||
| def make_objdir_name(p): | ||||
|     return 'obj-' + util.Platform() + '-' + p.target_arch | ||||
| 
 | ||||
| parser = run.BuildParser(sourcePath=sys.path[0], api='2.2') | ||||
| parser.options.add_argument('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None, | ||||
| parser = run.BuildParser(sourcePath=sys.path[0], api='2.1') | ||||
| parser.default_arch = 'x86' | ||||
| parser.default_build_folder = make_objdir_name | ||||
| parser.options.add_option('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None, | ||||
| 		                   help='Root search folder for HL2SDKs') | ||||
| parser.options.add_argument('--mysql-path', type=str, dest='mysql_path', default=None, | ||||
| parser.options.add_option('--mysql-path', type=str, dest='mysql_path', default=None, | ||||
| 		                   help='Path to MySQL 5') | ||||
| parser.options.add_argument('--mysql64-path', type=str, dest='mysql64_path', default=None, | ||||
| parser.options.add_option('--mysql64-path', type=str, dest='mysql64_path', default=None, | ||||
| 		                   help='Path to 64-bit MySQL 5') | ||||
| parser.options.add_argument('--mms-path', type=str, dest='mms_path', default=None, | ||||
| parser.options.add_option('--mms-path', type=str, dest='mms_path', default=None, | ||||
|                        help='Path to Metamod:Source') | ||||
| parser.options.add_argument('--enable-debug', action='store_const', const='1', dest='debug', | ||||
| parser.options.add_option('--enable-debug', action='store_const', const='1', dest='debug', | ||||
|                        help='Enable debugging symbols') | ||||
| parser.options.add_argument('--enable-optimize', action='store_const', const='1', dest='opt', | ||||
| parser.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt', | ||||
|                        help='Enable optimization') | ||||
| parser.options.add_argument('--no-mysql', action='store_false', default=True, dest='hasMySql', | ||||
| parser.options.add_option('--no-mysql', action='store_false', default=True, dest='hasMySql', | ||||
|                        help='Disable building MySQL extension') | ||||
| parser.options.add_argument('-s', '--sdks', default='present', dest='sdks', | ||||
|                        help='Build against specified SDKs; valid args are "none", "all", "present",' | ||||
|                             ' or comma-delimited list of engine names') | ||||
| parser.options.add_argument('--breakpad-dump', action='store_true', dest='breakpad_dump', | ||||
| parser.options.add_option('-s', '--sdks', default='all', dest='sdks', | ||||
|                        help='Build against specified SDKs; valid args are "all", "present", or ' | ||||
|                             'comma-delimited list of engine names (default: %default)') | ||||
| parser.options.add_option('--breakpad-dump', action='store_true', dest='breakpad_dump', | ||||
| 											 default=False, help='Dump and upload breakpad symbols') | ||||
| parser.options.add_argument('--disable-auto-versioning', action='store_true', dest='disable_auto_versioning', | ||||
| parser.options.add_option('--disable-auto-versioning', action='store_true', dest='disable_auto_versioning', | ||||
|                        default=False, help='Disable the auto versioning script') | ||||
| parser.options.add_argument('--targets', type=str, dest='targets', default=None, | ||||
|                           help="Override the target architecture (use commas to separate multiple targets).") | ||||
| parser.options.add_argument('--scripting-only', action='store_true', dest='scripting_only', default=False, | ||||
|                           help="Only build and package the files required for scripting in SourcePawn.") | ||||
| parser.options.add_argument('--enable-asan', action='store_true', dest='enable_asan', | ||||
|                             default=False, help='Enable ASAN (clang only)') | ||||
| parser.Configure() | ||||
|  | ||||
| @ -1,8 +1,7 @@ | ||||
| # vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: | ||||
| import os | ||||
| 
 | ||||
| project = builder.LibraryProject('sourcemod') | ||||
| 
 | ||||
| project = SM.HL2Project(builder, 'sourcemod') | ||||
| project.sources += [ | ||||
|   'MenuStyle_Valve.cpp', | ||||
|   'logic_bridge.cpp', | ||||
| @ -38,22 +37,22 @@ project.sources += [ | ||||
|   'MenuStyle_Radio.cpp', | ||||
|   'sm_autonatives.cpp', | ||||
|   'ConsoleDetours.cpp', | ||||
|   'vprof_tool.cpp', | ||||
|   'smn_commandline.cpp', | ||||
|   'GameHooks.cpp', | ||||
| ] | ||||
| 
 | ||||
| for sdk_name in SM.sdks: | ||||
|   sdk = SM.sdks[sdk_name] | ||||
|   for cxx in builder.targets: | ||||
|     if not cxx.target.arch in sdk.platformSpec[cxx.target.platform]: | ||||
|   for arch in SM.archs: | ||||
|     if not arch in sdk.platformSpec[builder.target.platform]: | ||||
|       continue | ||||
| 
 | ||||
|     binary_name = 'sourcemod.' + sdk.ext | ||||
| 
 | ||||
|     binary = SM.HL2Config(project, builder, cxx, binary_name, sdk) | ||||
|     SM.ConfigureForExtension(builder, binary.compiler) | ||||
| 
 | ||||
|     binary = SM.HL2Config(project, binary_name, sdk, arch) | ||||
|     compiler = binary.compiler | ||||
| 
 | ||||
|     compiler.cxxincludes += [ | ||||
|       builder.sourcePath | ||||
|     ] | ||||
| @ -64,72 +63,51 @@ for sdk_name in SM.sdks: | ||||
|         os.path.join(sdk.path, 'public', 'engine', 'protobuf'), | ||||
|         os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf') | ||||
|       ] | ||||
|     elif sdk.name == 'blade': | ||||
|       compiler.cxxincludes += [ | ||||
|         os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'), | ||||
|         os.path.join(sdk.path, 'public', 'engine', 'protobuf'), | ||||
|         os.path.join(sdk.path, 'public', 'game', 'shared', 'berimbau', 'protobuf') | ||||
|       ] | ||||
| 
 | ||||
|     if compiler.like('msvc'): | ||||
|       compiler.defines += ['_ALLOW_KEYWORD_MACROS'] | ||||
|     if cxx.target.platform == 'linux': | ||||
|     if builder.target.platform == 'linux': | ||||
|       compiler.postlink += ['-lpthread', '-lrt'] | ||||
| 
 | ||||
|     if sdk.name in ['csgo', 'blade']: | ||||
|       if compiler.target.platform == 'linux': | ||||
|         if compiler.target.arch == 'x86': | ||||
|     if sdk.name == 'csgo': | ||||
|       if builder.target.platform == 'linux': | ||||
|         if arch == 'x86': | ||||
|           lib_path = os.path.join(sdk.path, 'lib', 'linux32', 'release', 'libprotobuf.a') | ||||
|         elif compiler.target.arch == 'x86_64': | ||||
|         elif arch == 'x64': | ||||
|           lib_path = os.path.join(sdk.path, 'lib', 'linux64', 'release', 'libprotobuf.a') | ||||
|         compiler.linkflags += ['-Wl,--exclude-libs=libprotobuf.a'] | ||||
|       elif compiler.target.platform == 'mac': | ||||
|         if compiler.target.arch == 'x86': | ||||
|       elif builder.target.platform == 'mac': | ||||
|         if arch == 'x86': | ||||
|           lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf.a') | ||||
|         elif compiler.target.arch == 'x86_64': | ||||
|         elif arch == 'x64': | ||||
|           lib_path = os.path.join(sdk.path, 'lib', 'osx64', 'release', 'libprotobuf.a') | ||||
|       elif compiler.target.platform == 'windows': | ||||
|       elif builder.target.platform == 'windows': | ||||
|         msvc_ver = compiler.version | ||||
|         vs_year = '' | ||||
|         platform = '' | ||||
|         if compiler.target.arch == 'x86': | ||||
|           platform = 'win32' | ||||
|         elif compiler.target.arch == 'x86_64': | ||||
|           platform = 'win64' | ||||
|          | ||||
|         if 1900 <= msvc_ver < 2000: | ||||
|         if msvc_ver == 1800: | ||||
|           vs_year = '2013' | ||||
|         elif 1900 <= msvc_ver < 2000: | ||||
|           vs_year = '2015' | ||||
|         else: | ||||
|           raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"') | ||||
| 
 | ||||
|         if 'DEBUG' in compiler.defines: | ||||
|           lib_path = os.path.join(sdk.path, 'lib', platform, 'debug', 'vs' + vs_year, 'libprotobuf.lib') | ||||
|           lib_path = os.path.join(sdk.path, 'lib', 'win32', 'debug', 'vs' + vs_year, 'libprotobuf.lib') | ||||
|         else: | ||||
|           lib_path = os.path.join(sdk.path, 'lib', platform, 'release', 'vs' + vs_year, 'libprotobuf.lib') | ||||
|       compiler.linkflags.insert(0, lib_path) | ||||
|           lib_path = os.path.join(sdk.path, 'lib', 'win32', 'release', 'vs' + vs_year, 'libprotobuf.lib') | ||||
|       compiler.linkflags.insert(0, binary.Dep(lib_path)) | ||||
|    | ||||
|     if sdk.name in ['csgo', 'blade']: | ||||
|     if sdk.name == 'csgo': | ||||
|       binary.sources += ['smn_protobuf.cpp'] | ||||
|     else: | ||||
|       binary.sources += ['smn_bitbuffer.cpp'] | ||||
| 
 | ||||
|     if sdk.name != 'blade': | ||||
|       binary.sources += [ | ||||
|         'vprof_tool.cpp', | ||||
|       ] | ||||
| 
 | ||||
|     if sdk.name == 'csgo': | ||||
|       binary.sources += [ | ||||
|         os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'), | ||||
|         os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessages.pb.cc'), | ||||
|         os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessage_helpers.cpp'), | ||||
|       ] | ||||
|     elif sdk.name == 'blade': | ||||
|       binary.sources += [ | ||||
|         os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'), | ||||
|         os.path.join(sdk.path, 'public', 'game', 'shared', 'berimbau', 'protobuf', 'berimbau_usermessages.pb.cc'), | ||||
|         os.path.join(sdk.path, 'public', 'game', 'shared', 'berimbau', 'protobuf', 'berimbau_usermessage_helpers.cpp'), | ||||
|       ] | ||||
| 
 | ||||
| SM.binaries += builder.Add(project) | ||||
| 
 | ||||
|  | ||||
| @ -29,8 +29,6 @@ | ||||
|  * Version: $Id$ | ||||
|  */ | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include <ITextParsers.h> | ||||
| #include "ChatTriggers.h" | ||||
| #include "sm_stringutil.h" | ||||
| @ -66,7 +64,7 @@ ChatTriggers::~ChatTriggers() | ||||
| 
 | ||||
| void ChatTriggers::SetChatTrigger(ChatTriggerType type, const char *value) | ||||
| { | ||||
| 	std::unique_ptr<char[]> filtered(new char[strlen(value) + 1]); | ||||
| 	ke::AutoPtr<char[]> filtered(new char[strlen(value) + 1]); | ||||
| 
 | ||||
| 	const char *src = value; | ||||
| 	char *dest = filtered.get(); | ||||
| @ -137,26 +135,26 @@ void ChatTriggers::OnSourceModGameInitialized() | ||||
| 	}; | ||||
| 
 | ||||
| 	if (ConCommand *say = FindCommand("say")) { | ||||
| 		hooks_.push_back(sCoreProviderImpl.AddCommandHook(say, pre_hook)); | ||||
| 		hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say, post_hook)); | ||||
| 		hooks_.append(sCoreProviderImpl.AddCommandHook(say, pre_hook)); | ||||
| 		hooks_.append(sCoreProviderImpl.AddPostCommandHook(say, post_hook)); | ||||
| 	} | ||||
| 	if (ConCommand *say_team = FindCommand("say_team")) { | ||||
| 		hooks_.push_back(sCoreProviderImpl.AddCommandHook(say_team, pre_hook)); | ||||
| 		hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say_team, post_hook)); | ||||
| 		hooks_.append(sCoreProviderImpl.AddCommandHook(say_team, pre_hook)); | ||||
| 		hooks_.append(sCoreProviderImpl.AddPostCommandHook(say_team, post_hook)); | ||||
| 	} | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_EPISODEONE | ||||
| 	m_bIsINS = (strcmp(g_SourceMod.GetGameFolderName(), "insurgency") == 0); | ||||
| 	if (m_bIsINS) { | ||||
| 		if (ConCommand *say2 = FindCommand("say2")) { | ||||
| 			hooks_.push_back(sCoreProviderImpl.AddCommandHook(say2, pre_hook)); | ||||
| 			hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say2, post_hook)); | ||||
| 			hooks_.append(sCoreProviderImpl.AddCommandHook(say2, pre_hook)); | ||||
| 			hooks_.append(sCoreProviderImpl.AddPostCommandHook(say2, post_hook)); | ||||
| 		} | ||||
| 	} | ||||
| #elif SOURCE_ENGINE == SE_NUCLEARDAWN | ||||
| 	if (ConCommand *say_squad = FindCommand("say_squad")) { | ||||
| 		hooks_.push_back(sCoreProviderImpl.AddCommandHook(say_squad, pre_hook)); | ||||
| 		hooks_.push_back(sCoreProviderImpl.AddPostCommandHook(say_squad, post_hook)); | ||||
| 		hooks_.append(sCoreProviderImpl.AddCommandHook(say_squad, pre_hook)); | ||||
| 		hooks_.append(sCoreProviderImpl.AddPostCommandHook(say_squad, post_hook)); | ||||
| 	} | ||||
| #endif | ||||
| } | ||||
| @ -277,10 +275,10 @@ bool ChatTriggers::OnSayCommand_Pre(int client, const ICommandArgs *command) | ||||
| 	bool is_silent = false; | ||||
| 
 | ||||
| 	// Prefer the silent trigger in case of clashes.
 | ||||
| 	if (strchr(m_PrivTrigger.c_str(), m_ArgSBackup[0])) { | ||||
| 	if (strchr(m_PrivTrigger.chars(), m_ArgSBackup[0])) { | ||||
| 		is_trigger = true; | ||||
| 		is_silent = true; | ||||
| 	} else if (strchr(m_PubTrigger.c_str(), m_ArgSBackup[0])) { | ||||
| 	} else if (strchr(m_PubTrigger.chars(), m_ArgSBackup[0])) { | ||||
| 		is_trigger = true; | ||||
| 	} | ||||
| 
 | ||||
| @ -363,7 +361,7 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args) | ||||
| 	if (!g_ConCmds.LookForSourceModCommand(cmd_buf)) | ||||
| 	{ | ||||
| 		/* Check if we had an "sm_" prefix */ | ||||
| 		if (strncasecmp(cmd_buf, "sm_", 3) == 0) | ||||
| 		if (strncmp(cmd_buf, "sm_", 3) == 0) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
| @ -387,7 +385,15 @@ bool ChatTriggers::PreProcessTrigger(edict_t *pEdict, const char *args) | ||||
| 	/* See if we need to do extra string manipulation */ | ||||
| 	if (prepended) | ||||
| 	{ | ||||
| 		ke::SafeSprintf(m_ToExecute, sizeof(m_ToExecute), "sm_%s", args); | ||||
| 		size_t len; | ||||
| 
 | ||||
| 		/* Check if we need to prepend sm_ */ | ||||
| 		if (prepended) | ||||
| 		{ | ||||
| 			len = ke::SafeSprintf(m_ToExecute, sizeof(m_ToExecute), "sm_%s", args); | ||||
| 		} else { | ||||
| 			len = ke::SafeStrcpy(m_ToExecute, sizeof(m_ToExecute), args); | ||||
| 		} | ||||
| 	} else { | ||||
| 		ke::SafeStrcpy(m_ToExecute, sizeof(m_ToExecute), args); | ||||
| 	} | ||||
|  | ||||
| @ -73,9 +73,9 @@ private: | ||||
| 	bool ClientIsFlooding(int client); | ||||
| 	cell_t CallOnClientSayCommand(int client); | ||||
| private: | ||||
| 	std::vector<ke::RefPtr<CommandHook>> hooks_; | ||||
| 	std::string m_PubTrigger; | ||||
| 	std::string m_PrivTrigger; | ||||
| 	ke::Vector<ke::RefPtr<CommandHook>> hooks_; | ||||
| 	ke::AString m_PubTrigger; | ||||
| 	ke::AString m_PrivTrigger; | ||||
| 	bool m_bWillProcessInPost; | ||||
| 	bool m_bIsChatTrigger; | ||||
| 	bool m_bWasFloodedMessage; | ||||
|  | ||||
| @ -30,22 +30,21 @@ | ||||
|  */ | ||||
| 
 | ||||
| #include "ConCmdManager.h" | ||||
| 
 | ||||
| #include <bridge/include/IScriptManager.h> | ||||
| #include "ChatTriggers.h" | ||||
| #include "HalfLife2.h" | ||||
| #include "PlayerManager.h" | ||||
| #include "command_args.h" | ||||
| #include "logic_bridge.h" | ||||
| #include "provider.h" | ||||
| #include "sm_stringutil.h" | ||||
| #include "PlayerManager.h" | ||||
| #include "HalfLife2.h" | ||||
| #include "ChatTriggers.h" | ||||
| #include "logic_bridge.h" | ||||
| #include "sourcemod.h" | ||||
| #include "provider.h" | ||||
| #include "command_args.h" | ||||
| #include <bridge/include/IScriptManager.h> | ||||
| 
 | ||||
| using namespace ke; | ||||
| 
 | ||||
| ConCmdManager g_ConCmds; | ||||
| 
 | ||||
| typedef std::list<CmdHook *> PluginHookList; | ||||
| typedef ke::LinkedList<CmdHook *> PluginHookList; | ||||
| void RegisterInPlugin(CmdHook *hook); | ||||
| 
 | ||||
| ConCmdManager::ConCmdManager() | ||||
| @ -121,13 +120,8 @@ void ConCmdManager::OnPluginDestroyed(IPlugin *plugin) | ||||
| 		if (hook->admin) | ||||
| 			hook->admin->group->hooks.remove(hook); | ||||
| 
 | ||||
| 		if (hook->info->hooks.empty()) { | ||||
| 		if (hook->info->hooks.empty()) | ||||
| 			RemoveConCmd(hook->info, hook->info->pCmd->GetName(), true); | ||||
| 		} | ||||
| 		else { // update plugin reference to next hook in line
 | ||||
| 			auto next = *hook->info->hooks.begin(); | ||||
| 			next->info->pPlugin = next->plugin; | ||||
| 		} | ||||
| 
 | ||||
| 		iter = pList->erase(iter); | ||||
| 		delete hook; | ||||
| @ -153,13 +147,30 @@ ConCmdInfo *ConCmdManager::FindInTrie(const char *name) | ||||
| 	return pInfo; | ||||
| } | ||||
| 
 | ||||
| ConCmdList::iterator ConCmdManager::FindInList(const char *cmd) | ||||
| { | ||||
| 	List<ConCmdInfo *>::iterator iter = m_CmdList.begin(); | ||||
| 
 | ||||
| 	while (iter != m_CmdList.end()) | ||||
| 	{ | ||||
| 		if (strcasecmp((*iter)->pCmd->GetName(), cmd) == 0) | ||||
| 			break; | ||||
| 		iter++; | ||||
| 	} | ||||
| 
 | ||||
| 	return iter; | ||||
| } | ||||
| 
 | ||||
| ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int args, ResultType type) | ||||
| { | ||||
| 	ConCmdInfo *pInfo = FindInTrie(cmd); | ||||
| 	ConCmdInfo *pInfo; | ||||
| 
 | ||||
| 	if (pInfo == NULL) | ||||
| 	if ((pInfo = FindInTrie(cmd)) == NULL) | ||||
| 	{ | ||||
| 		ConCmdList::iterator item = FindInList(cmd); | ||||
| 		if (item == m_CmdList.end()) | ||||
| 			return type; | ||||
| 		pInfo = *item; | ||||
| 	} | ||||
| 
 | ||||
| 	cell_t result = type; | ||||
| @ -170,7 +181,7 @@ ResultType ConCmdManager::DispatchClientCommand(int client, const char *cmd, int | ||||
| 		if (hook->type == CmdHook::Server || !hook->pf->IsRunnable()) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (hook->admin && !CheckAccess(client, cmd, hook->admin.get())) | ||||
| 		if (hook->admin && !CheckAccess(client, cmd, hook->admin)) | ||||
| 		{ | ||||
| 			if (result < Pl_Handled) | ||||
| 				result = Pl_Handled; | ||||
| @ -214,7 +225,17 @@ bool ConCmdManager::InternalDispatch(int client, const ICommandArgs *args) | ||||
| 	ConCmdInfo *pInfo = FindInTrie(cmd); | ||||
| 	if (pInfo == NULL) | ||||
| 	{ | ||||
|         /* Unfortunately, we now have to do a slow lookup because Valve made client commands 
 | ||||
|          * case-insensitive.  We can't even use our sortedness. | ||||
|          */ | ||||
|         if (client == 0 && !engine->IsDedicatedServer()) | ||||
|             return false; | ||||
| 
 | ||||
| 		ConCmdList::iterator item = FindInList(cmd); | ||||
| 		if (item == m_CmdList.end()) | ||||
| 			return false; | ||||
| 
 | ||||
| 		pInfo = *item; | ||||
| 	} | ||||
| 
 | ||||
| 	/* This is a hack to prevent say triggers from firing on messages that were 
 | ||||
| @ -250,7 +271,7 @@ bool ConCmdManager::InternalDispatch(int client, const ICommandArgs *args) | ||||
| 		} else { | ||||
| 			// Check admin rights if needed. realClient isn't needed since we
 | ||||
| 			// should bypass admin checks if client == 0 anyway.
 | ||||
| 			if (client && hook->admin && !CheckAccess(client, cmd, hook->admin.get())) | ||||
| 			if (client && hook->admin && !CheckAccess(client, cmd, hook->admin)) | ||||
| 			{ | ||||
| 				if (result < Pl_Handled) | ||||
| 					result = Pl_Handled; | ||||
| @ -338,8 +359,8 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction, | ||||
| 	} | ||||
| 	RefPtr<CommandGroup> cmdgroup = i->value; | ||||
| 
 | ||||
| 	CmdHook *pHook = new CmdHook(CmdHook::Client, pInfo, pFunction, description, pPlugin); | ||||
| 	pHook->admin = std::make_unique<AdminCmdInfo>(cmdgroup, adminflags); | ||||
| 	CmdHook *pHook = new CmdHook(CmdHook::Client, pInfo, pFunction, description); | ||||
| 	pHook->admin = new AdminCmdInfo(cmdgroup, adminflags); | ||||
| 
 | ||||
| 	/* First get the command group override, if any */ | ||||
| 	bool override = adminsys->GetCommandOverride(group,  | ||||
| @ -359,7 +380,7 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction, | ||||
| 		pHook->admin->eflags = pHook->admin->flags; | ||||
| 	pInfo->eflags = pHook->admin->eflags; | ||||
| 
 | ||||
| 	cmdgroup->hooks.push_back(pHook); | ||||
| 	cmdgroup->hooks.append(pHook); | ||||
| 	pInfo->hooks.append(pHook); | ||||
| 	RegisterInPlugin(pHook); | ||||
| 	return true; | ||||
| @ -377,7 +398,7 @@ bool ConCmdManager::AddServerCommand(IPluginFunction *pFunction, | ||||
| 	if (!pInfo) | ||||
| 		return false; | ||||
| 
 | ||||
| 	CmdHook *pHook = new CmdHook(CmdHook::Server, pInfo, pFunction, description, pPlugin); | ||||
| 	CmdHook *pHook = new CmdHook(CmdHook::Server, pInfo, pFunction, description); | ||||
| 
 | ||||
| 	pInfo->hooks.append(pHook); | ||||
| 	RegisterInPlugin(pHook); | ||||
| @ -404,13 +425,13 @@ void RegisterInPlugin(CmdHook *hook) | ||||
| 		const char *cmd = (*iter)->info->pCmd->GetName(); | ||||
| 		if (strcmp(orig, cmd) < 0) | ||||
| 		{ | ||||
| 			pList->emplace(iter, hook); | ||||
| 			pList->insertBefore(iter, hook); | ||||
| 			return; | ||||
| 		} | ||||
| 		iter++; | ||||
| 	} | ||||
| 
 | ||||
| 	pList->emplace_back(hook); | ||||
| 	pList->append(hook); | ||||
| } | ||||
| 
 | ||||
| void ConCmdManager::AddToCmdList(ConCmdInfo *info) | ||||
| @ -474,7 +495,7 @@ void ConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, Flag | ||||
| 		for (PluginHookList::iterator iter = group->hooks.begin(); iter != group->hooks.end(); iter++) | ||||
| 		{ | ||||
| 			CmdHook *hook = *iter; | ||||
| 			if (!remove) | ||||
| 			if (remove) | ||||
| 				hook->admin->eflags = bits; | ||||
| 			else | ||||
| 				hook->admin->eflags = hook->admin->flags; | ||||
| @ -541,6 +562,10 @@ ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *descri | ||||
| 	ConCmdInfo *pInfo; | ||||
| 	if (!m_Cmds.retrieve(name, &pInfo)) | ||||
| 	{ | ||||
| 		ConCmdList::iterator item = FindInList(name); | ||||
| 		if (item != m_CmdList.end()) | ||||
| 			return *item; | ||||
| 
 | ||||
| 		pInfo = new ConCmdInfo(); | ||||
| 		/* Find the commandopan */ | ||||
| 		ConCommand *pCmd = FindCommand(name); | ||||
| @ -623,7 +648,7 @@ void ConCmdManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs | ||||
| 
 | ||||
| 			name = hook->info->pCmd->GetName(); | ||||
| 			if (hook->helptext.length()) | ||||
| 				help = hook->helptext.c_str(); | ||||
| 				help = hook->helptext.chars(); | ||||
| 			else | ||||
| 				help = hook->info->pCmd->GetHelpText(); | ||||
| 			UTIL_ConsolePrint("  %-17.16s %-12.11s %s", name, type, help);		 | ||||
|  | ||||
| @ -32,14 +32,6 @@ | ||||
| #ifndef _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_ | ||||
| #define _INCLUDE_SOURCEMOD_CONCMDMANAGER_H_ | ||||
| 
 | ||||
| #include <list> | ||||
| #include <memory> | ||||
| 
 | ||||
| #include <am-inlinelist.h> | ||||
| #include <am-refcounting.h> | ||||
| #include <am-utility.h> | ||||
| #include <sm_stringhashmap.h> | ||||
| 
 | ||||
| #include "sm_globals.h" | ||||
| #include "sourcemm_api.h" | ||||
| #include <IForwardSys.h> | ||||
| @ -49,7 +41,12 @@ | ||||
| #include <IAdminSystem.h> | ||||
| #include "concmd_cleaner.h" | ||||
| #include "GameHooks.h" | ||||
| #include <sm_namehashset.h> | ||||
| #include <am-autoptr.h> | ||||
| #include <sm_stringhashmap.h> | ||||
| #include <am-utility.h> | ||||
| #include <am-inlinelist.h> | ||||
| #include <am-linkedlist.h> | ||||
| #include <am-refcounting.h> | ||||
| 
 | ||||
| using namespace SourceHook; | ||||
| 
 | ||||
| @ -58,7 +55,7 @@ struct ConCmdInfo; | ||||
| 
 | ||||
| struct CommandGroup : public ke::Refcounted<CommandGroup> | ||||
| { | ||||
| 	std::list<CmdHook *> hooks; | ||||
| 	ke::LinkedList<CmdHook *> hooks; | ||||
| }; | ||||
| 
 | ||||
| struct AdminCmdInfo | ||||
| @ -81,11 +78,10 @@ struct CmdHook : public ke::InlineListNode<CmdHook> | ||||
| 		Client | ||||
| 	}; | ||||
| 
 | ||||
| 	CmdHook(Type type, ConCmdInfo *cmd, IPluginFunction *fun, const char *description, IPlugin *plugin) | ||||
| 	CmdHook(Type type, ConCmdInfo *cmd, IPluginFunction *fun, const char *description) | ||||
| 		: type(type), | ||||
| 		  info(cmd), | ||||
| 		  pf(fun), | ||||
| 		  plugin(plugin), | ||||
| 		  helptext(description) | ||||
| 	{ | ||||
| 	} | ||||
| @ -93,9 +89,8 @@ struct CmdHook : public ke::InlineListNode<CmdHook> | ||||
| 	Type type; | ||||
| 	ConCmdInfo *info; | ||||
| 	IPluginFunction *pf;				/* function hook */ | ||||
| 	IPlugin *plugin;					/* owning plugin */ | ||||
| 	std::string helptext;				/* help text */ | ||||
| 	std::unique_ptr<AdminCmdInfo> admin;	/* admin requirements, if any */ | ||||
| 	ke::AString helptext;				/* help text */ | ||||
| 	ke::AutoPtr<AdminCmdInfo> admin;	/* admin requirements, if any */ | ||||
| }; | ||||
| 
 | ||||
| typedef ke::InlineList<CmdHook> CmdHookList; | ||||
| @ -109,32 +104,12 @@ struct ConCmdInfo | ||||
| 		pCmd = nullptr; | ||||
| 		eflags = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	bool sourceMod;					/**< Determines whether or not concmd was created by a SourceMod plugin */ | ||||
| 	ConCommand *pCmd;				/**< Pointer to the command itself */ | ||||
| 	CmdHookList hooks;				/**< Hook list */ | ||||
| 	FlagBits eflags;				/**< Effective admin flags */ | ||||
| 	ke::RefPtr<CommandHook> sh_hook;   /**< SourceHook hook, if any. */ | ||||
| 	IPlugin *pPlugin; 				/**< Owning plugin handle. */ | ||||
| 
 | ||||
| 	struct ConCmdPolicy | ||||
| 	{ | ||||
| 		static inline bool matches(const char *name, ConCmdInfo *info) | ||||
| 		{ | ||||
| 			const char *conCmdChars = info->pCmd->GetName(); | ||||
| 
 | ||||
| 			std::string concmdName = ke::Lowercase(conCmdChars); | ||||
| 			std::string input = ke::Lowercase(name); | ||||
| 
 | ||||
| 			return concmdName == input; | ||||
| 		} | ||||
| 
 | ||||
| 		static inline uint32_t hash(const detail::CharsAndLength &key) | ||||
| 		{ | ||||
| 			std::string lower = ke::Lowercase(key.c_str()); | ||||
| 			return detail::CharsAndLength(lower.c_str()).hash(); | ||||
| 		} | ||||
| 	}; | ||||
| }; | ||||
| 
 | ||||
| typedef List<ConCmdInfo *> ConCmdList; | ||||
| @ -178,6 +153,11 @@ private: | ||||
| 	void AddToCmdList(ConCmdInfo *info); | ||||
| 	void RemoveConCmd(ConCmdInfo *info, const char *cmd, bool untrack); | ||||
| 	bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin); | ||||
| 
 | ||||
| 	// Case insensitive
 | ||||
| 	ConCmdList::iterator FindInList(const char *name); | ||||
| 
 | ||||
| 	// Case sensitive
 | ||||
| 	ConCmdInfo *FindInTrie(const char *name); | ||||
| public: | ||||
| 	inline const List<ConCmdInfo *> & GetCommandList() | ||||
| @ -187,7 +167,7 @@ public: | ||||
| private: | ||||
| 	typedef StringHashMap<ke::RefPtr<CommandGroup> > GroupMap; | ||||
| 
 | ||||
| 	NameHashSet<ConCmdInfo *, ConCmdInfo::ConCmdPolicy> m_Cmds; /* command lookup */ | ||||
| 	StringHashMap<ConCmdInfo *> m_Cmds; /* command lookup */ | ||||
| 	GroupMap m_CmdGrps;				/* command group map */ | ||||
| 	ConCmdList m_CmdList;			/* command list */ | ||||
| }; | ||||
|  | ||||
| @ -41,11 +41,7 @@ ConVarManager g_ConVarManager; | ||||
| 
 | ||||
| const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String}; | ||||
| typedef List<const ConVar *> ConVarList; | ||||
| NameHashSet<ConVarInfo *, ConVarInfo::ConVarPolicy> convar_cache; | ||||
| 
 | ||||
| enum { | ||||
| 	eQueryCvarValueStatus_Cancelled = -1, | ||||
| }; | ||||
| NameHashSet<ConVarInfo *> convar_cache; | ||||
| 
 | ||||
| class ConVarReentrancyGuard | ||||
| { | ||||
| @ -210,27 +206,18 @@ void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na | ||||
| void ConVarManager::OnPluginUnloaded(IPlugin *plugin) | ||||
| { | ||||
| 	ConVarList *pConVarList; | ||||
| 	List<ConVarQuery>::iterator iter; | ||||
| 
 | ||||
| 	/* If plugin has a convar list, free its memory */ | ||||
| 	if (plugin->GetProperty("ConVarList", (void **)&pConVarList, true)) | ||||
| 	{ | ||||
| 		delete pConVarList; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Clear any references to this plugin as the convar creator */ | ||||
| 	for (List<ConVarInfo *>::iterator iter = m_ConVars.begin(); iter != m_ConVars.end(); ++iter) | ||||
| 	{ | ||||
| 		ConVarInfo *pInfo = (*iter); | ||||
| 
 | ||||
| 		if (pInfo->pPlugin == plugin) | ||||
| 		{ | ||||
| 			pInfo->pPlugin = nullptr; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	const IPluginRuntime * pRuntime = plugin->GetRuntime(); | ||||
| 
 | ||||
| 	/* Remove convar queries for this plugin that haven't returned results yet */ | ||||
| 	for (List<ConVarQuery>::iterator iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();) | ||||
| 	for (iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();) | ||||
| 	{ | ||||
| 		ConVarQuery &query = (*iter); | ||||
| 		if (query.pCallback->GetParentRuntime() == pRuntime) | ||||
| @ -251,19 +238,6 @@ void ConVarManager::OnClientDisconnected(int client) | ||||
| 		ConVarQuery &query = (*iter); | ||||
| 		if (query.client == client) | ||||
| 		{ | ||||
| 			IPluginFunction *pCallback = query.pCallback; | ||||
| 			if (pCallback) | ||||
| 			{ | ||||
| 				cell_t ret; | ||||
| 
 | ||||
| 				pCallback->PushCell(query.cookie); | ||||
| 				pCallback->PushCell(client); | ||||
| 				pCallback->PushCell(eQueryCvarValueStatus_Cancelled); | ||||
| 				pCallback->PushString(""); | ||||
| 				pCallback->PushString(""); | ||||
| 				pCallback->PushCell(query.value); | ||||
| 				pCallback->Execute(&ret); | ||||
| 			} | ||||
| 			iter = m_ConVarQueries.erase(iter); | ||||
| 			continue; | ||||
| 		} | ||||
| @ -356,8 +330,6 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, | ||||
| 	ConVarInfo *pInfo = NULL; | ||||
| 	Handle_t hndl = 0; | ||||
| 
 | ||||
| 	IPlugin *plugin = scripts->FindPluginByContext(pContext->GetContext()); | ||||
| 
 | ||||
| 	/* Find out if the convar exists already */ | ||||
| 	pConVar = icvar->FindVar(name); | ||||
| 
 | ||||
| @ -365,16 +337,11 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, | ||||
| 	if (pConVar) | ||||
| 	{ | ||||
| 		/* Add convar to plugin's list */ | ||||
| 		AddConVarToPluginList(plugin, pConVar); | ||||
| 		AddConVarToPluginList(pContext, pConVar); | ||||
| 
 | ||||
| 		/* First find out if we already have a handle to it */ | ||||
| 		if (convar_cache_lookup(name, &pInfo)) | ||||
| 		{ | ||||
| 			/* If the convar doesn't have an owning plugin, but SM created it, adopt it */ | ||||
| 			if (pInfo->sourceMod && pInfo->pPlugin == nullptr) { | ||||
| 				pInfo->pPlugin = plugin; | ||||
| 			} | ||||
| 
 | ||||
| 			return pInfo->handle; | ||||
| 		} | ||||
| 		else | ||||
| @ -415,7 +382,6 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, | ||||
| 	pInfo->handle = hndl; | ||||
| 	pInfo->sourceMod = true; | ||||
| 	pInfo->pChangeForward = NULL; | ||||
| 	pInfo->pPlugin = plugin; | ||||
| 
 | ||||
| 	/* Create a handle from the new convar */ | ||||
| 	hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL); | ||||
| @ -432,7 +398,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, | ||||
| 	pInfo->pVar = pConVar; | ||||
| 
 | ||||
| 	/* Add convar to plugin's list */ | ||||
| 	AddConVarToPluginList(plugin, pConVar); | ||||
| 	AddConVarToPluginList(pContext, pConVar); | ||||
| 
 | ||||
| 	/* Insert struct into caches */ | ||||
| 	m_ConVars.push_back(pInfo); | ||||
| @ -586,13 +552,15 @@ QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char | ||||
| 	return cookie; | ||||
| } | ||||
| 
 | ||||
| void ConVarManager::AddConVarToPluginList(IPlugin *plugin, const ConVar *pConVar) | ||||
| void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar) | ||||
| { | ||||
| 	ConVarList *pConVarList; | ||||
| 	ConVarList::iterator iter; | ||||
| 	bool inserted = false; | ||||
| 	const char *orig = pConVar->GetName(); | ||||
| 
 | ||||
| 	IPlugin *plugin = scripts->FindPluginByContext(pContext->GetContext()); | ||||
| 
 | ||||
| 	/* Check plugin for an existing convar list */ | ||||
| 	if (!plugin->GetProperty("ConVarList", (void **)&pConVarList)) | ||||
| 	{ | ||||
| @ -711,7 +679,7 @@ void ConVarManager::OnClientQueryFinished(QueryCvarCookie_t cookie, | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar, IPlugin **ppPlugin) | ||||
| HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar) | ||||
| { | ||||
| 	ConVarInfo *pInfo; | ||||
| 	HandleError error; | ||||
| @ -726,10 +694,5 @@ HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar, IPlugi | ||||
| 		*pVar = pInfo->pVar; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ppPlugin) | ||||
| 	{ | ||||
| 		*ppPlugin = pInfo->pPlugin; | ||||
| 	} | ||||
| 
 | ||||
| 	return error; | ||||
| } | ||||
|  | ||||
| @ -62,27 +62,16 @@ struct ConVarInfo | ||||
| 	bool sourceMod;						/**< Determines whether or not convar was created by a SourceMod plugin */ | ||||
| 	IChangeableForward *pChangeForward;	/**< Forward associated with convar */ | ||||
| 	ConVar *pVar;						/**< The actual convar */ | ||||
| 	IPlugin *pPlugin; 					/**< Originally owning plugin */ | ||||
| 	List<IConVarChangeListener *> changeListeners; | ||||
| 
 | ||||
| 	struct ConVarPolicy | ||||
| 	static inline bool matches(const char *name, const ConVarInfo *info) | ||||
| 	{ | ||||
| 		static inline bool matches(const char *name, ConVarInfo *info) | ||||
| 		{ | ||||
| 			const char *conVarChars = info->pVar->GetName(); | ||||
| 
 | ||||
| 			std::string convarName = ke::Lowercase(conVarChars); | ||||
| 			std::string input = ke::Lowercase(name); | ||||
| 
 | ||||
| 			return convarName == input; | ||||
| 		return strcmp(name, info->pVar->GetName()) == 0; | ||||
| 	} | ||||
| 
 | ||||
| 	static inline uint32_t hash(const detail::CharsAndLength &key) | ||||
| 	{ | ||||
| 			std::string lower = ke::Lowercase(key.c_str()); | ||||
| 			return detail::CharsAndLength(lower.c_str()).hash(); | ||||
| 		return key.hash(); | ||||
| 	} | ||||
| 	}; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| @ -155,7 +144,7 @@ public: | ||||
| 
 | ||||
| 	bool IsQueryingSupported(); | ||||
| 
 | ||||
| 	HandleError ReadConVarHandle(Handle_t hndl, ConVar **pVar, IPlugin **ppPlugin = nullptr); | ||||
| 	HandleError ReadConVarHandle(Handle_t hndl, ConVar **pVar); | ||||
| 
 | ||||
| 	// Called via game hooks.
 | ||||
| 	void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue); | ||||
| @ -172,7 +161,7 @@ private: | ||||
| 	/**
 | ||||
| 	 * Adds a convar to a plugin's list. | ||||
| 	 */ | ||||
| 	static void AddConVarToPluginList(IPlugin *plugin, const ConVar *pConVar); | ||||
| 	static void AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar); | ||||
| private: | ||||
| 	HandleType_t m_ConVarType; | ||||
| 	List<ConVarInfo *> m_ConVars; | ||||
|  | ||||
| @ -307,7 +307,7 @@ bool ConsoleDetours::AddListener(IPluginFunction *fun, const char *command) | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		std::unique_ptr<char[]> str(UTIL_ToLowerCase(command)); | ||||
| 		ke::AutoPtr<char[]> str(UTIL_ToLowerCase(command)); | ||||
| 		IChangeableForward *forward; | ||||
| 		if (!m_Listeners.retrieve(str.get(), &forward)) | ||||
| 		{ | ||||
| @ -329,7 +329,7 @@ bool ConsoleDetours::RemoveListener(IPluginFunction *fun, const char *command) | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		std::unique_ptr<char[]> str(UTIL_ToLowerCase(command)); | ||||
| 		ke::AutoPtr<char[]> str(UTIL_ToLowerCase(command)); | ||||
| 		IChangeableForward *forward; | ||||
| 		if (!m_Listeners.retrieve(str.get(), &forward)) | ||||
| 			return false; | ||||
|  | ||||
| @ -290,18 +290,18 @@ ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value, | ||||
| 		pBase = pBase->m_pGlobalClassNext; | ||||
| 	} | ||||
| 
 | ||||
| 	std::string vstr(value); | ||||
| 	m_KeyValues.replace(option, std::move(vstr)); | ||||
| 	ke::AString vstr(value); | ||||
| 	m_KeyValues.replace(option, ke::Move(vstr)); | ||||
| 
 | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| const char *CoreConfig::GetCoreConfigValue(const char *key) | ||||
| { | ||||
| 	StringHashMap<std::string>::Result r = m_KeyValues.find(key); | ||||
| 	StringHashMap<ke::AString>::Result r = m_KeyValues.find(key); | ||||
| 	if (!r.found()) | ||||
| 		return NULL; | ||||
| 	return r->value.c_str(); | ||||
| 	return r->value.chars(); | ||||
| } | ||||
| 
 | ||||
| bool SM_AreConfigsExecuted() | ||||
|  | ||||
| @ -68,7 +68,7 @@ private: | ||||
| 	 */ | ||||
| 	ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength); | ||||
| private: | ||||
| 	StringHashMap<std::string> m_KeyValues; | ||||
| 	StringHashMap<ke::AString> m_KeyValues; | ||||
| }; | ||||
| 
 | ||||
| extern bool SM_AreConfigsExecuted(); | ||||
|  | ||||
| @ -484,7 +484,7 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast) | ||||
| 				pForward->PushCell(BAD_HANDLE); | ||||
| 			} | ||||
| 
 | ||||
| 			pForward->PushString(pHook->name.c_str()); | ||||
| 			pForward->PushString(pHook->name.chars()); | ||||
| 			pForward->PushCell(bDontBroadcast); | ||||
| 			pForward->Execute(NULL); | ||||
| 
 | ||||
| @ -505,7 +505,7 @@ bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast) | ||||
| 		{ | ||||
| 			assert(pHook->pPostHook == NULL); | ||||
| 			assert(pHook->pPreHook == NULL); | ||||
| 			m_EventHooks.remove(pHook->name.c_str()); | ||||
| 			m_EventHooks.remove(pHook->name.chars()); | ||||
| 			delete pHook; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -71,11 +71,11 @@ struct EventHook | ||||
| 	IChangeableForward *pPostHook; | ||||
| 	bool postCopy; | ||||
| 	unsigned int refCount; | ||||
| 	std::string name; | ||||
| 	ke::AString name; | ||||
| 
 | ||||
| 	static inline bool matches(const char *name, const EventHook *hook) | ||||
| 	{ | ||||
| 		return strcmp(name, hook->name.c_str()) == 0; | ||||
| 		return strcmp(name, hook->name.chars()) == 0; | ||||
| 	} | ||||
| 	static inline uint32_t hash(const detail::CharsAndLength &key) | ||||
| 	{ | ||||
|  | ||||
| @ -91,7 +91,7 @@ void GameHooks::OnVSPReceived() | ||||
| 
 | ||||
| void GameHooks::Shutdown() | ||||
| { | ||||
| 	for (size_t i = 0; i < hooks_.size(); i++) | ||||
| 	for (size_t i = 0; i < hooks_.length(); i++) | ||||
| 		SH_REMOVE_HOOK_ID(hooks_[i]); | ||||
| 	hooks_.clear(); | ||||
| 
 | ||||
| @ -115,7 +115,7 @@ void GameHooks::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPla | ||||
|                                          const char *cvarName, const char *cvarValue){ | ||||
| 	int client = IndexOfEdict(pPlayer); | ||||
| 
 | ||||
| # if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| # if SOURCE_ENGINE == SE_CSGO | ||||
| 	if (g_Players.HandleConVarQuery(cookie, client, result, cvarName, cvarValue)) | ||||
| 		return; | ||||
| # endif | ||||
|  | ||||
| @ -63,7 +63,7 @@ class CommandHook : public ke::Refcounted<CommandHook> | ||||
| { | ||||
| public: | ||||
| 	// return false to RETURN_META(MRES_IGNORED), or true to SUPERCEDE.
 | ||||
| 	typedef ke::Function<bool(int, const ICommandArgs *)> Callback; | ||||
| 	typedef ke::Lambda<bool(int, const ICommandArgs *)> Callback; | ||||
| 
 | ||||
| public: | ||||
| 	CommandHook(ConCommand *cmd, const Callback &callback, bool post); | ||||
| @ -114,11 +114,11 @@ private: | ||||
| 	void SetCommandClient(int client); | ||||
| 
 | ||||
| private: | ||||
| 	class HookList : public std::vector<int> | ||||
| 	class HookList : public ke::Vector<int> | ||||
| 	{ | ||||
| 	public: | ||||
| 		HookList &operator += (int hook_id) { | ||||
| 			this->push_back(hook_id); | ||||
| 			this->append(hook_id); | ||||
| 			return *this; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| @ -45,10 +45,9 @@ | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| #include <cstrike15_usermessages.pb.h> | ||||
| #elif SOURCE_ENGINE == SE_BLADE | ||||
| #include <berimbau_usermessages.pb.h> | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| typedef ICommandLine *(*FakeGetCommandLine)(); | ||||
| 
 | ||||
| #define TIER0_NAME			FORMAT_SOURCE_BIN_NAME("tier0") | ||||
| @ -60,7 +59,6 @@ ConVar *sv_lan = NULL; | ||||
| static void *g_EntList = NULL; | ||||
| static void **g_pEntInfoList = NULL; | ||||
| static int entInfoOffset = -1; | ||||
| static int utlVecOffsetOffset = -1; | ||||
| 
 | ||||
| static CEntInfo *EntInfoArray() | ||||
| { | ||||
| @ -145,7 +143,6 @@ void CHalfLife2::OnSourceModAllInitialized_Post() | ||||
| 	m_CSGOBadList.add("m_nActiveCoinRank"); | ||||
| 	m_CSGOBadList.add("m_nMusicID"); | ||||
| #endif | ||||
| 	g_pGameConf->GetOffset("CSendPropExtra_UtlVector::m_Offset", &utlVecOffsetOffset); | ||||
| } | ||||
| 
 | ||||
| ConfigResult CHalfLife2::OnSourceModConfigChanged(const char *key, const char *value, | ||||
| @ -183,7 +180,6 @@ void CHalfLife2::InitLogicalEntData() | ||||
| 	|| SOURCE_ENGINE == SE_CSS     \ | ||||
| 	|| SOURCE_ENGINE == SE_SDK2013 \ | ||||
| 	|| SOURCE_ENGINE == SE_BMS     \ | ||||
| 	|| SOURCE_ENGINE == SE_BLADE   \ | ||||
| 	|| SOURCE_ENGINE == SE_NUCLEARDAWN | ||||
| 
 | ||||
| 	if (g_SMAPI->GetServerFactory(false)("VSERVERTOOLS003", nullptr)) | ||||
| @ -321,41 +317,23 @@ bool UTIL_FindInSendTable(SendTable *pTable, | ||||
| 						  sm_sendprop_info_t *info, | ||||
| 						  unsigned int offset) | ||||
| { | ||||
| 	const char *pname; | ||||
| 	int props = pTable->GetNumProps(); | ||||
| 	for (int i = 0; i < props; i++) | ||||
| 	SendProp *prop; | ||||
| 
 | ||||
| 	for (int i=0; i<props; i++) | ||||
| 	{ | ||||
| 		SendProp *prop = pTable->GetProp(i); | ||||
| 
 | ||||
| 		// Skip InsideArray props (SendPropArray / SendPropArray2),
 | ||||
| 		// we'll find them later by their containing array.
 | ||||
| 		if (prop->IsInsideArray()) { | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		const char *pname = prop->GetName(); | ||||
| 		SendTable *pInnerTable = prop->GetDataTable(); | ||||
| 
 | ||||
| 		prop = pTable->GetProp(i); | ||||
| 		pname = prop->GetName(); | ||||
| 		if (pname && strcmp(name, pname) == 0) | ||||
| 		{ | ||||
| 			// get true offset of CUtlVector
 | ||||
| 			if (utlVecOffsetOffset != -1 && prop->GetOffset() == 0 && pInnerTable && pInnerTable->GetNumProps()) | ||||
| 			{ | ||||
| 				SendProp *pLengthProxy = pInnerTable->GetProp(0); | ||||
| 				const char *ipname = pLengthProxy->GetName(); | ||||
| 				if (ipname && strcmp(ipname, "lengthproxy") == 0 && pLengthProxy->GetExtraData()) | ||||
| 				{ | ||||
| 					info->prop = prop; | ||||
| 					info->actual_offset = offset + *reinterpret_cast<size_t *>(reinterpret_cast<intptr_t>(pLengthProxy->GetExtraData()) + utlVecOffsetOffset); | ||||
| 					return true; | ||||
| 				} | ||||
| 			} | ||||
| 			info->prop = prop; | ||||
| 			info->actual_offset = offset + info->prop->GetOffset(); | ||||
| 			return true; | ||||
| 		} | ||||
| 		if (pInnerTable) | ||||
| 		if (prop->GetDataTable()) | ||||
| 		{ | ||||
| 			if (UTIL_FindInSendTable(pInnerTable,  | ||||
| 			if (UTIL_FindInSendTable(prop->GetDataTable(),  | ||||
| 				name, | ||||
| 				info, | ||||
| 				offset + prop->GetOffset()) | ||||
| @ -538,7 +516,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg) | ||||
| 			char buffer[253]; | ||||
| 			ke::SafeSprintf(buffer, sizeof(buffer), "%s\1\n", msg); | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 			CCSUsrMsg_SayText *pMsg; | ||||
| 			if ((pMsg = (CCSUsrMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) | ||||
| 			{ | ||||
| @ -565,7 +543,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	CCSUsrMsg_TextMsg *pMsg; | ||||
| 	if ((pMsg = (CCSUsrMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) | ||||
| 	{ | ||||
| @ -602,7 +580,7 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg) | ||||
| { | ||||
| 	cell_t players[] = {client}; | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	CCSUsrMsg_HintText *pMsg; | ||||
| 	if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) | ||||
| 	{ | ||||
| @ -632,7 +610,7 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg) | ||||
| 
 | ||||
| bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg) | ||||
| { | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	CCSUsrMsg_HintText *pMsg; | ||||
| 	if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL) | ||||
| 	{ | ||||
| @ -667,7 +645,7 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo | ||||
| 	int count = 0; | ||||
| 	cell_t players[] = {client}; | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	CCSUsrMsg_VGUIMenu *pMsg; | ||||
| 	if ((pMsg = (CCSUsrMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL) | ||||
| 	{ | ||||
| @ -692,7 +670,7 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo | ||||
| 		SubKey = data->GetFirstSubKey(); | ||||
| 	} | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	pMsg->set_name(name); | ||||
| 	pMsg->set_show(show); | ||||
| 
 | ||||
| @ -1234,45 +1212,6 @@ bool IsWindowsReservedDeviceName(const char *pMapname) | ||||
| } | ||||
| #endif  | ||||
| 
 | ||||
| #if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS && SOURCE_ENGINE != SE_MOCK | ||||
| // This frees memory allocated by the game using the game's CRT on Windows,
 | ||||
| // avoiding a crash due to heap corruption (issue #910).
 | ||||
| template< class T, class I > | ||||
| class CUtlMemoryGlobalMalloc : public CUtlMemory< T, I > | ||||
| { | ||||
| 	typedef CUtlMemory< T, I > BaseClass; | ||||
| 
 | ||||
| public: | ||||
| 	using BaseClass::BaseClass; | ||||
| 
 | ||||
| 	void Purge() | ||||
| 	{ | ||||
| 		if (!IsExternallyAllocated()) | ||||
| 		{ | ||||
| 			if (m_pMemory) | ||||
| 			{ | ||||
| 				UTLMEMORY_TRACK_FREE(); | ||||
| 				g_pMemAlloc->Free((void*)m_pMemory); | ||||
| 				m_pMemory = 0; | ||||
| 			} | ||||
| 			m_nAllocationCount = 0; | ||||
| 		} | ||||
| 		BaseClass::Purge(); | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| void CHalfLife2::FreeUtlVectorUtlString(CUtlVector<CUtlString, CUtlMemoryGlobalMalloc<CUtlString>> &vec) | ||||
| { | ||||
| 	CUtlMemoryGlobalMalloc<unsigned char> *pMemory; | ||||
| 	FOR_EACH_VEC(vec, i) | ||||
| 	{ | ||||
| 		pMemory = (CUtlMemoryGlobalMalloc<unsigned char> *) &vec[i].m_Storage.m_Memory; | ||||
| 		pMemory->Purge(); | ||||
| 		vec[i].m_Storage.SetLength(0); | ||||
| 	} | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_t nMapNameMax) | ||||
| { | ||||
| 	/* We need to ensure user input does not contain reserved device names on windows */ | ||||
| @ -1306,13 +1245,8 @@ SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_ | ||||
| 
 | ||||
| 	static size_t helperCmdLen = strlen(pHelperCmd->GetName()); | ||||
| 
 | ||||
| #ifdef PLATFORM_WINDOWS | ||||
| 	CUtlVector<CUtlString, CUtlMemoryGlobalMalloc<CUtlString>> results; | ||||
| 	pHelperCmd->AutoCompleteSuggest(pMapName, *(CUtlVector<CUtlString, CUtlMemory<CUtlString>>*)&results); | ||||
| #else | ||||
| 	CUtlVector<CUtlString> results; | ||||
| 	pHelperCmd->AutoCompleteSuggest(pMapName, results); | ||||
| #endif | ||||
| 	if (results.Count() == 0) | ||||
| 		return SMFindMapResult::NotFound; | ||||
| 
 | ||||
| @ -1324,17 +1258,11 @@ SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_ | ||||
| 	bool bExactMatch = Q_strcmp(pMapName, &results[0][helperCmdLen + 1]) == 0; | ||||
| 	if (bExactMatch) | ||||
| 	{ | ||||
| #ifdef PLATFORM_WINDOWS | ||||
| 		FreeUtlVectorUtlString(results); | ||||
| #endif | ||||
| 		return SMFindMapResult::Found; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		ke::SafeStrcpy(pFoundMap, nMapNameMax, &results[0][helperCmdLen + 1]); | ||||
| #ifdef PLATFORM_WINDOWS | ||||
| 		FreeUtlVectorUtlString(results); | ||||
| #endif | ||||
| 		return SMFindMapResult::FuzzyMatch; | ||||
| 	} | ||||
| 
 | ||||
| @ -1388,36 +1316,8 @@ bool CHalfLife2::IsMapValid(const char *map) | ||||
| 	return FindMap(map) == SMFindMapResult::Found; | ||||
| } | ||||
| 
 | ||||
| #if SOURCE_ENGINE < SE_ORANGEBOX | ||||
| class VKeyValuesSS_Helper {}; | ||||
| static bool VKeyValuesSS(CBaseEntity* pThisPtr, const char *pszKey, const char *pszValue, int offset) | ||||
| { | ||||
| 	void** this_ptr = *reinterpret_cast<void***>(&pThisPtr); | ||||
| 	void** vtable = *reinterpret_cast<void***>(pThisPtr); | ||||
| 	void* vfunc = vtable[offset]; | ||||
| 
 | ||||
| 	union | ||||
| 	{ | ||||
| 		bool (VKeyValuesSS_Helper::* mfpnew)(const char *, const char *); | ||||
| #ifndef PLATFORM_POSIX | ||||
| 		void* addr; | ||||
| 	} u; | ||||
| 	u.addr = vfunc; | ||||
| #else | ||||
| 		struct | ||||
| 		{ | ||||
| 			void* addr; | ||||
| 			intptr_t adjustor; | ||||
| 		} s; | ||||
| } u; | ||||
| 	u.s.addr = vfunc; | ||||
| 	u.s.adjustor = 0; | ||||
| #endif | ||||
| 
 | ||||
| 	return (bool)(reinterpret_cast<VKeyValuesSS_Helper*>(this_ptr)->*u.mfpnew)(pszKey, pszValue); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| // TODO: Add ep1 support for this. (No IServerTools available there)
 | ||||
| #if SOURCE_ENGINE >= SE_ORANGEBOX | ||||
| string_t CHalfLife2::AllocPooledString(const char *pszValue) | ||||
| { | ||||
| 	// This is admittedly a giant hack, but it's a relatively safe method for
 | ||||
| @ -1427,58 +1327,28 @@ string_t CHalfLife2::AllocPooledString(const char *pszValue) | ||||
| 	// current targetname string_t, set it to our string to insert via SetKeyValue,
 | ||||
| 	// read back the new targetname value, restore the old value, and return the new one.
 | ||||
| 
 | ||||
| #if SOURCE_ENGINE < SE_ORANGEBOX | ||||
| 	CBaseEntity* pEntity = nullptr; | ||||
| 	for (int i = 0; i < gpGlobals->maxEntities; ++i) | ||||
| 	{ | ||||
| 		pEntity = ReferenceToEntity(i); | ||||
| 		if (pEntity) | ||||
| 		{ | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (!pEntity) | ||||
| 	{ | ||||
| 		logger->LogError("Failed to locate a valid entity for AllocPooledString."); | ||||
| 		return NULL_STRING; | ||||
| 	} | ||||
| 
 | ||||
| #else | ||||
| 	CBaseEntity *pEntity = ((IServerUnknown *) servertools->FirstEntity())->GetBaseEntity(); | ||||
| #endif | ||||
| 	auto *pDataMap = GetDataMap(pEntity); | ||||
| 	assert(pDataMap); | ||||
| 
 | ||||
| 	static int iNameOffset = -1; | ||||
| 	if (iNameOffset == -1) | ||||
| 	static int offset = -1; | ||||
| 	if (offset == -1) | ||||
| 	{ | ||||
| 		sm_datatable_info_t info; | ||||
| 		bool found = FindDataMapInfo(pDataMap, "m_iName", &info); | ||||
| 		assert(found); | ||||
| 		iNameOffset = info.actual_offset; | ||||
| 		offset = info.actual_offset; | ||||
| 	} | ||||
| 
 | ||||
| 	string_t* pProp = (string_t*)((intp)pEntity + iNameOffset); | ||||
| 	string_t *pProp = (string_t *) ((intp) pEntity + offset); | ||||
| 	string_t backup = *pProp; | ||||
| 
 | ||||
| #if SOURCE_ENGINE < SE_ORANGEBOX | ||||
| 	static int iFuncOffset; | ||||
| 	if (!g_pGameConf->GetOffset("DispatchKeyValue", &iFuncOffset) || !iFuncOffset) | ||||
| 	{ | ||||
| 		logger->LogError("Failed to locate DispatchKeyValue in core gamedata. AllocPooledString unsupported."); | ||||
| 		return NULL_STRING; | ||||
| 	} | ||||
| 	VKeyValuesSS(pEntity, "targetname", pszValue, iFuncOffset); | ||||
| #else	 | ||||
| 	servertools->SetKeyValue(pEntity, "targetname", pszValue); | ||||
| #endif | ||||
| 
 | ||||
| 	string_t newString = *pProp; | ||||
| 	*pProp = backup; | ||||
| 
 | ||||
| 	return newString; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| bool CHalfLife2::GetServerSteam3Id(char *pszOut, size_t len) const | ||||
| { | ||||
|  | ||||
| @ -179,12 +179,6 @@ enum class SMFindMapResult : cell_t { | ||||
| 	PossiblyAvailable | ||||
| }; | ||||
| 
 | ||||
| #if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS | ||||
| template< class T, class I = int > | ||||
| class CUtlMemoryGlobalMalloc; | ||||
| class CUtlString; | ||||
| #endif | ||||
| 
 | ||||
| class CHalfLife2 :  | ||||
| 	public SMGlobalClass, | ||||
| 	public IGameHelpers | ||||
| @ -235,11 +229,10 @@ public: //IGameHelpers | ||||
| 	bool IsMapValid(const char *map); | ||||
| 	SMFindMapResult FindMap(char *pMapName, size_t nMapNameMax); | ||||
| 	SMFindMapResult FindMap(const char *pMapName, char *pFoundMap = NULL, size_t nMapNameMax = 0); | ||||
| #if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS && SOURCE_ENGINE != SE_MOCK | ||||
| 	void FreeUtlVectorUtlString(CUtlVector<CUtlString, CUtlMemoryGlobalMalloc<CUtlString>> &vec); | ||||
| #endif | ||||
| 	bool GetMapDisplayName(const char *pMapName, char *pDisplayname, size_t nMapNameMax); | ||||
| #if SOURCE_ENGINE >= SE_ORANGEBOX | ||||
| 	string_t AllocPooledString(const char *pszValue); | ||||
| #endif | ||||
| 	bool GetServerSteam3Id(char *pszOut, size_t len) const override; | ||||
| 	uint64_t GetServerSteamId64() const override; | ||||
| public: | ||||
| @ -278,7 +271,7 @@ public: | ||||
| 		return !m_bFollowCSGOServerGuidelines || !m_CSGOBadList.has(pszPropName); | ||||
| 	} | ||||
| private: | ||||
| 	ke::HashSet<std::string, detail::StringHashMapPolicy> m_CSGOBadList; | ||||
| 	ke::HashSet<ke::AString, detail::StringHashMapPolicy> m_CSGOBadList; | ||||
| 	bool m_bFollowCSGOServerGuidelines = true; | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| @ -36,7 +36,7 @@ | ||||
| #include "MenuManager.h" | ||||
| #include "CellRecipientFilter.h" | ||||
| #if defined MENU_DEBUG | ||||
| #include <bridge/include/ILogger.h> | ||||
| #include "Logger.h" | ||||
| #endif | ||||
| #include "logic_bridge.h" | ||||
| #include "AutoHandleRooter.h" | ||||
| @ -59,7 +59,7 @@ Handle_t BaseMenuStyle::GetHandle() | ||||
| void BaseMenuStyle::AddClientToWatch(int client) | ||||
| { | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("[SM_MENU] AddClientToWatch(%d)", client); | ||||
| 	g_Logger.LogMessage("[SM_MENU] AddClientToWatch(%d)", client); | ||||
| #endif | ||||
| 	m_WatchList.push_back(client); | ||||
| } | ||||
| @ -67,7 +67,7 @@ void BaseMenuStyle::AddClientToWatch(int client) | ||||
| void BaseMenuStyle::RemoveClientFromWatch(int client) | ||||
| { | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("[SM_MENU] RemoveClientFromWatch(%d)", client); | ||||
| 	g_Logger.LogMessage("[SM_MENU] RemoveClientFromWatch(%d)", client); | ||||
| #endif | ||||
| 	m_WatchList.remove(client); | ||||
| } | ||||
| @ -75,7 +75,7 @@ void BaseMenuStyle::RemoveClientFromWatch(int client) | ||||
| void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool bAutoIgnore/* =false */) | ||||
| { | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("[SM_MENU] _CancelClientMenu() (client %d) (bAutoIgnore %d) (reason %d)", client, bAutoIgnore, reason); | ||||
| 	g_Logger.LogMessage("[SM_MENU] _CancelClientMenu() (client %d) (bAutoIgnore %d) (reason %d)", client, bAutoIgnore, reason); | ||||
| #endif | ||||
| 	CBaseMenuPlayer *player = GetMenuPlayer(client); | ||||
| 	menu_states_t &states = player->states; | ||||
| @ -115,7 +115,7 @@ void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool | ||||
| void BaseMenuStyle::CancelMenu(CBaseMenu *menu) | ||||
| { | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("[SM_MENU] CancelMenu() (menu %p)", menu); | ||||
| 	g_Logger.LogMessage("[SM_MENU] CancelMenu() (menu %p)", menu); | ||||
| #endif | ||||
| 	int maxClients = g_Players.GetMaxClients(); | ||||
| 	for (int i=1; i<=maxClients; i++) | ||||
| @ -135,7 +135,7 @@ void BaseMenuStyle::CancelMenu(CBaseMenu *menu) | ||||
| bool BaseMenuStyle::CancelClientMenu(int client, bool autoIgnore) | ||||
| { | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("[SM_MENU] CancelClientMenu() (client %d) (bAutoIgnore %d)", client, autoIgnore); | ||||
| 	g_Logger.LogMessage("[SM_MENU] CancelClientMenu() (client %d) (bAutoIgnore %d)", client, autoIgnore); | ||||
| #endif | ||||
| 	if (client < 1 || client > g_Players.MaxClients()) | ||||
| 	{ | ||||
| @ -191,7 +191,7 @@ MenuSource BaseMenuStyle::GetClientMenu(int client, void **object) | ||||
| void BaseMenuStyle::OnClientDisconnected(int client) | ||||
| { | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("[SM_MENU] OnClientDisconnected(%d)", client); | ||||
| 	g_Logger.LogMessage("[SM_MENU] OnClientDisconnected(%d)", client); | ||||
| #endif | ||||
| 	CBaseMenuPlayer *player = GetMenuPlayer(client); | ||||
| 	if (!player->bInMenu) | ||||
| @ -214,7 +214,7 @@ void BaseMenuStyle::ProcessWatchList() | ||||
| 	} | ||||
| 
 | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)",  | ||||
| 	g_Logger.LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)",  | ||||
| 		m_WatchList.m_Size, | ||||
| 		m_WatchList.m_FirstLink, | ||||
| 		m_WatchList.m_FreeNodes, | ||||
| @ -232,7 +232,7 @@ void BaseMenuStyle::ProcessWatchList() | ||||
| #if defined MENU_DEBUG | ||||
| 	if (total) | ||||
| 	{ | ||||
| 		logger->LogMessage("[SM_MENU] ProcessWatchList() found %d clients", total); | ||||
| 		g_Logger.LogMessage("[SM_MENU] ProcessWatchList() found %d clients", total); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| @ -244,7 +244,7 @@ void BaseMenuStyle::ProcessWatchList() | ||||
| 		client = do_lookup[i]; | ||||
| 		player = GetMenuPlayer(client); | ||||
| #if defined MENU_DEBUG | ||||
| 		logger->LogMessage("[SM_MENU] ProcessWatchList() (client %d) (bInMenu %d) (menuHoldTime %d) (curTime %f) (menuStartTime %f)", | ||||
| 		g_Logger.LogMessage("[SM_MENU] ProcessWatchList() (client %d) (bInMenu %d) (menuHoldTime %d) (curTime %f) (menuStartTime %f)", | ||||
| 			client, | ||||
| 			player->bInMenu, | ||||
| 			player->menuHoldTime, | ||||
| @ -254,7 +254,7 @@ void BaseMenuStyle::ProcessWatchList() | ||||
| 		if (!player->bInMenu || !player->menuHoldTime) | ||||
| 		{ | ||||
| #if defined MENU_DEBUG | ||||
| 			logger->LogMessage("[SM_MENU] ProcessWatchList() removing client %d", client); | ||||
| 			g_Logger.LogMessage("[SM_MENU] ProcessWatchList() removing client %d", client); | ||||
| #endif | ||||
| 			m_WatchList.remove(client); | ||||
| 			continue; | ||||
| @ -269,7 +269,7 @@ void BaseMenuStyle::ProcessWatchList() | ||||
| void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press) | ||||
| { | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press); | ||||
| 	g_Logger.LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press); | ||||
| #endif | ||||
| 	CBaseMenuPlayer *player = GetMenuPlayer(client); | ||||
| 
 | ||||
| @ -412,7 +412,7 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press) | ||||
| bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time) | ||||
| { | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("[SM_MENU] DoClientMenu() (client %d) (panel %p) (mh %p) (time %d)", | ||||
| 	g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (panel %p) (mh %p) (time %d)", | ||||
| 		client, | ||||
| 		menu, | ||||
| 		mh, | ||||
| @ -475,7 +475,7 @@ bool BaseMenuStyle::DoClientMenu(int client, | ||||
| 								 unsigned int time) | ||||
| { | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("[SM_MENU] DoClientMenu() (client %d) (menu %p) (mh %p) (time %d)", | ||||
| 	g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (menu %p) (mh %p) (time %d)", | ||||
| 		client, | ||||
| 		menu, | ||||
| 		mh, | ||||
| @ -487,7 +487,7 @@ bool BaseMenuStyle::DoClientMenu(int client, | ||||
| 	if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame()) | ||||
| 	{ | ||||
| #if defined MENU_DEBUG | ||||
| 		logger->LogMessage("[SM_MENU] DoClientMenu(): Failed to display to client %d", client); | ||||
| 		g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to display to client %d", client); | ||||
| #endif | ||||
| 		mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay); | ||||
| 		mh->OnMenuEnd(menu, MenuEnd_Cancelled); | ||||
| @ -498,7 +498,7 @@ bool BaseMenuStyle::DoClientMenu(int client, | ||||
| 	if (player->bAutoIgnore) | ||||
| 	{ | ||||
| #if defined MENU_DEBUG | ||||
| 		logger->LogMessage("[SM_MENU] DoClientMenu(): Client %d is autoIgnoring", client); | ||||
| 		g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Client %d is autoIgnoring", client); | ||||
| #endif | ||||
| 		mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay); | ||||
| 		mh->OnMenuEnd(menu, MenuEnd_Cancelled); | ||||
| @ -517,7 +517,7 @@ bool BaseMenuStyle::DoClientMenu(int client, | ||||
| 	if (player->bInMenu) | ||||
| 	{ | ||||
| #if defined MENU_DEBUG | ||||
| 		logger->LogMessage("[SM_MENU] DoClientMenu(): Cancelling old menu to client %d", client); | ||||
| 		g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Cancelling old menu to client %d", client); | ||||
| #endif | ||||
| 		_CancelClientMenu(client, MenuCancel_Interrupted, true); | ||||
| 	} | ||||
| @ -532,7 +532,7 @@ bool BaseMenuStyle::DoClientMenu(int client, | ||||
| 	if (!display) | ||||
| 	{ | ||||
| #if defined MENU_DEBUG | ||||
| 		logger->LogMessage("[SM_MENU] DoClientMenu(): Failed to render to client %d", client); | ||||
| 		g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to render to client %d", client); | ||||
| #endif | ||||
| 		player->bAutoIgnore = false; | ||||
| 		player->bInMenu = false; | ||||
| @ -562,7 +562,7 @@ bool BaseMenuStyle::DoClientMenu(int client, | ||||
| 	player->bAutoIgnore = false; | ||||
| 
 | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("[SM_MENU] DoClientMenu() finished successfully (client %d)", client); | ||||
| 	g_Logger.LogMessage("[SM_MENU] DoClientMenu() finished successfully (client %d)", client); | ||||
| #endif | ||||
| 
 | ||||
| 	return true; | ||||
| @ -571,7 +571,7 @@ bool BaseMenuStyle::DoClientMenu(int client, | ||||
| bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order) | ||||
| { | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("[SM_MENU] RedoClientMenu() (client %d) (order %d)", client, order); | ||||
| 	g_Logger.LogMessage("[SM_MENU] RedoClientMenu() (client %d) (order %d)", client, order); | ||||
| #endif | ||||
| 	CBaseMenuPlayer *player = GetMenuPlayer(client); | ||||
| 	menu_states_t &states = player->states; | ||||
| @ -581,7 +581,7 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order) | ||||
| 	if (!display) | ||||
| 	{ | ||||
| #if defined MENU_DEBUG | ||||
| 		logger->LogMessage("[SM_MENU] RedoClientMenu(): Failed to render menu"); | ||||
| 		g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Failed to render menu"); | ||||
| #endif | ||||
| 		if (player->menuHoldTime) | ||||
| 		{ | ||||
| @ -598,7 +598,7 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order) | ||||
| 	player->bAutoIgnore = false; | ||||
| 
 | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("[SM_MENU] RedoClientMenu(): Succeeded to client %d", client); | ||||
| 	g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Succeeded to client %d", client); | ||||
| #endif | ||||
| 
 | ||||
| 	return true; | ||||
| @ -628,49 +628,49 @@ Handle_t CBaseMenu::GetHandle() | ||||
| bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw) | ||||
| { | ||||
| 	if (m_Pagination == (unsigned)MENU_NO_PAGINATION | ||||
| 		&& m_items.size() >= m_pStyle->GetMaxPageItems()) | ||||
| 		&& m_items.length() >= m_pStyle->GetMaxPageItems()) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	CItem item(m_items.size()); | ||||
| 	CItem item(m_items.length()); | ||||
| 
 | ||||
| 	item.info = info; | ||||
| 	if (draw.display) | ||||
| 		item.display = std::make_unique<std::string>(draw.display); | ||||
| 		item.display = new ke::AString(draw.display); | ||||
| 	item.style = draw.style; | ||||
| 
 | ||||
| 	m_items.push_back(std::move(item)); | ||||
| 	m_items.append(ke::Move(item)); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw) | ||||
| { | ||||
| 	if (m_Pagination == (unsigned)MENU_NO_PAGINATION && | ||||
| 	    m_items.size() >= m_pStyle->GetMaxPageItems()) | ||||
| 	    m_items.length() >= m_pStyle->GetMaxPageItems()) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (position >= m_items.size()) | ||||
| 	if (position >= m_items.length()) | ||||
| 		return false; | ||||
| 
 | ||||
| 	CItem item(position); | ||||
| 	item.info = info; | ||||
| 	if (draw.display) | ||||
| 		item.display = std::make_unique<std::string>(draw.display); | ||||
| 		item.display = new ke::AString(draw.display); | ||||
| 	item.style = draw.style; | ||||
| 
 | ||||
| 	m_items.emplace(m_items.begin() + position, std::move(item)); | ||||
| 	m_items.insert(position, ke::Move(item)); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool CBaseMenu::RemoveItem(unsigned int position) | ||||
| { | ||||
| 	if (position >= m_items.size()) | ||||
| 	if (position >= m_items.length()) | ||||
| 		return false; | ||||
| 
 | ||||
| 	m_items.erase(m_items.begin() + position); | ||||
| 	m_items.remove(position); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| @ -681,21 +681,21 @@ void CBaseMenu::RemoveAllItems() | ||||
| 
 | ||||
| const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */, int client/* =0 */) | ||||
| { | ||||
| 	if (position >= m_items.size()) | ||||
| 	if (position >= m_items.length()) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	if (client > 0 && position < m_RandomMaps[client].size()) | ||||
| 	if (client > 0 && position < m_RandomMaps[client].length()) | ||||
| 	{ | ||||
| 		position = m_RandomMaps[client][position]; | ||||
| 	} | ||||
| 
 | ||||
| 	if (draw) | ||||
| 	{ | ||||
| 		draw->display = m_items[position].display->c_str(); | ||||
| 		draw->display = m_items[position].display->chars(); | ||||
| 		draw->style = m_items[position].style; | ||||
| 	} | ||||
| 
 | ||||
| 	return m_items[position].info.c_str(); | ||||
| 	return m_items[position].info.chars(); | ||||
| } | ||||
| 
 | ||||
| void CBaseMenu::ShufflePerClient(int start, int stop) | ||||
| @ -705,7 +705,7 @@ void CBaseMenu::ShufflePerClient(int start, int stop) | ||||
| 	if (stop >= 0) | ||||
| 		length = MIN(length, stop); | ||||
| 
 | ||||
| 	for (int i = 1; i <= SM_MAXPLAYERS; i++) | ||||
| 	for (int i = 1; i < SM_MAXPLAYERS + 1; i++) | ||||
| 	{ | ||||
| 		// populate per-client map ...
 | ||||
| 		m_RandomMaps[i].resize(length); | ||||
| @ -735,9 +735,9 @@ void CBaseMenu::SetClientMapping(int client, int *array, int length) | ||||
| 
 | ||||
| bool CBaseMenu::IsPerClientShuffled() | ||||
| { | ||||
| 	for (int i = 1; i <= SM_MAXPLAYERS; i++) | ||||
| 	for (int i = 1; i < SM_MAXPLAYERS + 1; i++) | ||||
| 	{ | ||||
| 		if(m_RandomMaps[i].size() > 0) | ||||
| 		if(m_RandomMaps[i].length() > 0) | ||||
| 			return true; | ||||
| 	} | ||||
| 	return false; | ||||
| @ -745,7 +745,7 @@ bool CBaseMenu::IsPerClientShuffled() | ||||
| 
 | ||||
| unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position) | ||||
| { | ||||
| 	if (client > 0 && position < m_RandomMaps[client].size()) | ||||
| 	if (client > 0 && position < m_RandomMaps[client].length()) | ||||
| 	{ | ||||
| 		position = m_RandomMaps[client][position]; | ||||
| 		return m_items[position].index; | ||||
| @ -756,7 +756,7 @@ unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position) | ||||
| 
 | ||||
| unsigned int CBaseMenu::GetItemCount() | ||||
| { | ||||
| 	return m_items.size(); | ||||
| 	return m_items.length(); | ||||
| } | ||||
| 
 | ||||
| bool CBaseMenu::SetPagination(unsigned int itemsPerPage) | ||||
| @ -794,7 +794,7 @@ void CBaseMenu::SetDefaultTitle(const char *message) | ||||
| 
 | ||||
| const char *CBaseMenu::GetDefaultTitle() | ||||
| { | ||||
| 	return m_Title.c_str(); | ||||
| 	return m_Title.chars(); | ||||
| } | ||||
| 
 | ||||
| void CBaseMenu::Cancel() | ||||
| @ -805,7 +805,7 @@ void CBaseMenu::Cancel() | ||||
| 	} | ||||
| 
 | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_bShouldDelete %d)", | ||||
| 	g_Logger.LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_bShouldDelete %d)", | ||||
| 		this, | ||||
| 		m_bShouldDelete); | ||||
| #endif | ||||
| @ -829,7 +829,7 @@ void CBaseMenu::Destroy(bool releaseHandle) | ||||
| 	} | ||||
| 
 | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("[SM_MENU] CBaseMenu::Destroy(%p) (release %d) (m_bCancelling %d) (m_bShouldDelete %d)", | ||||
| 	g_Logger.LogMessage("[SM_MENU] CBaseMenu::Destroy(%p) (release %d) (m_bCancelling %d) (m_bShouldDelete %d)", | ||||
| 		this, | ||||
| 		releaseHandle, | ||||
| 		m_bCancelling, | ||||
| @ -886,5 +886,5 @@ IMenuHandler *CBaseMenu::GetHandler() | ||||
| 
 | ||||
| unsigned int CBaseMenu::GetBaseMemUsage() | ||||
| { | ||||
| 	return m_Title.size() + (m_items.size() * sizeof(CItem)); | ||||
| 	return m_Title.length() + (m_items.length() * sizeof(CItem)); | ||||
| } | ||||
|  | ||||
| @ -32,11 +32,9 @@ | ||||
| #ifndef _INCLUDE_MENUSTYLE_BASE_H | ||||
| #define _INCLUDE_MENUSTYLE_BASE_H | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <utility> | ||||
| 
 | ||||
| #include <IMenuManager.h> | ||||
| #include <IPlayerHelpers.h> | ||||
| #include <am-autoptr.h> | ||||
| #include <am-string.h> | ||||
| #include <am-vector.h> | ||||
| #include "sm_fastlink.h" | ||||
| @ -53,8 +51,8 @@ public: | ||||
| 		access = 0; | ||||
| 	} | ||||
| 	CItem(CItem &&other) | ||||
| 	: info(std::move(other.info)), | ||||
| 	  display(std::move(other.display)) | ||||
| 	: info(ke::Move(other.info)), | ||||
| 	  display(ke::Move(other.display)) | ||||
| 	{ | ||||
| 		index = other.index; | ||||
| 		style = other.style; | ||||
| @ -63,8 +61,8 @@ public: | ||||
| 	CItem & operator =(CItem &&other) | ||||
| 	{ | ||||
| 		index = other.index; | ||||
| 		info = std::move(other.info); | ||||
| 		display = std::move(other.display); | ||||
| 		info = ke::Move(other.info); | ||||
| 		display = ke::Move(other.display); | ||||
| 		style = other.style; | ||||
| 		access = other.access; | ||||
| 		return *this; | ||||
| @ -72,8 +70,8 @@ public: | ||||
| 
 | ||||
| public: | ||||
| 	unsigned int index; | ||||
| 	std::string info; | ||||
| 	std::unique_ptr<std::string> display; | ||||
| 	ke::AString info; | ||||
| 	ke::AutoPtr<ke::AString> display; | ||||
| 	unsigned int style; | ||||
| 	unsigned int access; | ||||
| 
 | ||||
| @ -166,10 +164,10 @@ public: | ||||
| private: | ||||
| 	void InternalDelete(); | ||||
| protected: | ||||
| 	std::string m_Title; | ||||
| 	ke::AString m_Title; | ||||
| 	IMenuStyle *m_pStyle; | ||||
| 	unsigned int m_Pagination; | ||||
| 	std::vector<CItem> m_items; | ||||
| 	ke::Vector<CItem> m_items; | ||||
| 	bool m_bShouldDelete; | ||||
| 	bool m_bCancelling; | ||||
| 	IdentityToken_t *m_pOwner; | ||||
| @ -178,7 +176,7 @@ protected: | ||||
| 	Handle_t m_hHandle; | ||||
| 	IMenuHandler *m_pHandler; | ||||
| 	unsigned int m_nFlags; | ||||
| 	std::vector<uint8_t> m_RandomMaps[SM_MAXPLAYERS+1]; | ||||
| 	ke::Vector<uint8_t> m_RandomMaps[SM_MAXPLAYERS+1]; | ||||
| }; | ||||
| 
 | ||||
| #endif //_INCLUDE_MENUSTYLE_BASE_H
 | ||||
|  | ||||
| @ -35,7 +35,7 @@ | ||||
| #include <IGameConfigs.h> | ||||
| #include "PlayerManager.h" | ||||
| #if defined MENU_DEBUG | ||||
| #include <bridge/include/ILogger.h> | ||||
| #include "Logger.h" | ||||
| #endif | ||||
| #include "logic_bridge.h" | ||||
| 
 | ||||
| @ -45,8 +45,6 @@ | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| #include <game/shared/csgo/protobuf/cstrike15_usermessages.pb.h> | ||||
| #elif SOURCE_ENGINE == SE_BLADE | ||||
| #include <game/shared/berimbau/protobuf/berimbau_usermessages.pb.h> | ||||
| #endif | ||||
| 
 | ||||
| extern const char *g_RadioNumTable[]; | ||||
| @ -61,7 +59,7 @@ unsigned int g_RadioMenuTimeout = 0; | ||||
| #define MAX_MENUSLOT_KEYS 10 | ||||
| 
 | ||||
| static unsigned int s_RadioMaxPageItems = MAX_MENUSLOT_KEYS; | ||||
| static bool s_RadioClosesOnInvalidSlot = false; | ||||
| 
 | ||||
| 
 | ||||
| CRadioStyle::CRadioStyle() | ||||
| { | ||||
| @ -124,12 +122,6 @@ void CRadioStyle::OnSourceModLevelChange(const char *mapName) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	const char *closes = g_pGameConf->GetKeyValue("RadioMenuClosesOnInvalidSlot"); | ||||
| 	if (closes != nullptr && strcmp(closes, "yes") == 0) | ||||
| 	{ | ||||
| 		s_RadioClosesOnInvalidSlot = true; | ||||
| 	} | ||||
| 
 | ||||
| 	g_Menus.SetDefaultStyle(this); | ||||
| 
 | ||||
| 	g_UserMsgs.HookUserMessage(g_ShowMenuId, this, false); | ||||
| @ -182,7 +174,7 @@ void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFil | ||||
| { | ||||
| 	int count = pFilter->GetRecipientCount(); | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	int c = ((CCSUsrMsg_ShowMenu &)msg).display_time(); | ||||
| #else | ||||
| 	bf_read br(bf->GetBasePointer(), 3); | ||||
| @ -205,7 +197,7 @@ void CRadioStyle::OnUserMessageSent(int msg_id) | ||||
| 	{ | ||||
| 		int client = g_last_clients[i]; | ||||
| #if defined MENU_DEBUG | ||||
| 		logger->LogMessage("[SM_MENU] CRadioStyle got ShowMenu (client %d) (bInMenu %d)", | ||||
| 		g_Logger.LogMessage("[SM_MENU] CRadioStyle got ShowMenu (client %d) (bInMenu %d)", | ||||
| 			client, | ||||
| 			m_players[client].bInExternMenu); | ||||
| #endif | ||||
| @ -470,16 +462,7 @@ void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text) | ||||
| 			sizeof(display_pkt),  | ||||
| 			text); | ||||
| 	} | ||||
| 
 | ||||
| 	// Some games have implemented CHudMenu::SelectMenuItem to close the menu
 | ||||
| 	// even if an invalid slot has been selected, which causes us a problem as
 | ||||
| 	// we'll never get any notification from the client and we'll keep the menu
 | ||||
| 	// alive on our end indefinitely. For these games, pretend that every slot
 | ||||
| 	// is valid for selection so we're guaranteed to get a menuselect command.
 | ||||
| 	// We don't want to do this for every game as the common SelectMenuItem
 | ||||
| 	// implementation ignores invalid selections and keeps the menu open, which
 | ||||
| 	// is a much nicer user experience.
 | ||||
| 	display_keys = s_RadioClosesOnInvalidSlot ? 0x7ff : keys; | ||||
| 	display_keys = keys; | ||||
| } | ||||
| 
 | ||||
| void CRadioMenuPlayer::Radio_Refresh() | ||||
| @ -500,13 +483,9 @@ void CRadioMenuPlayer::Radio_Refresh() | ||||
| 		time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime); | ||||
| 	} | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	// TODO: find what happens past 240 on CS:GO
 | ||||
| 	CCSUsrMsg_ShowMenu *msg = (CCSUsrMsg_ShowMenu *)g_UserMsgs.StartProtobufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS); | ||||
| 	if (!msg) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 	msg->set_bits_valid_slots(display_keys); | ||||
| 	msg->set_display_time(time); | ||||
| 	msg->set_menu_string(ptr); | ||||
| @ -597,7 +576,7 @@ bool CRadioMenu::DisplayAtItem(int client, | ||||
| 							   IMenuHandler *alt_handler) | ||||
| { | ||||
| #if defined MENU_DEBUG | ||||
| 	logger->LogMessage("[SM_MENU] CRadioMenu::Display(%p) (client %d) (time %d)", | ||||
| 	g_Logger.LogMessage("[SM_MENU] CRadioMenu::Display(%p) (client %d) (time %d)", | ||||
| 		this, | ||||
| 		client, | ||||
| 		time); | ||||
|  | ||||
| @ -63,7 +63,11 @@ bool g_forcedChange = false; | ||||
| 
 | ||||
| void NextMapManager::OnSourceModAllInitialized_Post() | ||||
| { | ||||
| #if SOURCE_ENGINE >= SE_ORANGEBOX | ||||
| 	SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false); | ||||
| #else | ||||
| 	SH_ADD_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false); | ||||
| #endif | ||||
| 
 | ||||
| 	ConCommand *pCmd = FindCommand("changelevel"); | ||||
| 	if (pCmd != NULL) | ||||
| @ -75,7 +79,11 @@ void NextMapManager::OnSourceModAllInitialized_Post() | ||||
| 
 | ||||
| void NextMapManager::OnSourceModShutdown() | ||||
| { | ||||
| #if SOURCE_ENGINE >= SE_ORANGEBOX | ||||
| 	SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false); | ||||
| #else | ||||
| 	SH_REMOVE_HOOK(IVEngineServer, ChangeLevel, engine, SH_MEMBER(this, &NextMapManager::HookChangeLevel), false); | ||||
| #endif | ||||
| 
 | ||||
| 	if (changeLevelCmd != NULL) | ||||
| 	{ | ||||
|  | ||||
| @ -97,7 +97,7 @@ SH_DECL_HOOK2_void(IVEngineServer, ClientPrintf, SH_NOATTRIB, 0, edict_t *, cons | ||||
| 
 | ||||
| static void PrintfBuffer_FrameAction(void *data) | ||||
| { | ||||
| 	g_Players.OnPrintfFrameAction(static_cast<unsigned int>(reinterpret_cast<uintptr_t>(data))); | ||||
| 	g_Players.OnPrintfFrameAction(reinterpret_cast<unsigned int>(data)); | ||||
| } | ||||
| 
 | ||||
| ConCommand *maxplayersCmd = NULL; | ||||
| @ -196,7 +196,6 @@ void PlayerManager::OnSourceModAllInitialized() | ||||
| 	m_clcommandkv_post = forwardsys->CreateForward("OnClientCommandKeyValues_Post", ET_Ignore, 2, NULL, Param_Cell, Param_Cell); | ||||
| 	m_clinfochanged = forwardsys->CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2); | ||||
| 	m_clauth = forwardsys->CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String); | ||||
| 	m_cllang = forwardsys->CreateForward("OnClientLanguageChanged", ET_Ignore, 2, NULL, Param_Cell, Param_Cell); | ||||
| 	m_onActivate = forwardsys->CreateForward("OnServerLoad", ET_Ignore, 0, NULL); | ||||
| 	m_onActivate2 = forwardsys->CreateForward("OnMapStart", ET_Ignore, 0, NULL); | ||||
| 
 | ||||
| @ -250,7 +249,6 @@ void PlayerManager::OnSourceModShutdown() | ||||
| 	forwardsys->ReleaseForward(m_clcommandkv_post); | ||||
| 	forwardsys->ReleaseForward(m_clinfochanged); | ||||
| 	forwardsys->ReleaseForward(m_clauth); | ||||
| 	forwardsys->ReleaseForward(m_cllang); | ||||
| 	forwardsys->ReleaseForward(m_onActivate); | ||||
| 	forwardsys->ReleaseForward(m_onActivate2); | ||||
| 
 | ||||
| @ -412,7 +410,7 @@ void PlayerManager::RunAuthChecks() | ||||
| 		pPlayer = &m_Players[m_AuthQueue[i]]; | ||||
| 		pPlayer->UpdateAuthIds(); | ||||
| 		 | ||||
| 		authstr = pPlayer->m_AuthID.c_str(); | ||||
| 		authstr = pPlayer->m_AuthID.chars(); | ||||
| 
 | ||||
| 		if (!pPlayer->IsAuthStringValidated()) | ||||
| 		{ | ||||
| @ -519,7 +517,7 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const | ||||
| 	/* Get the client's language */ | ||||
| 	if (m_QueryLang) | ||||
| 	{ | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 		pPlayer->m_LangId = translator->GetServerLanguage(); | ||||
| #else | ||||
| 		const char *name; | ||||
| @ -527,8 +525,6 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const | ||||
| 		{ | ||||
| 			unsigned int langid; | ||||
| 			pPlayer->m_LangId = (translator->GetLanguageByName(name, &langid)) ? langid : translator->GetServerLanguage(); | ||||
| 
 | ||||
| 			OnClientLanguageChanged(client, pPlayer->m_LangId); | ||||
| 		} else { | ||||
| 			pPlayer->m_LangId = translator->GetServerLanguage(); | ||||
| 		} | ||||
| @ -675,8 +671,6 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername | ||||
| 			&& (m_SourceTVUserId == userId | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 				|| strcmp(playername, "GOTV") == 0 | ||||
| #elif SOURCE_ENGINE == SE_BLADE | ||||
| 				|| strcmp(playername, "BBTV") == 0 | ||||
| #elif (SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013 \ | ||||
| 	|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN  || SOURCE_ENGINE == SE_LEFT4DEAD2) | ||||
| 				|| (tv_name && strcmp(playername, tv_name->GetString()) == 0) || (tv_name && tv_name->GetString()[0] == 0 && strcmp(playername, "unnamed") == 0) | ||||
| @ -720,19 +714,19 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername | ||||
| 		for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++) | ||||
| 		{ | ||||
| 			pListener = (*iter); | ||||
| 			pListener->OnClientAuthorized(client, steamId ? steamId : pPlayer->m_AuthID.c_str()); | ||||
| 			pListener->OnClientAuthorized(client, steamId ? steamId : pPlayer->m_AuthID.chars()); | ||||
| 		} | ||||
| 		/* Finally, tell plugins */ | ||||
| 		if (m_clauth->GetFunctionCount()) | ||||
| 		{ | ||||
| 			m_clauth->PushCell(client); | ||||
| 			/* For legacy reasons, people are expecting the Steam2 id here if using Steam auth */ | ||||
| 			m_clauth->PushString(steamId ? steamId : pPlayer->m_AuthID.c_str()); | ||||
| 			m_clauth->PushString(steamId ? steamId : pPlayer->m_AuthID.chars()); | ||||
| 			m_clauth->Execute(NULL); | ||||
| 		} | ||||
| 		pPlayer->Authorize_Post(); | ||||
| 	} | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	else if(m_QueryLang) | ||||
| 	{ | ||||
| 		// Not a bot
 | ||||
| @ -792,7 +786,7 @@ void PlayerManager::OnServerHibernationUpdate(bool bHibernating) | ||||
| 			CPlayer *pPlayer = &m_Players[i]; | ||||
| 			if (pPlayer->IsConnected() && pPlayer->IsFakeClient()) | ||||
| 			{ | ||||
| #if SOURCE_ENGINE < SE_LEFT4DEAD || SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_NUCLEARDAWN | ||||
| #if SOURCE_ENGINE < SE_LEFT4DEAD || SOURCE_ENGINE >= SE_CSGO || SOURCE_ENGINE == SE_NUCLEARDAWN | ||||
| 				// These games have the bug fixed where hltv/replay was getting kicked on hibernation
 | ||||
| 				if (pPlayer->IsSourceTV() || pPlayer->IsReplay()) | ||||
| 					continue; | ||||
| @ -879,7 +873,7 @@ void PlayerManager::OnClientPrintf(edict_t *pEdict, const char *szMsg) | ||||
| 		RETURN_META(MRES_IGNORED); | ||||
| 
 | ||||
| 	size_t nMsgLen = strlen(szMsg); | ||||
| #if SOURCE_ENGINE == SE_EPISODEONE || SOURCE_ENGINE == SE_DARKMESSIAH | ||||
| #if SOURCE_ENGINE == SE_EPISODEONE | ||||
| 	static const int nNumBitsWritten = 0; | ||||
| #else | ||||
| 	int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
 | ||||
| @ -897,7 +891,7 @@ void PlayerManager::OnClientPrintf(edict_t *pEdict, const char *szMsg) | ||||
| 		if (player.m_PrintfBuffer.empty()) | ||||
| 			g_SourceMod.AddFrameAction(PrintfBuffer_FrameAction, (void *)(uintptr_t)player.GetSerial()); | ||||
| 
 | ||||
| 		player.m_PrintfBuffer.push_back(szMsg); | ||||
| 		player.m_PrintfBuffer.append(szMsg); | ||||
| 
 | ||||
| 		RETURN_META(MRES_SUPERCEDE); | ||||
| 	} | ||||
| @ -924,21 +918,21 @@ void PlayerManager::OnPrintfFrameAction(unsigned int serial) | ||||
| 
 | ||||
| 	while (!player.m_PrintfBuffer.empty()) | ||||
| 	{ | ||||
| #if SOURCE_ENGINE == SE_EPISODEONE || SOURCE_ENGINE == SE_DARKMESSIAH | ||||
| #if SOURCE_ENGINE == SE_EPISODEONE | ||||
| 		static const int nNumBitsWritten = 0; | ||||
| #else | ||||
| 		int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
 | ||||
| #endif | ||||
| 
 | ||||
| 		std::string &string = player.m_PrintfBuffer.front(); | ||||
| 		ke::AString &string = player.m_PrintfBuffer.front(); | ||||
| 
 | ||||
| 		// stop if we'd overflow the SVC_Print buffer  (+7 as ceil)
 | ||||
| 		if ((nNumBitsWritten + NETMSG_TYPE_BITS + 7) / 8 + string.length() >= SVC_Print_BufferSize) | ||||
| 			break; | ||||
| 
 | ||||
| 		SH_CALL(engine, &IVEngineServer::ClientPrintf)(player.m_pEdict, string.c_str()); | ||||
| 		SH_CALL(engine, &IVEngineServer::ClientPrintf)(player.m_pEdict, string.chars()); | ||||
| 
 | ||||
| 		player.m_PrintfBuffer.pop_front(); | ||||
| 		player.m_PrintfBuffer.popFront(); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!player.m_PrintfBuffer.empty()) | ||||
| @ -1175,10 +1169,6 @@ void PlayerManager::OnClientCommand(edict_t *pEntity) | ||||
| 				" Scott \"DS\" Ehlert, Fyren"); | ||||
|  			ClientConsolePrint(pEntity, | ||||
| 				" Nicholas \"psychonic\" Hastings, Asher \"asherkin\" Baker"); | ||||
| 			ClientConsolePrint(pEntity, | ||||
| 				" Ruben \"Dr!fter\" Gonzalez, Josh \"KyleS\" Allard"); | ||||
| 			ClientConsolePrint(pEntity, | ||||
| 				" Michael \"Headline\" Flaherty, Jannik \"Peace-Maker\" Hartung"); | ||||
| 			ClientConsolePrint(pEntity, | ||||
| 				" Borja \"faluco\" Ferrer, Pavol \"PM OnoTo\" Marko"); | ||||
| 			ClientConsolePrint(pEntity, | ||||
| @ -1193,7 +1183,7 @@ void PlayerManager::OnClientCommand(edict_t *pEntity) | ||||
| 		ClientConsolePrint(pEntity, | ||||
| 			"To see credits, type \"sm credits\""); | ||||
| 		ClientConsolePrint(pEntity, | ||||
| 			"Visit https://www.sourcemod.net/"); | ||||
| 			"Visit http://www.sourcemod.net/"); | ||||
| 		RETURN_META(MRES_SUPERCEDE); | ||||
| 	} | ||||
| 
 | ||||
| @ -1348,13 +1338,29 @@ void PlayerManager::OnClientSettingsChanged(edict_t *pEntity) | ||||
| 	m_clinfochanged->PushCell(client); | ||||
| 	m_clinfochanged->Execute(&res, NULL); | ||||
| 
 | ||||
| 	if (pPlayer->IsFakeClient()) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	IPlayerInfo *info = pPlayer->GetPlayerInfo(); | ||||
| 	const char *new_name = info ? info->GetName() : engine->GetClientConVarValue(client, "name"); | ||||
| 	const char *old_name = pPlayer->m_Name.c_str(); | ||||
| 
 | ||||
| 	if (strcmp(old_name, new_name) != 0) | ||||
| #if SOURCE_ENGINE >= SE_LEFT4DEAD | ||||
| 	const char *networkid_force; | ||||
| 	if ((networkid_force = engine->GetClientConVarValue(client, "networkid_force")) && networkid_force[0] != '\0') | ||||
| 	{ | ||||
| 		if (!pPlayer->IsFakeClient()) | ||||
| 		unsigned int accountId = pPlayer->GetSteamAccountID(); | ||||
| 		logger->LogMessage("\"%s<%d><STEAM_1:%d:%d><>\" has bad networkid (id \"%s\") (ip \"%s\")", | ||||
| 			new_name, pPlayer->GetUserId(), accountId & 1, accountId >> 1, networkid_force, pPlayer->GetIPAddress()); | ||||
| 
 | ||||
| 		pPlayer->Kick("NetworkID spoofing detected."); | ||||
| 		RETURN_META(MRES_IGNORED); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	if (strcmp(old_name, new_name) != 0) | ||||
| 	{ | ||||
| 		AdminId id = adminsys->FindAdminByIdentity("name", new_name); | ||||
| 		if (id != INVALID_ADMIN_ID && pPlayer->GetAdminId() != id) | ||||
| @ -1366,26 +1372,21 @@ void PlayerManager::OnClientSettingsChanged(edict_t *pEntity) | ||||
| 				pPlayer->Kick(kickMsg); | ||||
| 				RETURN_META(MRES_IGNORED); | ||||
| 			} | ||||
| 			} | ||||
| 			else if ((id = adminsys->FindAdminByIdentity("name", old_name)) != INVALID_ADMIN_ID) { | ||||
| 		} else if ((id = adminsys->FindAdminByIdentity("name", old_name)) != INVALID_ADMIN_ID) { | ||||
| 			if (id == pPlayer->GetAdminId()) | ||||
| 			{ | ||||
| 				/* This player is changing their name; force them to drop admin privileges! */ | ||||
| 				pPlayer->SetAdminId(INVALID_ADMIN_ID, false); | ||||
| 			} | ||||
| 		} | ||||
| 		} | ||||
| 
 | ||||
| 		pPlayer->SetName(new_name); | ||||
| 	} | ||||
| 	 | ||||
| 	if (!pPlayer->IsFakeClient()) | ||||
| 	{ | ||||
| 	if (m_PassInfoVar.size() > 0) | ||||
| 	{ | ||||
| 		/* Try for a password change */ | ||||
| 			const char* old_pass = pPlayer->m_LastPassword.c_str(); | ||||
| 			const char* new_pass = engine->GetClientConVarValue(client, m_PassInfoVar.c_str()); | ||||
| 		const char *old_pass = pPlayer->m_LastPassword.c_str(); | ||||
| 		const char *new_pass = engine->GetClientConVarValue(client, m_PassInfoVar.c_str()); | ||||
| 		if (strcmp(old_pass, new_pass) != 0) | ||||
| 		{ | ||||
| 			pPlayer->m_LastPassword.assign(new_pass); | ||||
| @ -1396,21 +1397,6 @@ void PlayerManager::OnClientSettingsChanged(edict_t *pEntity) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| #if SOURCE_ENGINE >= SE_LEFT4DEAD | ||||
| 		const char* networkid_force; | ||||
| 		if ((networkid_force = engine->GetClientConVarValue(client, "networkid_force")) && networkid_force[0] != '\0') | ||||
| 		{ | ||||
| 			unsigned int accountId = pPlayer->GetSteamAccountID(); | ||||
| 			logger->LogMessage("\"%s<%d><STEAM_1:%d:%d><>\" has bad networkid (id \"%s\") (ip \"%s\")", | ||||
| 				new_name, pPlayer->GetUserId(), accountId & 1, accountId >> 1, networkid_force, pPlayer->GetIPAddress()); | ||||
| 
 | ||||
| 			pPlayer->Kick("NetworkID spoofing detected."); | ||||
| 			RETURN_META(MRES_IGNORED); | ||||
| 		} | ||||
| #endif | ||||
| 	} | ||||
| 
 | ||||
| 	/* Notify Extensions */ | ||||
| 	List<IClientListener *>::iterator iter; | ||||
| 	IClientListener *pListener = NULL; | ||||
| @ -1424,13 +1410,6 @@ void PlayerManager::OnClientSettingsChanged(edict_t *pEntity) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void PlayerManager::OnClientLanguageChanged(int client, unsigned int language) | ||||
| { | ||||
| 	m_cllang->PushCell(client); | ||||
| 	m_cllang->PushCell(language); | ||||
| 	m_cllang->Execute(NULL); | ||||
| } | ||||
| 
 | ||||
| int PlayerManager::GetMaxClients() | ||||
| { | ||||
| 	return m_maxClients; | ||||
| @ -1596,10 +1575,7 @@ void PlayerManager::InvalidatePlayer(CPlayer *pPlayer) | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	auto userid = engine->GetPlayerUserId(pPlayer->m_pEdict); | ||||
| 	if (userid != -1) | ||||
| 		m_UserIdLookUp[userid] = 0; | ||||
| 
 | ||||
| 	m_UserIdLookUp[engine->GetPlayerUserId(pPlayer->m_pEdict)] = 0; | ||||
| 	pPlayer->Disconnect(); | ||||
| } | ||||
| 
 | ||||
| @ -2035,7 +2011,7 @@ void CmdMaxplayersCallback() | ||||
| 	g_Players.MaxPlayersChanged(); | ||||
| } | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue) | ||||
| { | ||||
| 	for (int i = 1; i <= m_maxClients; i++) | ||||
| @ -2043,9 +2019,7 @@ bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQue | ||||
| 		if (m_Players[i].m_LanguageCookie == cookie) | ||||
| 		{ | ||||
| 			unsigned int langid; | ||||
| 			unsigned int new_langid = (translator->GetLanguageByName(cvarValue, &langid)) ? langid : translator->GetServerLanguage(); | ||||
| 			m_Players[i].m_LangId = new_langid; | ||||
| 			OnClientLanguageChanged(i, new_langid); | ||||
| 			m_Players[i].m_LangId = (translator->GetLanguageByName(cvarValue, &langid)) ? langid : translator->GetServerLanguage(); | ||||
| 
 | ||||
| 			return true; | ||||
| 		} | ||||
| @ -2114,8 +2088,7 @@ void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity) | ||||
| 	|| SOURCE_ENGINE == SE_HL2DM \ | ||||
| 	|| SOURCE_ENGINE == SE_BMS   \ | ||||
| 	|| SOURCE_ENGINE == SE_INSURGENCY \ | ||||
| 	|| SOURCE_ENGINE == SE_DOI   \ | ||||
| 	|| SOURCE_ENGINE == SE_BLADE | ||||
| 	|| SOURCE_ENGINE == SE_DOI | ||||
| 	m_pIClient = engine->GetIServer()->GetClient(m_iIndex - 1); | ||||
| #else | ||||
|   #if SOURCE_ENGINE == SE_SDK2013 | ||||
| @ -2291,7 +2264,7 @@ void CPlayer::Disconnect() | ||||
| 	m_bIsSourceTV = false; | ||||
| 	m_bIsReplay = false; | ||||
| 	m_Serial.value = -1; | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	m_LanguageCookie = InvalidQueryCvarCookie; | ||||
| #endif | ||||
| 	ClearNetchannelQueue(); | ||||
| @ -2300,7 +2273,7 @@ void CPlayer::Disconnect() | ||||
| void CPlayer::ClearNetchannelQueue(void) | ||||
| { | ||||
| 	while (!m_PrintfBuffer.empty()) | ||||
| 		m_PrintfBuffer.pop_front(); | ||||
| 		m_PrintfBuffer.popFront(); | ||||
| } | ||||
| 
 | ||||
| void CPlayer::SetName(const char *name) | ||||
| @ -2333,6 +2306,11 @@ void CPlayer::SetName(const char *name) | ||||
| 
 | ||||
| const char *CPlayer::GetName() | ||||
| { | ||||
| 	if (m_Info && m_pEdict->GetUnknown()) | ||||
| 	{ | ||||
| 		return m_Info->GetName(); | ||||
| 	} | ||||
| 	 | ||||
| 	return m_Name.c_str(); | ||||
| } | ||||
| 
 | ||||
| @ -2348,7 +2326,7 @@ const char *CPlayer::GetAuthString(bool validated) | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	return m_AuthID.c_str(); | ||||
| 	return m_AuthID.chars(); | ||||
| } | ||||
| 
 | ||||
| const CSteamID &CPlayer::GetSteamId(bool validated) | ||||
| @ -2369,7 +2347,7 @@ const char *CPlayer::GetSteam2Id(bool validated) | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	return m_Steam2Id.c_str(); | ||||
| 	return m_Steam2Id.chars(); | ||||
| } | ||||
| 
 | ||||
| const char *CPlayer::GetSteam3Id(bool validated) | ||||
| @ -2379,14 +2357,14 @@ const char *CPlayer::GetSteam3Id(bool validated) | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	return m_Steam3Id.c_str(); | ||||
| 	return m_Steam3Id.chars(); | ||||
| } | ||||
| 
 | ||||
| unsigned int CPlayer::GetSteamAccountID(bool validated) | ||||
| { | ||||
| 	if (!IsFakeClient() && (!validated || IsAuthStringValidated())) | ||||
| 	{ | ||||
| 		const CSteamID &id = GetSteamId(validated); | ||||
| 		const CSteamID &id = GetSteamId(); | ||||
| 		if (id.IsValid()) | ||||
| 			return id.GetAccountID(); | ||||
| 	} | ||||
| @ -2513,7 +2491,7 @@ void CPlayer::Kick(const char *str) | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 		pClient->Disconnect(str); | ||||
| #else | ||||
| 		pClient->Disconnect("%s", str); | ||||
| @ -2646,7 +2624,7 @@ void CPlayer::DoBasicAdminChecks() | ||||
| 	} | ||||
| 
 | ||||
| 	/* Check steam id */ | ||||
| 	if ((id = adminsys->FindAdminByIdentity("steam", m_AuthID.c_str())) != INVALID_ADMIN_ID) | ||||
| 	if ((id = adminsys->FindAdminByIdentity("steam", m_AuthID.chars())) != INVALID_ADMIN_ID) | ||||
| 	{ | ||||
| 		if (g_Players.CheckSetAdmin(client, this, id)) | ||||
| 		{ | ||||
| @ -2662,11 +2640,7 @@ unsigned int CPlayer::GetLanguageId() | ||||
| 
 | ||||
| void CPlayer::SetLanguageId(unsigned int id) | ||||
| { | ||||
| 	if(m_LangId != id) | ||||
| 	{ | ||||
| 	m_LangId = id; | ||||
| 		g_Players.OnClientLanguageChanged(m_iIndex, id); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int CPlayer::GetUserId() | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| /**
 | ||||
|  * vim: set ts=4 sts=8 sw=4 tw=99 noet : | ||||
|  * vim: set ts=4 : | ||||
|  * ============================================================================= | ||||
|  * SourceMod | ||||
|  * Copyright (C) 2004-2015 AlliedModders LLC.  All rights reserved. | ||||
| @ -133,9 +133,9 @@ private: | ||||
| 	String m_Name; | ||||
| 	String m_Ip; | ||||
| 	String m_IpNoPort; | ||||
| 	std::string m_AuthID; | ||||
| 	std::string m_Steam2Id; | ||||
| 	std::string m_Steam3Id; | ||||
| 	ke::AString m_AuthID; | ||||
| 	ke::AString m_Steam2Id; | ||||
| 	ke::AString m_Steam3Id; | ||||
| 	AdminId m_Admin = INVALID_ADMIN_ID; | ||||
| 	bool m_TempAdmin = false; | ||||
| 	edict_t *m_pEdict = nullptr; | ||||
| @ -151,10 +151,10 @@ private: | ||||
| 	bool m_bIsReplay = false; | ||||
| 	serial_t m_Serial; | ||||
| 	CSteamID m_SteamId; | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	QueryCvarCookie_t m_LanguageCookie = InvalidQueryCvarCookie; | ||||
| #endif | ||||
| 	std::deque<std::string> m_PrintfBuffer; | ||||
| 	ke::Deque<ke::AString> m_PrintfBuffer; | ||||
| }; | ||||
| 
 | ||||
| class PlayerManager :  | ||||
| @ -193,7 +193,6 @@ public: | ||||
| #endif | ||||
| 	void OnClientSettingsChanged(edict_t *pEntity); | ||||
| 	//void OnClientSettingsChanged_Pre(edict_t *pEntity);
 | ||||
| 	void OnClientLanguageChanged(int client, unsigned int language); | ||||
| 	void OnServerHibernationUpdate(bool bHibernating); | ||||
| 	void OnClientPrintf(edict_t *pEdict, const char *szMsg); | ||||
| 	void OnPrintfFrameAction(unsigned int serial); | ||||
| @ -217,9 +216,6 @@ public: //IPlayerManager | ||||
| 	void RecheckAnyAdmins(); | ||||
| public: // IGameEventListener2
 | ||||
| 	void FireGameEvent(IGameEvent *pEvent); | ||||
| #if SOURCE_ENGINE >= SE_ALIENSWARM | ||||
| 	virtual int	 GetEventDebugID( void ) { return 42; } | ||||
| #endif | ||||
| public: | ||||
| 	inline int MaxClients() | ||||
| 	{ | ||||
| @ -243,7 +239,7 @@ public: | ||||
| 	{ | ||||
| 		return m_bInCCKVHook; | ||||
| 	} | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	bool HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue); | ||||
| #endif | ||||
| private: | ||||
| @ -261,7 +257,6 @@ private: | ||||
| 	IForward *m_clcommandkv_post; | ||||
| 	IForward *m_clinfochanged; | ||||
| 	IForward *m_clauth; | ||||
| 	IForward *m_cllang; | ||||
| 	IForward *m_onActivate; | ||||
| 	IForward *m_onActivate2; | ||||
| 	CPlayer *m_Players; | ||||
|  | ||||
| @ -69,13 +69,6 @@ class DefaultMapTimer : | ||||
| 	public IConVarChangeListener | ||||
| { | ||||
| public: | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_BMS | ||||
| 	static constexpr int kMapTimeScaleFactor = 60; | ||||
| #else | ||||
| 	static constexpr int kMapTimeScaleFactor = 1; | ||||
| #endif | ||||
| 	 | ||||
| 	DefaultMapTimer() | ||||
| 	{ | ||||
| 		m_bInUse = false; | ||||
| @ -88,7 +81,7 @@ public: | ||||
| 
 | ||||
| 	int GetMapTimeLimit() | ||||
| 	{ | ||||
| 		return (mp_timelimit->GetInt() / kMapTimeScaleFactor); | ||||
| 		return mp_timelimit->GetInt(); | ||||
| 	} | ||||
| 
 | ||||
| 	void SetMapTimerStatus(bool enabled) | ||||
| @ -112,7 +105,7 @@ public: | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		extra_time /= (60 / kMapTimeScaleFactor); | ||||
| 		extra_time /= 60; | ||||
| 
 | ||||
| 		mp_timelimit->SetValue(mp_timelimit->GetInt() + extra_time); | ||||
| 	} | ||||
| @ -491,3 +484,4 @@ bool TimerSystem::GetMapTimeLeft(float *time_left) | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -816,7 +816,7 @@ public: | ||||
| 
 | ||||
| 	inline bool GetColor(const char *pszFieldName, Color *out) | ||||
| 	{ | ||||
| #if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE | ||||
| #if SOURCE_ENGINE != SE_CSGO | ||||
| 		return false; | ||||
| #else | ||||
| 		GETCHECK_FIELD(); | ||||
| @ -837,7 +837,7 @@ public: | ||||
| 
 | ||||
| 	inline bool SetColor(const char *pszFieldName, const Color &value) | ||||
| 	{ | ||||
| #if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE | ||||
| #if SOURCE_ENGINE != SE_CSGO | ||||
| 		return false; | ||||
| #else | ||||
| 		GETCHECK_FIELD(); | ||||
| @ -856,7 +856,7 @@ public: | ||||
| 
 | ||||
| 	inline bool GetRepeatedColor(const char *pszFieldName, int index, Color *out) | ||||
| 	{ | ||||
| #if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE | ||||
| #if SOURCE_ENGINE != SE_CSGO | ||||
| 		return false; | ||||
| #else | ||||
| 		GETCHECK_FIELD(); | ||||
| @ -878,7 +878,7 @@ public: | ||||
| 
 | ||||
| 	inline bool SetRepeatedColor(const char *pszFieldName, int index, const Color &value) | ||||
| 	{ | ||||
| #if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE | ||||
| #if SOURCE_ENGINE != SE_CSGO | ||||
| 		return false; | ||||
| #else | ||||
| 		GETCHECK_FIELD(); | ||||
| @ -898,7 +898,7 @@ public: | ||||
| 
 | ||||
| 	inline bool AddColor(const char *pszFieldName, const Color &value) | ||||
| 	{ | ||||
| #if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE | ||||
| #if SOURCE_ENGINE != SE_CSGO | ||||
| 		return false; | ||||
| #else | ||||
| 		GETCHECK_FIELD(); | ||||
|  | ||||
| @ -35,14 +35,12 @@ | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| #include <cstrike15_usermessage_helpers.h> | ||||
| #elif SOURCE_ENGINE == SE_BLADE | ||||
| #include <berimbau_usermessage_helpers.h> | ||||
| #endif | ||||
| #include <amtl/am-string.h> | ||||
| 
 | ||||
| UserMessages g_UserMsgs; | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &); | ||||
| #else | ||||
| #if SOURCE_ENGINE >= SE_LEFT4DEAD | ||||
| @ -51,7 +49,7 @@ SH_DECL_HOOK3(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRec | ||||
| SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int); | ||||
| #endif | ||||
| SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0); | ||||
| #endif // ==SE_CSGO || ==SE_BLADE
 | ||||
| #endif // ==SE_CSGO
 | ||||
| 
 | ||||
| UserMessages::UserMessages() | ||||
| #ifndef USE_PROTOBUF_USERMESSAGES | ||||
| @ -95,7 +93,7 @@ void UserMessages::OnSourceModAllShutdown() | ||||
| { | ||||
| 	if (m_HookCount) | ||||
| 	{ | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 		SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false); | ||||
| 		SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true); | ||||
| #else | ||||
| @ -113,8 +111,6 @@ int UserMessages::GetMessageIndex(const char *msg) | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	// Can split this per engine and/or game later
 | ||||
| 	return g_Cstrike15UsermessageHelpers.GetIndex(msg); | ||||
| #elif SOURCE_ENGINE == SE_BLADE | ||||
| 	return g_BerimbauUsermessageHelpers.GetIndex(msg); | ||||
| #else | ||||
| 
 | ||||
| 	int msgid; | ||||
| @ -152,8 +148,6 @@ bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) con | ||||
| #ifdef USE_PROTOBUF_USERMESSAGES | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid); | ||||
| #elif SOURCE_ENGINE == SE_BLADE | ||||
| 	const char *pszName = g_BerimbauUsermessageHelpers.GetName(msgid); | ||||
| #endif | ||||
| 	if (!pszName) | ||||
| 		return false; | ||||
| @ -303,7 +297,7 @@ bool UserMessages::EndMessage() | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	if (m_CurFlags & USERMSG_BLOCKHOOKS) | ||||
| 	{ | ||||
| 		ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer); | ||||
| @ -333,7 +327,7 @@ bool UserMessages::EndMessage() | ||||
| 	} else { | ||||
| 		engine->MessageEnd(); | ||||
| 	} | ||||
| #endif // SE_CSGO || SE_BLADE
 | ||||
| #endif // SE_CSGO
 | ||||
| 
 | ||||
| 	m_InExec = false; | ||||
| 	m_CurFlags = 0; | ||||
| @ -418,7 +412,7 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene | ||||
| 
 | ||||
| 	if (!m_HookCount++) | ||||
| 	{ | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 		SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false); | ||||
| 		SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true); | ||||
| #else | ||||
| @ -444,8 +438,6 @@ const protobuf::Message *UserMessages::GetMessagePrototype(int msg_type) | ||||
| { | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type); | ||||
| #elif SOURCE_ENGINE == SE_BLADE | ||||
| 	return g_BerimbauUsermessageHelpers.GetPrototype(msg_type); | ||||
| #endif | ||||
| } | ||||
| #endif | ||||
| @ -495,7 +487,7 @@ void UserMessages::_DecRefCounter() | ||||
| { | ||||
| 	if (--m_HookCount == 0) | ||||
| 	{ | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 		SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false); | ||||
| 		SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true); | ||||
| #else | ||||
| @ -507,17 +499,12 @@ void UserMessages::_DecRefCounter() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg) | ||||
| { | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msg_type); | ||||
| #elif SOURCE_ENGINE == SE_BLADE | ||||
| 	const char *pszName = g_BerimbauUsermessageHelpers.GetName(msg_type); | ||||
| 	OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type)); | ||||
| #endif | ||||
| 
 | ||||
| 	OnStartMessage_Pre(&filter, msg_type, pszName); | ||||
| 
 | ||||
| 	if (m_FakeMetaRes == MRES_SUPERCEDE) | ||||
| 	{ | ||||
| 		int size = msg.ByteSize(); | ||||
| @ -530,7 +517,9 @@ void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, | ||||
| 		m_FakeEngineBuffer = &const_cast<protobuf::Message &>(msg); | ||||
| 	} | ||||
| 
 | ||||
| 	OnStartMessage_Post(&filter, msg_type, pszName); | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type)); | ||||
| #endif | ||||
| 
 | ||||
| 	OnMessageEnd_Pre(); | ||||
| 	if (m_FakeMetaRes == MRES_SUPERCEDE) | ||||
| @ -562,7 +551,7 @@ void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type | ||||
| 	RETURN_META(res) | ||||
| #endif | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name) | ||||
| #elif SOURCE_ENGINE >= SE_LEFT4DEAD | ||||
| bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name) | ||||
| @ -602,7 +591,7 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ | ||||
| 	UM_RETURN_META_VALUE(MRES_IGNORED, NULL); | ||||
| } | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name) | ||||
| #elif SOURCE_ENGINE >= SE_LEFT4DEAD | ||||
| bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name) | ||||
| @ -767,7 +756,7 @@ void UserMessages::OnMessageEnd_Pre() | ||||
| 
 | ||||
| 	if (!handled && intercepted) | ||||
| 	{ | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 		ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer); | ||||
| #else | ||||
| 		bf_write *engine_bfw; | ||||
| @ -779,11 +768,11 @@ void UserMessages::OnMessageEnd_Pre() | ||||
| 		m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten()); | ||||
| 		engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten()); | ||||
| 		ENGINE_CALL(MessageEnd)(); | ||||
| #endif // SE_CSGO || SE_BLADE
 | ||||
| #endif // SE_CSGO
 | ||||
| 	} | ||||
| 
 | ||||
| 	{ | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 		int size = m_OrigBuffer->ByteSize(); | ||||
| 		uint8 *data = (uint8 *)stackalloc(size); | ||||
| 		m_OrigBuffer->SerializePartialToArray(data, size); | ||||
| @ -813,7 +802,7 @@ void UserMessages::OnMessageEnd_Pre() | ||||
| 			iter++; | ||||
| 		} | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 		delete pTempMsg; | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| @ -44,7 +44,7 @@ | ||||
| using namespace SourceHook; | ||||
| using namespace SourceMod; | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| #define USE_PROTOBUF_USERMESSAGES | ||||
| #endif | ||||
| 
 | ||||
| @ -102,12 +102,12 @@ public: //IUserMessages | ||||
| 		bool intercept=false); | ||||
| 	UserMessageType GetUserMessageType() const; | ||||
| public: | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	void OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg); | ||||
| 	void OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg); | ||||
| #endif | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	protobuf::Message *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name); | ||||
| 	protobuf::Message *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name); | ||||
| #elif SOURCE_ENGINE >= SE_LEFT4DEAD | ||||
|  | ||||
| @ -36,7 +36,7 @@ | ||||
| 
 | ||||
| #if SOURCE_ENGINE >= SE_ORANGEBOX | ||||
| SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *); | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| SH_DECL_HOOK2_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *, bool); | ||||
| #else | ||||
| SH_DECL_HOOK1_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *); | ||||
| @ -82,7 +82,7 @@ public: | ||||
| #endif | ||||
| 	} | ||||
| 
 | ||||
| #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE | ||||
| #if SOURCE_ENGINE == SE_CSGO | ||||
| 	void LinkConCommandBase(ConCommandBase *pBase, bool unknown) | ||||
| #else | ||||
| 	void LinkConCommandBase(ConCommandBase *pBase) | ||||
|  | ||||
| @ -1,8 +1,8 @@ | ||||
| # vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: | ||||
| import os | ||||
| 
 | ||||
| for cxx in builder.targets: | ||||
|   binary = SM.Library(builder, cxx, 'sourcemod.logic') | ||||
| for arch in SM.archs: | ||||
|   binary = SM.Library(builder, 'sourcemod.logic', arch) | ||||
|   binary.compiler.cxxincludes += [ | ||||
|     builder.sourcePath, | ||||
|     os.path.join(builder.sourcePath, 'core', 'logic'), | ||||
| @ -17,9 +17,9 @@ for cxx in builder.targets: | ||||
|     'SM_LOGIC' | ||||
|   ] | ||||
|    | ||||
|   if binary.compiler.target.platform == 'linux': | ||||
|   if builder.target.platform == 'linux': | ||||
|     binary.compiler.postlink += ['-lpthread', '-lrt'] | ||||
|   elif binary.compiler.target.platform == 'mac': | ||||
|   elif builder.target.platform == 'mac': | ||||
|     binary.compiler.cflags += ['-Wno-deprecated-declarations'] | ||||
|     binary.compiler.postlink += ['-framework', 'CoreServices'] | ||||
| 
 | ||||
| @ -35,7 +35,8 @@ for cxx in builder.targets: | ||||
|     'smn_maplists.cpp', | ||||
|     'ADTFactory.cpp', | ||||
|     'smn_adt_stack.cpp', | ||||
|     'BaseWorker.cpp', | ||||
|     'thread/ThreadWorker.cpp', | ||||
|     'thread/BaseWorker.cpp', | ||||
|     'ThreadSupport.cpp', | ||||
|     'smn_float.cpp', | ||||
|     'TextParsers.cpp', | ||||
| @ -84,12 +85,15 @@ for cxx in builder.targets: | ||||
|     'smn_halflife.cpp', | ||||
|     'FrameIterator.cpp', | ||||
|     'DatabaseConfBuilder.cpp', | ||||
|     'LumpManager.cpp', | ||||
|     'smn_entitylump.cpp', | ||||
|     'NativeInvoker.cpp', | ||||
|   ] | ||||
| 
 | ||||
|   if binary.compiler.target.arch == 'x86_64': | ||||
|   if arch == 'x64': | ||||
|     binary.sources += ['PseudoAddrManager.cpp'] | ||||
| 
 | ||||
|   if builder.target.platform == 'windows': | ||||
|     binary.sources += ['thread/WinThreads.cpp'] | ||||
|   else: | ||||
|     binary.sources += ['thread/PosixThreads.cpp'] | ||||
| 
 | ||||
|   SM.binaries += [builder.Add(binary)] | ||||
|  | ||||
| @ -1581,7 +1581,7 @@ bool AdminCache::CanAdminTarget(AdminId id, AdminId target) | ||||
| 		{ | ||||
| 			id = grp_table[i]; | ||||
| 			num = GetGroupImmunityCount(id); | ||||
| 			for (unsigned int j=0; j<num; j++) | ||||
| 			for (unsigned int j=0; j<num; i++) | ||||
| 			{ | ||||
| 				other = GetGroupImmunity(id, j); | ||||
| 				for (unsigned int k=0; k<pUser->grp_count; k++) | ||||
| @ -1843,13 +1843,13 @@ bool AdminCache::DumpCache(const char *filename) | ||||
| 		fprintf(fp, "\n\t\t\"Overrides\"\n\t\t{\n"); | ||||
| 		if (pGroup->pCmdGrpTable != NULL) | ||||
| 		{ | ||||
| 			for (OverrideMap::iterator iter = pGroup->pCmdGrpTable->iter(); !iter.empty(); iter.next()) | ||||
| 				iterator_group_grp_override(fp, iter->key.c_str(), iter->value); | ||||
| 			for (OverrideMap::iterator iter = pGroup->pCmdTable->iter(); !iter.empty(); iter.next()) | ||||
| 				iterator_group_grp_override(fp, iter->key.chars(), iter->value); | ||||
| 		} | ||||
| 		if (pGroup->pCmdTable != NULL) | ||||
| 		{ | ||||
| 			for (OverrideMap::iterator iter = pGroup->pCmdTable->iter(); !iter.empty(); iter.next()) | ||||
| 				iterator_group_basic_override(fp, iter->key.c_str(), iter->value); | ||||
| 				iterator_group_basic_override(fp, iter->key.chars(), iter->value); | ||||
| 		} | ||||
| 		fprintf(fp, "\t\t}\n"); | ||||
| 
 | ||||
| @ -1924,9 +1924,9 @@ bool AdminCache::DumpCache(const char *filename) | ||||
| 
 | ||||
| 	fprintf(fp, "\"Overrides\"\n{\n"); | ||||
| 	for (FlagMap::iterator iter = m_CmdGrpOverrides.iter(); !iter.empty(); iter.next()) | ||||
| 		iterator_glob_grp_override(fp, iter->key.c_str(), iter->value); | ||||
| 		iterator_glob_grp_override(fp, iter->key.chars(), iter->value); | ||||
| 	for (FlagMap::iterator iter = m_CmdOverrides.iter(); !iter.empty(); iter.next()) | ||||
| 		iterator_glob_basic_override(fp, iter->key.c_str(), iter->value); | ||||
| 		iterator_glob_basic_override(fp, iter->key.chars(), iter->value); | ||||
| 	fprintf(fp, "}\n"); | ||||
| 	 | ||||
| 	fclose(fp); | ||||
|  | ||||
| @ -31,10 +31,8 @@ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include "CDataPack.h" | ||||
| #include <amtl/am-autoptr.h> | ||||
| 
 | ||||
| CDataPack::CDataPack() | ||||
| { | ||||
| @ -46,15 +44,33 @@ CDataPack::~CDataPack() | ||||
| 	Initialize(); | ||||
| } | ||||
| 
 | ||||
| static ke::Vector<ke::AutoPtr<CDataPack>> sDataPackCache; | ||||
| 
 | ||||
| CDataPack *CDataPack::New() | ||||
| { | ||||
|   if (sDataPackCache.empty()) | ||||
|     return new CDataPack(); | ||||
| 
 | ||||
|   CDataPack *pack = sDataPackCache.back().take(); | ||||
|   sDataPackCache.pop(); | ||||
|   pack->Initialize(); | ||||
|   return pack; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| CDataPack::Free(CDataPack *pack) | ||||
| { | ||||
|   sDataPackCache.append(static_cast<CDataPack *>(pack)); | ||||
| } | ||||
| 
 | ||||
| void CDataPack::Initialize() | ||||
| { | ||||
| 	position = 0; | ||||
| 	 | ||||
| 	do | ||||
| 	{ | ||||
| 	} while (this->RemoveItem()); | ||||
| 
 | ||||
| 	elements.clear(); | ||||
| 	position = 0; | ||||
| } | ||||
| 
 | ||||
| void CDataPack::ResetSize() | ||||
| @ -68,7 +84,7 @@ size_t CDataPack::CreateMemory(size_t size, void **addr) | ||||
| 	val.type = CDataPackType::Raw; | ||||
| 	val.pData.vval = new uint8_t[size + sizeof(size)]; | ||||
| 	reinterpret_cast<size_t *>(val.pData.vval)[0] = size; | ||||
| 	elements.emplace(elements.begin() + position, val); | ||||
| 	elements.insert(position, val); | ||||
| 
 | ||||
| 	return position++; | ||||
| } | ||||
| @ -78,8 +94,7 @@ void CDataPack::PackCell(cell_t cell) | ||||
| 	InternalPack val; | ||||
| 	val.type = CDataPackType::Cell; | ||||
| 	val.pData.cval = cell; | ||||
| 	elements.emplace(elements.begin() + position, val); | ||||
| 	position++; | ||||
| 	elements.insert(position++, val); | ||||
| } | ||||
| 
 | ||||
| void CDataPack::PackFunction(cell_t function) | ||||
| @ -87,8 +102,7 @@ void CDataPack::PackFunction(cell_t function) | ||||
| 	InternalPack val; | ||||
| 	val.type = CDataPackType::Function; | ||||
| 	val.pData.cval = function; | ||||
| 	elements.emplace(elements.begin() + position, val); | ||||
| 	position++; | ||||
| 	elements.insert(position++, val); | ||||
| } | ||||
| 
 | ||||
| void CDataPack::PackFloat(float floatval) | ||||
| @ -96,42 +110,16 @@ void CDataPack::PackFloat(float floatval) | ||||
| 	InternalPack val; | ||||
| 	val.type = CDataPackType::Float; | ||||
| 	val.pData.fval = floatval; | ||||
| 	elements.emplace(elements.begin() + position, val); | ||||
| 	position++; | ||||
| 	elements.insert(position++, val); | ||||
| } | ||||
| 
 | ||||
| void CDataPack::PackString(const char *string) | ||||
| { | ||||
| 	InternalPack val; | ||||
| 	val.type = CDataPackType::String; | ||||
| 	std::string *sval = new std::string(string); | ||||
| 	ke::AString *sval = new ke::AString(string); | ||||
| 	val.pData.sval = sval; | ||||
| 	elements.emplace(elements.begin() + position, val); | ||||
| 	position++; | ||||
| } | ||||
| 
 | ||||
| void CDataPack::PackCellArray(cell_t const *vals, cell_t count) | ||||
| { | ||||
| 	InternalPack val; | ||||
| 	val.type = CDataPackType::CellArray; | ||||
| 
 | ||||
| 	val.pData.aval = new cell_t [count + 1]; | ||||
| 	memcpy(&val.pData.aval[1], vals, sizeof(cell_t) * count); | ||||
| 	val.pData.aval[0] = count; | ||||
| 	elements.emplace(elements.begin() + position, val); | ||||
| 	position++; | ||||
| } | ||||
| 
 | ||||
| void CDataPack::PackFloatArray(cell_t const *vals, cell_t count) | ||||
| { | ||||
| 	InternalPack val; | ||||
| 	val.type = CDataPackType::FloatArray; | ||||
| 
 | ||||
| 	val.pData.aval = new cell_t [count + 1]; | ||||
| 	memcpy(&val.pData.aval[1], vals, sizeof(cell_t) * count); | ||||
| 	val.pData.aval[0] = count; | ||||
| 	elements.emplace(elements.begin() + position, val); | ||||
| 	position++; | ||||
| 	elements.insert(position++, val); | ||||
| } | ||||
| 
 | ||||
| void CDataPack::Reset() const | ||||
| @ -146,7 +134,7 @@ size_t CDataPack::GetPosition() const | ||||
| 
 | ||||
| bool CDataPack::SetPosition(size_t pos) const | ||||
| { | ||||
| 	if (pos > elements.size()) | ||||
| 	if (pos > elements.length()) | ||||
| 		return false; | ||||
| 
 | ||||
| 	position = pos; | ||||
| @ -179,7 +167,7 @@ float CDataPack::ReadFloat() const | ||||
| 
 | ||||
| bool CDataPack::IsReadable(size_t bytes) const | ||||
| { | ||||
| 	return (position < elements.size()); | ||||
| 	return (position < elements.length()); | ||||
| } | ||||
| 
 | ||||
| const char *CDataPack::ReadString(size_t *len) const | ||||
| @ -192,51 +180,11 @@ const char *CDataPack::ReadString(size_t *len) const | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 
 | ||||
| 	const std::string &val = *elements[position++].pData.sval; | ||||
| 	const ke::AString &val = *elements[position++].pData.sval; | ||||
| 	if (len) | ||||
| 		*len = val.size(); | ||||
| 		*len = val.length(); | ||||
| 
 | ||||
| 	return val.c_str(); | ||||
| } | ||||
| 
 | ||||
| cell_t *CDataPack::ReadCellArray(cell_t *size) const | ||||
| { | ||||
| 	if (!IsReadable() || elements[position].type != CDataPackType::CellArray) | ||||
| 	{ | ||||
| 		if(size) | ||||
| 			*size = 0; | ||||
| 		 | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 
 | ||||
| 	cell_t *val = elements[position].pData.aval; | ||||
| 	cell_t *ptr = &(val[1]); | ||||
| 	++position; | ||||
| 
 | ||||
| 	if (size) | ||||
| 		*size = val[0]; | ||||
| 
 | ||||
| 	return ptr; | ||||
| } | ||||
| 
 | ||||
| cell_t *CDataPack::ReadFloatArray(cell_t *size) const | ||||
| { | ||||
| 	if (!IsReadable() || elements[position].type != CDataPackType::FloatArray) | ||||
| 	{ | ||||
| 		if(size) | ||||
| 			*size = 0; | ||||
| 		 | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 
 | ||||
| 	cell_t *val = elements[position].pData.aval; | ||||
| 	cell_t *ptr = &(val[1]); | ||||
| 	++position; | ||||
| 
 | ||||
| 	if (size) | ||||
| 		*size = val[0]; | ||||
| 
 | ||||
| 	return ptr; | ||||
| 	return val.chars(); | ||||
| } | ||||
| 
 | ||||
| void *CDataPack::ReadMemory(size_t *size) const | ||||
| @ -257,7 +205,7 @@ void *CDataPack::ReadMemory(size_t *size) const | ||||
| 
 | ||||
| bool CDataPack::RemoveItem(size_t pos) | ||||
| { | ||||
| 	if (!elements.size()) | ||||
| 	if (!elements.length()) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| @ -266,8 +214,7 @@ bool CDataPack::RemoveItem(size_t pos) | ||||
| 	{ | ||||
| 		pos = position; | ||||
| 	} | ||||
| 	 | ||||
| 	if (pos >= elements.size()) | ||||
| 	if (pos >= elements.length()) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| @ -281,7 +228,7 @@ bool CDataPack::RemoveItem(size_t pos) | ||||
| 	{ | ||||
| 		case CDataPackType::Raw: | ||||
| 		{ | ||||
| 			delete [] elements[pos].pData.vval; | ||||
| 			delete elements[pos].pData.vval; | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| @ -290,15 +237,8 @@ bool CDataPack::RemoveItem(size_t pos) | ||||
| 			delete elements[pos].pData.sval; | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		case CDataPackType::CellArray: | ||||
| 		case CDataPackType::FloatArray: | ||||
| 		{ | ||||
| 			delete [] elements[pos].pData.aval; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	elements.erase(elements.begin() + pos); | ||||
| 	elements.remove(pos); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| @ -43,9 +43,7 @@ enum CDataPackType { | ||||
| 	Cell, | ||||
| 	Float, | ||||
| 	String, | ||||
| 	Function, | ||||
| 	CellArray, | ||||
| 	FloatArray, | ||||
| 	Function | ||||
| }; | ||||
| 
 | ||||
| class CDataPack | ||||
| @ -54,6 +52,9 @@ public: | ||||
| 	CDataPack(); | ||||
| 	~CDataPack(); | ||||
| 
 | ||||
|     static CDataPack *New(); | ||||
|     static void Free(CDataPack *pack); | ||||
| 
 | ||||
| public: // Originally IDataReader
 | ||||
| 	/**
 | ||||
| 	 * @brief Resets the position in the data stream to the beginning. | ||||
| @ -89,21 +90,6 @@ public: // Originally IDataReader | ||||
| 	 */ | ||||
| 	float ReadFloat() const; | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Reads an array of values from the data stream. | ||||
| 	 * | ||||
| 	 * @param len       The size of the array stored at this position to return. | ||||
| 	 * @return			A cell array read from the current position. | ||||
| 	 */ | ||||
| 	cell_t *ReadCellArray(cell_t *len) const; | ||||
| 	/**
 | ||||
| 	 * @brief Reads an array of values from the data stream. | ||||
| 	 * | ||||
| 	 * @param len       The size of the array stored at this position to return. | ||||
| 	 * @return			A cell array read from the current position. | ||||
| 	 */ | ||||
| 	cell_t *ReadFloatArray(cell_t *len) const; | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Returns whether or not a specified number of bytes from the current stream | ||||
| 	 *  position to the end can be read. | ||||
| @ -164,21 +150,6 @@ public: // Originally IDataPack | ||||
| 	 */ | ||||
| 	void PackString(const char *string); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Packs an array of cells into the data stream. | ||||
| 	 * | ||||
| 	 * @param vals		Cells to write. | ||||
| 	 * @param count     Number of cells. | ||||
| 	 */ | ||||
| 	void PackCellArray(cell_t const *vals, cell_t count); | ||||
| 	/**
 | ||||
| 	 * @brief Packs an array of cells into the data stream. | ||||
| 	 * | ||||
| 	 * @param vals		Cells to write. | ||||
| 	 * @param count     Number of cells. | ||||
| 	 */ | ||||
| 	void PackFloatArray(cell_t const *vals, cell_t count); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Creates a generic block of memory in the stream. | ||||
| 	 * | ||||
| @ -201,7 +172,7 @@ public: // Originally IDataPack | ||||
| 
 | ||||
| public: | ||||
| 	void Initialize(); | ||||
| 	inline size_t GetCapacity() const { return this->elements.size(); }; | ||||
| 	inline size_t GetCapacity() const { return this->elements.length(); }; | ||||
| 	inline CDataPackType GetCurrentType(void) const { return this->elements[this->position].type; }; | ||||
| 	bool RemoveItem(size_t pos = -1); | ||||
| 
 | ||||
| @ -210,8 +181,7 @@ private: | ||||
| 		cell_t cval; | ||||
| 		float fval; | ||||
| 		uint8_t *vval; | ||||
| 		std::string *sval; | ||||
| 		cell_t *aval; | ||||
| 		ke::AString *sval; | ||||
| 	} InternalPackValue; | ||||
| 	 | ||||
| 	typedef struct { | ||||
| @ -219,7 +189,7 @@ private: | ||||
| 		CDataPackType type; | ||||
| 	} InternalPack; | ||||
| 
 | ||||
| 	std::vector<InternalPack> elements; | ||||
| 	ke::Vector<InternalPack> elements; | ||||
| 	mutable size_t position; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -35,7 +35,6 @@ | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <ICellArray.h> | ||||
| #include <amtl/am-bits.h> | ||||
| 
 | ||||
| extern HandleType_t htCellArray; | ||||
| 
 | ||||
| @ -215,34 +214,30 @@ private: | ||||
| 		{ | ||||
| 			return true; | ||||
| 		} | ||||
| 		size_t newAllocSize = m_AllocSize; | ||||
| 		/* Set a base allocation size of 8 items */ | ||||
| 		if (!newAllocSize) | ||||
| 		if (!m_AllocSize) | ||||
| 		{ | ||||
| 			newAllocSize = 8; | ||||
| 		} | ||||
| 		if (!ke::IsUintPtrAddSafe(m_Size, count)) | ||||
| 		{ | ||||
| 			return false; | ||||
| 			m_AllocSize = 8; | ||||
| 		} | ||||
| 		/* If it's not enough, keep doubling */ | ||||
| 		while (m_Size + count > newAllocSize) | ||||
| 		while (m_Size + count > m_AllocSize) | ||||
| 		{ | ||||
| 			if (!ke::IsUintPtrMultiplySafe(newAllocSize, 2)) | ||||
| 			m_AllocSize *= 2; | ||||
| 		} | ||||
| 		/* finally, allocate the new block */ | ||||
| 		if (m_Data) | ||||
| 		{ | ||||
| 			cell_t *data = static_cast<cell_t*>(realloc(m_Data, sizeof(cell_t) * m_BlockSize * m_AllocSize)); | ||||
| 			if (!data)  // allocation failure
 | ||||
| 			{ | ||||
| 				return false; | ||||
| 			} | ||||
| 			newAllocSize *= 2; | ||||
| 		} | ||||
| 		/* finally, allocate the new block */ | ||||
| 		cell_t *data = static_cast<cell_t*>(realloc(m_Data, sizeof(cell_t) * m_BlockSize * newAllocSize)); | ||||
| 		/* Update state if allocation was successful */ | ||||
| 		if (data) | ||||
| 		{ | ||||
| 			m_AllocSize = newAllocSize; | ||||
| 
 | ||||
| 			m_Data = data; | ||||
| 		} else { | ||||
| 			m_Data = static_cast<cell_t*>(malloc(sizeof(cell_t) * m_BlockSize * m_AllocSize)); | ||||
| 		} | ||||
| 		return (data != nullptr); | ||||
| 		return (m_Data != nullptr); | ||||
| 	} | ||||
| private: | ||||
| 	cell_t *m_Data; | ||||
|  | ||||
| @ -34,20 +34,17 @@ | ||||
| #include "HandleSys.h" | ||||
| #include "ExtensionSys.h" | ||||
| #include "PluginSys.h" | ||||
| #include <chrono> | ||||
| #include <amtl/am-thread.h> | ||||
| #include <stdlib.h> | ||||
| #include <IThreader.h> | ||||
| #include <bridge/include/ILogger.h> | ||||
| #include <bridge/include/CoreProvider.h> | ||||
| 
 | ||||
| using namespace std::chrono_literals; | ||||
| 
 | ||||
| #define DBPARSE_LEVEL_NONE		0 | ||||
| #define DBPARSE_LEVEL_MAIN		1 | ||||
| #define DBPARSE_LEVEL_DATABASE	2 | ||||
| 
 | ||||
| DBManager g_DBMan; | ||||
| static bool s_OneTimeThreaderErrorMsg = false; | ||||
| 
 | ||||
| DBManager::DBManager()  | ||||
| 	: m_Terminate(false), | ||||
| @ -128,8 +125,8 @@ void DBManager::OnHandleDestroy(HandleType_t type, void *object) | ||||
| 
 | ||||
| bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength) | ||||
| { | ||||
| 	ConfDbInfoList &list = m_Builder.GetConfigList(); | ||||
| 	ke::RefPtr<ConfDbInfo> pInfo = list.GetDatabaseConf(name); | ||||
| 	ConfDbInfoList *list = m_Builder.GetConfigList(); | ||||
| 	ke::RefPtr<ConfDbInfo> pInfo = list->GetDatabaseConf(name); | ||||
| 
 | ||||
| 	if (!pInfo) | ||||
| 	{ | ||||
| @ -148,12 +145,12 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool | ||||
| 		/* Try to assign a real driver pointer */ | ||||
| 		if (pInfo->info.driver[0] == '\0') | ||||
| 		{ | ||||
| 			std::string defaultDriver = list.GetDefaultDriver(); | ||||
| 			ke::AString defaultDriver = list->GetDefaultDriver(); | ||||
| 			if (!m_pDefault && defaultDriver.length() > 0) | ||||
| 			{ | ||||
| 				m_pDefault = FindOrLoadDriver(defaultDriver.c_str()); | ||||
| 				m_pDefault = FindOrLoadDriver(defaultDriver.chars()); | ||||
| 			} | ||||
| 			dname = defaultDriver.length() ? defaultDriver.c_str() : "default"; | ||||
| 			dname = defaultDriver.length() ? defaultDriver.chars() : "default"; | ||||
| 			pInfo->realDriver = m_pDefault; | ||||
| 		} else { | ||||
| 			pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver); | ||||
| @ -209,14 +206,17 @@ void DBManager::RemoveDriver(IDBDriver *pDriver) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ConfDbInfoList &list = m_Builder.GetConfigList(); | ||||
| 	for (auto conf : list) { | ||||
| 		if (conf->realDriver == pDriver) | ||||
| 	ConfDbInfoList *list = m_Builder.GetConfigList(); | ||||
| 	for (size_t i = 0; i < list->length(); i++) | ||||
| 	{ | ||||
| 			conf->realDriver = NULL; | ||||
| 		ke::RefPtr<ConfDbInfo> current = list->at(i); | ||||
| 		if (current->realDriver == pDriver) | ||||
| 		{ | ||||
| 			current->realDriver = NULL; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* Someone unloaded the default driver? Silly.. */ | ||||
| 	if (pDriver == m_pDefault) | ||||
| 	{ | ||||
| @ -252,11 +252,11 @@ void DBManager::RemoveDriver(IDBDriver *pDriver) | ||||
| 
 | ||||
| IDBDriver *DBManager::GetDefaultDriver() | ||||
| { | ||||
| 	ConfDbInfoList &list = m_Builder.GetConfigList(); | ||||
| 	std::string defaultDriver = list.GetDefaultDriver(); | ||||
| 	ConfDbInfoList *list = m_Builder.GetConfigList(); | ||||
| 	ke::AString defaultDriver = list->GetDefaultDriver(); | ||||
| 	if (!m_pDefault && defaultDriver.length() > 0) | ||||
| 	{ | ||||
| 		m_pDefault = FindOrLoadDriver(defaultDriver.c_str()); | ||||
| 		m_pDefault = FindOrLoadDriver(defaultDriver.chars()); | ||||
| 	} | ||||
| 
 | ||||
| 	return m_pDefault; | ||||
| @ -319,12 +319,12 @@ IDBDriver *DBManager::GetDriver(unsigned int index) | ||||
| 
 | ||||
| const DatabaseInfo *DBManager::FindDatabaseConf(const char *name) | ||||
| { | ||||
| 	ConfDbInfoList &list = m_Builder.GetConfigList(); | ||||
| 	ke::RefPtr<ConfDbInfo> info = list.GetDatabaseConf(name); | ||||
| 	ConfDbInfoList *list = m_Builder.GetConfigList(); | ||||
| 	ke::RefPtr<ConfDbInfo> info = list->GetDatabaseConf(name); | ||||
| 	if (!info) | ||||
| 	{ | ||||
| 		// couldn't find requested conf, return default if exists
 | ||||
| 		info = list.GetDefaultConfiguration(); | ||||
| 		info = list->GetDefaultConfiguration(); | ||||
| 		if (!info) | ||||
| 		{ | ||||
| 			return NULL; | ||||
| @ -334,10 +334,11 @@ const DatabaseInfo *DBManager::FindDatabaseConf(const char *name) | ||||
| 	return &info->info; | ||||
| } | ||||
| 
 | ||||
| ke::RefPtr<ConfDbInfo> DBManager::GetDatabaseConf(const char *name) | ||||
| ConfDbInfo *DBManager::GetDatabaseConf(const char *name) | ||||
| { | ||||
| 	ConfDbInfoList &list = m_Builder.GetConfigList(); | ||||
| 	return list.GetDatabaseConf(name); | ||||
| 	ConfDbInfoList *list = m_Builder.GetConfigList(); | ||||
| 	ke::RefPtr<ConfDbInfo> info(list->GetDatabaseConf(name)); | ||||
| 	return info; | ||||
| } | ||||
| 
 | ||||
| IDBDriver *DBManager::FindOrLoadDriver(const char *name) | ||||
| @ -376,12 +377,13 @@ void DBManager::KillWorkerThread() | ||||
| 	if (m_Worker) | ||||
| 	{ | ||||
| 		{ | ||||
| 			std::lock_guard<std::mutex> lock(m_Lock); | ||||
| 			ke::AutoLock lock(&m_QueueEvent); | ||||
| 			m_Terminate = true; | ||||
| 			m_QueueEvent.notify_all(); | ||||
| 			m_QueueEvent.Notify(); | ||||
| 		} | ||||
| 		m_Worker->join(); | ||||
| 		m_Worker->Join(); | ||||
| 		m_Worker = nullptr; | ||||
| 		s_OneTimeThreaderErrorMsg = false; | ||||
| 		m_Terminate = false; | ||||
| 	} | ||||
| } | ||||
| @ -397,17 +399,27 @@ bool DBManager::AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio) | ||||
| 
 | ||||
| 	if (!m_Worker) | ||||
| 	{ | ||||
| 		m_Worker = ke::NewThread("SM Database Worker", [this]() -> void { | ||||
| 		m_Worker = new ke::Thread([this]() -> void { | ||||
| 			Run(); | ||||
| 		}); | ||||
| 		}, "SM SQL Worker"); | ||||
| 		if (!m_Worker->Succeeded()) | ||||
| 		{ | ||||
| 			if (!s_OneTimeThreaderErrorMsg) | ||||
| 			{ | ||||
| 				logger->LogError("[SM] Unable to create db threader (error unknown)"); | ||||
| 				s_OneTimeThreaderErrorMsg = true; | ||||
| 			} | ||||
| 			m_Worker = nullptr; | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* Add to the queue */ | ||||
| 	{ | ||||
| 		std::lock_guard<std::mutex> lock(m_Lock); | ||||
| 		ke::AutoLock lock(&m_QueueEvent); | ||||
| 		Queue<IDBThreadOperation *> &queue = m_OpQueue.GetQueue(prio); | ||||
| 		queue.push(op); | ||||
| 		m_QueueEvent.notify_one(); | ||||
| 		m_QueueEvent.Notify(); | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| @ -438,7 +450,7 @@ void DBManager::Run() | ||||
| 
 | ||||
| void DBManager::ThreadMain() | ||||
| { | ||||
| 	std::unique_lock<std::mutex> lock(m_Lock); | ||||
| 	ke::AutoLock lock(&m_QueueEvent); | ||||
| 
 | ||||
| 	while (true) { | ||||
| 		// The lock has been acquired. Grab everything we can out of the
 | ||||
| @ -446,19 +458,14 @@ void DBManager::ThreadMain() | ||||
| 		// we process all operations we can before checking to terminate.
 | ||||
| 		// There's no risk of starvation since the main thread blocks on us
 | ||||
| 		// terminating.
 | ||||
| 		auto queue = &m_OpQueue.GetLikelyQueue(); | ||||
| 		if (queue->empty()) { | ||||
| 			// If the queue is empty and we've been asked to stop, leave now.
 | ||||
| 			if (m_Terminate) | ||||
| 				return; | ||||
| 		while (true) | ||||
| 		{ | ||||
| 			Queue<IDBThreadOperation *> &queue = m_OpQueue.GetLikelyQueue(); | ||||
| 			if (queue.empty()) | ||||
| 				break; | ||||
| 
 | ||||
| 			// Otherwise, wait for something to happen.
 | ||||
| 			m_QueueEvent.wait(lock); | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		IDBThreadOperation *op = queue->first(); | ||||
| 		queue->pop(); | ||||
| 			IDBThreadOperation *op = queue.first(); | ||||
| 			queue.pop(); | ||||
| 
 | ||||
| 			// Unlock the queue when we run the query, so the main thread can
 | ||||
| 			// keep pumping events. We re-acquire the lock to check for more
 | ||||
| @ -466,23 +473,31 @@ void DBManager::ThreadMain() | ||||
| 			// thread would be blocked and we'd need to flush the queue
 | ||||
| 			// anyway, so after we've depleted the queue here, we'll just
 | ||||
| 			// reach the terminate at the top of the loop.
 | ||||
| 		lock.unlock(); | ||||
| 			{ | ||||
| 				ke::AutoUnlock unlock(&m_QueueEvent); | ||||
| 				op->RunThreadPart(); | ||||
| 
 | ||||
| 		// Re-acquire the lock and give the data back to the main thread
 | ||||
| 		// immediately. We use a separate lock to minimize game thread
 | ||||
| 		// contention.
 | ||||
| 		{ | ||||
| 			std::lock_guard<std::mutex> think_lock(m_ThinkLock); | ||||
| 				ke::AutoLock lock(&m_ThinkLock); | ||||
| 				m_ThinkQueue.push(op); | ||||
| 			} | ||||
| 			 | ||||
| 		// Note that we add a 20ms delay after processing a query. This is
 | ||||
| 		// questionable but the intent is to avoid starving the game thread.
 | ||||
| 		if (!m_Terminate) | ||||
| 			std::this_thread::sleep_for(20ms); | ||||
| 			 | ||||
| 		lock.lock(); | ||||
| 			if (!m_Terminate) | ||||
| 			{ | ||||
| 				ke::AutoUnlock unlock(&m_QueueEvent); | ||||
| #ifdef _WIN32 | ||||
| 				Sleep(20); | ||||
| #else | ||||
| 				usleep(20000); | ||||
| #endif | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (m_Terminate) | ||||
| 			return; | ||||
| 
 | ||||
| 		// Release the lock and wait for a signal.
 | ||||
| 		m_QueueEvent.Wait(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -497,7 +512,7 @@ void DBManager::RunFrame() | ||||
| 	/* Dump one thing per-frame so the server stays sane. */ | ||||
| 	IDBThreadOperation *op; | ||||
| 	{ | ||||
| 		std::lock_guard<std::mutex> lock(m_ThinkLock); | ||||
| 		ke::AutoLock lock(&m_ThinkLock); | ||||
| 		op = m_ThinkQueue.first(); | ||||
| 		m_ThinkQueue.pop(); | ||||
| 	} | ||||
| @ -576,10 +591,10 @@ void DBManager::OnPluginWillUnload(IPlugin *plugin) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| std::string DBManager::GetDefaultDriverName() | ||||
| ke::AString DBManager::GetDefaultDriverName() | ||||
| { | ||||
| 	ConfDbInfoList &list = m_Builder.GetConfigList(); | ||||
| 	return list.GetDefaultDriver(); | ||||
| 	ConfDbInfoList *list = m_Builder.GetConfigList(); | ||||
| 	return list->GetDefaultDriver(); | ||||
| } | ||||
| 
 | ||||
| void DBManager::AddDependency(IExtension *myself, IDBDriver *driver) | ||||
|  | ||||
| @ -38,10 +38,7 @@ | ||||
| #include <sh_list.h> | ||||
| #include <IThreader.h> | ||||
| #include <IPluginSys.h> | ||||
| #include <condition_variable> | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| #include <thread> | ||||
| #include <am-thread-utils.h> | ||||
| #include "sm_simple_prioqueue.h" | ||||
| #include <am-refcounting.h> | ||||
| #include "DatabaseConfBuilder.h" | ||||
| @ -71,7 +68,7 @@ public: //IDBManager | ||||
| 	void AddDriver(IDBDriver *pDrivera); | ||||
| 	void RemoveDriver(IDBDriver *pDriver); | ||||
| 	const DatabaseInfo *FindDatabaseConf(const char *name); | ||||
| 	ke::RefPtr<ConfDbInfo> GetDatabaseConf(const char *name); | ||||
| 	ConfDbInfo *GetDatabaseConf(const char *name); | ||||
| 	bool Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength); | ||||
| 	unsigned int GetDriverCount(); | ||||
| 	IDBDriver *GetDriver(unsigned int index); | ||||
| @ -87,7 +84,7 @@ public: //IPluginsListener | ||||
| public: | ||||
| 	IDBDriver *FindOrLoadDriver(const char *name); | ||||
| 	IDBDriver *GetDefaultDriver(); | ||||
| 	std::string GetDefaultDriverName(); | ||||
| 	ke::AString GetDefaultDriverName(); | ||||
| 	bool AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio); | ||||
| 	void RunFrame(); | ||||
| 	inline HandleType_t GetDatabaseType() | ||||
| @ -104,10 +101,9 @@ private: | ||||
| 	PrioQueue<IDBThreadOperation *> m_OpQueue; | ||||
| 	Queue<IDBThreadOperation *> m_ThinkQueue; | ||||
| 	CVector<bool> m_drSafety;			/* which drivers are safe? */ | ||||
| 	std::unique_ptr<std::thread> m_Worker; | ||||
| 	std::condition_variable m_QueueEvent; | ||||
| 	std::mutex m_ThinkLock; | ||||
| 	std::mutex m_Lock; | ||||
| 	ke::AutoPtr<ke::Thread> m_Worker; | ||||
| 	ke::ConditionVariable m_QueueEvent; | ||||
| 	ke::Mutex m_ThinkLock; | ||||
| 	bool m_Terminate; | ||||
| 
 | ||||
| 	DatabaseConfBuilder m_Builder; | ||||
|  | ||||
| @ -36,8 +36,8 @@ | ||||
| #define DBPARSE_LEVEL_DATABASE	2 | ||||
| 
 | ||||
| DatabaseConfBuilder::DatabaseConfBuilder() | ||||
| 	: m_ParseList(), | ||||
| 	  m_InfoList() | ||||
| 	: m_ParseList(nullptr), | ||||
| 	  m_InfoList(new ConfDbInfoList()) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| @ -50,7 +50,7 @@ DatabaseConfBuilder::~DatabaseConfBuilder() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| ConfDbInfoList &DatabaseConfBuilder::GetConfigList() | ||||
| ConfDbInfoList *DatabaseConfBuilder::GetConfigList() | ||||
| { | ||||
| 	return m_InfoList; | ||||
| } | ||||
| @ -59,9 +59,9 @@ void DatabaseConfBuilder::StartParse() | ||||
| { | ||||
| 	SMCError err; | ||||
| 	SMCStates states = {0, 0}; | ||||
| 	if ((err = textparsers->ParseFile_SMC(m_Filename.c_str(), this, &states)) != SMCError_Okay) | ||||
| 	if ((err = textparsers->ParseFile_SMC(m_Filename.chars(), this, &states)) != SMCError_Okay) | ||||
| 	{ | ||||
| 		logger->LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename.c_str()); | ||||
| 		logger->LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename.chars()); | ||||
| 		if (err != SMCError_Custom) | ||||
| 		{ | ||||
| 			const char *txt = textparsers->GetSMCErrorString(err); | ||||
| @ -75,7 +75,7 @@ void DatabaseConfBuilder::ReadSMC_ParseStart() | ||||
| 	m_ParseLevel = 0; | ||||
| 	m_ParseState = DBPARSE_LEVEL_NONE; | ||||
| 	 | ||||
| 	m_ParseList.clear(); | ||||
| 	m_ParseList = new ConfDbInfoList(); | ||||
| } | ||||
|   | ||||
| SMCResult DatabaseConfBuilder::ReadSMC_NewSection(const SMCStates *states, const char *name) | ||||
| @ -116,7 +116,7 @@ SMCResult DatabaseConfBuilder::ReadSMC_KeyValue(const SMCStates *states, const c | ||||
| 	{ | ||||
| 		if (strcmp(key, "driver_default") == 0) | ||||
| 		{ | ||||
| 			m_ParseList.SetDefaultDriver(value); | ||||
| 			m_ParseList->SetDefaultDriver(value); | ||||
| 		} | ||||
| 	} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) { | ||||
| 		if (strcmp(key, "driver") == 0) | ||||
| @ -153,15 +153,15 @@ SMCResult DatabaseConfBuilder::ReadSMC_LeavingSection(const SMCStates *states) | ||||
| 
 | ||||
| 	if (m_ParseState == DBPARSE_LEVEL_DATABASE) | ||||
| 	{ | ||||
| 		m_ParseCurrent->info.driver = m_ParseCurrent->driver.c_str(); | ||||
| 		m_ParseCurrent->info.database = m_ParseCurrent->database.c_str(); | ||||
| 		m_ParseCurrent->info.host = m_ParseCurrent->host.c_str(); | ||||
| 		m_ParseCurrent->info.user = m_ParseCurrent->user.c_str(); | ||||
| 		m_ParseCurrent->info.pass = m_ParseCurrent->pass.c_str(); | ||||
| 		m_ParseCurrent->info.driver = m_ParseCurrent->driver.chars(); | ||||
| 		m_ParseCurrent->info.database = m_ParseCurrent->database.chars(); | ||||
| 		m_ParseCurrent->info.host = m_ParseCurrent->host.chars(); | ||||
| 		m_ParseCurrent->info.user = m_ParseCurrent->user.chars(); | ||||
| 		m_ParseCurrent->info.pass = m_ParseCurrent->pass.chars(); | ||||
| 		 | ||||
| 		/* Save it.. */ | ||||
| 		m_ParseCurrent->AddRef(); | ||||
| 		m_ParseList.push_back(m_ParseCurrent); | ||||
| 		m_ParseList->append(m_ParseCurrent); | ||||
| 		m_ParseCurrent = nullptr; | ||||
| 		 | ||||
| 		/* Go up one level */ | ||||
| @ -176,7 +176,9 @@ SMCResult DatabaseConfBuilder::ReadSMC_LeavingSection(const SMCStates *states) | ||||
| 
 | ||||
| void DatabaseConfBuilder::ReadSMC_ParseEnd(bool halted, bool failed) | ||||
| { | ||||
| 	m_InfoList.clear(); | ||||
| 	m_InfoList->ReleaseMembers(); | ||||
| 	delete m_InfoList; | ||||
| 	m_InfoList = m_ParseList; | ||||
| 	m_ParseList.clear(); | ||||
| 	 | ||||
| 	m_ParseList = nullptr; | ||||
| } | ||||
|  | ||||
| @ -38,7 +38,6 @@ | ||||
| 
 | ||||
| #include <am-vector.h> | ||||
| #include <am-string.h> | ||||
| #include <am-refcounting.h> | ||||
| #include <am-refcounting-threadsafe.h> | ||||
| 
 | ||||
| class ConfDbInfo : public ke::RefcountedThreadsafe<ConfDbInfo> | ||||
| @ -47,53 +46,58 @@ public: | ||||
| 	ConfDbInfo() : realDriver(NULL) | ||||
| 	{ | ||||
| 	} | ||||
| 	std::string name; | ||||
| 	std::string driver; | ||||
| 	std::string host; | ||||
| 	std::string user; | ||||
| 	std::string pass; | ||||
| 	std::string database; | ||||
| 	ke::AString name; | ||||
| 	ke::AString driver; | ||||
| 	ke::AString host; | ||||
| 	ke::AString user; | ||||
| 	ke::AString pass; | ||||
| 	ke::AString database; | ||||
| 	IDBDriver *realDriver; | ||||
| 	DatabaseInfo info; | ||||
| }; | ||||
| 
 | ||||
| class ConfDbInfoList : public std::vector<ke::RefPtr<ConfDbInfo>> | ||||
| class ConfDbInfoList : public ke::Vector<ConfDbInfo *> | ||||
| { | ||||
| 	/* Allow internal usage of ConfDbInfoList */ | ||||
| 	friend class DBManager; | ||||
| 	friend class DatabaseConfBuilder; | ||||
| private: | ||||
| 	std::string& GetDefaultDriver() { | ||||
| 	ke::AString& GetDefaultDriver() { | ||||
| 		return m_DefDriver; | ||||
| 	} | ||||
| 	 | ||||
| 	ke::RefPtr<ConfDbInfo> GetDatabaseConf(const char *name) { | ||||
| 		for (size_t i = 0; i < this->size(); i++) | ||||
| 	ConfDbInfo *GetDatabaseConf(const char *name) { | ||||
| 		for (size_t i = 0; i < this->length(); i++) | ||||
| 		{ | ||||
| 			ke::RefPtr<ConfDbInfo> current = this->at(i); | ||||
| 			ConfDbInfo *current = this->at(i); | ||||
| 			/* If we run into the default configuration, then we'll save it
 | ||||
| 			 * for the next call to GetDefaultConfiguration */  | ||||
| 			if (strcmp(current->name.c_str(), "default") == 0) | ||||
| 			if (strcmp(current->name.chars(), "default") == 0) | ||||
| 			{ | ||||
| 				m_DefaultConfig = current; | ||||
| 			} | ||||
| 			if (strcmp(current->name.c_str(), name) == 0) | ||||
| 			if (strcmp(current->name.chars(), name) == 0) | ||||
| 			{ | ||||
| 				return current; | ||||
| 			} | ||||
| 		} | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 
 | ||||
| 	ke::RefPtr<ConfDbInfo> GetDefaultConfiguration() { | ||||
| 	ConfDbInfo *GetDefaultConfiguration() { | ||||
| 		return m_DefaultConfig; | ||||
| 	} | ||||
| 	void SetDefaultDriver(const char *input) { | ||||
| 		m_DefDriver = std::string(input); | ||||
| 		m_DefDriver = ke::AString(input); | ||||
| 	} | ||||
| 	void ReleaseMembers() { | ||||
| 		for (size_t i = 0; i < this->length(); i++) { | ||||
| 			ConfDbInfo *current = this->at(i); | ||||
| 			current->Release(); | ||||
| 		} | ||||
| 	} | ||||
| private: | ||||
| 	ke::RefPtr<ConfDbInfo> m_DefaultConfig; | ||||
| 	std::string m_DefDriver; | ||||
| 	ConfDbInfo *m_DefaultConfig; | ||||
| 	ke::AString m_DefDriver; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| @ -104,7 +108,7 @@ public: | ||||
| 	~DatabaseConfBuilder(); | ||||
| 	void StartParse(); | ||||
| 	void SetPath(char* path); | ||||
| 	ConfDbInfoList &GetConfigList(); | ||||
| 	ConfDbInfoList *GetConfigList(); | ||||
| public: //ITextListener_SMC
 | ||||
| 	void ReadSMC_ParseStart(); | ||||
| 	SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name); | ||||
| @ -116,10 +120,10 @@ private: | ||||
| 	unsigned int m_ParseLevel; | ||||
| 	unsigned int m_ParseState; | ||||
| 	ConfDbInfo *m_ParseCurrent; | ||||
| 	ConfDbInfoList m_ParseList; | ||||
| 	ConfDbInfoList *m_ParseList; | ||||
| private: | ||||
| 	std::string m_Filename; | ||||
| 	ConfDbInfoList m_InfoList; | ||||
| 	ke::AString m_Filename; | ||||
| 	ConfDbInfoList *m_InfoList; | ||||
| }; | ||||
| 
 | ||||
| #endif //_INCLUDE_DATABASE_CONF_BUILDER_H_
 | ||||
|  | ||||
| @ -69,12 +69,12 @@ void DebugReport::GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, | ||||
| 	ke::SafeVsprintf(buffer, sizeof(buffer), message, ap); | ||||
| 
 | ||||
| 	const char *plname = pluginsys->FindPluginByContext(ctx->GetContext())->GetFilename(); | ||||
| 
 | ||||
| 	if (err >= 0) { | ||||
| 	const char *error = g_pSourcePawn2->GetErrorString(err); | ||||
| 
 | ||||
| 	if (error) | ||||
| 	{ | ||||
| 		g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error); | ||||
| 		else | ||||
| 	} else { | ||||
| 		g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err); | ||||
| 	} | ||||
| 
 | ||||
| @ -194,22 +194,22 @@ void DebugReport::ReportError(const IErrorReport &report, IFrameIterator &iter) | ||||
| 		g_Logger.LogError("[SM] Blaming: %s", blame); | ||||
| 	} | ||||
| 
 | ||||
| 	std::vector<std::string> arr = GetStackTrace(&iter); | ||||
| 	for (size_t i = 0; i < arr.size(); i++) | ||||
| 	ke::Vector<ke::AString> arr = GetStackTrace(&iter); | ||||
| 	for (size_t i = 0; i < arr.length(); i++) | ||||
| 	{ | ||||
| 		g_Logger.LogError("%s", arr[i].c_str()); | ||||
| 		g_Logger.LogError("%s", arr[i].chars()); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| std::vector<std::string> DebugReport::GetStackTrace(IFrameIterator *iter) | ||||
| ke::Vector<ke::AString> DebugReport::GetStackTrace(IFrameIterator *iter) | ||||
| { | ||||
| 	char temp[3072]; | ||||
| 	std::vector<std::string> trace; | ||||
| 	ke::Vector<ke::AString> trace; | ||||
| 	iter->Reset(); | ||||
| 	 | ||||
| 	if (!iter->Done()) | ||||
| 	{ | ||||
| 		trace.push_back("[SM] Call stack trace:"); | ||||
| 		trace.append("[SM] Call stack trace:"); | ||||
| 
 | ||||
| 		for (int index = 0; !iter->Done(); iter->Next(), index++)  | ||||
| 		{ | ||||
| @ -221,7 +221,7 @@ std::vector<std::string> DebugReport::GetStackTrace(IFrameIterator *iter) | ||||
| 			if (iter->IsNativeFrame())  | ||||
| 			{ | ||||
| 				g_pSM->Format(temp, sizeof(temp), "[SM]   [%d] %s", index, fn); | ||||
| 				trace.push_back(temp); | ||||
| 				trace.append(temp); | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (iter->IsScriptedFrame())  | ||||
| @ -237,7 +237,7 @@ std::vector<std::string> DebugReport::GetStackTrace(IFrameIterator *iter) | ||||
| 						file, | ||||
| 						fn); | ||||
| 				 | ||||
| 				trace.push_back(temp); | ||||
| 				trace.append(temp); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -47,12 +47,10 @@ public: // IDebugListener | ||||
| 	void ReportError(const IErrorReport &report, IFrameIterator &iter); | ||||
| 	void OnDebugSpew(const char *msg, ...); | ||||
| public: | ||||
| 	// If err is -1, caller assumes the automatic reporting by SourcePawn is
 | ||||
| 	// good enough, and only wants the supplemental logging provided here.
 | ||||
| 	void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...); | ||||
| 	void GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, const char *message, va_list ap);  | ||||
| 	void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...); | ||||
| 	std::vector<std::string> GetStackTrace(IFrameIterator *iter); | ||||
| 	ke::Vector<ke::AString> GetStackTrace(IFrameIterator *iter); | ||||
| private: | ||||
| 	int _GetPluginIndex(IPluginContext *ctx); | ||||
| }; | ||||
|  | ||||
| @ -30,9 +30,6 @@ | ||||
|  */ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include "ExtensionSys.h" | ||||
| #include <ILibrarySys.h> | ||||
| #include <ISourceMod.h> | ||||
| @ -79,7 +76,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired) | ||||
| 		g_pSM->BuildPath(Path_SM, | ||||
| 			path, | ||||
| 			PLATFORM_MAX_PATH, | ||||
| 			"extensions/" PLATFORM_ARCH_FOLDER "%s." PLATFORM_LIB_EXT, | ||||
| 			"extensions/%s." PLATFORM_LIB_EXT, | ||||
| 			filename); | ||||
| 	} | ||||
| 	else | ||||
| @ -88,7 +85,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired) | ||||
| 		g_pSM->BuildPath(Path_SM, | ||||
| 			path, | ||||
| 			PLATFORM_MAX_PATH, | ||||
| 			"extensions/" PLATFORM_ARCH_FOLDER "%s.%s." PLATFORM_LIB_EXT, | ||||
| 			"extensions/%s.%s." PLATFORM_LIB_EXT, | ||||
| 			filename, | ||||
| 			bridge->gamesuffix); | ||||
| 
 | ||||
| @ -103,7 +100,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired) | ||||
| 				g_pSM->BuildPath(Path_SM, | ||||
| 					path, | ||||
| 					PLATFORM_MAX_PATH, | ||||
| 					"extensions/" PLATFORM_ARCH_FOLDER "%s.2.ep2v." PLATFORM_LIB_EXT, | ||||
| 					"extensions/%s.2.ep2v." PLATFORM_LIB_EXT, | ||||
| 					filename); | ||||
| 			} | ||||
| 			else if (strcmp(bridge->gamesuffix, "2.nd") == 0) | ||||
| @ -111,7 +108,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired) | ||||
| 				g_pSM->BuildPath(Path_SM, | ||||
| 					path, | ||||
| 					PLATFORM_MAX_PATH, | ||||
| 					"extensions/" PLATFORM_ARCH_FOLDER "%s.2.l4d2." PLATFORM_LIB_EXT, | ||||
| 					"extensions/%s.2.l4d2." PLATFORM_LIB_EXT, | ||||
| 					filename); | ||||
| 			} | ||||
| 
 | ||||
| @ -122,7 +119,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired) | ||||
| 				g_pSM->BuildPath(Path_SM, | ||||
| 					path, | ||||
| 					PLATFORM_MAX_PATH, | ||||
| 					"extensions/" PLATFORM_ARCH_FOLDER "auto.%s/%s." PLATFORM_LIB_EXT, | ||||
| 					"extensions/auto.%s/%s." PLATFORM_LIB_EXT, | ||||
| 					filename, | ||||
| 					bridge->gamesuffix); | ||||
| 
 | ||||
| @ -132,7 +129,7 @@ CLocalExtension::CLocalExtension(const char *filename, bool bRequired) | ||||
| 					g_pSM->BuildPath(Path_SM, | ||||
| 						path, | ||||
| 						PLATFORM_MAX_PATH, | ||||
| 						"extensions/" PLATFORM_ARCH_FOLDER "%s." PLATFORM_LIB_EXT, | ||||
| 						"extensions/%s." PLATFORM_LIB_EXT, | ||||
| 						filename); | ||||
| 				} | ||||
| 			} | ||||
| @ -240,8 +237,6 @@ void CLocalExtension::Unload() | ||||
| 		m_pLib->CloseLibrary(); | ||||
| 		m_pLib = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	m_bFullyLoaded = false; | ||||
| } | ||||
| 
 | ||||
| bool CRemoteExtension::Reload(char *error, size_t maxlength) | ||||
| @ -306,7 +301,7 @@ bool CExtension::Load(char *error, size_t maxlength) | ||||
| 	/* Check if we're past load time */ | ||||
| 	if (!bridge->IsMapLoading()) | ||||
| 	{ | ||||
| 		MarkAllLoaded(); | ||||
| 		m_pAPI->OnExtensionsAllLoaded(); | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| @ -501,7 +496,7 @@ void CExtensionManager::TryAutoload() | ||||
| 
 | ||||
| 	g_pSM->BuildPath(Path_SM, path, sizeof(path), "extensions"); | ||||
| 
 | ||||
| 	std::unique_ptr<IDirectory> pDir(libsys->OpenDirectory(path)); | ||||
| 	ke::AutoPtr<IDirectory> pDir(libsys->OpenDirectory(path)); | ||||
| 	if (!pDir) | ||||
| 		return; | ||||
| 
 | ||||
| @ -633,15 +628,9 @@ IExtension *CExtensionManager::FindExtensionByName(const char *ext) | ||||
| 
 | ||||
| IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength) | ||||
| { | ||||
| 	if (strstr(file, "..") != NULL) | ||||
| 	{ | ||||
| 		ke::SafeStrcpy(error, maxlength, "Cannot load extensions outside the \"extensions\" folder."); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Remove platform extension if it's there. Compat hack. */ | ||||
| 	const char *ext = libsys->GetFileExtension(file); | ||||
| 	if (ext && strcmp(ext, PLATFORM_LIB_EXT) == 0) | ||||
| 	if (strcmp(ext, PLATFORM_LIB_EXT) == 0) | ||||
| 	{ | ||||
| 		char path2[PLATFORM_MAX_PATH]; | ||||
| 		ke::SafeStrcpy(path2, sizeof(path2), file); | ||||
| @ -1182,6 +1171,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const ICommand | ||||
| 						rootmenu->ConsolePrint(" -> %s", pPlugin->GetFilename()); | ||||
| 					} | ||||
| 				} | ||||
| 				srand(static_cast<int>(time(NULL))); | ||||
| 				pExt->unload_code = (rand() % 877) + 123;	//123 to 999
 | ||||
| 				rootmenu->ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename()); | ||||
| 				rootmenu->ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code); | ||||
| @ -1374,7 +1364,7 @@ bool CLocalExtension::IsSameFile(const char *file) | ||||
| 
 | ||||
| bool CRemoteExtension::IsSameFile(const char *file) | ||||
| { | ||||
| 	/* Check full path and name passed in from LoadExternal */ | ||||
| 	return strcmp(file, m_Path.c_str()) == 0 || strcmp(file, m_File.c_str()) == 0; | ||||
| 	/* :TODO: this could be better, but no one uses this API anyway. */ | ||||
| 	return strcmp(file, m_Path.c_str()) == 0; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -61,7 +61,7 @@ IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned | ||||
| 	{ | ||||
| 		scripts->AddFunctionsToForward(name, fwd); | ||||
| 
 | ||||
| 		m_managed.push_back(fwd); | ||||
| 		m_managed.append(fwd); | ||||
| 	} | ||||
| 
 | ||||
| 	return fwd; | ||||
| @ -78,7 +78,7 @@ IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType | ||||
| 
 | ||||
| 	if (fwd) | ||||
| 	{ | ||||
| 		m_unmanaged.push_back(fwd); | ||||
| 		m_unmanaged.append(fwd); | ||||
| 	} | ||||
| 
 | ||||
| 	return fwd; | ||||
| @ -751,9 +751,9 @@ bool CForward::AddFunction(IPluginFunction *func) | ||||
| 		return false; | ||||
| 
 | ||||
| 	if (func->IsRunnable()) | ||||
| 		m_functions.push_back(func); | ||||
| 		m_functions.append(func); | ||||
| 	else | ||||
| 		m_paused.push_back(func); | ||||
| 		m_paused.append(func); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| @ -780,7 +780,7 @@ const char *CForward::GetForwardName() | ||||
| 
 | ||||
| unsigned int CForward::GetFunctionCount() | ||||
| { | ||||
| 	return m_functions.size(); | ||||
| 	return m_functions.length(); | ||||
| } | ||||
| 
 | ||||
| ExecType CForward::GetExecType() | ||||
|  | ||||
| @ -36,7 +36,7 @@ SafeFrameIterator::SafeFrameIterator(IFrameIterator *it) | ||||
| 	while (!it->Done()) | ||||
| 	{ | ||||
| 		FrameInfo info = FrameInfo(it); | ||||
| 		frames.push_back(info); | ||||
| 		frames.append(info); | ||||
| 		it->Next();  | ||||
| 	} | ||||
| 	 | ||||
| @ -46,7 +46,7 @@ SafeFrameIterator::SafeFrameIterator(IFrameIterator *it) | ||||
| 
 | ||||
| bool SafeFrameIterator::Done() const | ||||
| { | ||||
| 	return current >= frames.size(); | ||||
| 	return current >= frames.length(); | ||||
| } | ||||
| 
 | ||||
| bool SafeFrameIterator::Next() | ||||
| @ -77,7 +77,7 @@ const char *SafeFrameIterator::FunctionName() const | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	return frames[current].FunctionName.c_str(); | ||||
| 	return frames[current].FunctionName.chars(); | ||||
| } | ||||
| 
 | ||||
| const char *SafeFrameIterator::FilePath() const | ||||
| @ -87,5 +87,5 @@ const char *SafeFrameIterator::FilePath() const | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	return frames[current].FilePath.c_str(); | ||||
| 	return frames[current].FilePath.chars(); | ||||
| } | ||||
|  | ||||
| @ -48,17 +48,15 @@ public: | ||||
| 	 */ | ||||
| 	struct FrameInfo | ||||
| 	{	 | ||||
| 		std::string FunctionName; | ||||
| 		std::string FilePath; | ||||
| 		ke::AString FunctionName; | ||||
| 		ke::AString FilePath; | ||||
| 		unsigned LineNumber; | ||||
| 
 | ||||
| 		FrameInfo(IFrameIterator *it) | ||||
| 		{		 | ||||
| 			LineNumber = it->LineNumber(); | ||||
| 			 | ||||
| 			if (it->FunctionName()) | ||||
| 			FunctionName = it->FunctionName(); | ||||
| 			if (it->FilePath()) | ||||
| 			FilePath = it->FilePath(); | ||||
| 		} | ||||
| 	}; | ||||
| @ -75,5 +73,5 @@ public: | ||||
| 
 | ||||
| private: | ||||
| 	size_t current; | ||||
| 	std::vector<FrameInfo> frames; | ||||
| 	ke::Vector<FrameInfo> frames; | ||||
| }; | ||||
| @ -85,12 +85,15 @@ static const char *g_pParseEngine = NULL; | ||||
| 
 | ||||
| #if defined PLATFORM_WINDOWS | ||||
| #define PLATFORM_NAME				"windows" PLATFORM_ARCH_SUFFIX | ||||
| #define PLATFORM_SERVER_BINARY		"server.dll" | ||||
| #elif defined PLATFORM_LINUX | ||||
| #define PLATFORM_NAME				"linux" PLATFORM_ARCH_SUFFIX | ||||
| #define PLATFORM_COMPAT_ALT			"mac" PLATFORM_ARCH_SUFFIX	/* Alternate platform name if game data is missing for primary one */ | ||||
| #define PLATFORM_SERVER_BINARY		"server_i486.so" | ||||
| #elif defined PLATFORM_APPLE | ||||
| #define PLATFORM_NAME				"mac" PLATFORM_ARCH_SUFFIX | ||||
| #define PLATFORM_COMPAT_ALT			"linux" PLATFORM_ARCH_SUFFIX | ||||
| #define PLATFORM_SERVER_BINARY		"server.dylib" | ||||
| #endif | ||||
| 
 | ||||
| struct TempSigInfo | ||||
| @ -150,23 +153,6 @@ static inline bool IsPlatformCompatible(const char *platform, bool *hadPrimaryMa | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| static inline time_t GetFileModTime(const char *path) | ||||
| { | ||||
| 	char filepath[PLATFORM_MAX_PATH]; | ||||
| 	g_pSM->BuildPath(Path_SM, filepath, sizeof(filepath), "gamedata/%s.txt", path); | ||||
| #ifdef PLATFORM_WINDOWS | ||||
| 	struct _stat64 s; | ||||
| 	if (_stat64(filepath, &s) != 0) | ||||
| #elif defined PLATFORM_POSIX | ||||
| 	struct stat s; | ||||
| 	if (stat(filepath, &s) != 0) | ||||
| #endif | ||||
| 	{ | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return s.st_mtime; | ||||
| } | ||||
| 
 | ||||
| CGameConfig::CGameConfig(const char *file, const char *engine) | ||||
| { | ||||
| 	strncopy(m_File, file, sizeof(m_File)); | ||||
| @ -174,8 +160,6 @@ CGameConfig::CGameConfig(const char *file, const char *engine) | ||||
| 	m_CustomLevel = 0; | ||||
| 	m_CustomHandler = NULL; | ||||
| 
 | ||||
| 	m_ModTime = GetFileModTime(file); | ||||
| 
 | ||||
| 	if (!engine) | ||||
| 		m_pEngine = bridge->GetSourceEngineName(); | ||||
| 	else | ||||
| @ -222,7 +206,7 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n | ||||
| 			{ | ||||
| 				bShouldBeReadingDefault = true; | ||||
| 				m_ParseState = PSTATE_GAMEDEFS; | ||||
| 				m_Game = name; | ||||
| 				strncopy(m_Game, name, sizeof(m_Game)); | ||||
| 			} else { | ||||
| 				m_IgnoreLevel++; | ||||
| 			} | ||||
| @ -238,7 +222,7 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n | ||||
| 			{ | ||||
| 				m_ParseState = PSTATE_GAMEDEFS_KEYS; | ||||
| 			} | ||||
| 			else if ((strcmp(name, "#supported") == 0) && (m_Game == "#default")) | ||||
| 			else if ((strcmp(name, "#supported") == 0) && (strcmp(m_Game, "#default") == 0)) | ||||
| 			{ | ||||
| 				m_ParseState = PSTATE_GAMEDEFS_SUPPORTED; | ||||
| 				/* Ignore this section unless we get a game. */ | ||||
| @ -277,23 +261,23 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n | ||||
| 		} | ||||
| 	case PSTATE_GAMEDEFS_KEYS: | ||||
| 		{ | ||||
| 			m_Key = name; | ||||
| 			strncopy(m_Key, name, sizeof(m_Key)); | ||||
| 			m_ParseState = PSTATE_GAMEDEFS_KEYS_PLATFORM; | ||||
| 			matched_platform = false; | ||||
| 			break; | ||||
| 		} | ||||
| 	case PSTATE_GAMEDEFS_OFFSETS: | ||||
| 		{ | ||||
| 			m_Prop.clear(); | ||||
| 			m_Class.clear(); | ||||
| 			m_offset = name; | ||||
| 			m_Prop[0] = '\0'; | ||||
| 			m_Class[0] = '\0'; | ||||
| 			strncopy(m_offset, name, sizeof(m_offset)); | ||||
| 			m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET; | ||||
| 			matched_platform = false; | ||||
| 			break; | ||||
| 		} | ||||
| 	case PSTATE_GAMEDEFS_SIGNATURES: | ||||
| 		{ | ||||
| 			m_offset = name; | ||||
| 			strncopy(m_offset, name, sizeof(m_offset)); | ||||
| 			s_TempSig.Reset(); | ||||
| 			m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG; | ||||
| 			matched_platform = false; | ||||
| @ -312,10 +296,7 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n | ||||
| 				FILE *fp; | ||||
| 				char path[PLATFORM_MAX_PATH]; | ||||
| 
 | ||||
| 				char binName[64]; | ||||
| 				bridge->FormatSourceBinaryName(name, binName, sizeof(binName)); | ||||
| 
 | ||||
| 				g_pSM->BuildPath(Path_Game, path, sizeof(path), "bin/%s", binName); | ||||
| 				g_pSM->BuildPath(Path_Game, path, sizeof(path), "bin/" PLATFORM_SERVER_BINARY); | ||||
| 				if ((fp = fopen(path, "rb")) == NULL) | ||||
| 				{ | ||||
| 					ke::SafeSprintf(error, sizeof(error), "Could not open binary: %s", path); | ||||
| @ -338,7 +319,7 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n | ||||
| 			if (error[0] != '\0') | ||||
| 			{ | ||||
| 				m_IgnoreLevel = 1; | ||||
| 				logger->LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game.c_str(), m_CurFile); | ||||
| 				logger->LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game, m_CurFile); | ||||
| 				logger->LogError("[SM] %s", error); | ||||
| 			} else { | ||||
| 				m_ParseState = PSTATE_GAMEDEFS_CRC_BINARY; | ||||
| @ -353,12 +334,12 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n | ||||
| 		} | ||||
| 	case PSTATE_GAMEDEFS_ADDRESSES: | ||||
| 		{ | ||||
| 			m_Address.clear(); | ||||
| 			m_AddressSignature.clear(); | ||||
| 			m_Address[0] = '\0'; | ||||
| 			m_AddressSignature[0] = '\0'; | ||||
| 			m_AddressReadCount = 0; | ||||
| 			m_AddressLastIsOffset = false; | ||||
| 
 | ||||
| 			m_Address = name; | ||||
| 			strncopy(m_Address, name, sizeof(m_Address)); | ||||
| 			m_ParseState = PSTATE_GAMEDEFS_ADDRESSES_ADDRESS; | ||||
| 
 | ||||
| 			break; | ||||
| @ -374,7 +355,7 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n | ||||
| 				if (strcmp(name, "linux") != 0 && strcmp(name, "windows") != 0 && strcmp(name, "mac") != 0 && | ||||
| 					strcmp(name, "linux64") != 0 && strcmp(name, "windows64") != 0 && strcmp(name, "mac64") != 0) | ||||
| 				{ | ||||
| 					logger->LogError("[SM] Error while parsing Address section for \"%s\" (%s):", m_Address.c_str(), m_CurFile); | ||||
| 					logger->LogError("[SM] Error while parsing Address section for \"%s\" (%s):", m_Address, m_CurFile); | ||||
| 					logger->LogError("[SM] Unrecognized platform \"%s\"", name); | ||||
| 				} | ||||
| 				m_IgnoreLevel = 1; | ||||
| @ -411,21 +392,21 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key | ||||
| 	{ | ||||
| 		if (strcmp(key, "class") == 0) | ||||
| 		{ | ||||
| 			m_Class = value; | ||||
| 			strncopy(m_Class, value, sizeof(m_Class)); | ||||
| 		} else if (strcmp(key, "prop") == 0) { | ||||
| 			m_Prop = value; | ||||
| 			strncopy(m_Prop, value, sizeof(m_Prop)); | ||||
| 		} else if (IsPlatformCompatible(key, &matched_platform)) { | ||||
| 			m_Offsets.replace(m_offset.c_str(), static_cast<int>(strtol(value, NULL, 0))); | ||||
| 			m_Offsets.replace(m_offset, atoi(value)); | ||||
| 		} | ||||
| 	} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) { | ||||
| 		std::string vstr(value); | ||||
| 		m_Keys.replace(key, std::move(vstr)); | ||||
| 		ke::AString vstr(value); | ||||
| 		m_Keys.replace(key, ke::Move(vstr)); | ||||
| 	} | ||||
| 	else if (m_ParseState == PSTATE_GAMEDEFS_KEYS_PLATFORM) { | ||||
| 		if (IsPlatformCompatible(key, &matched_platform)) | ||||
| 		{ | ||||
| 			std::string vstr(value); | ||||
| 			m_Keys.replace(m_Key.c_str(), std::move(vstr)); | ||||
| 			ke::AString vstr(value); | ||||
| 			m_Keys.replace(m_Key, ke::Move(vstr)); | ||||
| 		} | ||||
| 	} else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) { | ||||
| 		if (strcmp(key, "game") == 0) | ||||
| @ -476,7 +457,7 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key | ||||
| 			int limit = sizeof(m_AddressRead)/sizeof(m_AddressRead[0]); | ||||
| 			if (m_AddressLastIsOffset) | ||||
| 			{ | ||||
| 				logger->LogError("[SM] Error parsing Address \"%s\", 'offset' entry must be the last entry (gameconf \"%s\")", m_Address.c_str(), m_CurFile); | ||||
| 				logger->LogError("[SM] Error parsing Address \"%s\", 'offset' entry must be the last entry (gameconf \"%s\")", m_Address, m_CurFile); | ||||
| 			} | ||||
| 			else if (m_AddressReadCount < limit) | ||||
| 			{ | ||||
| @ -484,15 +465,15 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key | ||||
| 				{ | ||||
| 					m_AddressLastIsOffset = true; | ||||
| 				} | ||||
| 				m_AddressRead[m_AddressReadCount] = static_cast<int>(strtol(value, NULL, 0)); | ||||
| 				m_AddressRead[m_AddressReadCount] = atoi(value); | ||||
| 				m_AddressReadCount++; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				logger->LogError("[SM] Error parsing Address \"%s\", does not support more than %d read offsets (gameconf \"%s\")", m_Address.c_str(), limit, m_CurFile); | ||||
| 				logger->LogError("[SM] Error parsing Address \"%s\", does not support more than %d read offsets (gameconf \"%s\")", m_Address, limit, m_CurFile); | ||||
| 			} | ||||
| 		} else if (strcmp(key, "signature") == 0) { | ||||
| 			m_AddressSignature = value; | ||||
| 			strncopy(m_AddressSignature, value, sizeof(m_AddressSignature)); | ||||
| 		} | ||||
| 	} else if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) { | ||||
| 		return m_CustomHandler->ReadSMC_KeyValue(states, key, value); | ||||
| @ -548,24 +529,25 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states) | ||||
| 	case PSTATE_GAMEDEFS_OFFSETS_OFFSET: | ||||
| 		{ | ||||
| 			/* Parse the offset... */ | ||||
| 			if (!m_Class.empty() && !m_Prop.empty()) | ||||
| 			if (m_Class[0] != '\0' | ||||
| 				&& m_Prop[0] != '\0') | ||||
| 			{ | ||||
| 				SendProp *pProp = gamehelpers->FindInSendTable(m_Class.c_str(), m_Prop.c_str()); | ||||
| 				SendProp *pProp = gamehelpers->FindInSendTable(m_Class, m_Prop); | ||||
| 				if (pProp) | ||||
| 				{ | ||||
| 					int val = gamehelpers->GetSendPropOffset(pProp); | ||||
| 					m_Offsets.replace(m_offset.c_str(), val); | ||||
| 					m_Props.replace(m_offset.c_str(), pProp); | ||||
| 					m_Offsets.replace(m_offset, val); | ||||
| 					m_Props.replace(m_offset, pProp); | ||||
| 				} else { | ||||
| 					/* Check if it's a non-default game and no offsets exist */ | ||||
| 					if ((m_Game != "*" && m_Game != "#default") | ||||
| 						&& (!m_Offsets.retrieve(m_offset.c_str()))) | ||||
| 					if (((strcmp(m_Game, "*") != 0) && strcmp(m_Game, "#default") != 0) | ||||
| 						&& (!m_Offsets.retrieve(m_offset))) | ||||
| 					{ | ||||
| 						logger->LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")",  | ||||
| 							m_Class.c_str(), | ||||
| 							m_Prop.c_str(), | ||||
| 							m_Class, | ||||
| 							m_Prop, | ||||
| 							m_CurFile, | ||||
| 							m_Game.c_str()); | ||||
| 							m_Game); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| @ -673,7 +655,7 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states) | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				m_Sigs.replace(m_offset.c_str(), final_addr); | ||||
| 				m_Sigs.replace(m_offset, final_addr); | ||||
| 			} | ||||
| 
 | ||||
| 			m_ParseState = PSTATE_GAMEDEFS_SIGNATURES; | ||||
| @ -689,10 +671,10 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states) | ||||
| 		{ | ||||
| 			m_ParseState = PSTATE_GAMEDEFS_ADDRESSES; | ||||
| 
 | ||||
| 			if (!m_Address.empty() && !m_AddressSignature.empty()) | ||||
| 			if (m_Address[0] != '\0' && m_AddressSignature[0] != '\0') | ||||
| 			{ | ||||
| 				AddressConf addrConf(std::move(m_AddressSignature), m_AddressReadCount, m_AddressRead, m_AddressLastIsOffset); | ||||
| 				m_Addresses.replace(m_Address.c_str(), addrConf); | ||||
| 				AddressConf addrConf(m_AddressSignature, sizeof(m_AddressSignature), m_AddressReadCount, m_AddressRead, m_AddressLastIsOffset); | ||||
| 				m_Addresses.replace(m_Address, addrConf); | ||||
| 			} | ||||
| 
 | ||||
| 			break; | ||||
| @ -809,12 +791,9 @@ public: | ||||
| 				(!had_engine && matched_game) || | ||||
| 				(!had_game && matched_engine) || | ||||
| 				(matched_engine && matched_game)) | ||||
| 			{ | ||||
| 				if (fileList->find(cur_file) == fileList->end()) | ||||
| 			{ | ||||
| 				fileList->push_back(cur_file); | ||||
| 			} | ||||
| 			} | ||||
| 			state = MSTATE_MAIN; | ||||
| 		} | ||||
| 		else if (state == MSTATE_MAIN) | ||||
| @ -1022,10 +1001,10 @@ bool CGameConfig::GetOffset(const char *key, int *value) | ||||
| 
 | ||||
| const char *CGameConfig::GetKeyValue(const char *key) | ||||
| { | ||||
| 	StringHashMap<std::string>::Result r = m_Keys.find(key); | ||||
| 	StringHashMap<ke::AString>::Result r = m_Keys.find(key); | ||||
| 	if (!r.found()) | ||||
| 		return NULL; | ||||
| 	return r->value.c_str(); | ||||
| 	return r->value.chars(); | ||||
| } | ||||
| 
 | ||||
| //memory addresses below 0x10000 are automatically considered invalid for dereferencing
 | ||||
| @ -1043,7 +1022,7 @@ bool CGameConfig::GetAddress(const char *key, void **retaddr) | ||||
| 	AddressConf &addrConf = r->value; | ||||
| 
 | ||||
| 	void *addr; | ||||
| 	if (!GetMemSig(addrConf.signatureName.c_str(), &addr)) | ||||
| 	if (!GetMemSig(addrConf.signatureName, &addr)) | ||||
| 	{ | ||||
| 		*retaddr = NULL; | ||||
| 		return false; | ||||
| @ -1076,11 +1055,11 @@ static inline unsigned minOf(unsigned a, unsigned b) | ||||
| 	return a <= b ? a : b; | ||||
| } | ||||
| 
 | ||||
| CGameConfig::AddressConf::AddressConf(std::string&& sigName, unsigned readCount, int *read, bool lastIsOffset) | ||||
| CGameConfig::AddressConf::AddressConf(char *sigName, unsigned sigLength, unsigned readCount, int *read, bool lastIsOffset) | ||||
| { | ||||
| 	unsigned readLimit = minOf(readCount, sizeof(this->read) / sizeof(this->read[0])); | ||||
| 
 | ||||
| 	this->signatureName = std::move(sigName); | ||||
| 	strncopy(signatureName, sigName, sizeof(signatureName) / sizeof(signatureName[0])); | ||||
| 	this->readCount = readLimit; | ||||
| 	memcpy(&this->read[0], read, sizeof(this->read[0])*readLimit); | ||||
| 
 | ||||
| @ -1153,17 +1132,9 @@ bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pCon | ||||
| 
 | ||||
| 	if (m_Lookup.retrieve(file, &pConfig)) | ||||
| 	{ | ||||
| 		bool ret = true; | ||||
| 		time_t modtime = GetFileModTime(file); | ||||
| 		if (pConfig->m_ModTime != modtime) | ||||
| 		{ | ||||
| 			pConfig->m_ModTime = modtime; | ||||
| 			ret = pConfig->Reparse(error, maxlength); | ||||
| 		} | ||||
| 
 | ||||
| 		pConfig->AddRef(); | ||||
| 		*_pConfig = pConfig; | ||||
| 		return ret; | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	pConfig = new CGameConfig(file); | ||||
|  | ||||
| @ -81,16 +81,16 @@ private: | ||||
| 	char m_CurFile[PLATFORM_MAX_PATH]; | ||||
| 	StringHashMap<int> m_Offsets; | ||||
| 	StringHashMap<SendProp *> m_Props; | ||||
| 	StringHashMap<std::string> m_Keys; | ||||
| 	StringHashMap<ke::AString> m_Keys; | ||||
| 	StringHashMap<void *> m_Sigs; | ||||
| 	/* Parse states */ | ||||
| 	int m_ParseState; | ||||
| 	unsigned int m_IgnoreLevel; | ||||
| 	std::string m_Class; | ||||
| 	std::string m_Prop; | ||||
| 	std::string m_offset; | ||||
| 	std::string m_Game; | ||||
| 	std::string m_Key; | ||||
| 	char m_Class[64]; | ||||
| 	char m_Prop[64]; | ||||
| 	char m_offset[64]; | ||||
| 	char m_Game[256]; | ||||
| 	char m_Key[64]; | ||||
| 	bool bShouldBeReadingDefault; | ||||
| 	bool had_game; | ||||
| 	bool matched_game; | ||||
| @ -105,25 +105,24 @@ private: | ||||
| 	/* Support for reading Addresses */ | ||||
| 	struct AddressConf | ||||
| 	{ | ||||
| 		std::string signatureName; | ||||
| 		char signatureName[64]; | ||||
| 		int readCount; | ||||
| 		int read[8]; | ||||
| 		bool lastIsOffset; | ||||
| 
 | ||||
| 		AddressConf(std::string&& sigName, unsigned readCount, int *read, bool lastIsOffset); | ||||
| 		AddressConf(char *sigName, unsigned sigLength, unsigned readCount, int *read, bool lastIsOffset); | ||||
| 
 | ||||
| 		AddressConf() {} | ||||
| 	}; | ||||
| 
 | ||||
| 	std::string m_Address; | ||||
| 	std::string m_AddressSignature; | ||||
| 	char m_Address[64]; | ||||
| 	char m_AddressSignature[64]; | ||||
| 	int m_AddressReadCount; | ||||
| 	int m_AddressRead[8]; | ||||
| 	bool m_AddressLastIsOffset; | ||||
| 	StringHashMap<AddressConf> m_Addresses; | ||||
| 	const char *m_pEngine; | ||||
| 	const char *m_pBaseEngine; | ||||
| 	time_t m_ModTime; | ||||
| }; | ||||
| 
 | ||||
| class GameConfigManager :  | ||||
|  | ||||
| @ -30,7 +30,6 @@ | ||||
|  */ | ||||
| 
 | ||||
| #include "HandleSys.h" | ||||
| #include <time.h> | ||||
| #include <assert.h> | ||||
| #include <string.h> | ||||
| #include "common_logic.h" | ||||
| @ -39,20 +38,10 @@ | ||||
| #include "PluginSys.h" | ||||
| #include <am-string.h> | ||||
| #include <bridge/include/ILogger.h> | ||||
| #include <bridge/include/CoreProvider.h> | ||||
| #include <ISourceMod.h> | ||||
| 
 | ||||
| #include "sm_platform.h" | ||||
| #ifdef PLATFORM_WINDOWS | ||||
| #include "sm_invalidparamhandler.h" | ||||
| #endif | ||||
| 
 | ||||
| using namespace std::string_literals; | ||||
| 
 | ||||
| HandleSystem g_HandleSys; | ||||
| 
 | ||||
| QHandle *ignore_handle; | ||||
| extern ConVar *g_datetime_format; | ||||
| 
 | ||||
| inline HandleType_t TypeParent(HandleType_t type) | ||||
| { | ||||
| @ -217,7 +206,7 @@ HandleType_t HandleSystem::CreateType(const char *name, | ||||
| 	pType->dispatch = dispatch; | ||||
| 	if (name && name[0] != '\0') | ||||
| 	{ | ||||
| 		pType->name = std::make_unique<std::string>(name); | ||||
| 		pType->name = new ke::AString(name); | ||||
| 		m_TypeLookup.insert(name, pType); | ||||
| 	} | ||||
| 
 | ||||
| @ -301,28 +290,6 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (owner) | ||||
| 	{ | ||||
| 		owner->num_handles++; | ||||
| 		if (!owner->warned_handle_usage && owner->num_handles >= HANDLESYS_WARN_USAGE) | ||||
| 		{ | ||||
| 			owner->warned_handle_usage = true; | ||||
| 
 | ||||
| 			std::string path = "<unknown>"; | ||||
| 			if (auto plugin = scripts->FindPluginByIdentity(owner)) | ||||
| 			{ | ||||
| 				path = "plugin "s + plugin->GetFilename(); | ||||
| 			} | ||||
| 			else if (auto ext = g_Extensions.GetExtensionFromIdent(owner)) | ||||
| 			{ | ||||
| 				path = "extension "s + ext->GetFilename(); | ||||
| 			} | ||||
| 
 | ||||
| 			logger->LogError("[SM] Warning: %s is using more than %d handles!", | ||||
| 				path.c_str(), HANDLESYS_WARN_USAGE); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	QHandle *pHandle = &m_Handles[handle]; | ||||
| 	 | ||||
| 	assert(pHandle->set == false); | ||||
| @ -344,7 +311,7 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type, | ||||
| 
 | ||||
| 	/* Create the hash value */ | ||||
| 	Handle_t hash = pHandle->serial; | ||||
| 	hash <<= HANDLESYS_HANDLE_BITS; | ||||
| 	hash <<= 16; | ||||
| 	hash |= handle; | ||||
| 
 | ||||
| 	/* Add a reference count to the type */ | ||||
| @ -463,7 +430,7 @@ Handle_t HandleSystem::CreateHandleInt(HandleType_t type, | ||||
| 
 | ||||
| 	pHandle->object = object; | ||||
| 	pHandle->clone = 0; | ||||
| 	pHandle->timestamp = g_pSM->GetAdjustedTime(); | ||||
| 
 | ||||
| 	return handle; | ||||
| } | ||||
| 
 | ||||
| @ -508,7 +475,7 @@ HandleError HandleSystem::GetHandle(Handle_t handle, | ||||
| 									unsigned int *in_index, | ||||
| 									bool ignoreFree) | ||||
| { | ||||
| 	unsigned int serial = (handle >> HANDLESYS_HANDLE_BITS); | ||||
| 	unsigned int serial = (handle >> 16); | ||||
| 	unsigned int index = (handle & HANDLESYS_HANDLE_MASK); | ||||
| 
 | ||||
| 	if (index == 0 || index > m_HandleTail || index > HANDLESYS_MAX_HANDLES) | ||||
| @ -664,7 +631,7 @@ Handle_t HandleSystem::FastCloneHandle(Handle_t hndl) | ||||
| void HandleSystem::GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index) | ||||
| { | ||||
| #ifndef NDEBUG | ||||
| 	unsigned int serial = (hndl >> HANDLESYS_HANDLE_BITS); | ||||
| 	unsigned int serial = (hndl >> 16); | ||||
| #endif | ||||
| 	index = (hndl & HANDLESYS_HANDLE_MASK); | ||||
| 
 | ||||
| @ -688,9 +655,6 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index) | ||||
| 
 | ||||
| 	QHandleType *pType = &m_Types[pHandle->type]; | ||||
| 
 | ||||
| 	if (pHandle->owner && pHandle->owner->num_handles > 0) | ||||
| 		pHandle->owner->num_handles--; | ||||
| 
 | ||||
| 	if (pHandle->clone) | ||||
| 	{ | ||||
| 		/* If we're a clone, decrease the parent reference count */ | ||||
| @ -961,7 +925,7 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident) | ||||
| 
 | ||||
| 	/* Remove it from the type cache. */ | ||||
| 	if (pType->name) | ||||
| 		m_TypeLookup.remove(pType->name->c_str()); | ||||
| 		m_TypeLookup.remove(pType->name->chars()); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| @ -1050,8 +1014,6 @@ bool HandleSystem::TryAndFreeSomeHandles() | ||||
| 	unsigned int * pCount = new unsigned int[HANDLESYS_TYPEARRAY_SIZE+1]; | ||||
| 	memset(pCount, 0, ((HANDLESYS_TYPEARRAY_SIZE + 1) * sizeof(unsigned int))); | ||||
| 
 | ||||
| 	const QHandle *oldest = nullptr; | ||||
| 	const QHandle *newest = nullptr; | ||||
| 	for (unsigned int i = 1; i <= m_HandleTail; ++i) | ||||
| 	{ | ||||
| 		const QHandle &Handle = m_Handles[i]; | ||||
| @ -1068,15 +1030,6 @@ bool HandleSystem::TryAndFreeSomeHandles() | ||||
| 			highest_index = ((Handle.type) + 1); | ||||
| 		} | ||||
| 
 | ||||
| 		if (!oldest || oldest->timestamp > Handle.timestamp) | ||||
| 		{ | ||||
| 			oldest = &Handle; | ||||
| 		} | ||||
| 		if (!newest || newest->timestamp < Handle.timestamp) | ||||
| 		{ | ||||
| 			newest = &Handle; | ||||
| 		} | ||||
| 		 | ||||
| 		if (Handle.clone != 0) | ||||
| 		{ | ||||
| 			continue; | ||||
| @ -1098,39 +1051,13 @@ bool HandleSystem::TryAndFreeSomeHandles() | ||||
| 		} | ||||
| 
 | ||||
| 		if (m_Types[i].name) | ||||
| 			pTypeName = m_Types[i].name->c_str(); | ||||
| 			pTypeName = m_Types[i].name->chars(); | ||||
| 		else | ||||
| 			pTypeName = "ANON"; | ||||
| 
 | ||||
| 		HANDLE_LOG_VERY_BAD("Type\t%-20.20s|\tCount\t%u", pTypeName, pCount[i]); | ||||
| 	} | ||||
| 
 | ||||
| 	const char *fmt = bridge->GetCvarString(g_datetime_format); | ||||
| 
 | ||||
| 	char oldstamp[256], newstamp[256]; // 256 should be more than enough
 | ||||
| 
 | ||||
| 	// scope for InvalidParameterHandler
 | ||||
| 	{ | ||||
| #ifdef PLATFORM_WINDOWS | ||||
| 		InvalidParameterHandler p; | ||||
| #endif | ||||
| 		size_t written = strftime(oldstamp, sizeof(oldstamp), fmt, localtime(&oldest->timestamp)); | ||||
| 		if (!written) | ||||
| 		{ | ||||
| 			ke::SafeStrcpy(oldstamp, sizeof(oldstamp), "INVALID"); | ||||
| 		} | ||||
| 
 | ||||
| 		written = strftime(newstamp, sizeof(newstamp), fmt, localtime(&newest->timestamp)); | ||||
| 		if (!written) | ||||
| 		{ | ||||
| 			ke::SafeStrcpy(newstamp, sizeof(newstamp), "INVALID"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	HANDLE_LOG_VERY_BAD("--------------------------------------------------------------------------"); | ||||
| 	HANDLE_LOG_VERY_BAD("Oldest Living Handle: %s created at %s", m_Types[oldest->type].name->c_str(), oldstamp); | ||||
| 	HANDLE_LOG_VERY_BAD("Newest Living Handle: %s created at %s", m_Types[newest->type].name->c_str(), newstamp); | ||||
| 	HANDLE_LOG_VERY_BAD("-- Approximately %d bytes of memory are in use by (%u) Handles.\n", total_size, total); | ||||
| 	delete [] pCount; | ||||
| 
 | ||||
| @ -1154,10 +1081,8 @@ static void rep(const HandleReporter &fn, const char *fmt, ...) | ||||
| void HandleSystem::Dump(const HandleReporter &fn) | ||||
| { | ||||
| 	unsigned int total_size = 0; | ||||
| 	rep(fn, "%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s\t%-30.30s", "Handle", "Owner", "Type", "Memory", "Time Created"); | ||||
| 	rep(fn, "---------------------------------------------------------------------------------------------"); | ||||
| 	 | ||||
| 	const char *fmt = bridge->GetCvarString(g_datetime_format); | ||||
| 	rep(fn, "%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s", "Handle", "Owner", "Type", "Memory"); | ||||
| 	rep(fn, "--------------------------------------------------------------------------"); | ||||
| 	for (unsigned int i = 1; i <= m_HandleTail; i++) | ||||
| 	{ | ||||
| 		if (m_Handles[i].set != HandleSet_Used) | ||||
| @ -1165,7 +1090,7 @@ void HandleSystem::Dump(const HandleReporter &fn) | ||||
| 			continue; | ||||
| 		} | ||||
| 		/* Get the index */ | ||||
| 		unsigned int index = (m_Handles[i].serial << HANDLESYS_HANDLE_BITS) | i; | ||||
| 		unsigned int index = (m_Handles[i].serial << 16) | i; | ||||
| 		/* Determine the owner */ | ||||
| 		const char *owner = "UNKNOWN"; | ||||
| 		if (m_Handles[i].owner) | ||||
| @ -1206,7 +1131,7 @@ void HandleSystem::Dump(const HandleReporter &fn) | ||||
| 		unsigned int parentIdx; | ||||
| 		bool bresult; | ||||
| 		if (pType->name) | ||||
| 			type = pType->name->c_str(); | ||||
| 			type = pType->name->chars(); | ||||
| 
 | ||||
| 		if ((parentIdx = m_Handles[i].clone) != 0) | ||||
| 		{ | ||||
| @ -1225,33 +1150,19 @@ void HandleSystem::Dump(const HandleReporter &fn) | ||||
| 			bresult = pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size); | ||||
| 		} | ||||
| 
 | ||||
| 		char date[256]; // 256 should be more than enough
 | ||||
| 		size_t written = 0; | ||||
| 		// scope for InvalidParameterHandler
 | ||||
| 		{ | ||||
| #ifdef PLATFORM_WINDOWS | ||||
| 			InvalidParameterHandler p; | ||||
| #endif | ||||
| 			written = strftime(date, sizeof(date), fmt, localtime(&m_Handles[i].timestamp)); | ||||
| 		} | ||||
| 
 | ||||
| 		if (!written) | ||||
| 		{ | ||||
| 			ke::SafeStrcpy(date, sizeof(date), "INVALID"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION | ||||
| 			|| !bresult) | ||||
| 		{ | ||||
| 			rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s\t%-30.30s", index, owner, type, "-1", date); | ||||
| 			rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1"); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			char buffer[32]; | ||||
| 			ke::SafeSprintf(buffer, sizeof(buffer), "%d", size); | ||||
| 			rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s\t%-30.30s", index, owner, type, buffer, date); | ||||
| 			rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer); | ||||
| 			total_size += size; | ||||
| 		} | ||||
| 	} | ||||
| 	rep(fn, "-- Approximately %d bytes of memory are in use by Handles.\n", total_size); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -32,27 +32,22 @@ | ||||
| #ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_ | ||||
| #define _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_ | ||||
| 
 | ||||
| #include <IHandleSys.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include <sm_namehashset.h> | ||||
| #include <amtl/am-autoptr.h> | ||||
| #include <amtl/am-string.h> | ||||
| #include <amtl/am-function.h> | ||||
| #include <IHandleSys.h> | ||||
| #include <sm_namehashset.h> | ||||
| #include "common_logic.h" | ||||
| 
 | ||||
| #define HANDLESYS_HANDLE_BITS   20 | ||||
| #define HANDLESYS_MAX_HANDLES		((1 << HANDLESYS_HANDLE_BITS) - 1) | ||||
| #define HANDLESYS_MAX_HANDLES		(1<<15) | ||||
| #define HANDLESYS_MAX_TYPES			(1<<9) | ||||
| #define HANDLESYS_MAX_SUBTYPES		0xF | ||||
| #define HANDLESYS_SUBTYPE_MASK		0xF | ||||
| #define HANDLESYS_TYPEARRAY_SIZE	(HANDLESYS_MAX_TYPES * (HANDLESYS_MAX_SUBTYPES + 1)) | ||||
| #define HANDLESYS_SERIAL_BITS		(32 - HANDLESYS_HANDLE_BITS) | ||||
| #define HANDLESYS_MAX_SERIALS		(1 << HANDLESYS_SERIAL_BITS) | ||||
| #define HANDLESYS_SERIAL_MASK		(((1 << HANDLESYS_SERIAL_BITS) - 1) << HANDLESYS_HANDLE_BITS) | ||||
| #define HANDLESYS_HANDLE_MASK		((1 << HANDLESYS_HANDLE_BITS) - 1) | ||||
| #define HANDLESYS_WARN_USAGE		100000 | ||||
| #define HANDLESYS_MAX_SERIALS		0xFFFF | ||||
| #define HANDLESYS_SERIAL_MASK		0xFFFF0000 | ||||
| #define HANDLESYS_HANDLE_MASK		0x0000FFFF | ||||
| 
 | ||||
| #define HANDLESYS_MEMUSAGE_MIN_VERSION		3 | ||||
| 
 | ||||
| @ -93,7 +88,6 @@ struct QHandle | ||||
| 	bool access_special;		/* Whether or not access rules are special or type-derived */ | ||||
| 	bool is_destroying;			/* Whether or not the handle is being destroyed */ | ||||
| 	HandleAccess sec;			/* Security rules */ | ||||
| 	time_t timestamp;			/* Creation timestamp */ | ||||
| 	/* The following variables are unrelated to the Handle array, and used 
 | ||||
| 	 * as an inlined chain of information */ | ||||
| 	unsigned int freeID;		/* ID of a free handle in the free handle chain */ | ||||
| @ -111,7 +105,7 @@ struct QHandleType | ||||
| 	TypeAccess typeSec; | ||||
| 	HandleAccess hndlSec; | ||||
| 	unsigned int opened; | ||||
| 	std::unique_ptr<std::string> name; | ||||
| 	ke::AutoPtr<ke::AString> name; | ||||
| 
 | ||||
| 	static inline bool matches(const char *key, const QHandleType *type) | ||||
| 	{ | ||||
| @ -123,7 +117,7 @@ struct QHandleType | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| typedef ke::Function<void(const char *)> HandleReporter; | ||||
| typedef ke::Lambda<void(const char *)> HandleReporter; | ||||
| 
 | ||||
| class HandleSystem :  | ||||
| 	public IHandleSys | ||||
|  | ||||
| @ -319,7 +319,7 @@ void Logger::_UpdateFiles(bool bLevelChange) | ||||
| 	char buff[PLATFORM_MAX_PATH]; | ||||
| 	ke::SafeSprintf(buff, sizeof(buff), "%04d%02d%02d", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday); | ||||
| 
 | ||||
| 	std::string currentDate(buff); | ||||
| 	ke::AString currentDate(buff); | ||||
| 
 | ||||
| 	if (m_Mode == LoggingMode_PerMap) | ||||
| 	{ | ||||
| @ -327,7 +327,7 @@ void Logger::_UpdateFiles(bool bLevelChange) | ||||
| 		{ | ||||
| 			for (size_t iter = 0; iter < static_cast<size_t>(-1); ++iter) | ||||
| 			{ | ||||
| 				g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/L%s%u.log", currentDate.c_str(), iter); | ||||
| 				g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/L%s%u.log", currentDate.chars(), iter); | ||||
| 				if (!libsys->IsPathFile(buff)) | ||||
| 				{ | ||||
| 					break; | ||||
| @ -336,12 +336,12 @@ void Logger::_UpdateFiles(bool bLevelChange) | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			ke::SafeStrcpy(buff, sizeof(buff), m_NormalFileName.c_str()); | ||||
| 			ke::SafeStrcpy(buff, sizeof(buff), m_NormalFileName.chars()); | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/L%s.log", currentDate.c_str()); | ||||
| 		g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/L%s.log", currentDate.chars()); | ||||
| 	} | ||||
| 
 | ||||
| 	if (m_NormalFileName.compare(buff)) | ||||
| @ -353,11 +353,11 @@ void Logger::_UpdateFiles(bool bLevelChange) | ||||
| 	{ | ||||
| 		if (bLevelChange) | ||||
| 		{ | ||||
| 			LogMessage("-------- Mapchange to %s --------", m_CurrentMapName.c_str()); | ||||
| 			LogMessage("-------- Mapchange to %s --------", m_CurrentMapName.chars()); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/errors_%s.log", currentDate.c_str()); | ||||
| 	g_pSM->BuildPath(Path_SM, buff, sizeof(buff), "logs/errors_%s.log", currentDate.chars()); | ||||
| 	if (bLevelChange || m_ErrorFileName.compare(buff)) | ||||
| 	{ | ||||
| 		_CloseError(); | ||||
| @ -369,7 +369,7 @@ FILE *Logger::_OpenNormal() | ||||
| { | ||||
| 	_UpdateFiles(); | ||||
| 
 | ||||
| 	FILE *pFile = fopen(m_NormalFileName.c_str(), "a+"); | ||||
| 	FILE *pFile = fopen(m_NormalFileName.chars(), "a+"); | ||||
| 	if (pFile == NULL) | ||||
| 	{ | ||||
| 		_LogFatalOpen(m_NormalFileName); | ||||
| @ -383,7 +383,7 @@ FILE *Logger::_OpenNormal() | ||||
| 		char date[32]; | ||||
| 
 | ||||
| 		strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime); | ||||
| 		fprintf(pFile, "L %s: SourceMod log file session started (file \"%s\") (Version \"%s\")\n", date, m_NormalFileName.c_str(), SOURCEMOD_VERSION); | ||||
| 		fprintf(pFile, "L %s: SourceMod log file session started (file \"%s\") (Version \"%s\")\n", date, m_NormalFileName.chars(), SOURCEMOD_VERSION); | ||||
| 		m_DamagedNormalFile = true; | ||||
| 	} | ||||
| 
 | ||||
| @ -394,7 +394,7 @@ FILE *Logger::_OpenError() | ||||
| { | ||||
| 	_UpdateFiles(); | ||||
| 
 | ||||
| 	FILE *pFile = fopen(m_ErrorFileName.c_str(), "a+"); | ||||
| 	FILE *pFile = fopen(m_ErrorFileName.chars(), "a+"); | ||||
| 	if (pFile == NULL) | ||||
| 	{ | ||||
| 		_LogFatalOpen(m_ErrorFileName); | ||||
| @ -409,7 +409,7 @@ FILE *Logger::_OpenError() | ||||
| 		char date[32]; | ||||
| 		strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime); | ||||
| 		fprintf(pFile, "L %s: SourceMod error session started\n", date); | ||||
| 		fprintf(pFile, "L %s: Info (map \"%s\") (file \"%s\")\n", date, m_CurrentMapName.c_str(), m_ErrorFileName.c_str()); | ||||
| 		fprintf(pFile, "L %s: Info (map \"%s\") (file \"%s\")\n", date, m_CurrentMapName.chars(), m_ErrorFileName.chars()); | ||||
| 		m_DamagedErrorFile = true; | ||||
| 	} | ||||
| 
 | ||||
| @ -423,11 +423,11 @@ FILE *Logger::_OpenFatal() | ||||
| 	return fopen(path, "at"); | ||||
| } | ||||
| 
 | ||||
| void Logger::_LogFatalOpen(std::string &str) | ||||
| void Logger::_LogFatalOpen(ke::AString &str) | ||||
| { | ||||
| 	char error[255]; | ||||
| 	libsys->GetPlatformError(error, sizeof(error)); | ||||
| 	LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", str.c_str()); | ||||
| 	LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", str.chars()); | ||||
| 	LogFatal("[SM] Platform returned error: \"%s\"", error); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -92,13 +92,13 @@ private: | ||||
| 	FILE *_OpenError(); | ||||
| 	FILE *_OpenFatal(); | ||||
| 
 | ||||
| 	void _LogFatalOpen(std::string &str); | ||||
| 	void _LogFatalOpen(ke::AString &str); | ||||
| 	void _PrintToGameLog(const char *fmt, va_list ap); | ||||
| 	void _UpdateFiles(bool bLevelChange = false); | ||||
| private: | ||||
| 	std::string m_NormalFileName; | ||||
| 	std::string m_ErrorFileName; | ||||
| 	std::string m_CurrentMapName; | ||||
| 	ke::AString m_NormalFileName; | ||||
| 	ke::AString m_ErrorFileName; | ||||
| 	ke::AString m_CurrentMapName; | ||||
| 
 | ||||
| 	int m_Day; | ||||
| 
 | ||||
|  | ||||
| @ -1,131 +0,0 @@ | ||||
| /**
 | ||||
|  * vim: set ts=4 : | ||||
|  * ============================================================================= | ||||
|  * Entity Lump Manager | ||||
|  * Copyright (C) 2021-2022 AlliedModders LLC.  All rights reserved. | ||||
|  * ============================================================================= | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it under | ||||
|  * the terms of the GNU General Public License, version 3.0, as published by the | ||||
|  * Free Software Foundation. | ||||
|  *  | ||||
|  * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||||
|  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more | ||||
|  * details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along with | ||||
|  * this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * As a special exception, AlliedModders LLC gives you permission to link the | ||||
|  * code of this program (as well as its derivative works) to "Half-Life 2," the | ||||
|  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software | ||||
|  * by the Valve Corporation.  You must obey the GNU General Public License in | ||||
|  * all respects for all other code used.  Additionally, AlliedModders LLC grants | ||||
|  * this exception to all derivative works.  AlliedModders LLC defines further | ||||
|  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), | ||||
|  * or <http://www.sourcemod.net/license.php>.
 | ||||
|  * | ||||
|  * Version: $Id$ | ||||
|  */ | ||||
| 
 | ||||
| #include "LumpManager.h" | ||||
| 
 | ||||
| #include <iomanip> | ||||
| #include <sstream> | ||||
| 
 | ||||
| EntityLumpParseResult::operator bool() const { | ||||
| 	return m_Status == Status_OK; | ||||
| } | ||||
| 
 | ||||
| EntityLumpParseResult EntityLumpManager::Parse(const char* pMapEntities) { | ||||
| 	m_Entities.clear(); | ||||
| 	 | ||||
| 	std::istringstream mapEntities(pMapEntities); | ||||
| 	 | ||||
| 	for (;;) { | ||||
| 		std::string token; | ||||
| 		mapEntities >> std::ws >> token >> std::ws; | ||||
| 		 | ||||
| 		// Assert that we're at the start of a new block, otherwise we're done parsing
 | ||||
| 		if (token != "{") { | ||||
| 			if (token == "\0") { | ||||
| 				break; | ||||
| 			} else { | ||||
| 				return EntityLumpParseResult { | ||||
| 					Status_UnexpectedChar, mapEntities.tellg() | ||||
| 				}; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/**
 | ||||
| 		 * Parse key / value pairs until we reach a closing brace.  We currently assume there | ||||
| 		 * are only quoted keys / values up to the next closing brace. | ||||
| 		 * | ||||
| 		 * The SDK suggests that there are cases that could use non-quoted symbols and nested | ||||
| 		 * braces (`shared/mapentities_shared.cpp::MapEntity_ParseToken`), but I haven't seen | ||||
| 		 * those in practice. | ||||
| 		 */ | ||||
| 		EntityLumpEntry entry; | ||||
| 		while (mapEntities.peek() != '}') { | ||||
| 			std::string key, value; | ||||
| 			 | ||||
| 			if (mapEntities.peek() != '"') { | ||||
| 				return EntityLumpParseResult { | ||||
| 					Status_UnexpectedChar, mapEntities.tellg() | ||||
| 				}; | ||||
| 			} | ||||
| 			mapEntities >> quoted(key) >> std::ws; | ||||
| 			 | ||||
| 			if (mapEntities.peek() != '"') { | ||||
| 				return EntityLumpParseResult { | ||||
| 					Status_UnexpectedChar, mapEntities.tellg() | ||||
| 				}; | ||||
| 			} | ||||
| 			mapEntities >> quoted(value) >> std::ws; | ||||
| 			 | ||||
| 			entry.emplace_back(key, value); | ||||
| 		} | ||||
| 		mapEntities.get(); | ||||
| 		m_Entities.push_back(std::make_shared<EntityLumpEntry>(entry)); | ||||
| 	} | ||||
| 	 | ||||
| 	return EntityLumpParseResult{}; | ||||
| } | ||||
| 
 | ||||
| std::string EntityLumpManager::Dump() { | ||||
| 	std::ostringstream stream; | ||||
| 	for (const auto& entry : m_Entities) { | ||||
| 		// ignore empty entries
 | ||||
| 		if (entry->empty()) { | ||||
| 			continue; | ||||
| 		} | ||||
| 		stream << "{\n"; | ||||
| 		for (const auto& pair : *entry) { | ||||
| 			stream << '"' << pair.first << "\" \"" << pair.second << '"' << '\n'; | ||||
| 		} | ||||
| 		stream << "}\n"; | ||||
| 	} | ||||
| 	return stream.str(); | ||||
| } | ||||
| 
 | ||||
| std::weak_ptr<EntityLumpEntry> EntityLumpManager::Get(size_t index) { | ||||
| 	return m_Entities[index]; | ||||
| } | ||||
| 
 | ||||
| void EntityLumpManager::Erase(size_t index) { | ||||
| 	m_Entities.erase(m_Entities.begin() + index); | ||||
| } | ||||
| 
 | ||||
| void EntityLumpManager::Insert(size_t index) { | ||||
| 	m_Entities.emplace(m_Entities.begin() + index, std::make_shared<EntityLumpEntry>()); | ||||
| } | ||||
| 
 | ||||
| size_t EntityLumpManager::Append() { | ||||
| 	auto it = m_Entities.emplace(m_Entities.end(), std::make_shared<EntityLumpEntry>()); | ||||
| 	return std::distance(m_Entities.begin(), it); | ||||
| } | ||||
| 
 | ||||
| size_t EntityLumpManager::Length() { | ||||
| 	return m_Entities.size(); | ||||
| } | ||||
| @ -1,116 +0,0 @@ | ||||
| /**
 | ||||
|  * vim: set ts=4 : | ||||
|  * ============================================================================= | ||||
|  * Entity Lump Manager | ||||
|  * Copyright (C) 2021-2022 AlliedModders LLC.  All rights reserved. | ||||
|  * ============================================================================= | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it under | ||||
|  * the terms of the GNU General Public License, version 3.0, as published by the | ||||
|  * Free Software Foundation. | ||||
|  *  | ||||
|  * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||||
|  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more | ||||
|  * details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along with | ||||
|  * this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * As a special exception, AlliedModders LLC gives you permission to link the | ||||
|  * code of this program (as well as its derivative works) to "Half-Life 2," the | ||||
|  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software | ||||
|  * by the Valve Corporation.  You must obey the GNU General Public License in | ||||
|  * all respects for all other code used.  Additionally, AlliedModders LLC grants | ||||
|  * this exception to all derivative works.  AlliedModders LLC defines further | ||||
|  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), | ||||
|  * or <http://www.sourcemod.net/license.php>.
 | ||||
|  * | ||||
|  * Version: $Id$ | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _INCLUDE_LUMPMANAGER_H_ | ||||
| #define _INCLUDE_LUMPMANAGER_H_ | ||||
| 
 | ||||
| #include <vector> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| 
 | ||||
| /**
 | ||||
|  * Entity lump manager.  Provides a list that stores a list of key / value pairs and the | ||||
|  * functionality to (de)serialize it from / to an entity string. | ||||
|  * This file and its corresponding .cpp should be compilable independently of SourceMod; | ||||
|  * the SourceMod interop is located within smn_entitylump. | ||||
|  * | ||||
|  * @file lumpmanager.h | ||||
|  * @brief Class definition for object that parses lumps. | ||||
|  */ | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief A container of key / value pairs. | ||||
|  */ | ||||
| using EntityLumpEntry = std::vector<std::pair<std::string, std::string>>; | ||||
| 
 | ||||
| enum EntityLumpParseStatus { | ||||
| 	Status_OK, | ||||
| 	Status_UnexpectedChar, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Result of parsing an entity lump.  On a parse error, m_Status is not Status_OK and | ||||
|  * m_Position indicates the offset within the string that caused the parse error. | ||||
|  */ | ||||
| struct EntityLumpParseResult { | ||||
| 	EntityLumpParseStatus m_Status; | ||||
| 	std::streamoff m_Position; | ||||
| 	 | ||||
| 	operator bool() const; | ||||
| 	const char* Description() const; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Manages entity lump entries. | ||||
|  */ | ||||
| class EntityLumpManager | ||||
| { | ||||
| public: | ||||
| 	/**
 | ||||
| 	 * @brief Parses the map entities string into an internal representation. | ||||
| 	 */ | ||||
| 	EntityLumpParseResult Parse(const char* pMapEntities); | ||||
| 	 | ||||
| 	/**
 | ||||
| 	 * @brief Dumps the current internal representation out to an std::string. | ||||
| 	 */ | ||||
| 	std::string Dump(); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Returns a weak reference to an EntityLumpEntry.  Used for handles on the scripting side. | ||||
| 	 */ | ||||
| 	std::weak_ptr<EntityLumpEntry> Get(size_t index); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Removes an EntityLumpEntry at the given index, shifting down all entries after it by one. | ||||
| 	 */ | ||||
| 	void Erase(size_t index); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Inserts a new EntityLumpEntry at the given index, shifting up the entries previously at the index and after it up by one. | ||||
| 	 */ | ||||
| 	void Insert(size_t index); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Adds a new EntityLumpEntry to the end.  Returns the index of the entry. | ||||
| 	 */ | ||||
| 	size_t Append(); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Returns the number of EntityLumpEntry items in the list. | ||||
| 	 */ | ||||
| 	size_t Length(); | ||||
| 
 | ||||
| private: | ||||
| 	std::vector<std::shared_ptr<EntityLumpEntry>> m_Entities; | ||||
| }; | ||||
| 
 | ||||
| #endif // _INCLUDE_LUMPMANAGER_H_
 | ||||
| @ -49,7 +49,6 @@ MemoryUtils g_MemUtils; | ||||
| 
 | ||||
| MemoryUtils::MemoryUtils() | ||||
| { | ||||
| 	m_InfoMap.init(); | ||||
| #ifdef PLATFORM_APPLE | ||||
| 
 | ||||
| 	task_dyld_info_data_t dyld_info; | ||||
| @ -78,19 +77,20 @@ void MemoryUtils::OnSourceModAllInitialized() | ||||
| 
 | ||||
| void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len) | ||||
| { | ||||
| 	const DynLibInfo* lib = nullptr; | ||||
| 	DynLibInfo lib; | ||||
| 	bool found; | ||||
| 	char *ptr, *end; | ||||
| 
 | ||||
| 	if ((lib = GetLibraryInfo(libPtr)) == nullptr) | ||||
| 	memset(&lib, 0, sizeof(DynLibInfo)); | ||||
| 
 | ||||
| 	if (!GetLibraryInfo(libPtr, lib)) | ||||
| 	{ | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	// Search in the original unaltered state of the binary.
 | ||||
| 	char *start = lib->originalCopy.get(); | ||||
| 	char *ptr = start; | ||||
| 	char *end = ptr + lib->memorySize - len; | ||||
| 	ptr = reinterpret_cast<char *>(lib.baseAddress); | ||||
| 	end = ptr + lib.memorySize - len; | ||||
| 
 | ||||
| 	bool found; | ||||
| 	while (ptr < end) | ||||
| 	{ | ||||
| 		found = true; | ||||
| @ -103,9 +103,8 @@ void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t l | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// Translate the found offset into the actual live binary memory space.
 | ||||
| 		if (found) | ||||
| 			return reinterpret_cast<char *>(lib->baseAddress) + (ptr - start); | ||||
| 			return ptr; | ||||
| 
 | ||||
| 		ptr++; | ||||
| 	} | ||||
| @ -117,8 +116,6 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol) | ||||
| { | ||||
| #ifdef PLATFORM_WINDOWS | ||||
| 
 | ||||
| 	/* Add this this library into the cache */ | ||||
| 	GetLibraryInfo(handle); | ||||
| 	return GetProcAddress((HMODULE)handle, symbol); | ||||
| 	 | ||||
| #elif defined PLATFORM_LINUX | ||||
| @ -165,9 +162,6 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* Add this this library into the cache */ | ||||
| 	GetLibraryInfo((void *)dlmap->l_addr); | ||||
| 
 | ||||
| 	/* If we don't have a symbol table for this library, then create one */ | ||||
| 	if (table == NULL) | ||||
| 	{ | ||||
| @ -332,9 +326,6 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol) | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Add this this library into the cache */ | ||||
| 	GetLibraryInfo((void *)dlbase); | ||||
| 	 | ||||
| 	/* See if we already have a symbol table for this library */ | ||||
| 	for (size_t i = 0; i < m_SymTables.size(); i++) | ||||
| 	{ | ||||
| @ -438,25 +429,21 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol) | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| const DynLibInfo *MemoryUtils::GetLibraryInfo(const void *libPtr) | ||||
| bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib) | ||||
| { | ||||
| 	uintptr_t baseAddr; | ||||
| 
 | ||||
| 	if (libPtr == NULL) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	DynLibInfo lib; | ||||
| 
 | ||||
| #ifdef PLATFORM_WINDOWS | ||||
| 
 | ||||
| #ifdef PLATFORM_X86 | ||||
| 	const WORD PE_FILE_MACHINE = IMAGE_FILE_MACHINE_I386; | ||||
| 	const WORD PE_NT_OPTIONAL_HDR_MAGIC = IMAGE_NT_OPTIONAL_HDR32_MAGIC; | ||||
| #else | ||||
| 	const WORD PE_FILE_MACHINE = IMAGE_FILE_MACHINE_AMD64; | ||||
| 	const WORD PE_NT_OPTIONAL_HDR_MAGIC = IMAGE_NT_OPTIONAL_HDR64_MAGIC; | ||||
| #endif | ||||
| 
 | ||||
| 	MEMORY_BASIC_INFORMATION info; | ||||
| @ -467,7 +454,7 @@ const DynLibInfo *MemoryUtils::GetLibraryInfo(const void *libPtr) | ||||
| 
 | ||||
| 	if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION))) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase); | ||||
| @ -479,21 +466,21 @@ const DynLibInfo *MemoryUtils::GetLibraryInfo(const void *libPtr) | ||||
| 	opt = &pe->OptionalHeader; | ||||
| 
 | ||||
| 	/* Check PE magic and signature */ | ||||
| 	if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != PE_NT_OPTIONAL_HDR_MAGIC) | ||||
| 	if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Check architecture */ | ||||
| 	if (file->Machine != PE_FILE_MACHINE) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/* For our purposes, this must be a dynamic library */ | ||||
| 	if ((file->Characteristics & IMAGE_FILE_DLL) == 0) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Finally, we can do this */ | ||||
| @ -520,12 +507,12 @@ const DynLibInfo *MemoryUtils::GetLibraryInfo(const void *libPtr) | ||||
| 
 | ||||
| 	if (!dladdr(libPtr, &info)) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!info.dli_fbase || !info.dli_fname) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/* This is for our insane sanity checks :o */ | ||||
| @ -535,31 +522,31 @@ const DynLibInfo *MemoryUtils::GetLibraryInfo(const void *libPtr) | ||||
| 	/* Check ELF magic */ | ||||
| 	if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Check ELF version */ | ||||
| 	if (file->e_ident[EI_VERSION] != EV_CURRENT) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Check ELF endianness */ | ||||
| 	if (file->e_ident[EI_DATA] != ELFDATA2LSB) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Check ELF architecture */ | ||||
| 	if (file->e_ident[EI_CLASS] != ELF_CLASS || file->e_machine != ELF_MACHINE) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/* For our purposes, this must be a dynamic library/shared object */ | ||||
| 	if (file->e_type != ET_DYN) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	phdrCount = file->e_phnum; | ||||
| @ -609,12 +596,12 @@ const DynLibInfo *MemoryUtils::GetLibraryInfo(const void *libPtr) | ||||
| 
 | ||||
| 	if (!dladdr(libPtr, &info)) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!info.dli_fbase || !info.dli_fname) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/* This is for our insane sanity checks :o */ | ||||
| @ -624,19 +611,19 @@ const DynLibInfo *MemoryUtils::GetLibraryInfo(const void *libPtr) | ||||
| 	/* Check Mach-O magic */ | ||||
| 	if (file->magic != MACH_MAGIC) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Check architecture */ | ||||
| 	if (file->cputype != MACH_CPU_TYPE || file->cpusubtype != MACH_CPU_SUBTYPE) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/* For our purposes, this must be a dynamic library */ | ||||
| 	if (file->filetype != MH_DYLIB) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	cmd_count = file->ncmds; | ||||
| @ -657,17 +644,5 @@ const DynLibInfo *MemoryUtils::GetLibraryInfo(const void *libPtr) | ||||
| 
 | ||||
| 	lib.baseAddress = reinterpret_cast<void *>(baseAddr); | ||||
| 
 | ||||
| 	LibraryInfoMap::Insert i = m_InfoMap.findForAdd(lib.baseAddress); | ||||
| 	if (i.found()) | ||||
| 	{ | ||||
| 		// We already loaded this binary before.
 | ||||
| 		return &i->value; | ||||
| 	} | ||||
| 	 | ||||
| 	// Keep a copy of the binary in its initial unpatched state for lookup.
 | ||||
| 	lib.originalCopy = std::make_unique<char[]>(lib.memorySize); | ||||
| 	memcpy(lib.originalCopy.get(), lib.baseAddress, lib.memorySize); | ||||
| 	m_InfoMap.add(i, lib.baseAddress, std::move(lib)); | ||||
| 
 | ||||
| 	return &i->value; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| @ -32,8 +32,6 @@ | ||||
| 
 | ||||
| #include "common_logic.h" | ||||
| #include <IMemoryUtils.h> | ||||
| #include <am-hashmap.h> | ||||
| #include <memory> | ||||
| #if defined PLATFORM_LINUX || defined PLATFORM_APPLE | ||||
| #include <sh_vector.h> | ||||
| #include "sm_symtable.h" | ||||
| @ -51,7 +49,6 @@ struct DynLibInfo | ||||
| { | ||||
| 	void *baseAddress; | ||||
| 	size_t memorySize; | ||||
| 	std::unique_ptr<char[]> originalCopy; | ||||
| }; | ||||
| 
 | ||||
| #if defined PLATFORM_LINUX || defined PLATFORM_APPLE | ||||
| @ -76,7 +73,7 @@ public: // IMemoryUtils | ||||
| 	void *FindPattern(const void *libPtr, const char *pattern, size_t len); | ||||
| 	void *ResolveSymbol(void *handle, const char *symbol); | ||||
| public: | ||||
| 	const DynLibInfo *GetLibraryInfo(const void *libPtr); | ||||
| 	bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib); | ||||
| #if defined PLATFORM_LINUX || defined PLATFORM_APPLE | ||||
| private: | ||||
| 	CVector<LibSymbolTable *> m_SymTables; | ||||
| @ -86,8 +83,6 @@ private: | ||||
| 	SInt32 m_OSXMinor; | ||||
| #endif | ||||
| #endif | ||||
| 	typedef ke::HashMap<void *, DynLibInfo, ke::PointerPolicy<void> > LibraryInfoMap; | ||||
| 	LibraryInfoMap m_InfoMap; | ||||
| }; | ||||
| 
 | ||||
| extern MemoryUtils g_MemUtils; | ||||
|  | ||||
| @ -33,6 +33,7 @@ | ||||
| 
 | ||||
| #include <IShareSys.h> | ||||
| #include <IHandleSys.h> | ||||
| #include <am-autoptr.h> | ||||
| #include <am-string.h> | ||||
| #include <am-utility.h> | ||||
| #include <am-refcounting.h> | ||||
| @ -46,14 +47,16 @@ struct FakeNative | ||||
| 	FakeNative(const char *name, IPluginFunction *fun) | ||||
| 		: name(name), | ||||
| 		  ctx(fun->GetParentContext()), | ||||
| 		  call(fun) | ||||
| 		  call(fun), | ||||
| 		  gate(NULL) | ||||
| 	{ | ||||
| 	} | ||||
| 	~FakeNative(); | ||||
| 
 | ||||
| 	std::string name; | ||||
| 	ke::AString name; | ||||
| 	IPluginContext *ctx; | ||||
| 	IPluginFunction *call; | ||||
| 	ke::RefPtr<INativeCallback> wrapper; | ||||
| 	SPVM_NATIVE_FUNC gate; | ||||
| }; | ||||
| 
 | ||||
| struct Native : public ke::Refcounted<Native> | ||||
| @ -61,25 +64,31 @@ struct Native : public ke::Refcounted<Native> | ||||
| 	Native(CNativeOwner *owner, const sp_nativeinfo_t *native) | ||||
| 		: owner(owner), | ||||
| 		  native(native), | ||||
| 		  fake(nullptr) | ||||
| 		  fake(NULL) | ||||
| 	{ | ||||
| 	} | ||||
| 	Native(CNativeOwner *owner, std::unique_ptr<FakeNative>&& fake) | ||||
| 	Native(CNativeOwner *owner, FakeNative *fake) | ||||
| 		: owner(owner), | ||||
| 		  native(nullptr), | ||||
| 		  fake(std::move(fake)) | ||||
| 		  native(NULL), | ||||
| 		  fake(fake) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	CNativeOwner *owner; | ||||
| 	const sp_nativeinfo_t *native; | ||||
| 	std::unique_ptr<FakeNative> fake; | ||||
| 	ke::AutoPtr<FakeNative> fake; | ||||
| 
 | ||||
| 	SPVM_NATIVE_FUNC func() const | ||||
| 	{ | ||||
| 		if (native) | ||||
| 			return native->func; | ||||
| 		return fake->gate; | ||||
| 	} | ||||
| 	const char *name() const | ||||
| 	{ | ||||
| 		if (native) | ||||
| 			return native->name; | ||||
| 		return fake->name.c_str(); | ||||
| 		return fake->name.chars(); | ||||
| 	} | ||||
| 
 | ||||
| 	static inline bool matches(const char *name, const ke::RefPtr<Native> &entry) | ||||
|  | ||||
| @ -273,10 +273,7 @@ NativeInvoker::Invoke(cell_t *result) | ||||
|   /* Make the call if we can */ | ||||
|   if (ok) | ||||
|   { | ||||
|     if(native_->native) | ||||
|       *result = native_->native->func(context_, _temp_params); | ||||
|     else | ||||
|       *result = native_->fake->wrapper->Invoke(context_, _temp_params); | ||||
|     *result = native_->func()(context_, _temp_params); | ||||
|   } | ||||
| 
 | ||||
|   /* i should be equal to the last valid parameter + 1 */ | ||||
|  | ||||
| @ -14,6 +14,7 @@ | ||||
| #define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_ | ||||
| 
 | ||||
| #include <sp_vm_api.h> | ||||
| #include <amtl/am-autoptr.h> | ||||
| #include <amtl/am-refcounting.h> | ||||
| #include "Native.h" | ||||
| 
 | ||||
|  | ||||
| @ -62,7 +62,7 @@ void CNativeOwner::AddNatives(const sp_nativeinfo_t *natives) | ||||
| 	for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++) | ||||
| 		g_ShareSys.AddNativeToCache(this, native); | ||||
| 
 | ||||
| 	m_natives.push_back(natives); | ||||
| 	m_natives.append(natives); | ||||
| } | ||||
| 
 | ||||
| void CNativeOwner::UnbindWeakRef(const WeakNative &ref) | ||||
| @ -90,14 +90,14 @@ void CNativeOwner::DropEverything() | ||||
| 	} | ||||
| 
 | ||||
| 	/* Strip all of our natives from the cache */ | ||||
| 	for (size_t i = 0; i < m_natives.size(); i++) { | ||||
| 	for (size_t i = 0; i < m_natives.length(); i++) { | ||||
| 		const sp_nativeinfo_t *natives = m_natives[i]; | ||||
| 		for (const sp_nativeinfo_t *native = natives; native->func && native->name; native++) | ||||
| 			g_ShareSys.ClearNativeFromCache(this, native->name); | ||||
| 	} | ||||
| 	m_natives.clear(); | ||||
| 
 | ||||
| 	for (size_t i = 0; i < m_fakes.size(); i++) | ||||
| 	for (size_t i = 0; i < m_fakes.length(); i++) | ||||
| 		g_ShareSys.ClearNativeFromCache(this, m_fakes[i]->name()); | ||||
| 	m_fakes.clear(); | ||||
| } | ||||
|  | ||||
| @ -33,6 +33,7 @@ | ||||
| 
 | ||||
| #include <sp_vm_types.h> | ||||
| #include <sh_list.h> | ||||
| #include <am-linkedlist.h> | ||||
| #include <am-vector.h> | ||||
| #include "common_logic.h" | ||||
| #include "Native.h" | ||||
| @ -79,8 +80,8 @@ protected: | ||||
| 	List<CPlugin *> m_Dependents; | ||||
| 	unsigned int m_nMarkSerial; | ||||
| 	List<WeakNative> m_WeakRefs; | ||||
| 	std::vector<const sp_nativeinfo_t *> m_natives; | ||||
| 	std::vector<ke::RefPtr<Native> > m_fakes; | ||||
| 	ke::Vector<const sp_nativeinfo_t *> m_natives; | ||||
| 	ke::Vector<ke::RefPtr<Native> > m_fakes; | ||||
| }; | ||||
| 
 | ||||
| extern CNativeOwner g_CoreNatives; | ||||
|  | ||||
| @ -45,6 +45,7 @@ | ||||
| #include "Logger.h" | ||||
| #include "frame_tasks.h" | ||||
| #include <amtl/am-string.h> | ||||
| #include <amtl/am-linkedlist.h> | ||||
| #include <bridge/include/IVEngineServerBridge.h> | ||||
| #include <bridge/include/CoreProvider.h> | ||||
| 
 | ||||
| @ -78,7 +79,7 @@ CPlugin::CPlugin(const char *file) | ||||
| 
 | ||||
| 	memset(&m_info, 0, sizeof(m_info)); | ||||
| 
 | ||||
| 	m_pPhrases.reset(g_Translator.CreatePhraseCollection()); | ||||
| 	m_pPhrases = g_Translator.CreatePhraseCollection(); | ||||
| } | ||||
| 
 | ||||
| CPlugin::~CPlugin() | ||||
| @ -226,7 +227,7 @@ bool CPlugin::SetProperty(const char *prop, void *ptr) | ||||
| 
 | ||||
| IPluginRuntime *CPlugin::GetRuntime() | ||||
| { | ||||
| 	return m_pRuntime.get(); | ||||
| 	return m_pRuntime; | ||||
| } | ||||
| 
 | ||||
| void CPlugin::EvictWithError(PluginStatus status, const char *error_fmt, ...) | ||||
| @ -275,7 +276,7 @@ bool CPlugin::ReadInfo() | ||||
| 		sm_plugininfo_c_t *cinfo; | ||||
| 		cell_t local_addr; | ||||
| 
 | ||||
| 		auto update_field = [base](cell_t addr, std::string *dest) { | ||||
| 		auto update_field = [base](cell_t addr, ke::AString *dest) { | ||||
| 			const char* ptr; | ||||
| 			if (base->LocalToString(addr, (char **)&ptr) == SP_ERROR_NONE) | ||||
| 				*dest = ptr; | ||||
| @ -482,7 +483,7 @@ bool CPlugin::TryCompile() | ||||
| 	g_pSM->BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", m_filename); | ||||
| 
 | ||||
| 	char loadmsg[255]; | ||||
| 	m_pRuntime.reset(g_pSourcePawn2->LoadBinaryFromFile(fullpath, loadmsg, sizeof(loadmsg))); | ||||
| 	m_pRuntime = g_pSourcePawn2->LoadBinaryFromFile(fullpath, loadmsg, sizeof(loadmsg)); | ||||
| 	if (!m_pRuntime) { | ||||
| 		EvictWithError(Plugin_BadLoad, "Unable to load plugin (%s)", loadmsg); | ||||
| 		return false; | ||||
| @ -523,11 +524,11 @@ PluginType CPlugin::GetType() | ||||
| 
 | ||||
| const sm_plugininfo_t *CPlugin::GetPublicInfo() | ||||
| { | ||||
| 	m_info.author = info_author_.c_str(); | ||||
| 	m_info.description = info_description_.c_str(); | ||||
| 	m_info.name = info_name_.c_str(); | ||||
| 	m_info.url = info_url_.c_str(); | ||||
| 	m_info.version = info_version_.c_str(); | ||||
| 	m_info.author = info_author_.chars(); | ||||
| 	m_info.description = info_description_.chars(); | ||||
| 	m_info.name = info_name_.chars(); | ||||
| 	m_info.url = info_url_.chars(); | ||||
| 	m_info.version = info_version_.chars(); | ||||
| 	return &m_info; | ||||
| } | ||||
| 
 | ||||
| @ -657,7 +658,7 @@ time_t CPlugin::GetFileTimeStamp() | ||||
| 
 | ||||
| IPhraseCollection *CPlugin::GetPhrases() | ||||
| { | ||||
| 	return m_pPhrases.get(); | ||||
| 	return m_pPhrases; | ||||
| } | ||||
| 
 | ||||
| void CPlugin::DependencyDropped(CPlugin *pOwner) | ||||
| @ -673,7 +674,7 @@ void CPlugin::DependencyDropped(CPlugin *pOwner) | ||||
| 	} | ||||
| 
 | ||||
| 	unsigned int unbound = 0; | ||||
| 	for (size_t i = 0; i < pOwner->m_fakes.size(); i++) | ||||
| 	for (size_t i = 0; i < pOwner->m_fakes.length(); i++) | ||||
| 	{ | ||||
| 		ke::RefPtr<Native> entry(pOwner->m_fakes[i]); | ||||
| 
 | ||||
| @ -772,13 +773,13 @@ bool CPlugin::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKEN | ||||
| 	if (!entry) | ||||
| 		return false; | ||||
| 
 | ||||
| 	m_fakes.push_back(entry); | ||||
| 	m_fakes.append(entry); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void CPlugin::BindFakeNativesTo(CPlugin *other) | ||||
| { | ||||
| 	for (size_t i = 0; i < m_fakes.size(); i++) | ||||
| 	for (size_t i = 0; i < m_fakes.length(); i++) | ||||
| 		g_ShareSys.BindNativeToPlugin(other, m_fakes[i]); | ||||
| } | ||||
| 
 | ||||
| @ -789,7 +790,7 @@ void CPlugin::BindFakeNativesTo(CPlugin *other) | ||||
| CPluginManager::CPluginIterator::CPluginIterator(ReentrantList<CPlugin *>& in) | ||||
| { | ||||
| 	for (PluginIter iter(in); !iter.done(); iter.next()) | ||||
| 		mylist.push_back(*iter); | ||||
| 		mylist.append(*iter); | ||||
| 	current = mylist.begin(); | ||||
| 	g_PluginSys.AddPluginsListener(this); | ||||
| } | ||||
| @ -846,7 +847,11 @@ CPluginManager::~CPluginManager() | ||||
| 
 | ||||
| void CPluginManager::Shutdown() | ||||
| { | ||||
| 	UnloadAll(); | ||||
| 	List<CPlugin *>::iterator iter; | ||||
| 
 | ||||
| 	for (PluginIter iter(m_plugins); !iter.done(); iter.next()) { | ||||
| 		UnloadPlugin(*iter); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void CPluginManager::LoadAll(const char *config_path, const char *plugins_path) | ||||
| @ -974,20 +979,6 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ | ||||
| 	LoadRes res; | ||||
| 
 | ||||
| 	*wasloaded = false; | ||||
| 
 | ||||
| 	if (strstr(path, "..") != NULL) | ||||
| 	{ | ||||
| 		ke::SafeStrcpy(error, maxlength, "Cannot load plugins outside the \"plugins\" folder"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	const char *ext = libsys->GetFileExtension(path); | ||||
| 	if (!ext || strcmp(ext, "smx") != 0) | ||||
| 	{ | ||||
| 		ke::SafeStrcpy(error, maxlength, "Plugin files must have the \".smx\" file extension"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((res=LoadPlugin(&pl, path, true, PluginType_MapUpdated)) == LoadRes_Failure) | ||||
| 	{ | ||||
| 		ke::SafeStrcpy(error, maxlength, pl->GetErrorMsg()); | ||||
| @ -1042,7 +1033,7 @@ void CPluginManager::LoadAutoPlugin(const char *plugin) | ||||
| 
 | ||||
| void CPluginManager::AddPlugin(CPlugin *pPlugin) | ||||
| { | ||||
| 	m_plugins.push_back(pPlugin); | ||||
| 	m_plugins.append(pPlugin); | ||||
| 	m_LoadLookup.insert(pPlugin->GetFilename(), pPlugin); | ||||
| 
 | ||||
| 	pPlugin->SetRegistered(); | ||||
| @ -1174,7 +1165,7 @@ bool CPlugin::ForEachExtVar(const ExtVarCallback& callback) | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void CPlugin::ForEachLibrary(ke::Function<void(const char *)> callback) | ||||
| void CPlugin::ForEachLibrary(ke::Lambda<void(const char *)> callback) | ||||
| { | ||||
| 	for (auto iter = m_Libraries.begin(); iter != m_Libraries.end(); iter++) | ||||
| 		callback((*iter).c_str()); | ||||
| @ -1186,7 +1177,7 @@ void CPlugin::AddRequiredLib(const char *name) | ||||
| 		m_RequiredLibs.push_back(name); | ||||
| } | ||||
| 
 | ||||
| bool CPlugin::ForEachRequiredLib(ke::Function<bool(const char *)> callback) | ||||
| bool CPlugin::ForEachRequiredLib(ke::Lambda<bool(const char *)> callback) | ||||
| { | ||||
| 	for (auto iter = m_RequiredLibs.begin(); iter != m_RequiredLibs.end(); iter++) { | ||||
| 		if (!callback((*iter).c_str())) | ||||
| @ -1220,7 +1211,7 @@ void CPluginManager::LoadExtensions(CPlugin *pPlugin) | ||||
| 		} | ||||
| 		return true; | ||||
| 	}; | ||||
| 	pPlugin->ForEachExtVar(std::move(callback)); | ||||
| 	pPlugin->ForEachExtVar(ke::Move(callback)); | ||||
| } | ||||
| 
 | ||||
| bool CPluginManager::RequireExtensions(CPlugin *pPlugin) | ||||
| @ -1256,7 +1247,7 @@ bool CPluginManager::RequireExtensions(CPlugin *pPlugin) | ||||
| 		return true; | ||||
| 	}; | ||||
| 
 | ||||
| 	return pPlugin->ForEachExtVar(std::move(callback)); | ||||
| 	return pPlugin->ForEachExtVar(ke::Move(callback)); | ||||
| } | ||||
| 
 | ||||
| CPlugin *CPluginManager::CompileAndPrep(const char *path) | ||||
| @ -1499,9 +1490,6 @@ void CPluginManager::Purge(CPlugin *plugin) | ||||
| 	if (plugin->GetStatus() == Plugin_Running) | ||||
| 		plugin->Call_OnPluginEnd(); | ||||
| 
 | ||||
| 	m_pOnNotifyPluginUnloaded->PushCell(plugin->GetMyHandle()); | ||||
| 	m_pOnNotifyPluginUnloaded->Execute(NULL); | ||||
| 
 | ||||
| 	// Notify listeners of unloading.
 | ||||
| 	if (plugin->EnteredSecondPass()) { | ||||
| 		for (ListenerIter iter(m_listeners); !iter.done(); iter.next()) | ||||
| @ -1548,12 +1536,12 @@ CPlugin *CPluginManager::GetPluginByCtx(const sp_context_t *ctx) | ||||
| 
 | ||||
| unsigned int CPluginManager::GetPluginCount() | ||||
| { | ||||
| 	return m_plugins.size(); | ||||
| 	return m_plugins.length(); | ||||
| } | ||||
| 
 | ||||
| void CPluginManager::AddPluginsListener(IPluginsListener *listener) | ||||
| { | ||||
| 	m_listeners.push_back(listener); | ||||
| 	m_listeners.append(listener); | ||||
| } | ||||
| 
 | ||||
| void CPluginManager::RemovePluginsListener(IPluginsListener *listener) | ||||
| @ -1590,7 +1578,6 @@ void CPluginManager::OnSourceModAllInitialized() | ||||
| 
 | ||||
| 	m_pOnLibraryAdded = forwardsys->CreateForward("OnLibraryAdded", ET_Ignore, 1, NULL, Param_String); | ||||
| 	m_pOnLibraryRemoved = forwardsys->CreateForward("OnLibraryRemoved", ET_Ignore, 1, NULL, Param_String); | ||||
| 	m_pOnNotifyPluginUnloaded = forwardsys->CreateForward("OnNotifyPluginUnloaded", ET_Ignore, 1, NULL, Param_Cell); | ||||
| } | ||||
| 
 | ||||
| void CPluginManager::OnSourceModShutdown() | ||||
| @ -1605,7 +1592,6 @@ void CPluginManager::OnSourceModShutdown() | ||||
| 
 | ||||
| 	forwardsys->ReleaseForward(m_pOnLibraryAdded); | ||||
| 	forwardsys->ReleaseForward(m_pOnLibraryRemoved); | ||||
| 	forwardsys->ReleaseForward(m_pOnNotifyPluginUnloaded); | ||||
| } | ||||
| 
 | ||||
| ConfigResult CPluginManager::OnSourceModConfigChanged(const char *key, | ||||
| @ -1729,7 +1715,7 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg | ||||
| 				rootmenu->ConsolePrint("[SM] Listing %d plugin%s:", plnum, (plnum > 1) ? "s" : ""); | ||||
| 			} | ||||
| 
 | ||||
| 			std::list<CPlugin *> fail_list; | ||||
| 			ke::LinkedList<CPlugin *> fail_list; | ||||
| 
 | ||||
| 			for (PluginIter iter(m_plugins); !iter.done(); iter.next(), id++) { | ||||
| 				CPlugin *pl = (*iter); | ||||
| @ -1741,7 +1727,7 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg | ||||
| 					len += ke::SafeSprintf(buffer, sizeof(buffer), "  %0*d <%s>", plpadding, id, GetStatusText(pl->GetDisplayStatus())); | ||||
| 
 | ||||
| 					/* Plugin has failed to load. */ | ||||
| 					fail_list.push_back(pl); | ||||
| 					fail_list.append(pl); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| @ -2047,8 +2033,7 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg | ||||
| 					//the unload/reload attempt next frame will print a message
 | ||||
| 					case PluginState::WaitingToUnload: | ||||
| 					case PluginState::WaitingToUnloadAndReload: | ||||
| 						rootmenu->ConsolePrint("[SM] Plugin %s will be reloaded on the next frame.", name); | ||||
| 						break; | ||||
| 						return; | ||||
| 
 | ||||
| 					default: | ||||
| 						rootmenu->ConsolePrint("[SM] Failed to reload plugin %s.", name); | ||||
| @ -2078,7 +2063,7 @@ bool CPluginManager::ReloadPlugin(CPlugin *pl, bool print) | ||||
| 	if (state == PluginState::WaitingToUnloadAndReload) | ||||
| 		return false; | ||||
| 
 | ||||
| 	std::string filename(pl->GetFilename()); | ||||
| 	ke::AString filename(pl->GetFilename()); | ||||
| 	PluginType ptype = pl->GetType(); | ||||
| 
 | ||||
| 	int id = 1; | ||||
| @ -2093,13 +2078,13 @@ bool CPluginManager::ReloadPlugin(CPlugin *pl, bool print) | ||||
| 		{ | ||||
| 			pl->SetWaitingToUnload(true); | ||||
| 			ScheduleTaskForNextFrame([this, id, filename, ptype, print]() -> void { | ||||
| 				ReloadPluginImpl(id, filename.c_str(), ptype, print); | ||||
| 				ReloadPluginImpl(id, filename.chars(), ptype, print); | ||||
| 			}); | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	ReloadPluginImpl(id, filename.c_str(), ptype, false); | ||||
| 	ReloadPluginImpl(id, filename.chars(), ptype, false); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| @ -2223,6 +2208,7 @@ void CPluginManager::UnloadAll() | ||||
| int CPluginManager::GetOrderOfPlugin(IPlugin *pl) | ||||
| { | ||||
| 	int id = 1; | ||||
| 	List<CPlugin *>::iterator iter; | ||||
| 
 | ||||
| 	for (PluginIter iter(m_plugins); !iter.done(); iter.next()) { | ||||
| 		if ((*iter) == pl) | ||||
| @ -2287,7 +2273,7 @@ void CPluginManager::FreePluginList(const CVector<SMPlugin *> *list) | ||||
| 	delete const_cast<CVector<SMPlugin *> *>(list); | ||||
| } | ||||
| 
 | ||||
| void CPluginManager::ForEachPlugin(ke::Function<void(CPlugin *)> callback) | ||||
| void CPluginManager::ForEachPlugin(ke::Lambda<void(CPlugin *)> callback) | ||||
| { | ||||
| 	for (PluginIter iter(m_plugins); !iter.done(); iter.next()) | ||||
| 		callback(*iter); | ||||
| @ -2365,7 +2351,7 @@ public: | ||||
| 	{ | ||||
| 		ke::RefPtr<PluginsListenerV1Wrapper> wrapper = new PluginsListenerV1Wrapper(listener); | ||||
| 
 | ||||
| 		v1_wrappers_.push_back(wrapper); | ||||
| 		v1_wrappers_.append(wrapper); | ||||
| 		g_PluginSys.AddPluginsListener(wrapper); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -32,12 +32,9 @@ | ||||
| #ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ | ||||
| #define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_ | ||||
| 
 | ||||
| #include <time.h> | ||||
| #include <errno.h> | ||||
| #include <sys/stat.h> | ||||
| #include <time.h> | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include <IPluginSys.h> | ||||
| #include <IHandleSys.h> | ||||
| #include <IForwardSys.h> | ||||
| @ -132,10 +129,10 @@ public: | ||||
| 		bool required; | ||||
| 	}; | ||||
| 
 | ||||
| 	typedef ke::Function<bool(const sp_pubvar_t *, const ExtVar& ext)> ExtVarCallback; | ||||
| 	typedef ke::Lambda<bool(const sp_pubvar_t *, const ExtVar& ext)> ExtVarCallback; | ||||
| 	bool ForEachExtVar(const ExtVarCallback& callback); | ||||
| 
 | ||||
| 	void ForEachLibrary(ke::Function<void(const char *)> callback); | ||||
| 	void ForEachLibrary(ke::Lambda<void(const char *)> callback); | ||||
| public: | ||||
| 	/**
 | ||||
| 	 * Creates a plugin object with default values. | ||||
| @ -218,7 +215,7 @@ public: | ||||
| 	} | ||||
| 
 | ||||
| 	void AddRequiredLib(const char *name); | ||||
| 	bool ForEachRequiredLib(ke::Function<bool(const char *)> callback); | ||||
| 	bool ForEachRequiredLib(ke::Lambda<bool(const char *)> callback); | ||||
| 
 | ||||
| 	bool HasMissingFakeNatives() const { | ||||
| 		return m_FakeNativesMissing; | ||||
| @ -227,7 +224,7 @@ public: | ||||
| 		return m_LibraryMissing; | ||||
| 	} | ||||
| 	bool HasFakeNatives() const { | ||||
| 		return m_fakes.size() > 0; | ||||
| 		return m_fakes.length() > 0; | ||||
| 	} | ||||
| 
 | ||||
| 	// True if we got far enough into the second pass to call OnPluginLoaded
 | ||||
| @ -270,8 +267,8 @@ private: | ||||
| 	char m_errormsg[256]; | ||||
| 
 | ||||
| 	// Internal properties that must by reset if the runtime is evicted.
 | ||||
| 	std::unique_ptr<IPluginRuntime> m_pRuntime; | ||||
| 	std::unique_ptr<CPhraseCollection> m_pPhrases; | ||||
| 	ke::AutoPtr<IPluginRuntime> m_pRuntime; | ||||
| 	ke::AutoPtr<CPhraseCollection> m_pPhrases; | ||||
| 	IPluginContext *m_pContext; | ||||
| 	sp_pubvar_t *m_MaxClientsVar; | ||||
| 	StringHashMap<void *> m_Props; | ||||
| @ -289,11 +286,11 @@ private: | ||||
| 
 | ||||
| 	// Cached.
 | ||||
| 	sm_plugininfo_t m_info; | ||||
| 	std::string info_name_; | ||||
| 	std::string info_author_; | ||||
| 	std::string info_description_; | ||||
| 	std::string info_version_; | ||||
| 	std::string info_url_; | ||||
| 	ke::AString info_name_; | ||||
| 	ke::AString info_author_; | ||||
| 	ke::AString info_description_; | ||||
| 	ke::AString info_version_; | ||||
| 	ke::AString info_url_; | ||||
| }; | ||||
| 
 | ||||
| class CPluginManager :  | ||||
| @ -320,8 +317,8 @@ public: | ||||
| 		void Release(); | ||||
| 		void OnPluginDestroyed(IPlugin *plugin) override; | ||||
| 	private: | ||||
| 		std::list<CPlugin *> mylist; | ||||
| 		std::list<CPlugin *>::iterator current; | ||||
| 		ke::LinkedList<CPlugin *> mylist; | ||||
| 		ke::LinkedList<CPlugin *>::iterator current; | ||||
| 	}; | ||||
| 	friend class CPluginManager::CPluginIterator; | ||||
| public: //IScriptManager
 | ||||
| @ -435,7 +432,7 @@ public: | ||||
| 
 | ||||
| 	void _SetPauseState(CPlugin *pPlugin, bool pause); | ||||
| 
 | ||||
| 	void ForEachPlugin(ke::Function<void(CPlugin *)> callback); | ||||
| 	void ForEachPlugin(ke::Lambda<void(CPlugin *)> callback); | ||||
| private: | ||||
| 	LoadRes LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type); | ||||
| 
 | ||||
| @ -476,7 +473,7 @@ private: | ||||
| private: | ||||
| 	ReentrantList<IPluginsListener *> m_listeners; | ||||
| 	ReentrantList<CPlugin *> m_plugins; | ||||
| 	std::list<CPluginIterator *> m_iterators; | ||||
| 	ke::LinkedList<CPluginIterator *> m_iterators; | ||||
| 
 | ||||
| 	typedef decltype(m_listeners)::iterator ListenerIter; | ||||
| 	typedef decltype(m_plugins)::iterator PluginIter; | ||||
| @ -487,8 +484,10 @@ private: | ||||
| 		{ | ||||
| /* For windows & mac, we convert the path to lower-case in order to avoid duplicate plugin loading */ | ||||
| #if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE | ||||
| 			std::string lower = ke::Lowercase(key.c_str()); | ||||
| 			return detail::CharsAndLength(lower.c_str()).hash(); | ||||
| 			ke::AString original(key.chars()); | ||||
| 			ke::AString lower = original.lowercase(); | ||||
| 			 | ||||
| 			return detail::CharsAndLength(lower.chars()).hash(); | ||||
| #else | ||||
| 			return key.hash(); | ||||
| #endif | ||||
| @ -498,8 +497,8 @@ private: | ||||
| 		{ | ||||
| 			const char *pluginFileChars = const_cast<CPlugin*>(plugin)->GetFilename(); | ||||
| #if defined PLATFORM_WINDOWS || defined PLATFORM_APPLE | ||||
| 			std::string pluginFile = ke::Lowercase(pluginFileChars); | ||||
| 			std::string input = ke::Lowercase(file); | ||||
| 			ke::AString pluginFile = ke::AString(pluginFileChars).lowercase(); | ||||
| 			ke::AString input = ke::AString(file).lowercase(); | ||||
| 			 | ||||
| 			return pluginFile == input; | ||||
| #else | ||||
| @ -523,7 +522,6 @@ private: | ||||
| 	// Forwards
 | ||||
| 	IForward *m_pOnLibraryAdded; | ||||
| 	IForward *m_pOnLibraryRemoved; | ||||
| 	IForward *m_pOnNotifyPluginUnloaded; | ||||
| }; | ||||
| 
 | ||||
| extern CPluginManager g_PluginSys; | ||||
|  | ||||
| @ -52,7 +52,7 @@ ProfileToolManager::OnSourceModShutdown() | ||||
| IProfilingTool * | ||||
| ProfileToolManager::FindToolByName(const char *name) | ||||
| { | ||||
| 	for (size_t i = 0; i < tools_.size(); i++) { | ||||
| 	for (size_t i = 0; i < tools_.length(); i++) { | ||||
| 		if (strcmp(tools_[i]->Name(), name) == 0) | ||||
| 			return tools_[i]; | ||||
| 	} | ||||
| @ -97,7 +97,7 @@ ProfileToolManager::StartFromConsole(IProfilingTool *tool) | ||||
| void | ||||
| ProfileToolManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs *args) | ||||
| { | ||||
| 	if (tools_.size() == 0) { | ||||
| 	if (tools_.length() == 0) { | ||||
| 		rootmenu->ConsolePrint("No profiling tools are enabled."); | ||||
| 		return; | ||||
| 	} | ||||
| @ -107,7 +107,7 @@ ProfileToolManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs | ||||
| 
 | ||||
| 		if (strcmp(cmdname, "list") == 0) { | ||||
| 			rootmenu->ConsolePrint("Profiling tools:"); | ||||
| 			for (size_t i = 0; i < tools_.size(); i++) { | ||||
| 			for (size_t i = 0; i < tools_.length(); i++) { | ||||
| 				rootmenu->DrawGenericOption(tools_[i]->Name(), tools_[i]->Description()); | ||||
| 			} | ||||
| 			return; | ||||
| @ -135,7 +135,7 @@ ProfileToolManager::OnRootConsoleCommand(const char *cmdname, const ICommandArgs | ||||
| 			if (strcmp(cmdname, "start") == 0) { | ||||
| 				if (!default_) { | ||||
| 					default_ = FindToolByName("vprof"); | ||||
| 					if (!default_ && tools_.size() > 0) | ||||
| 					if (!default_ && tools_.length() > 0) | ||||
| 						default_ = tools_[0]; | ||||
| 					if (!default_) { | ||||
| 						rootmenu->ConsolePrint("Could not find any profiler to use."); | ||||
|  | ||||
| @ -51,7 +51,7 @@ public: | ||||
| 	void OnRootConsoleCommand(const char *cmdname, const ICommandArgs *args) override; | ||||
| 
 | ||||
| 	void RegisterTool(IProfilingTool *tool) { | ||||
| 		tools_.push_back(tool); | ||||
| 		tools_.append(tool); | ||||
| 	} | ||||
| 
 | ||||
| 	bool IsActive() const { | ||||
| @ -76,7 +76,7 @@ private: | ||||
| 	void StartFromConsole(IProfilingTool *tool); | ||||
| 
 | ||||
| private: | ||||
| 	std::vector<IProfilingTool *> tools_; | ||||
| 	ke::Vector<IProfilingTool *> tools_; | ||||
| 	IProfilingTool *active_; | ||||
| 	IProfilingTool *default_; | ||||
| 	bool enabled_; | ||||
|  | ||||
| @ -221,15 +221,11 @@ void RootConsoleMenu::OnRootConsoleCommand(const char *cmdname, const ICommandAr | ||||
| 		ConsolePrint("  Fyren"); | ||||
| 		ConsolePrint("  Nicholas \"psychonic\" Hastings"); | ||||
| 		ConsolePrint("  Asher \"asherkin\" Baker"); | ||||
| 		ConsolePrint("  Ruben \"Dr!fter\" Gonzalez"); | ||||
| 		ConsolePrint("  Josh \"KyleS\" Allard"); | ||||
| 		ConsolePrint("  Michael \"Headline\" Flaherty"); | ||||
| 		ConsolePrint("  Jannik \"Peace-Maker\" Hartung"); | ||||
| 		ConsolePrint("  Borja \"faluco\" Ferrer"); | ||||
| 		ConsolePrint("  Pavol \"PM OnoTo\" Marko"); | ||||
| 		ConsolePrint(" Special thanks to Liam, ferret, and Mani"); | ||||
| 		ConsolePrint(" Special thanks to Viper and SteamFriends"); | ||||
| 		ConsolePrint(" https://www.sourcemod.net/"); | ||||
| 		ConsolePrint(" http://www.sourcemod.net/"); | ||||
| 	} | ||||
| 	else if (strcmp(cmdname, "version") == 0) | ||||
| 	{ | ||||
|  | ||||
| @ -29,16 +29,13 @@ | ||||
|  * Version: $Id$ | ||||
|  */ | ||||
| 
 | ||||
| #include <assert.h> | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include "ShareSys.h" | ||||
| #include "ExtensionSys.h" | ||||
| #include <ILibrarySys.h> | ||||
| #include "common_logic.h" | ||||
| #include "PluginSys.h" | ||||
| #include "HandleSys.h" | ||||
| #include <assert.h> | ||||
| 
 | ||||
| using namespace ke; | ||||
| 
 | ||||
| @ -364,11 +361,11 @@ void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, const sp_native_t *native | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	auto rt = pPlugin->GetRuntime(); | ||||
| 	if (pEntry->fake) | ||||
| 		rt->UpdateNativeBindingObject(index, pEntry->fake->wrapper, flags, nullptr); | ||||
| 	else | ||||
| 		rt->UpdateNativeBinding(index, pEntry->native->func, flags, nullptr); | ||||
| 	pPlugin->GetRuntime()->UpdateNativeBinding( | ||||
| 	  index, | ||||
| 	  pEntry->func(), | ||||
| 	  flags, | ||||
| 	  nullptr); | ||||
| } | ||||
| 
 | ||||
| AlreadyRefed<Native> ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv) | ||||
| @ -382,6 +379,11 @@ AlreadyRefed<Native> ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const s | ||||
| 	return entry.forget(); | ||||
| } | ||||
| 
 | ||||
| FakeNative::~FakeNative() | ||||
| { | ||||
| 	g_pSourcePawn2->DestroyFakeNative(gate); | ||||
| } | ||||
| 
 | ||||
| void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name) | ||||
| { | ||||
| 	NativeCache::Result r = m_NtvCache.find(name); | ||||
| @ -398,44 +400,21 @@ void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name) | ||||
| 	m_NtvCache.remove(r); | ||||
| } | ||||
| 
 | ||||
| class DynamicNative final : public INativeCallback | ||||
| { | ||||
| public: | ||||
| 	DynamicNative(SPVM_FAKENATIVE_FUNC callback, void* data) | ||||
| 		: callback_(callback), | ||||
| 		  data_(data) | ||||
| 	{} | ||||
| 
 | ||||
| 	void AddRef() override { | ||||
| 		refcount_++; | ||||
| 	} | ||||
| 	void Release() override { | ||||
| 		assert(refcount_ > 0); | ||||
| 		if (--refcount_ == 0) | ||||
| 			delete this; | ||||
| 	} | ||||
| 	int Invoke(IPluginContext* ctx, const cell_t* params) override { | ||||
| 		return callback_(ctx, params, data_); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	size_t refcount_ = 0; | ||||
| 	SPVM_FAKENATIVE_FUNC callback_; | ||||
| 	void* data_; | ||||
| }; | ||||
| 
 | ||||
| AlreadyRefed<Native> ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func) | ||||
| { | ||||
| 	RefPtr<Native> entry(FindNative(name)); | ||||
| 	if (entry) | ||||
| 		return nullptr; | ||||
| 
 | ||||
| 	std::unique_ptr<FakeNative> fake(new FakeNative(name, pFunc)); | ||||
| 	fake->wrapper = new DynamicNative(func, fake.get()); | ||||
| 	AutoPtr<FakeNative> fake(new FakeNative(name, pFunc)); | ||||
| 
 | ||||
| 	fake->gate = g_pSourcePawn2->CreateFakeNative(func, fake); | ||||
| 	if (!fake->gate) | ||||
| 		return nullptr; | ||||
| 
 | ||||
| 	CNativeOwner *owner = g_PluginSys.GetPluginByCtx(fake->ctx->GetContext()); | ||||
| 
 | ||||
| 	entry = new Native(owner, std::move(fake)); | ||||
| 	entry = new Native(owner, fake.take()); | ||||
| 	m_NtvCache.insert(name, entry); | ||||
| 
 | ||||
| 	return entry.forget(); | ||||
|  | ||||
| @ -49,11 +49,9 @@ namespace SourceMod | ||||
| { | ||||
| 	struct IdentityToken_t | ||||
| 	{ | ||||
| 		Handle_t ident = 0; | ||||
| 		void *ptr = nullptr; | ||||
| 		IdentityType_t type = 0; | ||||
| 		size_t num_handles = 0; | ||||
| 		bool warned_handle_usage = false; | ||||
| 		Handle_t ident; | ||||
| 		void *ptr; | ||||
| 		IdentityType_t type; | ||||
| 	}; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| /**
 | ||||
|  * vim: set ts=4 sw=4 tw=99 noet : | ||||
|  * vim: set ts=4 sw=4 : | ||||
|  * ============================================================================= | ||||
|  * SourceMod | ||||
|  * Copyright (C) 2004-2009 AlliedModders LLC.  All rights reserved. | ||||
| @ -29,518 +29,17 @@ | ||||
|  * Version: $Id$ | ||||
|  */ | ||||
| #include <sm_platform.h> | ||||
| #include <amtl/am-deque.h> | ||||
| #include <amtl/am-maybe.h> | ||||
| #include <amtl/am-thread.h> | ||||
| #include <atomic> | ||||
| #include <chrono> | ||||
| #include <condition_variable> | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| #include <thread> | ||||
| #include "BaseWorker.h" | ||||
| #include "ThreadSupport.h" | ||||
| #include "common_logic.h" | ||||
| 
 | ||||
| static constexpr unsigned int DEFAULT_THINK_TIME_MS	= 20; | ||||
| 
 | ||||
| class CompatWorker final : public IThreadWorker | ||||
| { | ||||
|   public: | ||||
| 	explicit CompatWorker(IThreadWorkerCallbacks* callbacks); | ||||
| 	~CompatWorker(); | ||||
| 
 | ||||
| 	void MakeThread(IThread *pThread) override; | ||||
| 	IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags) override; | ||||
| 	IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params) override; | ||||
| 	void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min) override; | ||||
| 	unsigned int RunFrame() override; | ||||
| 	bool Pause() override; | ||||
| 	bool Unpause() override; | ||||
| 	bool Start() override; | ||||
| 	bool Stop(bool flush) override; | ||||
| 	WorkerState GetStatus(unsigned int *numThreads) override; | ||||
| 	void SetMaxThreadsPerFrame(unsigned int threads) override; | ||||
| 	void SetThinkTimePerFrame(unsigned int thinktime) override; | ||||
| 
 | ||||
|   private: | ||||
| 	void Flush(); | ||||
| 	void Worker(); | ||||
| 	void RunWork(SWThreadHandle* handle); | ||||
| 	void RunWorkLocked(std::unique_lock<std::mutex>* lock, SWThreadHandle* handle); | ||||
| 
 | ||||
|   private: | ||||
| 	IThreadWorkerCallbacks* callbacks_; | ||||
| 	WorkerState state_; | ||||
| 	std::mutex mutex_; | ||||
| 	std::condition_variable work_cv_; | ||||
| 	std::deque<SWThreadHandle*> work_; | ||||
| 	std::unique_ptr<std::thread> thread_; | ||||
| 	std::atomic<unsigned int> jobs_per_wakeup_; | ||||
| 	std::atomic<unsigned int> wait_between_jobs_; | ||||
| }; | ||||
| 
 | ||||
| CompatWorker::CompatWorker(IThreadWorkerCallbacks* callbacks) | ||||
| 	: callbacks_(callbacks), | ||||
| 	  state_(Worker_Stopped), | ||||
| 	  jobs_per_wakeup_(SM_DEFAULT_THREADS_PER_FRAME), | ||||
| 	  wait_between_jobs_(DEFAULT_THINK_TIME_MS) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| CompatWorker::~CompatWorker() | ||||
| { | ||||
| 	Stop(false /* ignored */); | ||||
| 	Flush(); | ||||
| } | ||||
| 
 | ||||
| bool CompatWorker::Start() | ||||
| { | ||||
| 	std::lock_guard<std::mutex> lock(mutex_); | ||||
| 	if (state_ != Worker_Stopped) | ||||
| 		return false; | ||||
| 
 | ||||
| 	thread_ = ke::NewThread("SM CompatWorker Thread", [this]() -> void { | ||||
| 		Worker(); | ||||
| 	}); | ||||
| 
 | ||||
| 	state_ = Worker_Running; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool CompatWorker::Stop(bool) | ||||
| { | ||||
| 	{ | ||||
| 		std::lock_guard<std::mutex> lock(mutex_); | ||||
| 
 | ||||
| 		if (state_ <= Worker_Stopped) | ||||
| 			return false; | ||||
| 
 | ||||
| 		state_ = Worker_Stopped; | ||||
| 		work_cv_.notify_all(); | ||||
| 	} | ||||
| 
 | ||||
| 	thread_->join(); | ||||
| 	thread_ = nullptr; | ||||
| 
 | ||||
| 	Flush(); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool CompatWorker::Pause() | ||||
| { | ||||
| 	std::lock_guard<std::mutex> lock(mutex_); | ||||
| 	if (state_ != Worker_Running) | ||||
| 		return false; | ||||
| 
 | ||||
| 	state_ = Worker_Paused; | ||||
| 	work_cv_.notify_all(); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool CompatWorker::Unpause() | ||||
| { | ||||
| 	std::lock_guard<std::mutex> lock(mutex_); | ||||
| 	if (state_ != Worker_Paused) | ||||
| 		return false; | ||||
| 
 | ||||
| 	state_ = Worker_Running; | ||||
| 	work_cv_.notify_all(); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void CompatWorker::Flush() | ||||
| { | ||||
| 	while (!work_.empty()) { | ||||
| 		auto handle = ke::PopFront(&work_); | ||||
| 		handle->GetThread()->OnTerminate(handle, true); | ||||
| 		if (handle->m_params.flags & Thread_AutoRelease) | ||||
| 			delete handle; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void CompatWorker::Worker() | ||||
| { | ||||
| 	// Note: this must be first to ensure an ordering between Worker() and
 | ||||
| 	// Start(). It must also be outside of the loop to ensure the lock is
 | ||||
| 	// held across wakeup and retesting the predicates.
 | ||||
| 	std::unique_lock<std::mutex> lock(mutex_); | ||||
| 
 | ||||
| 	if (callbacks_) { | ||||
| 		lock.unlock(); | ||||
| 		callbacks_->OnWorkerStart(this); | ||||
| 		lock.lock(); | ||||
| 	} | ||||
| 
 | ||||
| 	typedef std::chrono::system_clock Clock; | ||||
| 	typedef std::chrono::time_point<Clock> TimePoint; | ||||
| 
 | ||||
| 	auto can_work = [this]() -> bool { | ||||
| 		return state_ == Worker_Running && !work_.empty(); | ||||
| 	}; | ||||
| 
 | ||||
| 	ke::Maybe<TimePoint> wait; | ||||
| 	unsigned int work_in_frame = 0; | ||||
| 	for (;;) { | ||||
| 		if (state_ == Worker_Stopped) | ||||
| 			break; | ||||
| 
 | ||||
| 		if (!can_work()) { | ||||
| 			// Wait for work or a Stop.
 | ||||
| 			work_cv_.wait(lock); | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if (wait.isValid()) { | ||||
| 			// Wait until the specified time has passed. If we wake up with a
 | ||||
| 			// timeout, then the wait has elapsed, so reset the holder.
 | ||||
| 			if (work_cv_.wait_until(lock, wait.get()) == std::cv_status::timeout) | ||||
| 				wait = ke::Nothing(); | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		assert(state_ == Worker_Running); | ||||
| 		assert(!work_.empty()); | ||||
| 
 | ||||
| 		SWThreadHandle* handle = ke::PopFront(&work_); | ||||
| 		RunWorkLocked(&lock, handle); | ||||
| 		work_in_frame++; | ||||
| 
 | ||||
| 		// If we've reached our max jobs per "frame", signal that the next
 | ||||
| 		// immediate job must be delayed. We retain the old ThreadWorker
 | ||||
| 		// behavior by checking if the queue has more work. Thus, a delay
 | ||||
| 		// only occurs if two jobs would be processed in the same wakeup.
 | ||||
| 		if (work_in_frame >= jobs_per_wakeup_ && wait_between_jobs_ && can_work()) | ||||
| 			wait = ke::Some(Clock::now() + std::chrono::milliseconds(wait_between_jobs_)); | ||||
| 	} | ||||
| 
 | ||||
| 	assert(lock.owns_lock()); | ||||
| 
 | ||||
| 	while (!work_.empty()) { | ||||
| 		SWThreadHandle* handle = ke::PopFront(&work_); | ||||
| 		RunWorkLocked(&lock, handle); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| unsigned int CompatWorker::RunFrame() | ||||
| { | ||||
| 	unsigned int nprocessed = 0; | ||||
| 	for (unsigned int i = 1; i <= jobs_per_wakeup_; i++) { | ||||
| 		SWThreadHandle* handle; | ||||
| 		{ | ||||
| 			std::lock_guard<std::mutex> lock(mutex_); | ||||
| 			if (work_.empty()) | ||||
| 				break; | ||||
| 			handle = ke::PopFront(&work_); | ||||
| 		} | ||||
| 
 | ||||
| 		RunWork(handle); | ||||
| 		nprocessed++; | ||||
| 	} | ||||
| 	return nprocessed; | ||||
| } | ||||
| 
 | ||||
| void CompatWorker::RunWorkLocked(std::unique_lock<std::mutex>* lock, SWThreadHandle* handle) | ||||
| { | ||||
| 	lock->unlock(); | ||||
| 	RunWork(handle); | ||||
| 	lock->lock(); | ||||
| } | ||||
| 
 | ||||
| void CompatWorker::RunWork(SWThreadHandle* handle) | ||||
| { | ||||
| 	bool autorelease = !!(handle->m_params.flags & Thread_AutoRelease); | ||||
| 	handle->m_state = Thread_Running; | ||||
| 	handle->GetThread()->RunThread(handle); | ||||
| 	handle->m_state = Thread_Done; | ||||
| 	handle->GetThread()->OnTerminate(handle, false); | ||||
| 	if (autorelease) | ||||
| 		delete handle; | ||||
| } | ||||
| 
 | ||||
| void CompatWorker::MakeThread(IThread *pThread) | ||||
| { | ||||
| 	ThreadParams params; | ||||
| 	params.flags = Thread_AutoRelease; | ||||
| 	MakeThread(pThread, ¶ms); | ||||
| } | ||||
| 
 | ||||
| IThreadHandle *CompatWorker::MakeThread(IThread *pThread, ThreadFlags flags) | ||||
| { | ||||
| 	ThreadParams params; | ||||
| 	params.flags = flags; | ||||
| 	return MakeThread(pThread, ¶ms); | ||||
| } | ||||
| 
 | ||||
| IThreadHandle *CompatWorker::MakeThread(IThread *pThread, const ThreadParams *params) | ||||
| { | ||||
| 	std::lock_guard<std::mutex> lock(mutex_); | ||||
| 
 | ||||
| 	ThreadParams def_params; | ||||
| 	if (!params) | ||||
| 		params = &def_params; | ||||
| 
 | ||||
| 	if (state_ <= Worker_Stopped) | ||||
| 		return nullptr; | ||||
| 
 | ||||
| 	SWThreadHandle* handle = new SWThreadHandle(this, params, pThread); | ||||
| 	work_.push_back(handle); | ||||
| 	work_cv_.notify_one(); | ||||
| 	return handle; | ||||
| } | ||||
| 
 | ||||
| void CompatWorker::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min) | ||||
| { | ||||
| 	min = ThreadPrio_Normal; | ||||
| 	max = ThreadPrio_Normal; | ||||
| } | ||||
| 
 | ||||
| void CompatWorker::SetMaxThreadsPerFrame(unsigned int threads) | ||||
| { | ||||
| 	jobs_per_wakeup_ = threads; | ||||
| } | ||||
| 
 | ||||
| void CompatWorker::SetThinkTimePerFrame(unsigned int thinktime) | ||||
| { | ||||
| 	wait_between_jobs_ = thinktime; | ||||
| } | ||||
| 
 | ||||
| WorkerState CompatWorker::GetStatus(unsigned int *numThreads) | ||||
| {  | ||||
| 	std::lock_guard<std::mutex> lock(mutex_); | ||||
| 
 | ||||
| 	// This number is meaningless and the status is racy.
 | ||||
| 	if (numThreads) | ||||
| 		*numThreads = jobs_per_wakeup_; | ||||
| 	return state_; | ||||
| } | ||||
| 
 | ||||
| class CompatThread final : public IThreadHandle | ||||
| { | ||||
| public: | ||||
| 	CompatThread(IThread* callbacks, const ThreadParams* params); | ||||
| 
 | ||||
| 	bool WaitForThread() override; | ||||
| 	void DestroyThis() override; | ||||
| 	IThreadCreator *Parent() override; | ||||
| 	void GetParams(ThreadParams *ptparams) override; | ||||
| 	ThreadPriority GetPriority() override; | ||||
| 	bool SetPriority(ThreadPriority prio) override; | ||||
| 	ThreadState GetState() override; | ||||
| 	bool Unpause() override; | ||||
| 
 | ||||
| private: | ||||
| 	void Run(); | ||||
| 
 | ||||
| private: | ||||
| 	IThread* callbacks_; | ||||
| 	ThreadParams params_; | ||||
| 	std::unique_ptr<std::thread> thread_; | ||||
| 	std::mutex mutex_; | ||||
| 	std::condition_variable check_cv_; | ||||
| 	std::atomic<bool> finished_; | ||||
| }; | ||||
| 
 | ||||
| CompatThread::CompatThread(IThread* callbacks, const ThreadParams* params) | ||||
| 	: callbacks_(callbacks), | ||||
| 	  params_(*params) | ||||
| { | ||||
| 	if (!(params_.flags & Thread_CreateSuspended)) | ||||
| 		Unpause(); | ||||
| } | ||||
| 
 | ||||
| bool CompatThread::Unpause() | ||||
| { | ||||
| 	std::unique_lock<std::mutex> lock(mutex_); | ||||
| 	if (thread_) | ||||
| 		return false; | ||||
| 
 | ||||
| 	thread_ = ke::NewThread("SM CompatThread", [this]() -> void { | ||||
| 		Run(); | ||||
| 	}); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void CompatThread::Run() | ||||
| { | ||||
| 	// Create an ordering between when the thread runs and when thread_ is assigned.
 | ||||
| 	std::unique_lock<std::mutex> lock(mutex_); | ||||
| 
 | ||||
| 	lock.unlock(); | ||||
| 	callbacks_->RunThread(this); | ||||
| 	finished_ = true; | ||||
| 	callbacks_->OnTerminate(this, false); | ||||
| 
 | ||||
| 	if (params_.flags & Thread_AutoRelease) { | ||||
| 		// There should be no handles outstanding, so it's safe to self-destruct.
 | ||||
| 		thread_->detach(); | ||||
| 		delete this; | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	lock.lock(); | ||||
| 	callbacks_ = nullptr; | ||||
| 	check_cv_.notify_all(); | ||||
| } | ||||
| 
 | ||||
| bool CompatThread::WaitForThread() | ||||
| { | ||||
| 	std::unique_lock<std::mutex> lock(mutex_); | ||||
| 	for (;;) { | ||||
| 		// When done, callbacks are unset. If paused, this will deadlock.
 | ||||
| 		if (!callbacks_) | ||||
| 			break; | ||||
| 		check_cv_.wait(lock); | ||||
| 	} | ||||
| 
 | ||||
| 	thread_->join(); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| ThreadState CompatThread::GetState() | ||||
| { | ||||
| 	std::unique_lock<std::mutex> lock(mutex_); | ||||
| 	if (!thread_) | ||||
| 		return Thread_Paused; | ||||
| 	return finished_ ? Thread_Done : Thread_Running; | ||||
| } | ||||
| 
 | ||||
| void CompatThread::DestroyThis() | ||||
| { | ||||
| 	delete this; | ||||
| } | ||||
| 
 | ||||
| ThreadPriority CompatThread::GetPriority() | ||||
| { | ||||
| 	return ThreadPrio_Normal; | ||||
| } | ||||
| 
 | ||||
| bool CompatThread::SetPriority(ThreadPriority prio) | ||||
| { | ||||
| 	return prio == ThreadPrio_Normal; | ||||
| } | ||||
| 
 | ||||
| IThreadCreator *CompatThread::Parent() | ||||
| { | ||||
| 	return g_pThreader; | ||||
| } | ||||
| 
 | ||||
| void CompatThread::GetParams(ThreadParams *ptparams) | ||||
| { | ||||
| 	*ptparams = params_; | ||||
| } | ||||
| 
 | ||||
| class CompatMutex : public IMutex | ||||
| { | ||||
| public: | ||||
| 	bool TryLock() { | ||||
| 		return mutex_.try_lock(); | ||||
| 	} | ||||
| 	void Lock() { | ||||
| 		mutex_.lock(); | ||||
| 	} | ||||
| 	void Unlock() { | ||||
| 		mutex_.unlock(); | ||||
| 	} | ||||
| 	void DestroyThis() { | ||||
| 		delete this; | ||||
| 	} | ||||
| private: | ||||
| 	std::mutex mutex_; | ||||
| }; | ||||
| 
 | ||||
| class CompatThreader final : public IThreader | ||||
| { | ||||
| public: | ||||
| 	void MakeThread(IThread *pThread) override; | ||||
| 	IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags) override; | ||||
| 	IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params) override; | ||||
| 	void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min) override; | ||||
| 	IMutex *MakeMutex() override; | ||||
| 	void ThreadSleep(unsigned int ms) override; | ||||
| 	IEventSignal *MakeEventSignal() override; | ||||
| 	IThreadWorker *MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded) override; | ||||
| 	void DestroyWorker(IThreadWorker *pWorker) override; | ||||
| } sCompatThreader; | ||||
| 
 | ||||
| void CompatThreader::MakeThread(IThread *pThread) | ||||
| { | ||||
| 	ThreadParams params; | ||||
| 	params.flags = Thread_AutoRelease; | ||||
| 	MakeThread(pThread, ¶ms); | ||||
| } | ||||
| 
 | ||||
| IThreadHandle *CompatThreader::MakeThread(IThread *pThread, ThreadFlags flags) | ||||
| { | ||||
| 	ThreadParams params; | ||||
| 	params.flags = flags; | ||||
| 	return MakeThread(pThread, ¶ms); | ||||
| } | ||||
| 
 | ||||
| IThreadHandle *CompatThreader::MakeThread(IThread *pThread, const ThreadParams *params) | ||||
| { | ||||
| 	ThreadParams def_params; | ||||
| 	if (!params) | ||||
| 		params = &def_params; | ||||
| 
 | ||||
| 	return new CompatThread(pThread, params); | ||||
| } | ||||
| 
 | ||||
| void CompatThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min) | ||||
| { | ||||
| 	min = ThreadPrio_Normal; | ||||
| 	max = ThreadPrio_Normal; | ||||
| } | ||||
| 
 | ||||
| IMutex *CompatThreader::MakeMutex() | ||||
| { | ||||
| 	return new CompatMutex(); | ||||
| } | ||||
| 
 | ||||
| void CompatThreader::ThreadSleep(unsigned int ms) | ||||
| { | ||||
| 	std::this_thread::sleep_for(std::chrono::milliseconds(ms)); | ||||
| } | ||||
| 
 | ||||
| class CompatEventSignal final : public IEventSignal | ||||
| { | ||||
| public: | ||||
| 	void Wait() override { | ||||
| 		std::unique_lock<std::mutex> lock(mutex_); | ||||
| 		cv_.wait(lock); | ||||
| 	} | ||||
| 	void Signal() override { | ||||
| 		std::lock_guard<std::mutex> lock(mutex_); | ||||
| 		cv_.notify_all(); | ||||
| 	} | ||||
| 	void DestroyThis() override { | ||||
| 		delete this; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	std::mutex mutex_; | ||||
| 	std::condition_variable cv_; | ||||
| }; | ||||
| 
 | ||||
| IEventSignal *CompatThreader::MakeEventSignal() | ||||
| { | ||||
| 	return new CompatEventSignal(); | ||||
| } | ||||
| 
 | ||||
| IThreadWorker *CompatThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded) | ||||
| { | ||||
| 	if (!threaded) | ||||
| 		return new BaseWorker(hooks); | ||||
|     return new CompatWorker(hooks); | ||||
| } | ||||
| 
 | ||||
| void CompatThreader::DestroyWorker(IThreadWorker *pWorker) | ||||
| { | ||||
| 	delete pWorker; | ||||
| } | ||||
| 
 | ||||
| IThreader *g_pThreader = &sCompatThreader; | ||||
| #if defined PLATFORM_POSIX | ||||
| #include "thread/PosixThreads.h" | ||||
| #elif defined PLATFORM_WINDOWS | ||||
| #include "thread/WinThreads.h" | ||||
| #endif | ||||
| 
 | ||||
| MainThreader g_MainThreader; | ||||
| IThreader *g_pThreader = &g_MainThreader; | ||||
| 
 | ||||
| class RegThreadStuff : public SMGlobalClass | ||||
| { | ||||
|  | ||||
| @ -32,13 +32,49 @@ | ||||
| #ifndef _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H | ||||
| #define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H | ||||
| 
 | ||||
| #include <mutex> | ||||
| 
 | ||||
| #include <IThreader.h> | ||||
| #include <am-thread-utils.h> | ||||
| #include <am-utility.h> | ||||
| 
 | ||||
| using namespace SourceMod; | ||||
| 
 | ||||
| class CompatMutex : public IMutex | ||||
| { | ||||
| public: | ||||
| 	bool TryLock() { | ||||
| 		return mutex_.TryLock(); | ||||
| 	} | ||||
| 	void Lock() { | ||||
| 		mutex_.Lock(); | ||||
| 	} | ||||
| 	void Unlock() { | ||||
| 		mutex_.Unlock(); | ||||
| 	} | ||||
| 	void DestroyThis() { | ||||
| 		delete this; | ||||
| 	} | ||||
| private: | ||||
| 	ke::Mutex mutex_; | ||||
| }; | ||||
| 
 | ||||
| class CompatCondVar : public IEventSignal | ||||
| { | ||||
| public: | ||||
| 	void Wait() { | ||||
| 		ke::AutoLock lock(&cv_); | ||||
| 		cv_.Wait(); | ||||
| 	} | ||||
| 	void Signal() { | ||||
| 		ke::AutoLock lock(&cv_); | ||||
| 		cv_.Notify(); | ||||
| 	} | ||||
| 	void DestroyThis() { | ||||
| 		delete this; | ||||
| 	} | ||||
| private: | ||||
| 	ke::ConditionVariable cv_; | ||||
| }; | ||||
| 
 | ||||
| extern IThreader *g_pThreader; | ||||
| 
 | ||||
| #endif //_INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
 | ||||
|  | ||||
| @ -56,7 +56,6 @@ | ||||
| #include "LibrarySys.h" | ||||
| #include "RootConsoleMenu.h" | ||||
| #include "CellArray.h" | ||||
| #include "smn_entitylump.h" | ||||
| #include <bridge/include/BridgeAPI.h> | ||||
| #include <bridge/include/IProviderCallbacks.h> | ||||
| 
 | ||||
| @ -90,8 +89,6 @@ CNativeOwner g_CoreNatives; | ||||
| PseudoAddressManager pseudoAddr; | ||||
| #endif | ||||
| 
 | ||||
| EntityLumpParseResult lastParseResult; | ||||
| 
 | ||||
| static void AddCorePhraseFile(const char *filename) | ||||
| { | ||||
| 	g_pCorePhrases->AddPhraseFile(filename); | ||||
| @ -138,35 +135,6 @@ static uint32_t ToPseudoAddress(void *addr) | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static void SetEntityLumpWritable(bool writable) | ||||
| { | ||||
| 	g_bLumpAvailableForWriting = writable; | ||||
| 	 | ||||
| 	// write-lock causes the map entities to be serialized out to string
 | ||||
| 	if (!writable) | ||||
| 	{ | ||||
| 		g_strMapEntities = lumpmanager->Dump(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static bool ParseEntityLumpString(const char *pMapEntities, int &status, size_t &position) | ||||
| { | ||||
| 	lastParseResult = lumpmanager->Parse(pMapEntities); | ||||
| 	status = static_cast<int>(lastParseResult.m_Status); | ||||
| 	position = static_cast<size_t>(lastParseResult.m_Position); | ||||
| 	return lastParseResult; | ||||
| } | ||||
| 
 | ||||
| // returns nullptr if the original lump failed to parse
 | ||||
| static const char* GetEntityLumpString() | ||||
| { | ||||
| 	if (!lastParseResult) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return g_strMapEntities.c_str(); | ||||
| } | ||||
| 
 | ||||
| // Defined in smn_filesystem.cpp.
 | ||||
| extern bool OnLogPrint(const char *msg); | ||||
| 
 | ||||
| @ -202,9 +170,6 @@ static sm_logic_t logic = | ||||
| 	CellArray::Free, | ||||
| 	FromPseudoAddress, | ||||
| 	ToPseudoAddress, | ||||
| 	SetEntityLumpWritable, | ||||
| 	ParseEntityLumpString, | ||||
| 	GetEntityLumpString, | ||||
| 	&g_PluginSys, | ||||
| 	&g_ShareSys, | ||||
| 	&g_Extensions, | ||||
|  | ||||
| @ -26,17 +26,16 @@ | ||||
| // or <http://www.sourcemod.net/license.php>.
 | ||||
| #include "frame_tasks.h" | ||||
| #include <am-vector.h> | ||||
| #include <utility> | ||||
| 
 | ||||
| using namespace SourceMod; | ||||
| 
 | ||||
| std::vector<ke::Function<void()>> sNextTasks; | ||||
| std::vector<ke::Function<void()>> sWorkTasks; | ||||
| ke::Vector<ke::Lambda<void()>> sNextTasks; | ||||
| ke::Vector<ke::Lambda<void()>> sWorkTasks; | ||||
| 
 | ||||
| void | ||||
| SourceMod::ScheduleTaskForNextFrame(ke::Function<void()>&& task) | ||||
| SourceMod::ScheduleTaskForNextFrame(ke::Lambda<void()>&& task) | ||||
| { | ||||
| 	sNextTasks.push_back(std::forward<decltype(task)>(task)); | ||||
| 	sNextTasks.append(ke::Forward<decltype(task)>(task)); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| @ -46,11 +45,11 @@ SourceMod::RunScheduledFrameTasks(bool simulating) | ||||
| 		return; | ||||
| 
 | ||||
| 	// Swap.
 | ||||
| 	std::vector<ke::Function<void()>> temp(std::move(sNextTasks)); | ||||
| 	sNextTasks = std::move(sWorkTasks); | ||||
| 	sWorkTasks = std::move(temp); | ||||
| 	ke::Vector<ke::Lambda<void()>> temp(ke::Move(sNextTasks)); | ||||
| 	sNextTasks = ke::Move(sWorkTasks); | ||||
| 	sWorkTasks = ke::Move(temp); | ||||
| 
 | ||||
| 	for (size_t i = 0; i < sWorkTasks.size(); i++) | ||||
| 	for (size_t i = 0; i < sWorkTasks.length(); i++) | ||||
| 		sWorkTasks[i](); | ||||
| 	sWorkTasks.clear(); | ||||
| } | ||||
| @ -31,7 +31,7 @@ | ||||
| 
 | ||||
| namespace SourceMod { | ||||
| 
 | ||||
| void ScheduleTaskForNextFrame(ke::Function<void()>&& task); | ||||
| void ScheduleTaskForNextFrame(ke::Lambda<void()>&& task); | ||||
| 
 | ||||
| void RunScheduledFrameTasks(bool simulating); | ||||
| 
 | ||||
|  | ||||
| @ -89,6 +89,6 @@ unsigned int UTIL_CRC32(const void *pdata, size_t data_length) | ||||
| 		crc = CRCTable[c] ^ (crc >> 8); | ||||
| 	} | ||||
| 
 | ||||
| 	return ~crc; | ||||
| 	return crc; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -75,11 +75,7 @@ static cell_t CreateArray(IPluginContext *pContext, const cell_t *params) | ||||
| 
 | ||||
| 	if (params[2]) | ||||
| 	{ | ||||
| 		if (!array->resize(params[2])) | ||||
| 		{ | ||||
| 			delete array; | ||||
| 			return pContext->ThrowNativeError("Failed to resize array to startsize \"%u\".", params[2]); | ||||
| 		} | ||||
| 		array->resize(params[2]); | ||||
| 	} | ||||
| 
 | ||||
| 	Handle_t hndl = handlesys->CreateHandle(htCellArray, array, pContext->GetIdentity(), g_pCoreIdent, NULL); | ||||
|  | ||||
| @ -83,48 +83,6 @@ static cell_t CreateStack(IPluginContext *pContext, const cell_t *params) | ||||
| 	return hndl; | ||||
| } | ||||
| 
 | ||||
| static cell_t ClearStack(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	CellArray *array; | ||||
| 	HandleError err; | ||||
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); | ||||
| 
 | ||||
| 	if ((err = handlesys->ReadHandle(params[1], htCellStack, &sec, (void **)&array)) != HandleError_None) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); | ||||
| 	} | ||||
| 
 | ||||
| 	array->clear(); | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static cell_t CloneStack(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	CellArray *oldArray; | ||||
| 	HandleError err; | ||||
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); | ||||
| 
 | ||||
| 	if ((err = handlesys->ReadHandle(params[1], htCellStack, &sec, (void **)&oldArray)) != HandleError_None) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); | ||||
| 	} | ||||
| 
 | ||||
| 	ICellArray *array = oldArray->clone(); | ||||
| 	if (!array) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Failed to clone stack. Out of memory."); | ||||
| 	} | ||||
| 
 | ||||
| 	Handle_t hndl = handlesys->CreateHandle(htCellStack, array, pContext->GetIdentity(), g_pCoreIdent, NULL); | ||||
| 	if (!hndl) | ||||
| 	{ | ||||
| 		delete array; | ||||
| 	} | ||||
| 
 | ||||
| 	return hndl; | ||||
| } | ||||
| 
 | ||||
| static cell_t PushStackCell(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	CellArray *array; | ||||
| @ -429,7 +387,6 @@ static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params) | ||||
| REGISTER_NATIVES(cellStackNatives) | ||||
| { | ||||
| 	{"CreateStack",					CreateStack}, | ||||
| 	{"CloneStack",					CloneStack}, | ||||
| 	{"IsStackEmpty",				IsStackEmpty}, | ||||
| 	{"PopStackArray",				PopStackArray}, | ||||
| 	{"PopStackCell",				PopStackCell}, | ||||
| @ -441,8 +398,6 @@ REGISTER_NATIVES(cellStackNatives) | ||||
| 
 | ||||
| 	// Transitional syntax support.
 | ||||
| 	{"ArrayStack.ArrayStack",		CreateStack}, | ||||
| 	{"ArrayStack.Clear",			ClearStack}, | ||||
| 	{"ArrayStack.Clone",			CloneStack}, | ||||
| 	{"ArrayStack.Pop",				ArrayStack_Pop}, | ||||
| 	{"ArrayStack.PopString",		ArrayStack_PopString}, | ||||
| 	{"ArrayStack.PopArray",			ArrayStack_PopArray}, | ||||
|  | ||||
| @ -30,10 +30,9 @@ | ||||
|  */ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include "common_logic.h" | ||||
| #include <am-autoptr.h> | ||||
| #include <am-moveable.h> | ||||
| #include <am-refcounting.h> | ||||
| #include <sm_stringhashmap.h> | ||||
| #include "sm_memtable.h" | ||||
| @ -104,7 +103,7 @@ public: | ||||
| 		assert(isArray()); | ||||
| 		return reinterpret_cast<cell_t *>(raw()->base()); | ||||
| 	} | ||||
| 	char *c_str() const { | ||||
| 	char *chars() const { | ||||
| 		assert(isString()); | ||||
| 		return reinterpret_cast<char *>(raw()->base()); | ||||
| 	} | ||||
| @ -183,7 +182,7 @@ struct TrieSnapshot | ||||
| 	} | ||||
| 
 | ||||
| 	size_t length; | ||||
| 	std::unique_ptr<int[]> keys; | ||||
| 	ke::AutoPtr<int[]> keys; | ||||
| 	BaseStringTable strings; | ||||
| }; | ||||
| 
 | ||||
| @ -350,27 +349,6 @@ static cell_t SetTrieString(IPluginContext *pContext, const cell_t *params) | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static cell_t ContainsKeyInTrie(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	CellTrie *pTrie; | ||||
| 	HandleError err; | ||||
| 	HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent); | ||||
| 
 | ||||
| 	Handle_t hndl = params[1]; | ||||
| 
 | ||||
| 	if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie)) != HandleError_None) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err); | ||||
| 	} | ||||
| 
 | ||||
| 	char *key; | ||||
| 	pContext->LocalToString(params[2], &key); | ||||
| 
 | ||||
| 	StringHashMap<Entry>::Result r = pTrie->map.find(key); | ||||
| 
 | ||||
| 	return r.found() ? 1 : 0; | ||||
| } | ||||
| 
 | ||||
| static cell_t RemoveFromTrie(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	CellTrie *pTrie; | ||||
| @ -539,7 +517,7 @@ static cell_t GetTrieString(IPluginContext *pContext, const cell_t *params) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	size_t written; | ||||
| 	pContext->StringToLocalUTF8(params[3], params[4], r->value.c_str(), &written); | ||||
| 	pContext->StringToLocalUTF8(params[3], params[4], r->value.chars(), &written); | ||||
| 
 | ||||
| 	*pSize = (cell_t)written; | ||||
| 	return 1; | ||||
| @ -579,10 +557,10 @@ static cell_t CreateTrieSnapshot(IPluginContext *pContext, const cell_t *params) | ||||
| 
 | ||||
| 	TrieSnapshot *snapshot = new TrieSnapshot; | ||||
| 	snapshot->length = pTrie->map.elements(); | ||||
| 	snapshot->keys = std::make_unique<int[]>(snapshot->length); | ||||
| 	snapshot->keys = ke::MakeUnique<int[]>(snapshot->length); | ||||
| 	size_t i = 0; | ||||
| 	for (StringHashMap<Entry>::iterator iter = pTrie->map.iter(); !iter.empty(); iter.next(), i++) | ||||
| 		 snapshot->keys[i] = snapshot->strings.AddString(iter->key.c_str(), iter->key.length()); | ||||
| 		snapshot->keys[i] = snapshot->strings.AddString(iter->key.chars(), iter->key.length()); | ||||
| 	assert(i == snapshot->length); | ||||
| 
 | ||||
| 	if ((hndl = handlesys->CreateHandle(htSnapshot, snapshot, pContext->GetIdentity(), g_pCoreIdent, NULL)) | ||||
| @ -657,56 +635,6 @@ static cell_t GetTrieSnapshotKey(IPluginContext *pContext, const cell_t *params) | ||||
| 	return written; | ||||
| } | ||||
| 
 | ||||
| static cell_t CloneTrie(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	HandleError err; | ||||
| 	HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent); | ||||
| 
 | ||||
| 	CellTrie *pOldTrie; | ||||
| 	if ((err = handlesys->ReadHandle(params[1], htCellTrie, &sec, (void **)&pOldTrie)) | ||||
| 		!= HandleError_None) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err); | ||||
| 	} | ||||
| 
 | ||||
| 	CellTrie *pNewTrie = new CellTrie; | ||||
| 	Handle_t hndl = handlesys->CreateHandle(htCellTrie, pNewTrie, pContext->GetIdentity(), g_pCoreIdent, NULL); | ||||
| 	if (!hndl) | ||||
| 	{ | ||||
| 		delete pNewTrie; | ||||
| 		return hndl; | ||||
| 	} | ||||
| 
 | ||||
| 	for (StringHashMap<Entry>::iterator it = pOldTrie->map.iter(); !it.empty(); it.next()) | ||||
| 	{ | ||||
| 		const char *key = it->key.c_str(); | ||||
| 		StringHashMap<Entry>::Insert insert = pNewTrie->map.findForAdd(key); | ||||
| 		if (pNewTrie->map.add(insert, key)) | ||||
| 		{ | ||||
| 			StringHashMap<Entry>::Result result = pOldTrie->map.find(key); | ||||
| 			if (result->value.isCell()) | ||||
| 			{ | ||||
| 				insert->value.setCell(result->value.cell()); | ||||
| 			} | ||||
| 			else if (result->value.isString()) | ||||
| 			{ | ||||
| 				insert->value.setString(result->value.c_str()); | ||||
| 			} | ||||
| 			else if (result->value.isArray()) | ||||
| 			{ | ||||
| 				insert->value.setArray(result->value.array(), result->value.arrayLength()); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				handlesys->FreeHandle(hndl, NULL); | ||||
| 				return pContext->ThrowNativeError("Unhandled data type encountered, file a bug and reference pr #852"); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return hndl; | ||||
| } | ||||
| 
 | ||||
| REGISTER_NATIVES(trieNatives) | ||||
| { | ||||
| 	{"ClearTrie",				ClearTrie}, | ||||
| @ -731,14 +659,12 @@ REGISTER_NATIVES(trieNatives) | ||||
| 	{"StringMap.GetArray",		GetTrieArray}, | ||||
| 	{"StringMap.GetString",		GetTrieString}, | ||||
| 	{"StringMap.GetValue",		GetTrieValue}, | ||||
| 	{"StringMap.ContainsKey",	ContainsKeyInTrie}, | ||||
| 	{"StringMap.Remove",		RemoveFromTrie}, | ||||
| 	{"StringMap.SetArray",		SetTrieArray}, | ||||
| 	{"StringMap.SetString",		SetTrieString}, | ||||
| 	{"StringMap.SetValue",		SetTrieValue}, | ||||
| 	{"StringMap.Size.get",		GetTrieSize}, | ||||
| 	{"StringMap.Snapshot",		CreateTrieSnapshot}, | ||||
| 	{"StringMap.Clone",			CloneTrie}, | ||||
| 
 | ||||
| 	{"StringMapSnapshot.Length.get",	TrieSnapshotLength}, | ||||
| 	{"StringMapSnapshot.KeyBufferSize", TrieSnapshotKeyBufferSize}, | ||||
|  | ||||
| @ -127,8 +127,6 @@ static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	g_pSM->SetGlobalTarget(index); | ||||
| 
 | ||||
| 	char buffer[1024]; | ||||
| 	char *fmt; | ||||
| 	int arg = 3; | ||||
|  | ||||
| @ -32,7 +32,6 @@ | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| #include <list> | ||||
| #include "common_logic.h" | ||||
| #include "Logger.h" | ||||
| 
 | ||||
| @ -46,7 +45,6 @@ | ||||
| 
 | ||||
| #if defined PLATFORM_WINDOWS | ||||
| #include <windows.h> | ||||
| #include "sm_invalidparamhandler.h" | ||||
| #elif defined PLATFORM_POSIX | ||||
| #include <limits.h> | ||||
| #include <unistd.h> | ||||
| @ -57,7 +55,6 @@ | ||||
| #include <bridge/include/CoreProvider.h> | ||||
| #include <bridge/include/IScriptManager.h> | ||||
| #include <bridge/include/IExtensionBridge.h> | ||||
| #include <sh_vector.h> | ||||
| 
 | ||||
| using namespace SourceMod; | ||||
| using namespace SourcePawn; | ||||
| @ -68,7 +65,7 @@ HandleType_t g_FrameIter; | ||||
| 
 | ||||
| IForward *g_OnLogAction = NULL; | ||||
| 
 | ||||
| ConVar *g_datetime_format = NULL; | ||||
| static ConVar *sm_datetime_format = NULL; | ||||
| 
 | ||||
| class CoreNativeHelpers :  | ||||
| 	public SMGlobalClass, | ||||
| @ -94,7 +91,7 @@ public: | ||||
| 			Param_Cell, | ||||
| 			Param_String); | ||||
| 		 | ||||
| 		g_datetime_format = bridge->FindConVar("sm_datetime_format"); | ||||
| 		sm_datetime_format = bridge->FindConVar("sm_datetime_format"); | ||||
| 	} | ||||
| 	void OnHandleDestroy(HandleType_t type, void *object) | ||||
| 	{ | ||||
| @ -116,71 +113,6 @@ public: | ||||
| 	} | ||||
| } g_CoreNativeHelpers; | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Nearly identical to the standard core plugin iterator | ||||
|  * with one key difference. Next doesn't increment the counter | ||||
|  * the first time it is ran. This is a hack for the methodmap.. | ||||
|  */ | ||||
| class CMMPluginIterator | ||||
| 	: public IPluginIterator, | ||||
| 	  public IPluginsListener | ||||
| { | ||||
| public: | ||||
| 	CMMPluginIterator(const CVector<SMPlugin *> *list) | ||||
| 		: m_hasStarted(false) | ||||
| 	{ | ||||
| 		for(auto iter = list->begin(); iter != list->end(); ++iter) { | ||||
| 			m_list.push_back(*iter); | ||||
| 		} | ||||
| 		scripts->FreePluginList(list); | ||||
| 
 | ||||
| 		m_current = m_list.begin(); | ||||
| 
 | ||||
| 		scripts->AddPluginsListener(this); | ||||
| 	} | ||||
| 
 | ||||
| 	virtual ~CMMPluginIterator() | ||||
| 	{ | ||||
| 		scripts->RemovePluginsListener(this); | ||||
| 	} | ||||
| 	virtual bool MorePlugins() override | ||||
| 	{ | ||||
| 		return (m_current != m_list.end()); | ||||
| 	} | ||||
| 	virtual IPlugin *GetPlugin() override | ||||
| 	{ | ||||
| 		return *m_current; | ||||
| 	} | ||||
| 	virtual void NextPlugin() override | ||||
| 	{ | ||||
| 		if(!m_hasStarted) | ||||
| 		{ | ||||
| 			m_hasStarted = true; | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		m_current++; | ||||
| 	} | ||||
| 	virtual void Release() override | ||||
| 	{ | ||||
| 		delete this; | ||||
| 	} | ||||
| 
 | ||||
| public: | ||||
| 	virtual void OnPluginDestroyed(IPlugin *plugin) override | ||||
| 	{ | ||||
| 		if (*m_current == plugin) | ||||
| 			m_current = m_list.erase(m_current); | ||||
| 		else | ||||
| 			m_list.remove(static_cast<SMPlugin *>(plugin)); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	std::list<SMPlugin *> m_list; | ||||
| 	std::list<SMPlugin *>::iterator m_current; | ||||
| 	bool m_hasStarted; | ||||
| }; | ||||
| 
 | ||||
| void LogAction(Handle_t hndl, int type, int client, int target, const char *message) | ||||
| { | ||||
| 	if (g_OnLogAction->GetFunctionCount()) | ||||
| @ -213,7 +145,7 @@ void LogAction(Handle_t hndl, int type, int client, int target, const char *mess | ||||
| 	g_Logger.LogMessage("[%s] %s", logtag, message); | ||||
| } | ||||
|   | ||||
| static cell_t ThrowError(IPluginContext *pContext, const cell_t *params) | ||||
|  static cell_t ThrowError(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	char buffer[512]; | ||||
| 
 | ||||
| @ -241,6 +173,19 @@ static cell_t GetTime(IPluginContext *pContext, const cell_t *params) | ||||
| 	return static_cast<cell_t>(t); | ||||
| } | ||||
| 
 | ||||
| #if defined SUBPLATFORM_SECURECRT | ||||
| void _ignore_invalid_parameter( | ||||
| 						const wchar_t * expression, | ||||
| 						const wchar_t * function,  | ||||
| 						const wchar_t * file,  | ||||
| 						unsigned int line, | ||||
| 						uintptr_t pReserved | ||||
| 						) | ||||
| { | ||||
| 	/* Wow we don't care, thanks Microsoft. */ | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static cell_t FormatTime(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	char *format, *buffer; | ||||
| @ -249,20 +194,19 @@ static cell_t FormatTime(IPluginContext *pContext, const cell_t *params) | ||||
| 
 | ||||
| 	if (format == NULL) | ||||
| 	{ | ||||
| 		format = const_cast<char *>(bridge->GetCvarString(g_datetime_format)); | ||||
| 		format = const_cast<char *>(bridge->GetCvarString(sm_datetime_format)); | ||||
| 	} | ||||
| 
 | ||||
| 	time_t t; | ||||
| 	size_t written = 0; | ||||
| 	 | ||||
| 	// scope for InvalidParameterHandler
 | ||||
| 	{ | ||||
| #ifdef PLATFORM_WINDOWS | ||||
| 		InvalidParameterHandler p; | ||||
| #if defined SUBPLATFORM_SECURECRT | ||||
| 	_invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter); | ||||
| #endif | ||||
| 
 | ||||
| 	time_t t = (params[4] == -1) ? g_pSM->GetAdjustedTime() : (time_t)params[4]; | ||||
| 	size_t written = strftime(buffer, params[2], format, localtime(&t)); | ||||
| 
 | ||||
| #if defined SUBPLATFORM_SECURECRT | ||||
| 	_set_invalid_parameter_handler(handler); | ||||
| #endif | ||||
| 		t = (params[4] == -1) ? g_pSM->GetAdjustedTime() : (time_t)params[4]; | ||||
| 		written = strftime(buffer, params[2], format, localtime(&t)); | ||||
| 	} | ||||
| 
 | ||||
| 	if (params[2] && format[0] != '\0' && !written) | ||||
| 	{ | ||||
| @ -331,60 +275,6 @@ static cell_t ReadPlugin(IPluginContext *pContext, const cell_t *params) | ||||
| 	return pPlugin->GetMyHandle(); | ||||
| } | ||||
| 
 | ||||
| static cell_t PluginIterator_Create(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	IPluginIterator *iter = new CMMPluginIterator(scripts->ListPlugins()); | ||||
| 
 | ||||
| 	Handle_t hndl = handlesys->CreateHandle(g_PlIter, iter, pContext->GetIdentity(), g_pCoreIdent, NULL); | ||||
| 
 | ||||
| 	if (hndl == BAD_HANDLE) | ||||
| 	{ | ||||
| 		iter->Release(); | ||||
| 	} | ||||
| 
 | ||||
| 	return hndl; | ||||
| } | ||||
| 
 | ||||
| static cell_t PluginIterator_Next(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	Handle_t hndl = (Handle_t)params[1]; | ||||
| 	HandleSecurity sec{pContext->GetIdentity(), g_pCoreIdent}; | ||||
| 	HandleError err{}; | ||||
| 	IPluginIterator *pIter = nullptr; | ||||
| 
 | ||||
| 	if ((err=handlesys->ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); | ||||
| 	} | ||||
| 
 | ||||
| 	if(!pIter->MorePlugins()) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	pIter->NextPlugin(); | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static cell_t PluginIterator_Plugin_get(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	Handle_t hndl = (Handle_t)params[1]; | ||||
| 	HandleSecurity sec{pContext->GetIdentity(), g_pCoreIdent}; | ||||
| 	HandleError err{}; | ||||
| 	IPluginIterator *pIter = nullptr; | ||||
| 
 | ||||
| 	if ((err=handlesys->ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); | ||||
| 	} | ||||
| 	 | ||||
| 	IPlugin *pPlugin = pIter->GetPlugin(); | ||||
| 	if (!pPlugin) | ||||
| 	{ | ||||
| 		return BAD_HANDLE; | ||||
| 	} | ||||
| 
 | ||||
| 	return pPlugin->GetMyHandle(); | ||||
| } | ||||
| 
 | ||||
| IPlugin *GetPluginFromHandle(IPluginContext *pContext, Handle_t hndl) | ||||
| { | ||||
| 	if (hndl == BAD_HANDLE) | ||||
| @ -868,34 +758,18 @@ static cell_t StoreToAddress(IPluginContext *pContext, const cell_t *params) | ||||
| 
 | ||||
| 	NumberType size = static_cast<NumberType>(params[3]); | ||||
| 
 | ||||
| 	// new parameter added after SM 1.10; defaults to true for backwards compatibility
 | ||||
| 	bool updateMemAccess = true; | ||||
| 	if (params[0] >= 4) | ||||
| 	{ | ||||
| 		updateMemAccess = params[4]; | ||||
| 	} | ||||
| 
 | ||||
| 	switch(size) | ||||
| 	{ | ||||
| 	case NumberType_Int8: | ||||
| 		if (updateMemAccess) | ||||
| 		{ | ||||
| 		SourceHook::SetMemAccess(addr, sizeof(uint8_t), SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC); | ||||
| 		} | ||||
| 		*reinterpret_cast<uint8_t*>(addr) = data; | ||||
| 		break; | ||||
| 	case NumberType_Int16: | ||||
| 		if (updateMemAccess) | ||||
| 		{ | ||||
| 		SourceHook::SetMemAccess(addr, sizeof(uint16_t), SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC); | ||||
| 		} | ||||
| 		*reinterpret_cast<uint16_t*>(addr) = data; | ||||
| 		break; | ||||
| 	case NumberType_Int32: | ||||
| 		if (updateMemAccess) | ||||
| 		{ | ||||
| 		SourceHook::SetMemAccess(addr, sizeof(uint32_t), SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC); | ||||
| 		} | ||||
| 		*reinterpret_cast<uint32_t*>(addr) = data; | ||||
| 		break; | ||||
| 	default: | ||||
| @ -1069,16 +943,16 @@ static cell_t LogStackTrace(IPluginContext *pContext, const cell_t *params) | ||||
| 	g_pSM->FormatString(buffer, sizeof(buffer), pContext, params, 1); | ||||
| 
 | ||||
| 	IFrameIterator *it = pContext->CreateFrameIterator(); | ||||
| 	std::vector<std::string> arr = g_DbgReporter.GetStackTrace(it); | ||||
| 	ke::Vector<ke::AString> arr = g_DbgReporter.GetStackTrace(it); | ||||
| 	pContext->DestroyFrameIterator(it); | ||||
| 
 | ||||
| 	IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext()); | ||||
| 
 | ||||
| 	g_Logger.LogError("[SM] Stack trace requested: %s", buffer); | ||||
| 	g_Logger.LogError("[SM] Called from: %s", pPlugin->GetFilename()); | ||||
| 	for (size_t i = 0; i < arr.size(); ++i) | ||||
| 	for (size_t i = 0; i < arr.length(); ++i) | ||||
| 	{ | ||||
| 		g_Logger.LogError("%s", arr[i].c_str()); | ||||
| 		g_Logger.LogError("%s", arr[i].chars()); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| @ -1121,9 +995,5 @@ REGISTER_NATIVES(coreNatives) | ||||
| 	{"FrameIterator.LineNumber.get",			FrameIterator_LineNumber}, | ||||
| 	{"FrameIterator.GetFunctionName",			FrameIterator_GetFunctionName}, | ||||
| 	{"FrameIterator.GetFilePath",				FrameIterator_GetFilePath}, | ||||
| 
 | ||||
| 	{"PluginIterator.PluginIterator", 			PluginIterator_Create}, | ||||
| 	{"PluginIterator.Next", 					PluginIterator_Next}, | ||||
| 	{"PluginIterator.Plugin.get", 				PluginIterator_Plugin_get}, | ||||
| 	{NULL,						NULL}, | ||||
| }; | ||||
|  | ||||
| @ -29,8 +29,6 @@ | ||||
|  * Version: $Id$ | ||||
|  */ | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include "common_logic.h" | ||||
| #include "Database.h" | ||||
| #include "ExtensionSys.h" | ||||
| @ -64,11 +62,11 @@ struct Transaction | ||||
| { | ||||
| 	struct Entry | ||||
| 	{ | ||||
| 		std::string query; | ||||
| 		ke::AString query; | ||||
| 		cell_t data; | ||||
| 	}; | ||||
| 
 | ||||
| 	std::vector<Entry> entries; | ||||
| 	ke::Vector<Entry> entries; | ||||
| }; | ||||
| 
 | ||||
| class DatabaseHelpers :  | ||||
| @ -457,7 +455,7 @@ static cell_t ConnectToDbAsync(IPluginContext *pContext, const cell_t *params, A | ||||
| 			g_pSM->Format(error,  | ||||
| 				sizeof(error),  | ||||
| 				"Could not find driver \"%s\"",  | ||||
| 				pInfo->driver[0] == '\0' ? g_DBMan.GetDefaultDriverName().c_str() : pInfo->driver); | ||||
| 				pInfo->driver[0] == '\0' ? g_DBMan.GetDefaultDriverName().chars() : pInfo->driver); | ||||
| 		} else if (!driver->IsThreadSafe()) { | ||||
| 			g_pSM->Format(error, | ||||
| 				sizeof(error), | ||||
| @ -1540,9 +1538,9 @@ static cell_t SQL_AddQuery(IPluginContext *pContext, const cell_t *params) | ||||
| 	Transaction::Entry entry; | ||||
| 	entry.query = query; | ||||
| 	entry.data = params[3]; | ||||
| 	txn->entries.push_back(std::move(entry)); | ||||
| 	txn->entries.append(ke::Move(entry)); | ||||
| 
 | ||||
| 	return cell_t(txn->entries.size() - 1); | ||||
| 	return cell_t(txn->entries.length() - 1); | ||||
| } | ||||
| 
 | ||||
| class TTransactOp : public IDBThreadOperation | ||||
| @ -1564,7 +1562,7 @@ public: | ||||
| 
 | ||||
| 	~TTransactOp() | ||||
| 	{ | ||||
| 		for (size_t i = 0; i < results_.size(); i++) | ||||
| 		for (size_t i = 0; i < results_.length(); i++) | ||||
| 			results_[i]->Destroy(); | ||||
| 		results_.clear(); | ||||
| 	} | ||||
| @ -1585,7 +1583,7 @@ public: | ||||
| private: | ||||
| 	bool Succeeded() const | ||||
| 	{ | ||||
| 		return error_.size() == 0; | ||||
| 		return error_.length() == 0; | ||||
| 	} | ||||
| 
 | ||||
| 	void SetDbError() | ||||
| @ -1617,16 +1615,16 @@ private: | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		for (size_t i = 0; i < txn_->entries.size(); i++) | ||||
| 		for (size_t i = 0; i < txn_->entries.length(); i++) | ||||
| 		{ | ||||
| 			Transaction::Entry &entry = txn_->entries[i]; | ||||
| 			IQuery *result = Exec(entry.query.c_str()); | ||||
| 			IQuery *result = Exec(entry.query.chars()); | ||||
| 			if (!result) | ||||
| 			{ | ||||
| 				failIndex_ = (cell_t)i; | ||||
| 				return; | ||||
| 			} | ||||
| 			results_.push_back(result); | ||||
| 			results_.append(result); | ||||
| 		} | ||||
| 
 | ||||
| 		if (!db_->DoSimpleQuery("COMMIT")) | ||||
| @ -1667,11 +1665,11 @@ private: | ||||
| 		// Add an extra refcount for the handle.
 | ||||
| 		db_->AddRef(); | ||||
| 
 | ||||
| 		assert(results_.size() == txn_->entries.size()); | ||||
| 		assert(results_.length() == txn_->entries.length()); | ||||
| 
 | ||||
| 		std::unique_ptr<cell_t[]> data = std::make_unique<cell_t[]>(results_.size()); | ||||
| 		std::unique_ptr<cell_t[]> handles = std::make_unique<cell_t[]>(results_.size()); | ||||
| 		for (size_t i = 0; i < results_.size(); i++) | ||||
| 		ke::AutoPtr<cell_t[]> data = ke::MakeUnique<cell_t[]>(results_.length()); | ||||
| 		ke::AutoPtr<cell_t[]> handles = ke::MakeUnique<cell_t[]>(results_.length()); | ||||
| 		for (size_t i = 0; i < results_.length(); i++) | ||||
| 		{ | ||||
| 			CombinedQuery *obj = new CombinedQuery(results_[i], db_); | ||||
| 			Handle_t rh = CreateLocalHandle(hCombinedQueryType, obj, &sec); | ||||
| @ -1682,7 +1680,7 @@ private: | ||||
| 				delete obj; | ||||
| 				for (size_t iter = 0; iter < i; iter++) | ||||
| 					handlesys->FreeHandle(handles[iter], &sec); | ||||
| 				for (size_t iter = i; iter < results_.size(); iter++) | ||||
| 				for (size_t iter = i; iter < results_.length(); iter++) | ||||
| 					results_[iter]->Destroy(); | ||||
| 				handlesys->FreeHandle(dbh, &sec); | ||||
| 				results_.clear(); | ||||
| @ -1698,15 +1696,15 @@ private: | ||||
| 		{ | ||||
| 			success_->PushCell(dbh); | ||||
| 			success_->PushCell(data_); | ||||
| 			success_->PushCell(txn_->entries.size()); | ||||
| 			success_->PushArray(handles.get(), results_.size()); | ||||
| 			success_->PushArray(data.get(), results_.size()); | ||||
| 			success_->PushCell(txn_->entries.length()); | ||||
| 			success_->PushArray(handles.get(), results_.length()); | ||||
| 			success_->PushArray(data.get(), results_.length()); | ||||
| 			success_->Execute(NULL); | ||||
| 		} | ||||
| 
 | ||||
| 		// Cleanup. Note we clear results_, since freeing their handles will
 | ||||
| 		// call Destroy(), and we don't want to double-free in ~TTransactOp.
 | ||||
| 		for (size_t i = 0; i < results_.size(); i++) | ||||
| 		for (size_t i = 0; i < results_.length(); i++) | ||||
| 			handlesys->FreeHandle(handles[i], &sec); | ||||
| 		handlesys->FreeHandle(dbh, &sec); | ||||
| 		results_.clear(); | ||||
| @ -1730,8 +1728,8 @@ public: | ||||
| 		{ | ||||
| 			HandleSecurity sec(ident_, g_pCoreIdent); | ||||
| 
 | ||||
| 			std::unique_ptr<cell_t[]> data = std::make_unique<cell_t[]>(txn_->entries.size()); | ||||
| 			for (size_t i = 0; i < txn_->entries.size(); i++) | ||||
| 			ke::AutoPtr<cell_t[]> data = ke::MakeUnique<cell_t[]>(txn_->entries.length()); | ||||
| 			for (size_t i = 0; i < txn_->entries.length(); i++) | ||||
| 				data[i] = txn_->entries[i].data; | ||||
| 
 | ||||
| 			Handle_t dbh = CreateLocalHandle(g_DBMan.GetDatabaseType(), db_, &sec); | ||||
| @ -1745,10 +1743,10 @@ public: | ||||
| 			{ | ||||
| 				failure_->PushCell(dbh); | ||||
| 				failure_->PushCell(data_); | ||||
| 				failure_->PushCell(txn_->entries.size()); | ||||
| 				failure_->PushString(error_.c_str()); | ||||
| 				failure_->PushCell(txn_->entries.length()); | ||||
| 				failure_->PushString(error_.chars()); | ||||
| 				failure_->PushCell(failIndex_); | ||||
| 				failure_->PushArray(data.get(), txn_->entries.size()); | ||||
| 				failure_->PushArray(data.get(), txn_->entries.length()); | ||||
| 				failure_->Execute(NULL); | ||||
| 			} | ||||
| 
 | ||||
| @ -1764,8 +1762,8 @@ private: | ||||
| 	IPluginFunction *failure_; | ||||
| 	cell_t data_; | ||||
| 	AutoHandleRooter autoHandle_; | ||||
| 	std::string error_; | ||||
| 	std::vector<IQuery *> results_; | ||||
| 	ke::AString error_; | ||||
| 	ke::Vector<IQuery *> results_; | ||||
| 	cell_t failIndex_; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -61,7 +61,7 @@ public: | ||||
| 	} | ||||
| 	void OnHandleDestroy(HandleType_t type, void *object) | ||||
| 	{ | ||||
| 		delete reinterpret_cast<CDataPack *>(object); | ||||
| 		CDataPack::Free(reinterpret_cast<CDataPack *>(object)); | ||||
| 	} | ||||
| 	bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) | ||||
| 	{ | ||||
| @ -73,7 +73,7 @@ public: | ||||
| 
 | ||||
| static cell_t smn_CreateDataPack(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	CDataPack *pDataPack = new CDataPack(); | ||||
| 	CDataPack *pDataPack = CDataPack::New(); | ||||
| 
 | ||||
| 	if (!pDataPack) | ||||
| 	{ | ||||
| @ -166,62 +166,6 @@ static cell_t smn_WritePackString(IPluginContext *pContext, const cell_t *params | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static cell_t smn_WritePackCellArray(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	HandleError herr; | ||||
| 	HandleSecurity sec; | ||||
| 	sec.pOwner = pContext->GetIdentity(); | ||||
| 	sec.pIdentity = g_pCoreIdent; | ||||
| 
 | ||||
| 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||
| 	CDataPack *pDataPack = nullptr; | ||||
| 	if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) | ||||
| 		!= HandleError_None) | ||||
| 	{ | ||||
| 		pContext->ReportError("Invalid data pack handle %x (error %d).", hndl, herr); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!params[4]) | ||||
| 	{ | ||||
| 		pDataPack->RemoveItem(); | ||||
| 	} | ||||
| 
 | ||||
| 	cell_t *pArray; | ||||
| 	pContext->LocalToPhysAddr(params[2], &pArray); | ||||
| 	pDataPack->PackCellArray(pArray, params[3]); | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static cell_t smn_WritePackFloatArray(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	HandleError herr; | ||||
| 	HandleSecurity sec; | ||||
| 	sec.pOwner = pContext->GetIdentity(); | ||||
| 	sec.pIdentity = g_pCoreIdent; | ||||
| 
 | ||||
| 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||
| 	CDataPack *pDataPack = nullptr; | ||||
| 	if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) | ||||
| 		!= HandleError_None) | ||||
| 	{ | ||||
| 		pContext->ReportError("Invalid data pack handle %x (error %d).", hndl, herr); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!params[4]) | ||||
| 	{ | ||||
| 		pDataPack->RemoveItem(); | ||||
| 	} | ||||
| 
 | ||||
| 	cell_t *pArray; | ||||
| 	pContext->LocalToPhysAddr(params[2], &pArray); | ||||
| 	pDataPack->PackFloatArray(pArray, params[3]); | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static cell_t smn_WritePackFunction(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||
| @ -368,108 +312,6 @@ static cell_t smn_ReadPackFunction(IPluginContext *pContext, const cell_t *param | ||||
| 	return pDataPack->ReadFunction(); | ||||
| } | ||||
| 
 | ||||
| static cell_t smn_ReadPackCellArray(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	HandleError herr;  | ||||
| 	HandleSecurity sec; | ||||
| 	sec.pOwner = pContext->GetIdentity(); | ||||
| 	sec.pIdentity = g_pCoreIdent; | ||||
| 
 | ||||
| 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||
| 	CDataPack *pDataPack = nullptr; | ||||
| 	if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) | ||||
| 		!= HandleError_None) | ||||
| 	{ | ||||
| 		pContext->ReportError("Invalid data pack handle %x (error %d).", hndl, herr); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!pDataPack->IsReadable()) | ||||
| 	{ | ||||
| 		pContext->ReportError("Data pack operation is out of bounds."); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (pDataPack->GetCurrentType() != CDataPackType::CellArray) | ||||
| 	{ | ||||
| 		pContext->ReportError("Invalid data pack type (got %d / expected %d).", pDataPack->GetCurrentType(), CDataPackType::CellArray); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	cell_t packCount = 0; | ||||
| 	cell_t *pData = pDataPack->ReadCellArray(&packCount); | ||||
| 	if(pData == nullptr || packCount == 0) | ||||
| 	{ | ||||
| 		pContext->ReportError("Invalid data pack operation: current position isn't an array!"); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	cell_t count = params[3]; | ||||
| 	if(packCount > count) | ||||
| 	{ | ||||
| 		pContext->ReportError("Input buffer too small (needed %d, got %d).", packCount, count); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	 | ||||
| 	cell_t *pArray; | ||||
| 	pContext->LocalToPhysAddr(params[2], &pArray); | ||||
| 
 | ||||
| 	memcpy(pArray, pData, sizeof(cell_t) * count); | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static cell_t smn_ReadPackFloatArray(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	HandleError herr; | ||||
| 	HandleSecurity sec; | ||||
| 	sec.pOwner = pContext->GetIdentity(); | ||||
| 	sec.pIdentity = g_pCoreIdent; | ||||
| 
 | ||||
| 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||
| 	CDataPack *pDataPack = nullptr; | ||||
| 	if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) | ||||
| 		!= HandleError_None) | ||||
| 	{ | ||||
| 		pContext->ReportError("Invalid data pack handle %x (error %d).", hndl, herr); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!pDataPack->IsReadable()) | ||||
| 	{ | ||||
| 		pContext->ReportError("Data pack operation is out of bounds."); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (pDataPack->GetCurrentType() != CDataPackType::FloatArray) | ||||
| 	{ | ||||
| 		pContext->ReportError("Invalid data pack type (got %d / expected %d).", pDataPack->GetCurrentType(), CDataPackType::FloatArray); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	cell_t packCount = 0; | ||||
| 	cell_t *pData = pDataPack->ReadFloatArray(&packCount); | ||||
| 	if(pData == nullptr || packCount == 0) | ||||
| 	{ | ||||
| 		pContext->ReportError("Invalid data pack operation: current position isn't an array!"); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	cell_t count = params[3]; | ||||
| 	if(packCount > count) | ||||
| 	{ | ||||
| 		pContext->ReportError("Input buffer too small (needed %d, got %d).", packCount, count); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	cell_t *pArray; | ||||
| 	pContext->LocalToPhysAddr(params[2], &pArray); | ||||
| 
 | ||||
| 	memcpy(pArray, pData, sizeof(cell_t) * count); | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static cell_t smn_ResetPack(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||
| @ -584,14 +426,10 @@ REGISTER_NATIVES(datapacknatives) | ||||
| 	{"DataPack.WriteFloat",			smn_WritePackFloat}, | ||||
| 	{"DataPack.WriteString",		smn_WritePackString}, | ||||
| 	{"DataPack.WriteFunction",		smn_WritePackFunction}, | ||||
| 	{"DataPack.WriteCellArray",		smn_WritePackCellArray}, | ||||
| 	{"DataPack.WriteFloatArray",	smn_WritePackFloatArray}, | ||||
| 	{"DataPack.ReadCell",			smn_ReadPackCell}, | ||||
| 	{"DataPack.ReadFloat",			smn_ReadPackFloat}, | ||||
| 	{"DataPack.ReadString",			smn_ReadPackString}, | ||||
| 	{"DataPack.ReadFunction",		smn_ReadPackFunction}, | ||||
| 	{"DataPack.ReadCellArray",		smn_ReadPackCellArray}, | ||||
| 	{"DataPack.ReadFloatArray",		smn_ReadPackFloatArray}, | ||||
| 	{"DataPack.Reset",				smn_ResetPack}, | ||||
| 	{"DataPack.Position.get",		smn_GetPackPosition}, | ||||
| 	{"DataPack.Position.set",		smn_SetPackPosition}, | ||||
|  | ||||
| @ -1,367 +0,0 @@ | ||||
| /**
 | ||||
|  * vim: set ts=4 : | ||||
|  * ============================================================================= | ||||
|  * Entity Lump Manager | ||||
|  * Copyright (C) 2021-2022 AlliedModders LLC.  All rights reserved. | ||||
|  * ============================================================================= | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it under | ||||
|  * the terms of the GNU General Public License, version 3.0, as published by the | ||||
|  * Free Software Foundation. | ||||
|  *  | ||||
|  * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||||
|  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more | ||||
|  * details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along with | ||||
|  * this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  * As a special exception, AlliedModders LLC gives you permission to link the | ||||
|  * code of this program (as well as its derivative works) to "Half-Life 2," the | ||||
|  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software | ||||
|  * by the Valve Corporation.  You must obey the GNU General Public License in | ||||
|  * all respects for all other code used.  Additionally, AlliedModders LLC grants | ||||
|  * this exception to all derivative works.  AlliedModders LLC defines further | ||||
|  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), | ||||
|  * or <http://www.sourcemod.net/license.php>.
 | ||||
|  * | ||||
|  * Version: $Id$ | ||||
|  */ | ||||
| 
 | ||||
| #include "HandleSys.h" | ||||
| #include "common_logic.h" | ||||
| 
 | ||||
| #include "LumpManager.h" | ||||
| 
 | ||||
| #include <algorithm> | ||||
| 
 | ||||
| HandleType_t g_EntityLumpEntryType; | ||||
| 
 | ||||
| std::string g_strMapEntities; | ||||
| bool g_bLumpAvailableForWriting = false; | ||||
| 
 | ||||
| static EntityLumpManager s_LumpManager; | ||||
| EntityLumpManager *lumpmanager = &s_LumpManager; | ||||
| 
 | ||||
| class LumpManagerNatives : | ||||
| 	public IHandleTypeDispatch, | ||||
| 	public SMGlobalClass | ||||
| { | ||||
| public: //SMGlobalClass
 | ||||
| 	void OnSourceModAllInitialized() | ||||
| 	{ | ||||
| 		g_EntityLumpEntryType = handlesys->CreateType("EntityLumpEntry", this, 0, NULL, NULL, g_pCoreIdent, NULL); | ||||
| 	} | ||||
| 	void OnSourceModShutdown() | ||||
| 	{ | ||||
| 		handlesys->RemoveType(g_EntityLumpEntryType, g_pCoreIdent); | ||||
| 	} | ||||
| public: //IHandleTypeDispatch
 | ||||
| 	void OnHandleDestroy(HandleType_t type, void* object) | ||||
| 	{ | ||||
| 		if (type == g_EntityLumpEntryType) | ||||
| 		{ | ||||
| 			delete reinterpret_cast<std::weak_ptr<EntityLumpEntry>*>(object); | ||||
| 		} | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| static LumpManagerNatives s_LumpManagerNatives; | ||||
| 
 | ||||
| cell_t sm_LumpManagerGet(IPluginContext *pContext, const cell_t *params) { | ||||
| 	int index = params[1]; | ||||
| 	if (index < 0 || index >= static_cast<int>(lumpmanager->Length())) { | ||||
| 		return pContext->ThrowNativeError("Invalid index %d", index); | ||||
| 	} | ||||
| 	 | ||||
| 	std::weak_ptr<EntityLumpEntry>* pReference = new std::weak_ptr<EntityLumpEntry>; | ||||
| 	*pReference = lumpmanager->Get(index); | ||||
| 	 | ||||
| 	return handlesys->CreateHandle(g_EntityLumpEntryType, pReference, | ||||
| 			pContext->GetIdentity(), g_pCoreIdent, NULL); | ||||
| } | ||||
| 
 | ||||
| cell_t sm_LumpManagerErase(IPluginContext *pContext, const cell_t *params) { | ||||
| 	if (!g_bLumpAvailableForWriting) { | ||||
| 		return pContext->ThrowNativeError("Cannot use EntityLump.Erase() outside of OnMapInit"); | ||||
| 	} | ||||
| 	 | ||||
| 	int index = params[1]; | ||||
| 	if (index < 0 || index >= static_cast<int>(lumpmanager->Length())) { | ||||
| 		return pContext->ThrowNativeError("Invalid index %d", index); | ||||
| 	} | ||||
| 	 | ||||
| 	lumpmanager->Erase(index); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| cell_t sm_LumpManagerInsert(IPluginContext *pContext, const cell_t *params) { | ||||
| 	if (!g_bLumpAvailableForWriting) { | ||||
| 		return pContext->ThrowNativeError("Cannot use EntityLump.Insert() outside of OnMapInit"); | ||||
| 	} | ||||
| 	 | ||||
| 	int index = params[1]; | ||||
| 	if (index < 0 || index > static_cast<int>(lumpmanager->Length())) { | ||||
| 		return pContext->ThrowNativeError("Invalid index %d", index); | ||||
| 	} | ||||
| 	 | ||||
| 	lumpmanager->Insert(index); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| cell_t sm_LumpManagerAppend(IPluginContext *pContext, const cell_t *params) { | ||||
| 	if (!g_bLumpAvailableForWriting) { | ||||
| 		return pContext->ThrowNativeError("Cannot use EntityLump.Append() outside of OnMapInit"); | ||||
| 	} | ||||
| 	return lumpmanager->Append(); | ||||
| } | ||||
| 
 | ||||
| cell_t sm_LumpManagerLength(IPluginContext *pContext, const cell_t *params) { | ||||
| 	return lumpmanager->Length(); | ||||
| } | ||||
| 
 | ||||
| cell_t sm_LumpEntryGet(IPluginContext *pContext, const cell_t *params) { | ||||
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); | ||||
| 	HandleError err; | ||||
| 	 | ||||
| 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||
| 	 | ||||
| 	std::weak_ptr<EntityLumpEntry>* entryref = nullptr; | ||||
| 	if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) { | ||||
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err); | ||||
| 	} | ||||
| 	 | ||||
| 	if (entryref->expired()) { | ||||
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl); | ||||
| 	} | ||||
| 	 | ||||
| 	auto entry = entryref->lock(); | ||||
| 	 | ||||
| 	int index = params[2]; | ||||
| 	if (index < 0 || index >= static_cast<int>(entry->size())) { | ||||
| 		return pContext->ThrowNativeError("Invalid index %d", index); | ||||
| 	} | ||||
| 	 | ||||
| 	const auto& pair = (*entry)[index]; | ||||
| 	 | ||||
| 	size_t nBytes; | ||||
| 	pContext->StringToLocalUTF8(params[3], params[4], pair.first.c_str(), &nBytes); | ||||
| 	pContext->StringToLocalUTF8(params[5], params[6], pair.second.c_str(), &nBytes); | ||||
| 	 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| cell_t sm_LumpEntryUpdate(IPluginContext *pContext, const cell_t *params) { | ||||
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); | ||||
| 	HandleError err; | ||||
| 	 | ||||
| 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||
| 	 | ||||
| 	std::weak_ptr<EntityLumpEntry>* entryref = nullptr; | ||||
| 	if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) { | ||||
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err); | ||||
| 	} | ||||
| 	 | ||||
| 	if (entryref->expired()) { | ||||
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl); | ||||
| 	} | ||||
| 	 | ||||
| 	if (!g_bLumpAvailableForWriting) { | ||||
| 		return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Update() outside of OnMapInit"); | ||||
| 	} | ||||
| 	 | ||||
| 	auto entry = entryref->lock(); | ||||
| 	 | ||||
| 	int index = params[2]; | ||||
| 	if (index < 0 || index >= static_cast<int>(entry->size())) { | ||||
| 		return pContext->ThrowNativeError("Invalid index %d", index); | ||||
| 	} | ||||
| 	 | ||||
| 	char *key, *value; | ||||
| 	pContext->LocalToStringNULL(params[3], &key); | ||||
| 	pContext->LocalToStringNULL(params[4], &value); | ||||
| 	 | ||||
| 	auto& pair = (*entry)[index]; | ||||
| 	if (key != nullptr) { | ||||
| 		pair.first = key; | ||||
| 	} | ||||
| 	if (value != nullptr) { | ||||
| 		pair.second = value; | ||||
| 	} | ||||
| 	 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| cell_t sm_LumpEntryInsert(IPluginContext *pContext, const cell_t *params) { | ||||
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); | ||||
| 	HandleError err; | ||||
| 	 | ||||
| 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||
| 	 | ||||
| 	std::weak_ptr<EntityLumpEntry>* entryref = nullptr; | ||||
| 	if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) { | ||||
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err); | ||||
| 	} | ||||
| 	 | ||||
| 	if (entryref->expired()) { | ||||
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl); | ||||
| 	} | ||||
| 	 | ||||
| 	if (!g_bLumpAvailableForWriting) { | ||||
| 		return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Insert() outside of OnMapInit"); | ||||
| 	} | ||||
| 	 | ||||
| 	auto entry = entryref->lock(); | ||||
| 	 | ||||
| 	int index = params[2]; | ||||
| 	if (index < 0 || index > static_cast<int>(entry->size())) { | ||||
| 		return pContext->ThrowNativeError("Invalid index %d", index); | ||||
| 	} | ||||
| 	 | ||||
| 	char *key, *value; | ||||
| 	pContext->LocalToString(params[3], &key); | ||||
| 	pContext->LocalToString(params[4], &value); | ||||
| 	 | ||||
| 	entry->emplace(entry->begin() + index, key, value); | ||||
| 	 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| cell_t sm_LumpEntryErase(IPluginContext *pContext, const cell_t *params) { | ||||
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); | ||||
| 	HandleError err; | ||||
| 	 | ||||
| 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||
| 	 | ||||
| 	std::weak_ptr<EntityLumpEntry>* entryref = nullptr; | ||||
| 	if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) { | ||||
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err); | ||||
| 	} | ||||
| 	 | ||||
| 	if (entryref->expired()) { | ||||
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl); | ||||
| 	} | ||||
| 	 | ||||
| 	if (!g_bLumpAvailableForWriting) { | ||||
| 		return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Erase() outside of OnMapInit"); | ||||
| 	} | ||||
| 	 | ||||
| 	auto entry = entryref->lock(); | ||||
| 	 | ||||
| 	int index = params[2]; | ||||
| 	if (index < 0 || index >= static_cast<int>(entry->size())) { | ||||
| 		return pContext->ThrowNativeError("Invalid index %d", index); | ||||
| 	} | ||||
| 	 | ||||
| 	entry->erase(entry->begin() + index); | ||||
| 	 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| cell_t sm_LumpEntryAppend(IPluginContext *pContext, const cell_t *params) { | ||||
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); | ||||
| 	HandleError err; | ||||
| 	 | ||||
| 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||
| 	 | ||||
| 	std::weak_ptr<EntityLumpEntry>* entryref = nullptr; | ||||
| 	if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) { | ||||
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err); | ||||
| 	} | ||||
| 	 | ||||
| 	if (entryref->expired()) { | ||||
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl); | ||||
| 	} | ||||
| 	 | ||||
| 	if (!g_bLumpAvailableForWriting) { | ||||
| 		return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Append() outside of OnMapInit"); | ||||
| 	} | ||||
| 	 | ||||
| 	auto entry = entryref->lock(); | ||||
| 	 | ||||
| 	char *key, *value; | ||||
| 	pContext->LocalToString(params[2], &key); | ||||
| 	pContext->LocalToString(params[3], &value); | ||||
| 	 | ||||
| 	entry->emplace_back(key, value); | ||||
| 	 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| cell_t sm_LumpEntryFindKey(IPluginContext *pContext, const cell_t *params) { | ||||
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); | ||||
| 	HandleError err; | ||||
| 	 | ||||
| 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||
| 	 | ||||
| 	std::weak_ptr<EntityLumpEntry>* entryref = nullptr; | ||||
| 	if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) { | ||||
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err); | ||||
| 	} | ||||
| 	 | ||||
| 	if (entryref->expired()) { | ||||
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl); | ||||
| 	} | ||||
| 	 | ||||
| 	// start from the index after the current one
 | ||||
| 	int start = params[3] + 1; | ||||
| 	 | ||||
| 	auto entry = entryref->lock(); | ||||
| 	 | ||||
| 	if (start < 0 || start >= static_cast<int>(entry->size())) { | ||||
| 		return -1; | ||||
| 	} | ||||
| 	 | ||||
| 	char *key; | ||||
| 	pContext->LocalToString(params[2], &key); | ||||
| 	 | ||||
| 	auto matches_key = [&key](std::pair<std::string,std::string> pair) { | ||||
| 		return pair.first == key; | ||||
| 	}; | ||||
| 	 | ||||
| 	auto result = std::find_if(entry->begin() + start, entry->end(), matches_key); | ||||
| 	 | ||||
| 	if (result == entry->end()) { | ||||
| 		return -1; | ||||
| 	} | ||||
| 	return std::distance(entry->begin(), result); | ||||
| } | ||||
| 
 | ||||
| cell_t sm_LumpEntryLength(IPluginContext *pContext, const cell_t *params) { | ||||
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); | ||||
| 	HandleError err; | ||||
| 	 | ||||
| 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||
| 	 | ||||
| 	std::weak_ptr<EntityLumpEntry>* entryref = nullptr; | ||||
| 	if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) { | ||||
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err); | ||||
| 	} | ||||
| 	 | ||||
| 	if (entryref->expired()) { | ||||
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl); | ||||
| 	} | ||||
| 	 | ||||
| 	auto entry = entryref->lock(); | ||||
| 	return entry->size(); | ||||
| } | ||||
| 
 | ||||
| REGISTER_NATIVES(entityLumpNatives) | ||||
| { | ||||
| 	{ "EntityLump.Get", sm_LumpManagerGet }, | ||||
| 	{ "EntityLump.Erase", sm_LumpManagerErase }, | ||||
| 	{ "EntityLump.Insert", sm_LumpManagerInsert }, | ||||
| 	{ "EntityLump.Append", sm_LumpManagerAppend }, | ||||
| 	{ "EntityLump.Length", sm_LumpManagerLength }, | ||||
| 	 | ||||
| 	{ "EntityLumpEntry.Get", sm_LumpEntryGet }, | ||||
| 	{ "EntityLumpEntry.Update", sm_LumpEntryUpdate }, | ||||
| 	{ "EntityLumpEntry.Insert", sm_LumpEntryInsert }, | ||||
| 	{ "EntityLumpEntry.Erase", sm_LumpEntryErase }, | ||||
| 	{ "EntityLumpEntry.Append", sm_LumpEntryAppend }, | ||||
| 	{ "EntityLumpEntry.FindKey", sm_LumpEntryFindKey }, | ||||
| 	{ "EntityLumpEntry.Length.get", sm_LumpEntryLength }, | ||||
| 	 | ||||
| 	{NULL, NULL} | ||||
| }; | ||||
| @ -1,44 +0,0 @@ | ||||
| /**
 | ||||
| * vim: set ts=4 : | ||||
| * ============================================================================= | ||||
| * SourceMod | ||||
| * Copyright (C) 2022-2022 AlliedModders LLC.  All rights reserved. | ||||
| * ============================================================================= | ||||
| * | ||||
| * This program is free software; you can redistribute it and/or modify it under | ||||
| * the terms of the GNU General Public License, version 3.0, as published by the | ||||
| * Free Software Foundation. | ||||
| * | ||||
| * This program is distributed in the hope that it will be useful, but WITHOUT | ||||
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||||
| * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more | ||||
| * details. | ||||
| * | ||||
| * You should have received a copy of the GNU General Public License along with | ||||
| * this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| * | ||||
| * As a special exception, AlliedModders LLC gives you permission to link the | ||||
| * code of this program (as well as its derivative works) to "Half-Life 2," the | ||||
| * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software | ||||
| * by the Valve Corporation.  You must obey the GNU General Public License in | ||||
| * all respects for all other code used.  Additionally, AlliedModders LLC grants | ||||
| * this exception to all derivative works.  AlliedModders LLC defines further | ||||
| * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), | ||||
| * or <http://www.sourcemod.net/license.php>.
 | ||||
| * | ||||
| * Version: $Id$ | ||||
| */ | ||||
| 
 | ||||
| #ifndef _INCLUDE_SOURCEMOD_ENTITYLUMP_H_ | ||||
| #define _INCLUDE_SOURCEMOD_ENTITYLUMP_H_ | ||||
| 
 | ||||
| #include <IHandleSys.h> | ||||
| #include "LumpManager.h" | ||||
| 
 | ||||
| using namespace SourceMod; | ||||
| 
 | ||||
| extern std::string g_strMapEntities; | ||||
| extern bool g_bLumpAvailableForWriting; | ||||
| extern EntityLumpManager *lumpmanager; | ||||
| 
 | ||||
| #endif // _INCLUDE_SOURCEMOD_ENTITYLUMP_H_
 | ||||
| @ -414,7 +414,7 @@ static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params) | ||||
| 		DetectExceptions eh(pContext); | ||||
| 		written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param); | ||||
| 		if (eh.HasException()) | ||||
| 			return pContext->GetLastNativeError(); | ||||
| 			return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	cell_t *addr; | ||||
|  | ||||
| @ -29,13 +29,12 @@ | ||||
|  * Version: $Id$ | ||||
|  */ | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include "common_logic.h" | ||||
| #include <IPluginSys.h> | ||||
| #include <IHandleSys.h> | ||||
| #include <IForwardSys.h> | ||||
| #include <ISourceMod.h> | ||||
| #include <amtl/am-autoptr.h> | ||||
| #include "ShareSys.h" | ||||
| #include "NativeInvoker.h" | ||||
| 
 | ||||
| @ -747,7 +746,7 @@ struct SMFrameActionData | ||||
| 
 | ||||
| static void PawnFrameAction(void *pData) | ||||
| { | ||||
| 	std::unique_ptr<SMFrameActionData> frame(reinterpret_cast<SMFrameActionData *>(pData)); | ||||
| 	ke::AutoPtr<SMFrameActionData> frame(reinterpret_cast<SMFrameActionData *>(pData)); | ||||
| 	IPlugin *pPlugin = pluginsys->PluginFromHandle(frame->ownerhandle, NULL); | ||||
| 	if (!pPlugin) | ||||
| 	{ | ||||
|  | ||||
| @ -162,38 +162,6 @@ static cell_t smn_GameConfGetAddress(IPluginContext *pCtx, const cell_t *params) | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static cell_t smn_GameConfGetMemSig(IPluginContext *pCtx, const cell_t *params) | ||||
| { | ||||
| 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||
| 	HandleError herr; | ||||
| 	HandleSecurity sec; | ||||
| 	IGameConfig *gc; | ||||
| 
 | ||||
| 	sec.pOwner = NULL; | ||||
| 	sec.pIdentity = g_pCoreIdent; | ||||
| 
 | ||||
| 	if ((herr=handlesys->ReadHandle(hndl, g_GameConfigsType, &sec, (void **)&gc)) | ||||
| 		!= HandleError_None) | ||||
| 	{ | ||||
| 		return pCtx->ThrowNativeError("Invalid game config handle %x (error %d)", hndl, herr); | ||||
| 	} | ||||
| 
 | ||||
| 	char *key; | ||||
| 	void *val; | ||||
| 	pCtx->LocalToString(params[2], &key); | ||||
| 
 | ||||
| 	if (!gc->GetMemSig(key, &val)) | ||||
| 	{ | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| #ifdef PLATFORM_X86 | ||||
| 	return (cell_t)val; | ||||
| #else | ||||
| 	return pseudoAddr.ToPseudoAddress(val); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static GameConfigsNatives s_GameConfigsNatives; | ||||
| 
 | ||||
| REGISTER_NATIVES(gameconfignatives) | ||||
| @ -208,6 +176,5 @@ REGISTER_NATIVES(gameconfignatives) | ||||
| 	{"GameData.GetOffset",			smn_GameConfGetOffset}, | ||||
| 	{"GameData.GetKeyValue",		smn_GameConfGetKeyValue}, | ||||
| 	{"GameData.GetAddress",			smn_GameConfGetAddress}, | ||||
| 	{"GameData.GetMemSig", 			smn_GameConfGetMemSig}, | ||||
| 	{NULL,							NULL} | ||||
| }; | ||||
|  | ||||
| @ -592,10 +592,7 @@ private: | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		char realpath[PLATFORM_MAX_PATH]; | ||||
| 		g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", pMapList->path); | ||||
| 
 | ||||
| 		if (!libsys->FileTime(realpath, FileTime_LastChange, &last_time) | ||||
| 		if (!libsys->FileTime(pMapList->path, FileTime_LastChange, &last_time) | ||||
| 			|| last_time > pMapList->last_modified_time) | ||||
| 		{ | ||||
| 			/* Reparse */ | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| /**
 | ||||
|  * vim: set ts=4 sw=4 tw=99 noet : | ||||
|  * vim: set ts=4 : | ||||
|  * ============================================================================= | ||||
|  * SourceMod | ||||
|  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved. | ||||
| @ -141,6 +141,10 @@ public: | ||||
| 	void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style); | ||||
| 	unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr); | ||||
| 	bool OnSetHandlerOption(const char *option, const void *data); | ||||
| #if 0 | ||||
| 	void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style); | ||||
| 	void OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display); | ||||
| #endif | ||||
| private: | ||||
| 	cell_t DoAction(IBaseMenu *menu, MenuAction action, cell_t param1, cell_t param2, cell_t def_res=0); | ||||
| private: | ||||
| @ -481,6 +485,7 @@ void CMenuHandler::OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t * | ||||
| 		if (num_items > 1) | ||||
| 		{ | ||||
| 			/* Yes, we do. */ | ||||
| 			srand(time(NULL)); | ||||
| 			winning_item = rand() % num_items; | ||||
| 			winning_item = results->item_list[winning_item].item; | ||||
| 		} else { | ||||
| @ -492,44 +497,80 @@ void CMenuHandler::OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t * | ||||
| 		unsigned int winning_votes = results->item_list[0].count; | ||||
| 
 | ||||
| 		DoAction(menu, MenuAction_VoteEnd, winning_item, (total_votes << 16) | (winning_votes & 0xFFFF)); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	} else { | ||||
| 		IPluginContext *pContext = m_pVoteResults->GetParentContext(); | ||||
| 	AutoEnterHeapScope heap_scope(pContext); | ||||
| 		bool no_call = false; | ||||
| 		int err; | ||||
| 
 | ||||
| 		/* First array */ | ||||
| 		cell_t client_array_address = -1; | ||||
| 	if (cell_t client_array_size = results->num_clients * 2) { | ||||
| 		auto init = std::make_unique<cell_t[]>(client_array_size); | ||||
| 		for (unsigned int i = 0; i < results->num_clients; i++) { | ||||
| 			init[i * 2] = results->client_list[i].client; | ||||
| 			init[i * 2 + 1] = results->client_list[i].item; | ||||
| 		cell_t *client_array_base = NULL; | ||||
| 		cell_t client_array_size = results->num_clients + (results->num_clients * 2); | ||||
| 		if (client_array_size) | ||||
| 		{ | ||||
| 			if ((err = pContext->HeapAlloc(client_array_size, &client_array_address, &client_array_base)) | ||||
| 				!= SP_ERROR_NONE) | ||||
| 			{ | ||||
| 				g_DbgReporter.GenerateError(pContext, m_fnVoteResult, err, "Menu callback could not allocate %d bytes for client list.", client_array_size * sizeof(cell_t)); | ||||
| 				no_call = true; | ||||
| 			} else { | ||||
| 				cell_t target_offs = sizeof(cell_t) * results->num_clients; | ||||
| 				cell_t *cur_index = client_array_base; | ||||
| 				cell_t *cur_array; | ||||
| 				for (unsigned int i=0; i<results->num_clients; i++) | ||||
| 				{ | ||||
| 					/* Copy the array index */ | ||||
| 					*cur_index = target_offs; | ||||
| 					/* Get the current array address */ | ||||
| 					cur_array = (cell_t *)((char *)cur_index + target_offs); | ||||
| 					/* Store information */ | ||||
| 					cur_array[0] = results->client_list[i].client; | ||||
| 					cur_array[1] = results->client_list[i].item; | ||||
| 					/* Adjust for the new target by subtracting one indirection
 | ||||
| 					 * and adding one array. | ||||
| 					 */ | ||||
| 					target_offs += (sizeof(cell_t) * 2) - sizeof(cell_t); | ||||
| 					cur_index++; | ||||
| 				} | ||||
| 
 | ||||
| 		if (!pContext->HeapAlloc2dArray(results->num_clients, 2, &client_array_address, init.get())) { | ||||
| 			g_DbgReporter.GenerateError(pContext, m_fnVoteResult, -1, | ||||
| 										"Menu callback could not allocate cells for client list."); | ||||
| 			return; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		/* Second array */ | ||||
| 		cell_t item_array_address = -1; | ||||
| 	if (cell_t item_array_size = results->num_items * 2) { | ||||
| 		auto init = std::make_unique<cell_t[]>(item_array_size); | ||||
| 		for (unsigned int i = 0; i < results->num_items; i++) { | ||||
| 			init[i * 2] = results->item_list[i].item; | ||||
| 			init[i * 2 + 1] = results->item_list[i].count; | ||||
| 		cell_t *item_array_base = NULL; | ||||
| 		cell_t item_array_size = results->num_items + (results->num_items * 2); | ||||
| 		if (item_array_size) | ||||
| 		{ | ||||
| 			if ((err = pContext->HeapAlloc(item_array_size, &item_array_address, &item_array_base)) | ||||
| 				!= SP_ERROR_NONE) | ||||
| 			{ | ||||
| 				g_DbgReporter.GenerateError(pContext, m_fnVoteResult, err, "Menu callback could not allocate %d bytes for item list.", item_array_size); | ||||
| 				no_call = true; | ||||
| 			} else { | ||||
| 				cell_t target_offs = sizeof(cell_t) * results->num_items; | ||||
| 				cell_t *cur_index = item_array_base; | ||||
| 				cell_t *cur_array; | ||||
| 				for (unsigned int i=0; i<results->num_items; i++) | ||||
| 				{ | ||||
| 					/* Copy the array index */ | ||||
| 					*cur_index = target_offs; | ||||
| 					/* Get the current array address */ | ||||
| 					cur_array = (cell_t *)((char *)cur_index + target_offs); | ||||
| 					/* Store information */ | ||||
| 					cur_array[0] = results->item_list[i].item; | ||||
| 					cur_array[1] = results->item_list[i].count; | ||||
| 					/* Adjust for the new target by subtracting one indirection
 | ||||
| 					 * and adding one array. | ||||
| 					 */ | ||||
| 					target_offs += (sizeof(cell_t) * 2) - sizeof(cell_t); | ||||
| 					cur_index++; | ||||
| 				} | ||||
| 		if (!pContext->HeapAlloc2dArray(results->num_items, 2, &item_array_address, init.get())) { | ||||
| 			g_DbgReporter.GenerateError(pContext, m_fnVoteResult, -1, | ||||
| 										"Menu callback could not allocate %d cells for item list.", | ||||
| 										item_array_size); | ||||
| 			return; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		/* Finally, push everything */ | ||||
| 		if (!no_call) | ||||
| 		{ | ||||
| 			m_pVoteResults->PushCell(menu->GetHandle()); | ||||
| 			m_pVoteResults->PushCell(results->num_votes); | ||||
| 			m_pVoteResults->PushCell(results->num_clients); | ||||
| @ -537,6 +578,18 @@ void CMenuHandler::OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t * | ||||
| 			m_pVoteResults->PushCell(results->num_items); | ||||
| 			m_pVoteResults->PushCell(item_array_address); | ||||
| 			m_pVoteResults->Execute(NULL); | ||||
| 		} | ||||
| 
 | ||||
| 		/* Free what we allocated, in reverse order as required */ | ||||
| 		if (item_array_address != -1) | ||||
| 		{ | ||||
| 			pContext->HeapPop(item_array_address); | ||||
| 		} | ||||
| 		if (client_array_address != -1) | ||||
| 		{ | ||||
| 			pContext->HeapPop(client_array_address); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| bool CMenuHandler::OnSetHandlerOption(const char *option, const void *data) | ||||
| @ -962,7 +1015,7 @@ static cell_t GetMenuExitBackButton(IPluginContext *pContext, const cell_t *para | ||||
| 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err); | ||||
| 	} | ||||
| 
 | ||||
| 	return ((menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXITBACK) ? 1 : 0; | ||||
| 	return ((menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXIT) ? 1 : 0; | ||||
| } | ||||
| 
 | ||||
| static cell_t SetMenuExitButton(IPluginContext *pContext, const cell_t *params) | ||||
|  | ||||
| @ -35,7 +35,6 @@ | ||||
| #include "common_logic.h" | ||||
| #include "CellArray.h" | ||||
| #include <IHandleSys.h> | ||||
| #include <amtl/am-raii.h> | ||||
| 
 | ||||
| /***********************************
 | ||||
|  *   About the double array hack   * | ||||
| @ -92,6 +91,8 @@ enum SortOrder | ||||
| 
 | ||||
| void sort_random(cell_t *array, cell_t size) | ||||
| { | ||||
| 	srand((unsigned int)time(NULL)); | ||||
| 
 | ||||
| 	for (int i = size-1; i > 0; i--) | ||||
| 	{ | ||||
|         int n = rand() % (i + 1); | ||||
| @ -196,7 +197,7 @@ static cell_t sm_SortFloats(IPluginContext *pContext, const cell_t *params) | ||||
| static cell_t *g_CurStringArray = NULL; | ||||
| static cell_t *g_CurRebaseMap = NULL; | ||||
| 
 | ||||
| int sort_strings_asc_legacy(const void *blk1, const void *blk2) | ||||
| int sort_strings_asc(const void *blk1, const void *blk2) | ||||
| { | ||||
| 	cell_t reloc1 = *(cell_t *)blk1; | ||||
| 	cell_t reloc2 = *(cell_t *)blk2; | ||||
| @ -207,7 +208,7 @@ int sort_strings_asc_legacy(const void *blk1, const void *blk2) | ||||
| 	return strcmp(str1, str2); | ||||
| } | ||||
| 
 | ||||
| int sort_strings_desc_legacy(const void *blk1, const void *blk2) | ||||
| int sort_strings_desc(const void *blk1, const void *blk2) | ||||
| { | ||||
| 	cell_t reloc1 = *(cell_t *)blk1; | ||||
| 	cell_t reloc2 = *(cell_t *)blk2; | ||||
| @ -218,7 +219,7 @@ int sort_strings_desc_legacy(const void *blk1, const void *blk2) | ||||
| 	return strcmp(str2, str1); | ||||
| } | ||||
| 
 | ||||
| static cell_t sm_SortStrings_Legacy(IPluginContext *pContext, const cell_t *params) | ||||
| static cell_t sm_SortStrings(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	cell_t *array; | ||||
| 	cell_t array_size = params[2]; | ||||
| @ -246,11 +247,11 @@ static cell_t sm_SortStrings_Legacy(IPluginContext *pContext, const cell_t *para | ||||
| 
 | ||||
| 	if (type == Sort_Ascending) | ||||
| 	{ | ||||
| 		qsort(array, array_size, sizeof(cell_t), sort_strings_asc_legacy); | ||||
| 		qsort(array, array_size, sizeof(cell_t), sort_strings_asc); | ||||
| 	}  | ||||
| 	else if (type == Sort_Descending) | ||||
| 	{ | ||||
| 		qsort(array, array_size, sizeof(cell_t), sort_strings_desc_legacy); | ||||
| 		qsort(array, array_size, sizeof(cell_t), sort_strings_desc); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -276,69 +277,6 @@ static cell_t sm_SortStrings_Legacy(IPluginContext *pContext, const cell_t *para | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static IPluginContext* sSortContext = nullptr; | ||||
| 
 | ||||
| int sort_strings_asc(const void *blk1, const void *blk2) | ||||
| { | ||||
| 	cell_t str_addr1 = *(cell_t *)blk1; | ||||
| 	cell_t str_addr2 = *(cell_t *)blk2; | ||||
| 
 | ||||
| 	char *str1; | ||||
| 	char *str2; | ||||
| 	if (sSortContext->LocalToString(str_addr1, &str1) != SP_ERROR_NONE || | ||||
| 		sSortContext->LocalToString(str_addr2, &str2) != SP_ERROR_NONE) | ||||
| 	{ | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	return strcmp(str1, str2); | ||||
| } | ||||
| 
 | ||||
| int sort_strings_desc(const void *blk1, const void *blk2) | ||||
| { | ||||
| 	cell_t str_addr1 = *(cell_t *)blk1; | ||||
| 	cell_t str_addr2 = *(cell_t *)blk2; | ||||
| 
 | ||||
| 	char *str1; | ||||
| 	char *str2; | ||||
| 	if (sSortContext->LocalToString(str_addr1, &str1) != SP_ERROR_NONE || | ||||
| 		sSortContext->LocalToString(str_addr2, &str2) != SP_ERROR_NONE) | ||||
| 	{ | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	return strcmp(str2, str1); | ||||
| } | ||||
| 
 | ||||
| static cell_t sm_SortStrings(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	auto rt = pContext->GetRuntime(); | ||||
| 	if (!rt->UsesDirectArrays()) | ||||
| 		return sm_SortStrings_Legacy(pContext, params); | ||||
| 
 | ||||
| 	cell_t *array; | ||||
| 	cell_t array_size = params[2]; | ||||
| 	cell_t type = params[3]; | ||||
| 
 | ||||
| 	pContext->LocalToPhysAddr(params[1], &array); | ||||
| 
 | ||||
| 	ke::SaveAndSet<IPluginContext*> set_context(&sSortContext, pContext); | ||||
| 
 | ||||
| 	if (type == Sort_Ascending) | ||||
| 	{ | ||||
| 		qsort(array, array_size, sizeof(cell_t), sort_strings_asc); | ||||
| 	} | ||||
| 	else if (type == Sort_Descending) | ||||
| 	{ | ||||
| 		qsort(array, array_size, sizeof(cell_t), sort_strings_desc); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		sort_random(array, array_size); | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| struct sort_info | ||||
| { | ||||
| 	IPluginFunction *pFunc; | ||||
| @ -399,7 +337,7 @@ static cell_t sm_SortCustom1D(IPluginContext *pContext, const cell_t *params) | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static int sort2d_amx_custom_legacy(const void *elem1, const void *elem2) | ||||
| int sort2d_amx_custom(const void *elem1, const void *elem2) | ||||
| { | ||||
| 	if (g_SortInfo.eh->HasException()) | ||||
| 		return 0; | ||||
| @ -425,7 +363,7 @@ static int sort2d_amx_custom_legacy(const void *elem1, const void *elem2) | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| static cell_t sm_SortCustom2D_Legacy(IPluginContext *pContext, const cell_t *params) | ||||
| static cell_t sm_SortCustom2D(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	cell_t *array; | ||||
| 	cell_t array_size = params[2]; | ||||
| @ -465,7 +403,7 @@ static cell_t sm_SortCustom2D_Legacy(IPluginContext *pContext, const cell_t *par | ||||
| 		array[i] = i; | ||||
| 	} | ||||
| 
 | ||||
| 	qsort(array, array_size, sizeof(cell_t), sort2d_amx_custom_legacy); | ||||
| 	qsort(array, array_size, sizeof(cell_t), sort2d_amx_custom); | ||||
| 
 | ||||
| 	/** Fixup process! */ | ||||
| 	for (int i=0; i<array_size; i++) | ||||
| @ -483,55 +421,6 @@ static cell_t sm_SortCustom2D_Legacy(IPluginContext *pContext, const cell_t *par | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static int sort2d_amx_custom(const void *elem1, const void *elem2) | ||||
| { | ||||
| 	if (g_SortInfo.eh->HasException()) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	cell_t iv1 = *(cell_t *)elem1; | ||||
| 	cell_t iv2 = *(cell_t *)elem2; | ||||
| 
 | ||||
| 	cell_t result = 0; | ||||
| 	g_SortInfo.pFunc->PushCell(iv1); | ||||
| 	g_SortInfo.pFunc->PushCell(iv2); | ||||
| 	g_SortInfo.pFunc->PushCell(g_SortInfo.array_addr); | ||||
| 	g_SortInfo.pFunc->PushCell(g_SortInfo.hndl); | ||||
| 	g_SortInfo.pFunc->Invoke(&result); | ||||
| 
 | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| static cell_t sm_SortCustom2D(IPluginContext *pContext, const cell_t *params) | ||||
| { | ||||
| 	auto rt = pContext->GetRuntime(); | ||||
| 	if (!rt->UsesDirectArrays()) | ||||
| 		return sm_SortCustom2D_Legacy(pContext, params); | ||||
| 
 | ||||
| 	cell_t *array; | ||||
| 	cell_t array_size = params[2]; | ||||
| 	IPluginFunction *pFunction; | ||||
| 
 | ||||
| 	pContext->LocalToPhysAddr(params[1], &array); | ||||
| 
 | ||||
| 	if ((pFunction=pContext->GetFunctionById(params[3])) == NULL) | ||||
| 	{ | ||||
| 		return pContext->ThrowNativeError("Function %x is not a valid function", params[3]); | ||||
| 	} | ||||
| 
 | ||||
| 	sort_info oldinfo = g_SortInfo; | ||||
| 
 | ||||
| 	DetectExceptions eh(pContext); | ||||
| 	g_SortInfo.pFunc = pFunction; | ||||
| 	g_SortInfo.hndl = params[4]; | ||||
| 	g_SortInfo.array_addr = params[1]; | ||||
| 	g_SortInfo.eh = &eh; | ||||
| 	 | ||||
| 	qsort(array, array_size, sizeof(cell_t), sort2d_amx_custom); | ||||
| 
 | ||||
| 	g_SortInfo = oldinfo; | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| enum SortType | ||||
| { | ||||
| 	Sort_Integer = 0, | ||||
| @ -553,6 +442,8 @@ void sort_adt_random(CellArray *cArray) | ||||
| { | ||||
| 	size_t arraysize = cArray->size(); | ||||
| 
 | ||||
| 	srand((unsigned int)time(NULL)); | ||||
| 
 | ||||
| 	for (int i = arraysize-1; i > 0; i--) | ||||
| 	{ | ||||
|         int n = rand() % (i + 1); | ||||
|  | ||||
| @ -139,22 +139,6 @@ static cell_t StringToIntEx(IPluginContext *pCtx, const cell_t *params) | ||||
| 	return dummy - str; | ||||
| } | ||||
| 
 | ||||
| static cell_t StringToInt64(IPluginContext *pCtx, const cell_t *params) | ||||
| { | ||||
| 	char *str, *dummy = NULL; | ||||
| 	cell_t *addr; | ||||
| 	pCtx->LocalToString(params[1], &str); | ||||
| 	pCtx->LocalToPhysAddr(params[2], &addr); | ||||
| 
 | ||||
| 	// uint64_t for correct signed right shift.
 | ||||
| 	uint64_t number = (uint64_t)strtoll(str, &dummy, params[3]); | ||||
| 
 | ||||
| 	addr[0] = (cell_t)(number & 0xFFFFFFFFull); | ||||
| 	addr[1] = (cell_t)(number >> 32ull); | ||||
| 
 | ||||
| 	return dummy - str; | ||||
| } | ||||
| 
 | ||||
| static cell_t sm_numtostr(IPluginContext *pCtx, const cell_t *params) | ||||
| { | ||||
| 	char *str; | ||||
| @ -164,17 +148,6 @@ static cell_t sm_numtostr(IPluginContext *pCtx, const cell_t *params) | ||||
| 	return static_cast<cell_t>(res); | ||||
| } | ||||
| 
 | ||||
| static cell_t Int64ToString(IPluginContext *pCtx, const cell_t *params) | ||||
| { | ||||
| 	cell_t *num; | ||||
| 	char *str; | ||||
| 	pCtx->LocalToPhysAddr(params[1], &num); | ||||
| 	pCtx->LocalToString(params[2], &str); | ||||
| 	size_t res = ke::SafeSprintf(str, params[3], "%" KE_FMT_I64, (uint64_t)num[1] << 32ll | (uint32_t)num[0]); | ||||
| 
 | ||||
| 	return static_cast<cell_t>(res); | ||||
| } | ||||
| 
 | ||||
| static cell_t sm_strtofloat(IPluginContext *pCtx, const cell_t *params) | ||||
| { | ||||
| 	char *str, *dummy; | ||||
| @ -618,7 +591,6 @@ REGISTER_NATIVES(basicStrings) | ||||
| 	{"FormatEx",			sm_formatex}, | ||||
| 	{"GetCharBytes",		GetCharBytes}, | ||||
| 	{"IntToString",			sm_numtostr}, | ||||
| 	{"Int64ToString",		Int64ToString}, | ||||
| 	{"IsCharAlpha",			IsCharAlpha}, | ||||
| 	{"IsCharLower",			IsCharLower}, | ||||
| 	{"IsCharMB",			IsCharMB}, | ||||
| @ -635,7 +607,6 @@ REGISTER_NATIVES(basicStrings) | ||||
| 	{"strcopy",				sm_strcopy}, | ||||
| 	{"StringToInt",			sm_strconvint}, | ||||
| 	{"StringToIntEx",		StringToIntEx}, | ||||
| 	{"StringToInt64",		StringToInt64}, | ||||
| 	{"StringToFloat",		sm_strtofloat}, | ||||
| 	{"StringToFloatEx",		StringToFloatEx}, | ||||
| 	{"StripQuotes",			StripQuotes}, | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user