Compare commits
	
		
			17 Commits
		
	
	
		
			master-reb
			...
			1.10-fork
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					178202a5b3 | ||
| 
						 | 
					60f3268236 | ||
| 
						 | 
					64b3c8fbd8 | ||
| 
						 | 
					4c4629fca7 | ||
| 
						 | 
					8749877c62 | ||
| 
						 | 
					102b01c626 | ||
| 
						 | 
					8e07790997 | ||
| 
						 | 
					a701408c71 | ||
| 
						 | 
					2d0fff79a8 | ||
| 
						 | 
					9da44d67f1 | ||
| 
						 | 
					1847f5e2dc | ||
| 
						 | 
					0dd3361050 | ||
| 
						 | 
					11d12aad11 | ||
| 
						 | 
					8ac0c18674 | ||
| 
						 | 
					a0b8153f4b | ||
| 
						 | 
					a363587be9 | ||
| 
						 | 
					fdcce81a41 | 
							
								
								
									
										8
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							@ -1,8 +0,0 @@
 | 
			
		||||
version: 2
 | 
			
		||||
updates:
 | 
			
		||||
 | 
			
		||||
  - package-ecosystem: "github-actions"
 | 
			
		||||
    directory: "/"
 | 
			
		||||
    schedule:
 | 
			
		||||
      # Check for updates to GitHub Actions every week
 | 
			
		||||
      interval: "weekly"
 | 
			
		||||
							
								
								
									
										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-20.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-20.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.12'
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v4
 | 
			
		||||
        with:
 | 
			
		||||
          submodules: recursive
 | 
			
		||||
          path: sourcemod
 | 
			
		||||
 | 
			
		||||
      - name: Cache dependencies
 | 
			
		||||
        uses: actions/cache@v4
 | 
			
		||||
        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@v5
 | 
			
		||||
        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
 | 
			
		||||
							
								
								
									
										104
									
								
								.github/workflows/mocktest.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										104
									
								
								.github/workflows/mocktest.yml
									
									
									
									
										vendored
									
									
								
							@ -1,104 +0,0 @@
 | 
			
		||||
name: hl2sdk-mock tests
 | 
			
		||||
on: 
 | 
			
		||||
  push:
 | 
			
		||||
    branches:
 | 
			
		||||
     - master
 | 
			
		||||
     - '[0-9]+.[0-9]+-dev'
 | 
			
		||||
  pull_request:
 | 
			
		||||
    branches:
 | 
			
		||||
     - master
 | 
			
		||||
     - '[0-9]+.[0-9]+-dev'
 | 
			
		||||
jobs:
 | 
			
		||||
  mock:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v4
 | 
			
		||||
        name: Clone sourcemod
 | 
			
		||||
        with:
 | 
			
		||||
          submodules: recursive
 | 
			
		||||
          path: sourcemod
 | 
			
		||||
      
 | 
			
		||||
      - uses: actions/checkout@v4
 | 
			
		||||
        name: Clone metamod-source
 | 
			
		||||
        with:
 | 
			
		||||
          repository: alliedmodders/metamod-source
 | 
			
		||||
          submodules: recursive
 | 
			
		||||
          path: metamod-source
 | 
			
		||||
      
 | 
			
		||||
      - uses: actions/checkout@v4
 | 
			
		||||
        name: Clone hl2sdk-mock
 | 
			
		||||
        with:
 | 
			
		||||
          repository: alliedmodders/hl2sdk-mock
 | 
			
		||||
          submodules: recursive
 | 
			
		||||
          path: hl2sdk-mock
 | 
			
		||||
      
 | 
			
		||||
      - uses: actions/setup-python@v5
 | 
			
		||||
        name: Setup Python 3.10
 | 
			
		||||
        with:
 | 
			
		||||
          python-version: "3.10"
 | 
			
		||||
      
 | 
			
		||||
      - name: Install AMBuild
 | 
			
		||||
        run: |
 | 
			
		||||
          python -m pip install --upgrade pip setuptools wheel
 | 
			
		||||
          pip install git+https://github.com/alliedmodders/ambuild
 | 
			
		||||
 | 
			
		||||
      - name: Build MetaMod:Source
 | 
			
		||||
        working-directory: metamod-source
 | 
			
		||||
        run: |
 | 
			
		||||
          python configure.py --enable-optimize --sdks=mock --targets=x86_64
 | 
			
		||||
          ambuild objdir
 | 
			
		||||
 | 
			
		||||
      - name: Build SourceMod
 | 
			
		||||
        working-directory: sourcemod
 | 
			
		||||
        run: |
 | 
			
		||||
          python configure.py --no-mysql --enable-optimize --sdks=mock --targets=x86_64
 | 
			
		||||
          ambuild objdir
 | 
			
		||||
      
 | 
			
		||||
      - name: Build hl2sdk-mock
 | 
			
		||||
        working-directory: hl2sdk-mock
 | 
			
		||||
        run: |
 | 
			
		||||
          python configure.py --enable-optimize --targets=x86_64
 | 
			
		||||
          ambuild objdir
 | 
			
		||||
      
 | 
			
		||||
      - name: Setup gamedir
 | 
			
		||||
        working-directory: hl2sdk-mock
 | 
			
		||||
        shell: bash
 | 
			
		||||
        run: |
 | 
			
		||||
          mkdir ../gamedir
 | 
			
		||||
          ./build_gamedir.sh ../gamedir ../metamod-source/objdir/package
 | 
			
		||||
          ./build_gamedir.sh ../gamedir ../sourcemod/objdir/package
 | 
			
		||||
      
 | 
			
		||||
      - name: Compile testsuite
 | 
			
		||||
        working-directory: hl2sdk-mock
 | 
			
		||||
        shell: bash
 | 
			
		||||
        run: |
 | 
			
		||||
          mkdir ../gamedir/addons/sourcemod/plugins/optional
 | 
			
		||||
 | 
			
		||||
          for f in ../sourcemod/plugins/testsuite/mock/*.sp; do
 | 
			
		||||
            echo "Compiling $(basename $f)"
 | 
			
		||||
            ../gamedir/addons/sourcemod/scripting/spcomp64 -i ../gamedir/addons/sourcemod/scripting/include -o "../gamedir/addons/sourcemod/plugins/optional/$(basename $f .sp).smx" -E "$f"
 | 
			
		||||
          done
 | 
			
		||||
      
 | 
			
		||||
      - name: Test
 | 
			
		||||
        working-directory: hl2sdk-mock
 | 
			
		||||
        shell: bash
 | 
			
		||||
        run: |
 | 
			
		||||
          for f in ../gamedir/addons/sourcemod/plugins/optional/*.smx; do
 | 
			
		||||
            echo "==================================="
 | 
			
		||||
            echo "Running $(basename $f)..."
 | 
			
		||||
            echo "==================================="
 | 
			
		||||
            timeout 60 ./objdir/dist/x86_64/srcds -game_dir ../gamedir +map de_thunder -command "sm plugins load optional/$(basename $f)" -run -run-ticks 20 |
 | 
			
		||||
            {
 | 
			
		||||
              failed=0
 | 
			
		||||
              while IFS= read -r line; do
 | 
			
		||||
                echo "$line"
 | 
			
		||||
                if [[ "$line" == *"FAIL"* ]]; then
 | 
			
		||||
                  failed=1
 | 
			
		||||
                fi
 | 
			
		||||
              done
 | 
			
		||||
              if [ "$failed" = "1" ]; then
 | 
			
		||||
                echo "$(basename $f) failed."
 | 
			
		||||
                exit 1
 | 
			
		||||
              fi
 | 
			
		||||
            }
 | 
			
		||||
          done
 | 
			
		||||
							
								
								
									
										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@v4
 | 
			
		||||
        with:
 | 
			
		||||
          submodules: recursive
 | 
			
		||||
 | 
			
		||||
      # Setup Python for AMBuild
 | 
			
		||||
      - uses: actions/setup-python@v5
 | 
			
		||||
        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 universal x64/arm64 on macOS
 | 
			
		||||
        if: startsWith(runner.os, 'macOS')
 | 
			
		||||
        run: echo "ARCH=x86_64,arm64" >> $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@v4
 | 
			
		||||
        with:
 | 
			
		||||
          name: sourcemod-tooling-${{ env.SM_VERSION }}-${{ matrix.os_short }}
 | 
			
		||||
          path: build/package
 | 
			
		||||
							
								
								
									
										42
									
								
								.github/workflows/translations.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										42
									
								
								.github/workflows/translations.yml
									
									
									
									
										vendored
									
									
								
							@ -1,42 +0,0 @@
 | 
			
		||||
name: Update translation project
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches:
 | 
			
		||||
      - master
 | 
			
		||||
    paths:
 | 
			
		||||
      - 'translations/**'
 | 
			
		||||
  workflow_dispatch:
 | 
			
		||||
jobs:
 | 
			
		||||
  update_translations:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v4
 | 
			
		||||
        with:
 | 
			
		||||
          submodules: recursive
 | 
			
		||||
 | 
			
		||||
      - uses: actions/setup-python@v5
 | 
			
		||||
        name: Setup Python 3.10
 | 
			
		||||
        with:
 | 
			
		||||
          python-version: "3.10"
 | 
			
		||||
 | 
			
		||||
      - name: Install Python dependencies
 | 
			
		||||
        working-directory: tools/language_check
 | 
			
		||||
        run: |
 | 
			
		||||
          python -m pip install --upgrade -r requirements.txt
 | 
			
		||||
 | 
			
		||||
      - name: Generate token
 | 
			
		||||
        id: generate_token
 | 
			
		||||
        uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a
 | 
			
		||||
        with:
 | 
			
		||||
          app_id: ${{ secrets.APP_ID }}
 | 
			
		||||
          private_key: ${{ secrets.APP_PEM }}
 | 
			
		||||
 | 
			
		||||
      - name: Update translation project
 | 
			
		||||
        working-directory: tools/language_check
 | 
			
		||||
        env:
 | 
			
		||||
          GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
 | 
			
		||||
          ORGANIZATION: alliedmodders
 | 
			
		||||
          PROJECT_NUMBER: 1
 | 
			
		||||
        run: |
 | 
			
		||||
          python ./compare_translation_phrases.py 
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										29
									
								
								.github/workflows/translations_sanitycheck.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								.github/workflows/translations_sanitycheck.yml
									
									
									
									
										vendored
									
									
								
							@ -1,29 +0,0 @@
 | 
			
		||||
name: Sanity check translation phrases
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches:
 | 
			
		||||
      - master
 | 
			
		||||
    paths:
 | 
			
		||||
      - 'translations/**'
 | 
			
		||||
  pull_request:
 | 
			
		||||
    branches:
 | 
			
		||||
     - master
 | 
			
		||||
    paths:
 | 
			
		||||
      - 'translations/**'
 | 
			
		||||
  workflow_dispatch:
 | 
			
		||||
jobs:
 | 
			
		||||
  check_translations:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v4
 | 
			
		||||
 | 
			
		||||
      - uses: actions/setup-python@v5
 | 
			
		||||
        name: Setup Python 3.10
 | 
			
		||||
        with:
 | 
			
		||||
          python-version: "3.10"
 | 
			
		||||
 | 
			
		||||
      - name: Check translation phrases syntax
 | 
			
		||||
        working-directory: tools/language_check
 | 
			
		||||
        run: |
 | 
			
		||||
          python ./sanity_check.py 
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -28,6 +28,7 @@ LIB-Debug/
 | 
			
		||||
[Tt]humbs.db
 | 
			
		||||
 | 
			
		||||
# AMBuild build directories
 | 
			
		||||
build/
 | 
			
		||||
obj-*/
 | 
			
		||||
*~
 | 
			
		||||
*.rej
 | 
			
		||||
@ -35,9 +36,3 @@ obj-*/
 | 
			
		||||
*.smx
 | 
			
		||||
*.swp
 | 
			
		||||
*.gdb_history
 | 
			
		||||
objdir
 | 
			
		||||
# Not standardized, but common name for build directories
 | 
			
		||||
build*/
 | 
			
		||||
 | 
			
		||||
.vs/*
 | 
			
		||||
.vscode/*
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							@ -1,14 +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
 | 
			
		||||
[submodule "hl2sdk-manifests"]
 | 
			
		||||
	path = hl2sdk-manifests
 | 
			
		||||
	url = https://github.com/alliedmodders/hl2sdk-manifests.git
 | 
			
		||||
[submodule "public/safetyhook"]
 | 
			
		||||
	path = public/safetyhook
 | 
			
		||||
	url = https://github.com/alliedmodders/safetyhook
 | 
			
		||||
	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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										688
									
								
								AMBuildScript
									
									
									
									
									
								
							
							
						
						
									
										688
									
								
								AMBuildScript
									
									
									
									
									
								
							@ -1,7 +1,63 @@
 | 
			
		||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
 | 
			
		||||
import collections
 | 
			
		||||
import os, sys
 | 
			
		||||
import subprocess
 | 
			
		||||
 | 
			
		||||
class SDK(object):
 | 
			
		||||
  def __init__(self, sdk, ext, aDef, name, platform, dir):
 | 
			
		||||
    self.folder = 'hl2sdk-' + dir
 | 
			
		||||
    self.envvar = sdk
 | 
			
		||||
    self.ext = ext
 | 
			
		||||
    self.code = aDef
 | 
			
		||||
    self.define = name
 | 
			
		||||
    self.platform = platform
 | 
			
		||||
    self.name = dir
 | 
			
		||||
    self.path = None # Actual path
 | 
			
		||||
    self.platformSpec = platform
 | 
			
		||||
 | 
			
		||||
    # By default, nothing supports x64.
 | 
			
		||||
    if type(platform) is list:
 | 
			
		||||
      self.platformSpec = {p: ['x86'] for p in platform}
 | 
			
		||||
    else:
 | 
			
		||||
      self.platformSpec = platform
 | 
			
		||||
 | 
			
		||||
  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']
 | 
			
		||||
CSGO = {
 | 
			
		||||
  'windows': ['x86'],
 | 
			
		||||
  'linux': ['x86', 'x64'],
 | 
			
		||||
  'mac': ['x64']
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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'),
 | 
			
		||||
  'hl2dm':  SDK('HL2SDKHL2DM', '2.hl2dm', '7', 'HL2DM', WinLinuxMac, 'hl2dm'),
 | 
			
		||||
  'dods': SDK('HL2SDKDODS', '2.dods', '8', 'DODS', WinLinuxMac, 'dods'),
 | 
			
		||||
  'sdk2013': SDK('HL2SDK2013', '2.sdk2013', '9', 'SDK2013', WinLinuxMac, 'sdk2013'),
 | 
			
		||||
  'tf2':  SDK('HL2SDKTF2', '2.tf2', '11', 'TF2', WinLinuxMac, 'tf2'),
 | 
			
		||||
  'l4d':  SDK('HL2SDKL4D', '2.l4d', '12', 'LEFT4DEAD', WinLinuxMac, 'l4d'),
 | 
			
		||||
  'nucleardawn': SDK('HL2SDKND', '2.nd', '13', 'NUCLEARDAWN', WinLinuxMac, 'nucleardawn'),
 | 
			
		||||
  'l4d2': SDK('HL2SDKL4D2', '2.l4d2', '15', 'LEFT4DEAD2', WinLinuxMac, 'l4d2'),
 | 
			
		||||
  'darkm':  SDK('HL2SDK-DARKM', '2.darkm', '2', 'DARKMESSIAH', WinOnly, 'darkm'),
 | 
			
		||||
  'swarm':  SDK('HL2SDK-SWARM', '2.swarm', '16', 'ALIENSWARM', WinOnly, 'swarm'),
 | 
			
		||||
  'bgt':  SDK('HL2SDK-BGT', '2.bgt', '4', 'BLOODYGOODTIME', WinOnly, 'bgt'),
 | 
			
		||||
  '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', 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'),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
def ResolveEnvPath(env, folder):
 | 
			
		||||
  if env in os.environ:
 | 
			
		||||
@ -24,60 +80,41 @@ 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']
 | 
			
		||||
 | 
			
		||||
SdkHelpers = builder.Eval('hl2sdk-manifests/SdkHelpers.ambuild', {
 | 
			
		||||
    'Project': 'sourcemod'
 | 
			
		||||
})
 | 
			
		||||
def AppendArchSuffix(binary, name, arch):
 | 
			
		||||
  if arch == 'x64':
 | 
			
		||||
    binary.localFolder = name + '.x64'
 | 
			
		||||
 | 
			
		||||
class SMConfig(object):
 | 
			
		||||
  def __init__(self):
 | 
			
		||||
    self.sdk_manifests = []
 | 
			
		||||
    self.sdks = {}
 | 
			
		||||
    self.sdk_targets = []
 | 
			
		||||
    self.binaries = []
 | 
			
		||||
    self.spvm = []
 | 
			
		||||
    self.extensions = []
 | 
			
		||||
    self.generated_headers = None
 | 
			
		||||
    self.mms_root = None
 | 
			
		||||
    self.mysql_root = {}
 | 
			
		||||
    self.spcomp = None
 | 
			
		||||
    self.spcomp_bins = []
 | 
			
		||||
    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 = {}
 | 
			
		||||
    self.libsafetyhook = {}
 | 
			
		||||
 | 
			
		||||
    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':
 | 
			
		||||
@ -97,38 +134,41 @@ class SMConfig(object):
 | 
			
		||||
    import re
 | 
			
		||||
    with open(os.path.join(builder.sourcePath, 'product.version'), 'r') as fp:
 | 
			
		||||
      productContents = fp.read()
 | 
			
		||||
    m = re.match(r'(\d+)\.(\d+)\.(\d+).*', productContents)
 | 
			
		||||
    m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
 | 
			
		||||
    if m == None:
 | 
			
		||||
      self.productVersion = '1.0.0'
 | 
			
		||||
    else:
 | 
			
		||||
      major, minor, release = m.groups()
 | 
			
		||||
      self.productVersion = '{0}.{1}.{2}'.format(major, minor, release)
 | 
			
		||||
 | 
			
		||||
  def findSdkPath(self, sdk_name):
 | 
			
		||||
    dir_name = 'hl2sdk-{}'.format(sdk_name)
 | 
			
		||||
    if builder.options.hl2sdk_root:
 | 
			
		||||
      sdk_path = os.path.join(builder.options.hl2sdk_root, dir_name)
 | 
			
		||||
      if os.path.exists(sdk_path):
 | 
			
		||||
        return sdk_path
 | 
			
		||||
    return ResolveEnvPath('HL2SDK{}'.format(sdk_name.upper()), dir_name)
 | 
			
		||||
 | 
			
		||||
  def shouldIncludeSdk(self, sdk):
 | 
			
		||||
    return not sdk.get('source2', False)
 | 
			
		||||
 | 
			
		||||
  def detectSDKs(self):
 | 
			
		||||
    sdk_list = [s for s in builder.options.sdks.split(',') if s]
 | 
			
		||||
    SdkHelpers.sdk_filter = self.shouldIncludeSdk
 | 
			
		||||
    SdkHelpers.find_sdk_path = self.findSdkPath
 | 
			
		||||
    SdkHelpers.findSdks(builder, self.all_targets, sdk_list)
 | 
			
		||||
    sdk_list = builder.options.sdks.split(',')
 | 
			
		||||
    use_all = sdk_list[0] == 'all'
 | 
			
		||||
    use_present = sdk_list[0] == 'present'
 | 
			
		||||
 | 
			
		||||
    self.sdks = SdkHelpers.sdks
 | 
			
		||||
    self.sdk_manifests = SdkHelpers.sdk_manifests
 | 
			
		||||
    self.sdk_targets = SdkHelpers.sdk_targets
 | 
			
		||||
    for sdk_name in PossibleSDKs:
 | 
			
		||||
      sdk = PossibleSDKs[sdk_name]
 | 
			
		||||
      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 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):
 | 
			
		||||
      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('MMSOURCE112', 'mmsource-1.12')
 | 
			
		||||
      self.mms_root = ResolveEnvPath('MMSOURCE110', 'mmsource-1.10')
 | 
			
		||||
      if not self.mms_root:
 | 
			
		||||
        self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
 | 
			
		||||
      if not self.mms_root:
 | 
			
		||||
@ -139,56 +179,40 @@ 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:
 | 
			
		||||
          for i in range(10):
 | 
			
		||||
            self.mysql_root['x86'] = ResolveEnvPath('MYSQL55', 'mysql-5.' + str(i))
 | 
			
		||||
            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.')
 | 
			
		||||
        self.mysql_root['x86'] = Normalize(self.mysql_root['x86'])
 | 
			
		||||
      if builder.options.mysql_path:
 | 
			
		||||
        self.mysql_root['x86'] = builder.options.mysql_path
 | 
			
		||||
      else:
 | 
			
		||||
        for i in range(10):
 | 
			
		||||
          self.mysql_root['x86'] = ResolveEnvPath('MYSQL55', 'mysql-5.' + str(i))
 | 
			
		||||
          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!')
 | 
			
		||||
      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')
 | 
			
		||||
    
 | 
			
		||||
    allowed_archs = ['x86_64']
 | 
			
		||||
    if builder.host.platform == 'mac':
 | 
			
		||||
        if getattr(builder.options, 'scripting_only', False):
 | 
			
		||||
            allowed_archs += ['arm64']
 | 
			
		||||
    else:
 | 
			
		||||
        allowed_archs += ['x86']
 | 
			
		||||
    if not set(self.archs).issubset(['x86', 'x64']):
 | 
			
		||||
      raise Exception('Unknown target architecture: {0}'.format(builder.target.arch))
 | 
			
		||||
 | 
			
		||||
    if not set(self.target_archs).issubset(allowed_archs):
 | 
			
		||||
      raise Exception('Unknown target architecture: {0}'.format(self.target_archs))
 | 
			
		||||
    cxx = builder.DetectCxx()
 | 
			
		||||
    
 | 
			
		||||
    for cxx in self.all_targets:
 | 
			
		||||
        self.configure_cxx(cxx)
 | 
			
		||||
 | 
			
		||||
  def configure_cxx(self, cxx):
 | 
			
		||||
    if cxx.family == 'msvc':
 | 
			
		||||
      if cxx.version < 1914 and builder.options.generator != 'vs':
 | 
			
		||||
        raise Exception(f'Only MSVC 2017 15.7 and later are supported, full C++17 support is required. ({str(cxx.version)} < 1914)')
 | 
			
		||||
    elif cxx.family == 'gcc':
 | 
			
		||||
      if cxx.version < 'gcc-9':
 | 
			
		||||
        raise Exception('Only GCC versions 9 or later are supported, full C++17 support is required.')
 | 
			
		||||
    elif cxx.family == 'clang':
 | 
			
		||||
      if cxx.version < 'clang-5':
 | 
			
		||||
        raise Exception('Only clang versions 5 or later are supported, full C++17 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)
 | 
			
		||||
@ -204,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.
 | 
			
		||||
@ -243,28 +267,25 @@ class SMConfig(object):
 | 
			
		||||
      '-Wno-unused',
 | 
			
		||||
      '-Wno-switch',
 | 
			
		||||
      '-Wno-array-bounds',
 | 
			
		||||
      '-msse',
 | 
			
		||||
      '-fvisibility=hidden',
 | 
			
		||||
    ]
 | 
			
		||||
    if cxx.target.arch in ['x86', 'x86_64']:
 | 
			
		||||
      cxx.cflags += ['-msse']
 | 
			
		||||
 | 
			
		||||
    cxx.cxxflags += ['-std=c++17']
 | 
			
		||||
 | 
			
		||||
    cxx.cxxflags += [
 | 
			
		||||
      '-std=c++11',
 | 
			
		||||
      '-fno-exceptions',
 | 
			
		||||
      '-fno-threadsafe-statics',
 | 
			
		||||
      '-Wno-non-virtual-dtor',
 | 
			
		||||
      '-Wno-overloaded-virtual',
 | 
			
		||||
      '-Wno-register',
 | 
			
		||||
      '-fvisibility-inlines-hidden',
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    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']
 | 
			
		||||
@ -284,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']
 | 
			
		||||
      cxx.cflags += ['-O3']
 | 
			
		||||
 | 
			
		||||
  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']
 | 
			
		||||
@ -331,7 +331,6 @@ class SMConfig(object):
 | 
			
		||||
      '/EHsc',
 | 
			
		||||
      '/GR-',
 | 
			
		||||
      '/TP',
 | 
			
		||||
      '/std:c++17',
 | 
			
		||||
    ]
 | 
			
		||||
    cxx.linkflags += [
 | 
			
		||||
      'kernel32.lib',
 | 
			
		||||
@ -359,63 +358,29 @@ 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', '_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
 | 
			
		||||
    cxx.defines += ['_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
 | 
			
		||||
    cxx.linkflags += ['-lm']
 | 
			
		||||
    if cxx.family == 'gcc':
 | 
			
		||||
      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.15']
 | 
			
		||||
    cxx.cflags += ['-mmacosx-version-min=10.5']
 | 
			
		||||
    cxx.linkflags += [
 | 
			
		||||
      '-mmacosx-version-min=10.15',
 | 
			
		||||
      '-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),
 | 
			
		||||
@ -423,39 +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']
 | 
			
		||||
    self.AddCxxCompat(binary)
 | 
			
		||||
 | 
			
		||||
    # 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'):
 | 
			
		||||
@ -464,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 += [
 | 
			
		||||
@ -493,82 +452,167 @@ 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 AddCxxCompat(self, binary):
 | 
			
		||||
    if binary.compiler.target.platform == 'linux':
 | 
			
		||||
      binary.sources += [
 | 
			
		||||
        os.path.join(builder.sourcePath, 'public', 'amtl', 'compat', 'stdcxx.cpp'),
 | 
			
		||||
      ]
 | 
			
		||||
 | 
			
		||||
  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'),
 | 
			
		||||
      os.path.join(self.mms_root, 'core', 'sourcehook'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    for other_sdk in self.sdk_manifests:
 | 
			
		||||
      compiler.defines += ['SE_{}={}'.format(other_sdk['define'], other_sdk['code'])]
 | 
			
		||||
    defines = ['SE_' + PossibleSDKs[i].define + '=' + PossibleSDKs[i].code for i in PossibleSDKs]
 | 
			
		||||
    compiler.defines += defines
 | 
			
		||||
 | 
			
		||||
    SdkHelpers.configureCxx(context, binary, sdk)
 | 
			
		||||
    paths = [
 | 
			
		||||
      ['public'],
 | 
			
		||||
      ['public', 'engine'],
 | 
			
		||||
      ['public', 'mathlib'],
 | 
			
		||||
      ['public', 'vstdlib'],
 | 
			
		||||
      ['public', 'tier0'],
 | 
			
		||||
      ['public', 'tier1']
 | 
			
		||||
    ]
 | 
			
		||||
    if sdk.name == 'episode1' or sdk.name == 'darkm':
 | 
			
		||||
      paths.append(['public', 'dlls'])
 | 
			
		||||
      paths.append(['game_shared'])
 | 
			
		||||
    else:
 | 
			
		||||
      paths.append(['public', 'game', 'server'])
 | 
			
		||||
      paths.append(['public', 'toolframework'])
 | 
			
		||||
      paths.append(['game', 'shared'])
 | 
			
		||||
      paths.append(['common'])
 | 
			
		||||
 | 
			
		||||
    compiler.defines += ['SOURCE_ENGINE=' + sdk.code]
 | 
			
		||||
 | 
			
		||||
    if sdk.name in ['sdk2013', 'bms'] and compiler.like('gcc'):
 | 
			
		||||
      # The 2013 SDK already has these in public/tier0/basetypes.h
 | 
			
		||||
      compiler.defines.remove('stricmp=strcasecmp')
 | 
			
		||||
      compiler.defines.remove('_stricmp=strcasecmp')
 | 
			
		||||
      compiler.defines.remove('_snprintf=snprintf')
 | 
			
		||||
      compiler.defines.remove('_vsnprintf=vsnprintf')
 | 
			
		||||
 | 
			
		||||
    if compiler.like('msvc'):
 | 
			
		||||
      compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32']
 | 
			
		||||
      if compiler.version >= 1900:
 | 
			
		||||
        compiler.linkflags += ['legacy_stdio_definitions.lib']
 | 
			
		||||
    else:
 | 
			
		||||
      compiler.defines += ['COMPILER_GCC']
 | 
			
		||||
 | 
			
		||||
    if arch == 'x64':
 | 
			
		||||
      compiler.defines += ['X64BITS', 'PLATFORM_64BITS']
 | 
			
		||||
 | 
			
		||||
    # For everything after Swarm, this needs to be defined for entity networking
 | 
			
		||||
    # to work properly with sendprop value changes.
 | 
			
		||||
    if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
 | 
			
		||||
      compiler.defines += ['NETWORK_VARS_ENABLED']
 | 
			
		||||
 | 
			
		||||
    if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2']:
 | 
			
		||||
      if builder.target.platform in ['linux', 'mac']:
 | 
			
		||||
        compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE']
 | 
			
		||||
 | 
			
		||||
    if sdk.name == 'csgo' and builder.target.platform == 'linux':
 | 
			
		||||
      compiler.linkflags += ['-lstdc++']
 | 
			
		||||
      compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0']
 | 
			
		||||
 | 
			
		||||
    for path in paths:
 | 
			
		||||
      compiler.cxxincludes += [os.path.join(sdk.path, *path)]
 | 
			
		||||
 | 
			
		||||
    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 arch == 'x64':
 | 
			
		||||
        lib_folder = os.path.join(sdk.path, 'lib', 'linux64')
 | 
			
		||||
      else:
 | 
			
		||||
        lib_folder = os.path.join(sdk.path, 'lib', 'linux')
 | 
			
		||||
    elif builder.target.platform == 'mac':
 | 
			
		||||
      if sdk.name in ['sdk2013', 'bms']:
 | 
			
		||||
        lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32')
 | 
			
		||||
      elif arch == 'x64':
 | 
			
		||||
        lib_folder = os.path.join(sdk.path, 'lib', 'osx64')
 | 
			
		||||
      else:
 | 
			
		||||
        lib_folder = os.path.join(sdk.path, 'lib', 'mac')
 | 
			
		||||
 | 
			
		||||
    if builder.target.platform in ['linux', 'mac']:
 | 
			
		||||
      if sdk.name in ['sdk2013', 'bms'] or arch == 'x64':
 | 
			
		||||
        compiler.postlink += [
 | 
			
		||||
          compiler.Dep(os.path.join(lib_folder, 'tier1.a')),
 | 
			
		||||
          compiler.Dep(os.path.join(lib_folder, 'mathlib.a'))
 | 
			
		||||
        ]
 | 
			
		||||
      else:
 | 
			
		||||
        compiler.postlink += [
 | 
			
		||||
          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 arch == 'x64':
 | 
			
		||||
          compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces.a'))]
 | 
			
		||||
        else:
 | 
			
		||||
          compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces_i486.a'))]
 | 
			
		||||
 | 
			
		||||
    dynamic_libs = []
 | 
			
		||||
    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 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 builder.target.platform == 'mac':
 | 
			
		||||
      compiler.linkflags.append('-liconv')
 | 
			
		||||
      dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib']
 | 
			
		||||
    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:
 | 
			
		||||
        lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib'
 | 
			
		||||
        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)
 | 
			
		||||
 | 
			
		||||
      def make_linker(source_path, output_path):
 | 
			
		||||
        def link(context, binary):
 | 
			
		||||
          cmd_node, (output,) = context.AddSymlink(source_path, output_path)
 | 
			
		||||
          return output
 | 
			
		||||
        return link
 | 
			
		||||
 | 
			
		||||
      linker = make_linker(source_path, output_path)
 | 
			
		||||
      compiler.linkflags[0:0] = [compiler.Dep(library, linker)]
 | 
			
		||||
 | 
			
		||||
    return binary
 | 
			
		||||
 | 
			
		||||
  def AddCDetour(self, binary):
 | 
			
		||||
    public_path = os.path.join(builder.sourcePath, 'public')
 | 
			
		||||
    binary.sources += [ os.path.join(public_path, 'CDetour', 'detours.cpp') ]
 | 
			
		||||
    binary.compiler.cxxincludes += [ os.path.join(public_path, 'safetyhook', 'include') ]
 | 
			
		||||
 | 
			
		||||
    for task in self.libsafetyhook:
 | 
			
		||||
      if task.target.arch == binary.compiler.target.arch:
 | 
			
		||||
        binary.compiler.linkflags += [task.binary]
 | 
			
		||||
        return
 | 
			
		||||
    raise Exception('No suitable build of safetyhook was found.')
 | 
			
		||||
 | 
			
		||||
  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.AddCxxCompat(binary)
 | 
			
		||||
    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.AddCxxCompat(binary)
 | 
			
		||||
    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(
 | 
			
		||||
@ -580,104 +624,46 @@ if SM.use_auto_versioning():
 | 
			
		||||
    { 'SM': SM }
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
class SafetyHookShim(object):
 | 
			
		||||
  def __init__(self):
 | 
			
		||||
    self.all_targets = {}
 | 
			
		||||
    self.libsafetyhook = {}
 | 
			
		||||
 | 
			
		||||
SafetyHook = SafetyHookShim()
 | 
			
		||||
SafetyHook.all_targets = SM.all_targets
 | 
			
		||||
builder.Build('public/safetyhook/AMBuilder', {'SafetyHook': SafetyHook })
 | 
			
		||||
SM.libsafetyhook = SafetyHook.libsafetyhook
 | 
			
		||||
 | 
			
		||||
class SPRoot(object):
 | 
			
		||||
  def __init__(self):
 | 
			
		||||
    self.generated_headers = SM.generated_headers
 | 
			
		||||
  # 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'],
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
def IsBetterDefaultSpcomp(spcomp, other):
 | 
			
		||||
    if other is None:
 | 
			
		||||
        return True
 | 
			
		||||
    if spcomp.target.arch == 'universal':
 | 
			
		||||
        return True
 | 
			
		||||
    if other.target.arch == 'universal':
 | 
			
		||||
        return False
 | 
			
		||||
    return spcomp.target.arch == 'x86'
 | 
			
		||||
 | 
			
		||||
for spcomp in SP.spcomp:
 | 
			
		||||
    if IsBetterDefaultSpcomp(spcomp, SM.spcomp):
 | 
			
		||||
        SM.spcomp = spcomp
 | 
			
		||||
    SM.spcomp_bins.append(spcomp)
 | 
			
		||||
 | 
			
		||||
# If we have a universal binary, ignore all other spcomps.
 | 
			
		||||
if SM.spcomp.target.arch == 'universal':
 | 
			
		||||
    SM.spcomp_bins = [SM.spcomp]
 | 
			
		||||
 | 
			
		||||
if not getattr(builder.options, 'scripting_only', False):
 | 
			
		||||
  for cxx in SM.all_targets:
 | 
			
		||||
    SM.spvm += [
 | 
			
		||||
      SP.libsourcepawn[cxx.target.arch]
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
if getattr(builder.options, 'scripting_only', False):
 | 
			
		||||
  BuildScripts = [
 | 
			
		||||
    'tools/buildbot/PackageHelpers',
 | 
			
		||||
    'tools/buildbot/ToolsPackageScript',
 | 
			
		||||
  ]
 | 
			
		||||
if len(SP.spcomp) > 1:
 | 
			
		||||
  SM.spcomp = SP.spcomp['x86']
 | 
			
		||||
else:
 | 
			
		||||
  BuildScripts = [
 | 
			
		||||
    'loader/AMBuilder',
 | 
			
		||||
    'core/AMBuilder',
 | 
			
		||||
    'core/logic/AMBuilder',
 | 
			
		||||
    'extensions/bintools/AMBuilder',
 | 
			
		||||
    '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',
 | 
			
		||||
    'extensions/sqlite/AMBuilder',
 | 
			
		||||
    'extensions/tf2/AMBuilder',
 | 
			
		||||
    'extensions/topmenus/AMBuilder',
 | 
			
		||||
    'extensions/updater/AMBuilder',
 | 
			
		||||
  SM.spcomp = SP.spcomp[list(SP.spcomp.keys())[0]]
 | 
			
		||||
SM.spcomp_bins = list(SP.spcomp.values())
 | 
			
		||||
for arch in SM.archs:
 | 
			
		||||
  SM.binaries += [
 | 
			
		||||
     SP.libsourcepawn[arch]
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
  if builder.backend == 'amb2':
 | 
			
		||||
    BuildScripts += [
 | 
			
		||||
      'plugins/AMBuilder',
 | 
			
		||||
      'tools/buildbot/PackageHelpers',
 | 
			
		||||
      'tools/buildbot/PackageScript',
 | 
			
		||||
    ]
 | 
			
		||||
BuildScripts = [
 | 
			
		||||
  'loader/AMBuilder',
 | 
			
		||||
  'core/AMBuilder',
 | 
			
		||||
  'core/logic/AMBuilder',
 | 
			
		||||
  'extensions/bintools/AMBuilder',
 | 
			
		||||
  'extensions/clientprefs/AMBuilder',
 | 
			
		||||
  'extensions/curl/AMBuilder',
 | 
			
		||||
  'extensions/cstrike/AMBuilder',
 | 
			
		||||
  'extensions/geoip/AMBuilder',
 | 
			
		||||
  'extensions/mysql/AMBuilder',
 | 
			
		||||
  'extensions/regex/AMBuilder',
 | 
			
		||||
  'extensions/sdkhooks/AMBuilder',
 | 
			
		||||
  'extensions/sdktools/AMBuilder',
 | 
			
		||||
  'extensions/sqlite/AMBuilder',
 | 
			
		||||
  'extensions/tf2/AMBuilder',
 | 
			
		||||
  'extensions/topmenus/AMBuilder',
 | 
			
		||||
  'extensions/updater/AMBuilder',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
if builder.backend == 'amb2':
 | 
			
		||||
  BuildScripts += [
 | 
			
		||||
    'plugins/AMBuilder',
 | 
			
		||||
    'tools/buildbot/PackageScript',
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
builder.Build(BuildScripts, { 'SM': SM })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,6 @@ Development
 | 
			
		||||
- [SourcePawn scripting](https://wiki.alliedmods.net/Category:SourceMod_Scripting): SourcePawn examples and introduction to the language
 | 
			
		||||
- [SourceMod plugin API](https://sm.alliedmods.net/new-api): Online SourceMod plugin API reference generated from the include files
 | 
			
		||||
- [SourceMod extension development](https://wiki.alliedmods.net/Category:SourceMod_Development): C++ examples and introduction to various extension interfaces
 | 
			
		||||
- [Translation project](https://github.com/orgs/alliedmodders/projects/1): Help [translate SourceMod](https://wiki.alliedmods.net/Translations_(SourceMod_Scripting)) into your language
 | 
			
		||||
 | 
			
		||||
Contact
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
{
 | 
			
		||||
@ -86,6 +86,9 @@ public:
 | 
			
		||||
	const char		*gamesuffix;
 | 
			
		||||
	/* Data */
 | 
			
		||||
	ServerGlobals   *serverGlobals;
 | 
			
		||||
	void *          serverFactory;
 | 
			
		||||
	void *          engineFactory;
 | 
			
		||||
	void *          matchmakingDSFactory;
 | 
			
		||||
	SMGlobalClass *	listeners;
 | 
			
		||||
 | 
			
		||||
	// ConVar functions.
 | 
			
		||||
@ -112,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;
 | 
			
		||||
 | 
			
		||||
@ -44,7 +44,6 @@ public:
 | 
			
		||||
	virtual char *ReadLine(char *pOutput, int maxChars, FileHandle_t file) = 0;
 | 
			
		||||
	virtual bool EndOfFile(FileHandle_t file) = 0;
 | 
			
		||||
	virtual bool FileExists(const char *pFileName, const char *pPathID = 0) = 0;
 | 
			
		||||
	virtual unsigned int Size(FileHandle_t file) = 0;
 | 
			
		||||
	virtual unsigned int Size(const char *pFileName, const char *pPathID = 0) = 0;
 | 
			
		||||
	virtual int Read(void* pOutput, int size, FileHandle_t file) = 0;
 | 
			
		||||
	virtual int Write(void const* pInput, int size, FileHandle_t file) = 0;
 | 
			
		||||
@ -57,7 +56,6 @@ public:
 | 
			
		||||
	virtual void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID = 0) = 0;
 | 
			
		||||
	virtual bool IsDirectory(const char *pFileName, const char *pathID = 0) = 0;
 | 
			
		||||
	virtual void CreateDirHierarchy(const char *path, const char *pathID = 0) = 0;
 | 
			
		||||
	virtual int GetSearchPath(const char* pathID, bool bGetPackFiles, char* pPath, int nMaxLen) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace SourceMod
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -54,6 +54,24 @@
 | 
			
		||||
	 */
 | 
			
		||||
	"PassInfoVar"			"_password"
 | 
			
		||||
	
 | 
			
		||||
	/**
 | 
			
		||||
	 * Specifies the sound that gets played when an item is selected from a menu.
 | 
			
		||||
	 */
 | 
			
		||||
	"MenuItemSound"			"buttons/button14.wav"
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Specifies the sound that gets played when an "Exit" button is selected 
 | 
			
		||||
	 * from a menu.
 | 
			
		||||
	 */
 | 
			
		||||
	"MenuExitSound"			"buttons/combine_button7.wav"
 | 
			
		||||
	
 | 
			
		||||
	/**
 | 
			
		||||
	 * Specifies the sound that gets played when an "Exit Back" button is selected 
 | 
			
		||||
	 * from a menu.  This is the special "Back" button that is intended to roll back
 | 
			
		||||
	 * to a previous menu.
 | 
			
		||||
	 */
 | 
			
		||||
	"MenuExitBackSound"		"buttons/combine_button7.wav"
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Enables or disables whether SourceMod reads a client's cl_language cvar to set 
 | 
			
		||||
	 * their language for server-side phrase translation.
 | 
			
		||||
@ -127,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,38 +1,4 @@
 | 
			
		||||
"Languages"
 | 
			
		||||
{
 | 
			
		||||
	"ar"		"Arabic"		// Arabic
 | 
			
		||||
	"bg"		"Bulgarian"		// Bulgarian
 | 
			
		||||
	"chi"		"SChinese"		// Chinese (Simplified)
 | 
			
		||||
	"cze"		"Czech"			// Czech
 | 
			
		||||
	"da"		"Danish"		// Danish
 | 
			
		||||
	"de"		"German"		// German
 | 
			
		||||
	"el"		"Greek"			// Greek
 | 
			
		||||
	"en"		"English"		// English
 | 
			
		||||
	"es"		"Spanish"		// Spanish
 | 
			
		||||
	"fi"		"Finnish"		// Finnish
 | 
			
		||||
	"fr"		"French"		// French
 | 
			
		||||
	"he"		"Hebrew"		// Hebrew
 | 
			
		||||
	"hu"		"Hungarian"		// Hungarian
 | 
			
		||||
	"it"		"Italian"		// Italian
 | 
			
		||||
	"jp"		"Japanese"		// Japanese
 | 
			
		||||
	"ko"		"Korean"		// Korean
 | 
			
		||||
 	"ko"		"KoreanA"		// Korean (https://bugs.alliedmods.net/show_bug.cgi?id=4667)
 | 
			
		||||
	"las"		"LatAm"			// Latin American Spanish
 | 
			
		||||
	"lt"		"Lithuanian"		// Lithuanian
 | 
			
		||||
	"lv"		"Latvian"		// Latvian
 | 
			
		||||
	"nl"		"Dutch"			// Dutch
 | 
			
		||||
	"no"		"Norwegian"		// Norwegian
 | 
			
		||||
	"pl"		"Polish"		// Polish
 | 
			
		||||
	"pt"		"Brazilian"		// Brazilian Portuguese
 | 
			
		||||
	"pt_p"		"Portuguese"		// Portuguese
 | 
			
		||||
	"ro"		"Romanian"		// Romanian
 | 
			
		||||
	"ru"		"Russian"		// Russian
 | 
			
		||||
	"sk"		"Slovak"		// Slovak
 | 
			
		||||
	"sv"		"Swedish"		// Swedish
 | 
			
		||||
	"th"		"Thai"			// Thai
 | 
			
		||||
	"tr"		"Turkish"		// Turkish
 | 
			
		||||
	"ua"		"Ukrainian"		// Ukrainian
 | 
			
		||||
	"vi"		"Vietnamese"		// Vietnamese
 | 
			
		||||
	"zho"		"TChinese"		// Chinese (Traditional)
 | 
			
		||||
 | 
			
		||||
	"en"			"English"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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');
 | 
			
		||||
							
								
								
									
										67
									
								
								configure.py
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								configure.py
									
									
									
									
									
								
							@ -1,49 +1,42 @@
 | 
			
		||||
# vim: set ts=2 sw=2 tw=99 noet:
 | 
			
		||||
import sys
 | 
			
		||||
try:
 | 
			
		||||
  from ambuild2 import run, util
 | 
			
		||||
	from ambuild2 import run, util
 | 
			
		||||
except:
 | 
			
		||||
  try:
 | 
			
		||||
    import ambuild
 | 
			
		||||
    sys.stderr.write('It looks like you have AMBuild 1 installed, but this project uses AMBuild 2.\n')
 | 
			
		||||
    sys.stderr.write('Upgrade to the latest version of AMBuild to continue.\n')
 | 
			
		||||
  except:
 | 
			
		||||
    sys.stderr.write('AMBuild must be installed to build this project.\n')
 | 
			
		||||
    sys.stderr.write('http://www.alliedmods.net/ambuild\n')
 | 
			
		||||
  sys.exit(1)
 | 
			
		||||
	try:
 | 
			
		||||
		import ambuild
 | 
			
		||||
		sys.stderr.write('It looks like you have AMBuild 1 installed, but this project uses AMBuild 2.\n')
 | 
			
		||||
		sys.stderr.write('Upgrade to the latest version of AMBuild to continue.\n')
 | 
			
		||||
	except:
 | 
			
		||||
		sys.stderr.write('AMBuild must be installed to build this project.\n')
 | 
			
		||||
		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,
 | 
			
		||||
                       help='Root search folder for HL2SDKs')
 | 
			
		||||
parser.options.add_argument('--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,
 | 
			
		||||
                       help='Path to 64-bit MySQL 5')
 | 
			
		||||
parser.options.add_argument('--mms-path', type=str, dest='mms_path', 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_option('--mysql-path', type=str, dest='mysql_path', default=None,
 | 
			
		||||
		                   help='Path to MySQL 5')
 | 
			
		||||
parser.options.add_option('--mysql64-path', type=str, dest='mysql64_path', default=None,
 | 
			
		||||
		                   help='Path to 64-bit MySQL 5')
 | 
			
		||||
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',
 | 
			
		||||
                       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('-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_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()
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										138
									
								
								core/AMBuilder
									
									
									
									
									
								
							
							
						
						
									
										138
									
								
								core/AMBuilder
									
									
									
									
									
								
							@ -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,103 +37,76 @@ project.sources += [
 | 
			
		||||
  'MenuStyle_Radio.cpp',
 | 
			
		||||
  'sm_autonatives.cpp',
 | 
			
		||||
  'ConsoleDetours.cpp',
 | 
			
		||||
  'vprof_tool.cpp',
 | 
			
		||||
  'smn_commandline.cpp',
 | 
			
		||||
  'GameHooks.cpp',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# SDK name to shipping gamedir
 | 
			
		||||
pb_gamedir_map = {
 | 
			
		||||
  'csgo': 'csgo',
 | 
			
		||||
  'blade': 'berimbau',
 | 
			
		||||
  'mcv': 'vietnam',
 | 
			
		||||
}
 | 
			
		||||
for sdk_name in SM.sdks:
 | 
			
		||||
  sdk = SM.sdks[sdk_name]
 | 
			
		||||
  for arch in SM.archs:
 | 
			
		||||
    if not arch in sdk.platformSpec[builder.target.platform]:
 | 
			
		||||
      continue
 | 
			
		||||
 | 
			
		||||
# SDK name to source code gamedir
 | 
			
		||||
pb_gamesrcdir_map = {
 | 
			
		||||
  'csgo': 'cstrike15',
 | 
			
		||||
  'blade': 'berimbau',
 | 
			
		||||
  'mcv': 'vietnam',
 | 
			
		||||
}
 | 
			
		||||
    binary_name = 'sourcemod.' + sdk.ext
 | 
			
		||||
 | 
			
		||||
for sdk_target in SM.sdk_targets:
 | 
			
		||||
  sdk = sdk_target.sdk
 | 
			
		||||
  cxx = sdk_target.cxx
 | 
			
		||||
    binary = SM.HL2Config(project, binary_name, sdk, arch)
 | 
			
		||||
    compiler = binary.compiler
 | 
			
		||||
 | 
			
		||||
  binary_name = 'sourcemod.' + sdk['extension']
 | 
			
		||||
  needs_protobuf = sdk['name'] in ['csgo', 'blade', 'mcv']
 | 
			
		||||
 | 
			
		||||
  binary = SM.HL2Config(project, builder, cxx, binary_name, sdk)
 | 
			
		||||
  SM.ConfigureForExtension(builder, binary.compiler)
 | 
			
		||||
 | 
			
		||||
  compiler = binary.compiler
 | 
			
		||||
  compiler.cxxincludes += [
 | 
			
		||||
    builder.sourcePath
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
  if needs_protobuf:
 | 
			
		||||
    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', pb_gamedir_map[sdk['name']], 'protobuf')
 | 
			
		||||
      builder.sourcePath
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
  if compiler.like('msvc'):
 | 
			
		||||
    compiler.defines += ['_ALLOW_KEYWORD_MACROS']
 | 
			
		||||
  if cxx.target.platform == 'linux':
 | 
			
		||||
    compiler.postlink += ['-lpthread', '-lrt']
 | 
			
		||||
    if sdk.name == 'csgo':
 | 
			
		||||
      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', 'csgo', 'protobuf')
 | 
			
		||||
      ]
 | 
			
		||||
 | 
			
		||||
  if needs_protobuf:
 | 
			
		||||
    if compiler.target.platform == 'linux':
 | 
			
		||||
      if compiler.target.arch == 'x86':
 | 
			
		||||
        lib_path = os.path.join(sdk['path'], 'lib', 'linux32', 'release', 'libprotobuf.a')
 | 
			
		||||
      elif compiler.target.arch == 'x86_64':
 | 
			
		||||
        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':
 | 
			
		||||
        lib_path = os.path.join(sdk['path'], 'lib', 'osx32', 'release', 'libprotobuf.a')
 | 
			
		||||
      elif compiler.target.arch == 'x86_64':
 | 
			
		||||
        lib_path = os.path.join(sdk['path'], 'lib', 'osx64', 'release', 'libprotobuf.a')
 | 
			
		||||
    elif compiler.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 compiler.like('msvc'):
 | 
			
		||||
      compiler.defines += ['_ALLOW_KEYWORD_MACROS']
 | 
			
		||||
    if builder.target.platform == 'linux':
 | 
			
		||||
      compiler.postlink += ['-lpthread', '-lrt']
 | 
			
		||||
 | 
			
		||||
      if 1900 <= msvc_ver < 2000:
 | 
			
		||||
        vs_year = '2015'
 | 
			
		||||
      else:
 | 
			
		||||
        raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"')
 | 
			
		||||
    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 arch == 'x64':
 | 
			
		||||
          lib_path = os.path.join(sdk.path, 'lib', 'linux64', 'release', 'libprotobuf.a')
 | 
			
		||||
        compiler.linkflags += ['-Wl,--exclude-libs=libprotobuf.a']
 | 
			
		||||
      elif builder.target.platform == 'mac':
 | 
			
		||||
        if arch == 'x86':
 | 
			
		||||
          lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf.a')
 | 
			
		||||
        elif arch == 'x64':
 | 
			
		||||
          lib_path = os.path.join(sdk.path, 'lib', 'osx64', 'release', 'libprotobuf.a')
 | 
			
		||||
      elif builder.target.platform == 'windows':
 | 
			
		||||
        msvc_ver = compiler.version
 | 
			
		||||
        vs_year = ''
 | 
			
		||||
        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')
 | 
			
		||||
      else:
 | 
			
		||||
        lib_path = os.path.join(sdk['path'], 'lib', platform, 'release', 'vs' + vs_year, 'libprotobuf.lib')
 | 
			
		||||
    compiler.linkflags.insert(0, lib_path)
 | 
			
		||||
        if 'DEBUG' in compiler.defines:
 | 
			
		||||
          lib_path = os.path.join(sdk.path, 'lib', 'win32', 'debug', 'vs' + vs_year, 'libprotobuf.lib')
 | 
			
		||||
        else:
 | 
			
		||||
          lib_path = os.path.join(sdk.path, 'lib', 'win32', 'release', 'vs' + vs_year, 'libprotobuf.lib')
 | 
			
		||||
      compiler.linkflags.insert(0, binary.Dep(lib_path))
 | 
			
		||||
  
 | 
			
		||||
  if needs_protobuf:
 | 
			
		||||
    binary.sources += ['smn_protobuf.cpp']
 | 
			
		||||
  else:
 | 
			
		||||
    binary.sources += ['smn_bitbuffer.cpp']
 | 
			
		||||
    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 needs_protobuf:
 | 
			
		||||
    binary.sources += [
 | 
			
		||||
      os.path.join(sdk['path'], 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
 | 
			
		||||
      os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf', pb_gamesrcdir_map[sdk['name']] + '_usermessages.pb.cc'),
 | 
			
		||||
      os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf', pb_gamesrcdir_map[sdk['name']] + '_usermessage_helpers.cpp'),
 | 
			
		||||
    ]
 | 
			
		||||
    if sdk['name'] == 'mcv':
 | 
			
		||||
    if sdk.name == 'csgo':
 | 
			
		||||
      binary.sources += [
 | 
			
		||||
        os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf', pb_gamesrcdir_map[sdk['name']] + '_gcmessages.pb.cc'),
 | 
			
		||||
        os.path.join(sdk['path'], 'public', 'engine', 'protobuf', 'engine_gcmessages.pb.cc'),
 | 
			
		||||
        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'),
 | 
			
		||||
      ]
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
	}
 | 
			
		||||
@ -461,23 +467,3 @@ bool ChatTriggers::WasFloodedMessage()
 | 
			
		||||
{
 | 
			
		||||
	return m_bWasFloodedMessage;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *ChatTriggers::GetPublicChatTrigger()
 | 
			
		||||
{
 | 
			
		||||
	if (!m_PubTrigger.length())
 | 
			
		||||
	{
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return m_PubTrigger.c_str();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *ChatTriggers::GetPrivateChatTrigger()
 | 
			
		||||
{
 | 
			
		||||
	if (!m_PrivTrigger.length())
 | 
			
		||||
	{
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return m_PrivTrigger.c_str();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -63,8 +63,6 @@ public:
 | 
			
		||||
	unsigned int SetReplyTo(unsigned int reply);
 | 
			
		||||
	bool IsChatTrigger();
 | 
			
		||||
	bool WasFloodedMessage();
 | 
			
		||||
	const char *GetPublicChatTrigger();
 | 
			
		||||
	const char *GetPrivateChatTrigger();
 | 
			
		||||
private:
 | 
			
		||||
	enum ChatTriggerType {
 | 
			
		||||
		ChatTrigger_Public,
 | 
			
		||||
@ -75,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)
 | 
			
		||||
	{
 | 
			
		||||
		return type;
 | 
			
		||||
		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)
 | 
			
		||||
	{
 | 
			
		||||
		return false;
 | 
			
		||||
        /* 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;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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 strcmp(name, info->pVar->GetName()) == 0;
 | 
			
		||||
	}
 | 
			
		||||
	static inline uint32_t hash(const detail::CharsAndLength &key)
 | 
			
		||||
	{
 | 
			
		||||
		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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
# 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,12 +45,9 @@
 | 
			
		||||
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
#include <cstrike15_usermessages.pb.h>
 | 
			
		||||
#elif SOURCE_ENGINE == SE_BLADE
 | 
			
		||||
#include <berimbau_usermessages.pb.h>
 | 
			
		||||
#elif SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#include <vietnam_usermessages.pb.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef ICommandLine *(*FakeGetCommandLine)();
 | 
			
		||||
 | 
			
		||||
#define TIER0_NAME			FORMAT_SOURCE_BIN_NAME("tier0")
 | 
			
		||||
@ -62,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()
 | 
			
		||||
{
 | 
			
		||||
@ -147,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,
 | 
			
		||||
@ -185,9 +180,7 @@ void CHalfLife2::InitLogicalEntData()
 | 
			
		||||
	|| SOURCE_ENGINE == SE_CSS     \
 | 
			
		||||
	|| SOURCE_ENGINE == SE_SDK2013 \
 | 
			
		||||
	|| SOURCE_ENGINE == SE_BMS     \
 | 
			
		||||
	|| SOURCE_ENGINE == SE_BLADE   \
 | 
			
		||||
	|| SOURCE_ENGINE == SE_NUCLEARDAWN \
 | 
			
		||||
	|| SOURCE_ENGINE == SE_PVKII
 | 
			
		||||
	|| SOURCE_ENGINE == SE_NUCLEARDAWN
 | 
			
		||||
 | 
			
		||||
	if (g_SMAPI->GetServerFactory(false)("VSERVERTOOLS003", nullptr))
 | 
			
		||||
	{
 | 
			
		||||
@ -324,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())
 | 
			
		||||
@ -413,17 +388,6 @@ ServerClass *CHalfLife2::FindServerClass(const char *classname)
 | 
			
		||||
	return pInfo->sc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ServerClass *CHalfLife2::FindEntityServerClass(CBaseEntity *pEntity)
 | 
			
		||||
{
 | 
			
		||||
	IServerNetworkable* pNetwork = ((IServerUnknown *)pEntity)->GetNetworkable();
 | 
			
		||||
	if (pNetwork == nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		return nullptr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return pNetwork->GetServerClass();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
 | 
			
		||||
{
 | 
			
		||||
	DataTableInfo *pInfo = NULL;
 | 
			
		||||
@ -456,25 +420,20 @@ bool CHalfLife2::FindSendPropInfo(const char *classname, const char *offset, sm_
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DataTableInfo::SendPropInfo temp;
 | 
			
		||||
 | 
			
		||||
	if (!pInfo->lookup.retrieve(offset, &temp))
 | 
			
		||||
	if (!pInfo->lookup.retrieve(offset, info))
 | 
			
		||||
	{
 | 
			
		||||
		bool found = UTIL_FindInSendTable(pInfo->sc->m_pTable, offset, &temp.info, 0);
 | 
			
		||||
		temp.name = offset;
 | 
			
		||||
		sm_sendprop_info_t temp_info;
 | 
			
		||||
 | 
			
		||||
		pInfo->lookup.insert(offset, temp);
 | 
			
		||||
 | 
			
		||||
		if (found)
 | 
			
		||||
		if (!UTIL_FindInSendTable(pInfo->sc->m_pTable, offset, &temp_info, 0))
 | 
			
		||||
		{
 | 
			
		||||
			*info = temp.info;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return found;
 | 
			
		||||
		pInfo->lookup.insert(offset, temp_info);
 | 
			
		||||
		*info = temp_info;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	*info = temp.info;
 | 
			
		||||
	return info->prop != nullptr;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset)
 | 
			
		||||
@ -508,25 +467,15 @@ bool CHalfLife2::FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatab
 | 
			
		||||
		m_Maps.add(i, pMap, new DataMapCache());
 | 
			
		||||
 | 
			
		||||
	DataMapCache *cache = i->value;
 | 
			
		||||
	DataMapCacheInfo temp;
 | 
			
		||||
 | 
			
		||||
	if (!cache->retrieve(offset, &temp))
 | 
			
		||||
	if (!cache->retrieve(offset, pDataTable))
 | 
			
		||||
	{
 | 
			
		||||
		bool found = UTIL_FindDataMapInfo(pMap, offset, &temp.info);
 | 
			
		||||
		temp.name = offset;
 | 
			
		||||
 | 
			
		||||
		cache->insert(offset, temp);
 | 
			
		||||
 | 
			
		||||
		if (found)
 | 
			
		||||
		{
 | 
			
		||||
			*pDataTable = temp.info;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return found;
 | 
			
		||||
		if (!UTIL_FindDataMapInfo(pMap, offset, pDataTable))
 | 
			
		||||
			return false;
 | 
			
		||||
		cache->insert(offset, *pDataTable);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*pDataTable = temp.info;
 | 
			
		||||
	return pDataTable->prop != nullptr;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
 | 
			
		||||
@ -567,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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
			CCSUsrMsg_SayText *pMsg;
 | 
			
		||||
			if ((pMsg = (CCSUsrMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
 | 
			
		||||
			{
 | 
			
		||||
@ -594,7 +543,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
	CCSUsrMsg_TextMsg *pMsg;
 | 
			
		||||
	if ((pMsg = (CCSUsrMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
 | 
			
		||||
	{
 | 
			
		||||
@ -631,7 +580,7 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
 | 
			
		||||
{
 | 
			
		||||
	cell_t players[] = {client};
 | 
			
		||||
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
	CCSUsrMsg_HintText *pMsg;
 | 
			
		||||
	if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
 | 
			
		||||
	{
 | 
			
		||||
@ -661,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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
	CCSUsrMsg_HintText *pMsg;
 | 
			
		||||
	if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
 | 
			
		||||
	{
 | 
			
		||||
@ -696,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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
	CCSUsrMsg_VGUIMenu *pMsg;
 | 
			
		||||
	if ((pMsg = (CCSUsrMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
 | 
			
		||||
	{
 | 
			
		||||
@ -721,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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
	pMsg->set_name(name);
 | 
			
		||||
	pMsg->set_show(show);
 | 
			
		||||
 | 
			
		||||
@ -1110,26 +1059,8 @@ int CHalfLife2::ReferenceToIndex(cell_t entRef)
 | 
			
		||||
 | 
			
		||||
		return hndl.GetEntryIndex();
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		CEntInfo *pInfo = LookupEntity(entRef);
 | 
			
		||||
		if (!pInfo)
 | 
			
		||||
		{
 | 
			
		||||
			return INVALID_EHANDLE_INDEX;
 | 
			
		||||
		}
 | 
			
		||||
		IServerUnknown *pUnk = static_cast<IServerUnknown *>(pInfo->m_pEntity);
 | 
			
		||||
		if (!pUnk)
 | 
			
		||||
		{
 | 
			
		||||
			return INVALID_EHANDLE_INDEX;
 | 
			
		||||
		}
 | 
			
		||||
		CBaseEntity *pEntity = pUnk->GetBaseEntity();
 | 
			
		||||
		if (!pEntity)
 | 
			
		||||
		{
 | 
			
		||||
			return INVALID_EHANDLE_INDEX; 
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return entRef;
 | 
			
		||||
	}
 | 
			
		||||
	return entRef;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cell_t CHalfLife2::EntityToBCompatRef(CBaseEntity *pEntity)
 | 
			
		||||
@ -1281,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 */
 | 
			
		||||
@ -1353,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;
 | 
			
		||||
 | 
			
		||||
@ -1371,22 +1258,16 @@ 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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#elif SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_HL2DM \
 | 
			
		||||
	|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_PVKII
 | 
			
		||||
	|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS
 | 
			
		||||
	static IVEngineServer *engine23 = (IVEngineServer *)(g_SMAPI->GetEngineFactory()("VEngineServer023", nullptr));
 | 
			
		||||
	if (engine23)
 | 
			
		||||
	{
 | 
			
		||||
@ -1435,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
 | 
			
		||||
@ -1474,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
 | 
			
		||||
{
 | 
			
		||||
@ -1573,9 +1396,7 @@ uint64_t CHalfLife2::GetServerSteamId64() const
 | 
			
		||||
	|| SOURCE_ENGINE == SE_DOI  \
 | 
			
		||||
	|| SOURCE_ENGINE == SE_SDK2013     \
 | 
			
		||||
	|| SOURCE_ENGINE == SE_ALIENSWARM  \
 | 
			
		||||
	|| SOURCE_ENGINE == SE_TF2 \
 | 
			
		||||
	|| SOURCE_ENGINE == SE_PVKII \
 | 
			
		||||
	|| SOURCE_ENGINE == SE_MCV
 | 
			
		||||
	|| SOURCE_ENGINE == SE_TF2
 | 
			
		||||
	const CSteamID *sid = engine->GetGameServerSteamID();
 | 
			
		||||
	if (sid)
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
@ -74,7 +74,7 @@ using namespace SourceMod;
 | 
			
		||||
	|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_INSURGENCY || SOURCE_ENGINE == SE_DOI
 | 
			
		||||
#define SOURCE_BIN_PREFIX "lib"
 | 
			
		||||
#define SOURCE_BIN_SUFFIX "_srv"
 | 
			
		||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD || SOURCE_ENGINE == SE_PVKII
 | 
			
		||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
 | 
			
		||||
#define SOURCE_BIN_PREFIX "lib"
 | 
			
		||||
#define SOURCE_BIN_SUFFIX ""
 | 
			
		||||
#else
 | 
			
		||||
@ -89,24 +89,16 @@ using namespace SourceMod;
 | 
			
		||||
 | 
			
		||||
struct DataTableInfo
 | 
			
		||||
{
 | 
			
		||||
	struct SendPropInfo
 | 
			
		||||
	struct SendPropPolicy
 | 
			
		||||
	{
 | 
			
		||||
		static inline bool matches(const char *name, const SendPropInfo &info)
 | 
			
		||||
		static inline bool matches(const char *name, const sm_sendprop_info_t &info)
 | 
			
		||||
		{
 | 
			
		||||
			return strcmp(name, info.name.c_str()) == 0;
 | 
			
		||||
			return strcmp(name, info.prop->GetName()) == 0;
 | 
			
		||||
		}
 | 
			
		||||
		static inline uint32_t hash(const detail::CharsAndLength &key)
 | 
			
		||||
		{
 | 
			
		||||
			return key.hash();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		SendPropInfo()
 | 
			
		||||
			: name(), info{nullptr, 0}
 | 
			
		||||
		{
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		std::string name;
 | 
			
		||||
		sm_sendprop_info_t info;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	static inline bool matches(const char *name, const DataTableInfo *info)
 | 
			
		||||
@ -124,30 +116,22 @@ struct DataTableInfo
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ServerClass *sc;
 | 
			
		||||
	NameHashSet<SendPropInfo> lookup;
 | 
			
		||||
	NameHashSet<sm_sendprop_info_t, SendPropPolicy> lookup;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct DataMapCacheInfo
 | 
			
		||||
struct DataMapCachePolicy
 | 
			
		||||
{
 | 
			
		||||
	static inline bool matches(const char *name, const DataMapCacheInfo &info)
 | 
			
		||||
	static inline bool matches(const char *name, const sm_datatable_info_t &info)
 | 
			
		||||
	{
 | 
			
		||||
		return strcmp(name, info.name.c_str()) == 0;
 | 
			
		||||
		return strcmp(name, info.prop->fieldName) == 0;
 | 
			
		||||
	}
 | 
			
		||||
	static inline uint32_t hash(const detail::CharsAndLength &key)
 | 
			
		||||
	{
 | 
			
		||||
		return key.hash();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DataMapCacheInfo()
 | 
			
		||||
		: name(), info{nullptr, 0}
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::string name;
 | 
			
		||||
	sm_datatable_info_t info;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef NameHashSet<DataMapCacheInfo> DataMapCache;
 | 
			
		||||
typedef NameHashSet<sm_datatable_info_t, DataMapCachePolicy> DataMapCache;
 | 
			
		||||
 | 
			
		||||
struct DelayedFakeCliCmd
 | 
			
		||||
{
 | 
			
		||||
@ -195,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
 | 
			
		||||
@ -221,7 +199,6 @@ public: //IGameHelpers
 | 
			
		||||
	bool FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info);
 | 
			
		||||
	datamap_t *GetDataMap(CBaseEntity *pEntity);
 | 
			
		||||
	ServerClass *FindServerClass(const char *classname);
 | 
			
		||||
	ServerClass *FindEntityServerClass(CBaseEntity *pEntity);
 | 
			
		||||
	typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset);
 | 
			
		||||
	bool FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatable_info_t *pDataTable);
 | 
			
		||||
	void SetEdictStateChanged(edict_t *pEdict, unsigned short offset);
 | 
			
		||||
@ -252,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:
 | 
			
		||||
@ -295,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
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -38,7 +38,6 @@
 | 
			
		||||
#include "sourcemm_api.h"
 | 
			
		||||
#include "PlayerManager.h"
 | 
			
		||||
#include "MenuStyle_Valve.h"
 | 
			
		||||
#include <IGameConfigs.h>
 | 
			
		||||
#include "sourcemm_api.h"
 | 
			
		||||
#include "logic_bridge.h"
 | 
			
		||||
 | 
			
		||||
@ -69,29 +68,6 @@ void MenuManager::OnSourceModAllInitialized()
 | 
			
		||||
	m_StyleType = handlesys->CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MenuManager::OnSourceModAllInitialized_Post()
 | 
			
		||||
{
 | 
			
		||||
	const char* pTmp;
 | 
			
		||||
	
 | 
			
		||||
	pTmp = g_pGameConf->GetKeyValue("MenuItemSound");
 | 
			
		||||
	if (nullptr != pTmp)
 | 
			
		||||
	{
 | 
			
		||||
		m_SelectSound = pTmp;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pTmp = g_pGameConf->GetKeyValue("MenuExitSound");
 | 
			
		||||
	if (nullptr != pTmp)
 | 
			
		||||
	{
 | 
			
		||||
		m_ExitSound = pTmp;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pTmp = g_pGameConf->GetKeyValue("MenuExitBackSound");
 | 
			
		||||
	if (nullptr != pTmp)
 | 
			
		||||
	{
 | 
			
		||||
		m_ExitBackSound = pTmp;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MenuManager::OnSourceModAllShutdown()
 | 
			
		||||
{
 | 
			
		||||
	handlesys->RemoveType(m_MenuType, g_pCoreIdent);
 | 
			
		||||
@ -723,9 +699,30 @@ bool MenuManager::MenuSoundsEnabled()
 | 
			
		||||
	return (sm_menu_sounds.GetInt() != 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string *MenuManager::GetMenuSound(ItemSelection sel)
 | 
			
		||||
ConfigResult MenuManager::OnSourceModConfigChanged(const char *key,
 | 
			
		||||
												   const char *value,
 | 
			
		||||
												   ConfigSource source,
 | 
			
		||||
												   char *error,
 | 
			
		||||
												   size_t maxlength)
 | 
			
		||||
{
 | 
			
		||||
	std::string *sound = nullptr;
 | 
			
		||||
	if (strcmp(key, "MenuItemSound") == 0)
 | 
			
		||||
	{
 | 
			
		||||
		m_SelectSound.assign(value);
 | 
			
		||||
		return ConfigResult_Accept;
 | 
			
		||||
	} else if (strcmp(key, "MenuExitBackSound") == 0) {
 | 
			
		||||
		m_ExitBackSound.assign(value);
 | 
			
		||||
		return ConfigResult_Accept;
 | 
			
		||||
	} else if (strcmp(key, "MenuExitSound") == 0) {
 | 
			
		||||
		m_ExitSound.assign(value);
 | 
			
		||||
		return ConfigResult_Accept;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ConfigResult_Ignore;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *MenuManager::GetMenuSound(ItemSelection sel)
 | 
			
		||||
{
 | 
			
		||||
	const char *sound = NULL;
 | 
			
		||||
 | 
			
		||||
	switch (sel)
 | 
			
		||||
	{
 | 
			
		||||
@ -735,7 +732,7 @@ std::string *MenuManager::GetMenuSound(ItemSelection sel)
 | 
			
		||||
		{
 | 
			
		||||
			if (m_SelectSound.size() > 0)
 | 
			
		||||
			{
 | 
			
		||||
				sound = &m_SelectSound;
 | 
			
		||||
				sound = m_SelectSound.c_str();
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
@ -743,7 +740,7 @@ std::string *MenuManager::GetMenuSound(ItemSelection sel)
 | 
			
		||||
		{
 | 
			
		||||
			if (m_ExitBackSound.size() > 0)
 | 
			
		||||
			{
 | 
			
		||||
				sound = &m_ExitBackSound;
 | 
			
		||||
				sound = m_ExitBackSound.c_str();
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
@ -751,7 +748,7 @@ std::string *MenuManager::GetMenuSound(ItemSelection sel)
 | 
			
		||||
		{
 | 
			
		||||
			if (m_ExitSound.size() > 0)
 | 
			
		||||
			{
 | 
			
		||||
				sound = &m_ExitSound;
 | 
			
		||||
				sound = m_ExitSound.c_str();
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -36,8 +36,8 @@
 | 
			
		||||
#include <sh_vector.h>
 | 
			
		||||
#include <sh_stack.h>
 | 
			
		||||
#include <sh_list.h>
 | 
			
		||||
#include <sh_string.h>
 | 
			
		||||
#include "sm_globals.h"
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
using namespace SourceMod;
 | 
			
		||||
using namespace SourceHook;
 | 
			
		||||
@ -55,8 +55,12 @@ public:
 | 
			
		||||
	MenuManager();
 | 
			
		||||
public: //SMGlobalClass
 | 
			
		||||
	void OnSourceModAllInitialized();
 | 
			
		||||
	void OnSourceModAllInitialized_Post();
 | 
			
		||||
	void OnSourceModAllShutdown();
 | 
			
		||||
	ConfigResult OnSourceModConfigChanged(const char *key,
 | 
			
		||||
		const char *value,
 | 
			
		||||
		ConfigSource source,
 | 
			
		||||
		char *error,
 | 
			
		||||
		size_t maxlength);
 | 
			
		||||
	void OnSourceModLevelChange(const char *mapName);
 | 
			
		||||
public: //IMenuManager
 | 
			
		||||
	virtual const char *GetInterfaceName()
 | 
			
		||||
@ -95,7 +99,7 @@ public:
 | 
			
		||||
	HandleError ReadStyleHandle(Handle_t handle, IMenuStyle **style);
 | 
			
		||||
public:
 | 
			
		||||
	bool MenuSoundsEnabled();
 | 
			
		||||
	std::string *GetMenuSound(ItemSelection sel);
 | 
			
		||||
	const char *GetMenuSound(ItemSelection sel);
 | 
			
		||||
protected:
 | 
			
		||||
	Handle_t CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner);
 | 
			
		||||
	Handle_t CreateStyleHandle(IMenuStyle *style);
 | 
			
		||||
@ -105,9 +109,9 @@ private:
 | 
			
		||||
	CVector<IMenuStyle *> m_Styles;
 | 
			
		||||
	HandleType_t m_StyleType;
 | 
			
		||||
	HandleType_t m_MenuType;
 | 
			
		||||
	std::string m_SelectSound = "";
 | 
			
		||||
	std::string m_ExitBackSound = "";
 | 
			
		||||
	std::string m_ExitSound = "";
 | 
			
		||||
	String m_SelectSound;
 | 
			
		||||
	String m_ExitBackSound;
 | 
			
		||||
	String m_ExitSound;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern MenuManager g_Menus;
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
@ -311,9 +311,9 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
 | 
			
		||||
			clients[0] = client;
 | 
			
		||||
			filter.Initialize(clients, 1);
 | 
			
		||||
 | 
			
		||||
			std::string *sound = g_Menus.GetMenuSound(type);
 | 
			
		||||
			const char *sound = g_Menus.GetMenuSound(type);
 | 
			
		||||
 | 
			
		||||
			if (nullptr != sound && !sound->empty())
 | 
			
		||||
			if (sound != NULL)
 | 
			
		||||
			{
 | 
			
		||||
				edict_t *pEdict = PEntityOfEntIndex(client);
 | 
			
		||||
				if (pEdict)
 | 
			
		||||
@ -327,10 +327,10 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
 | 
			
		||||
							client, 
 | 
			
		||||
							CHAN_AUTO, 
 | 
			
		||||
#if SOURCE_ENGINE >= SE_PORTAL2
 | 
			
		||||
							sound->c_str(),
 | 
			
		||||
							sound, 
 | 
			
		||||
							-1, 
 | 
			
		||||
#endif
 | 
			
		||||
							sound->c_str(),
 | 
			
		||||
							sound, 
 | 
			
		||||
							VOL_NORM, 
 | 
			
		||||
							ATTN_NORM, 
 | 
			
		||||
#if SOURCE_ENGINE >= SE_PORTAL2
 | 
			
		||||
@ -339,7 +339,7 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
 | 
			
		||||
							0, 
 | 
			
		||||
							PITCH_NORM, 
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS \
 | 
			
		||||
	|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_PVKII
 | 
			
		||||
	|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_TF2
 | 
			
		||||
							0,
 | 
			
		||||
#endif
 | 
			
		||||
							&pos);
 | 
			
		||||
@ -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,77 +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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CBaseMenu::ShufflePerClient(int start, int stop)
 | 
			
		||||
{
 | 
			
		||||
	// limit map len to 255 items since it's using uint8
 | 
			
		||||
	int length = MIN(GetItemCount(), 255);
 | 
			
		||||
	if (stop >= 0)
 | 
			
		||||
		length = MIN(length, stop);
 | 
			
		||||
 | 
			
		||||
	for (int i = 1; i <= SM_MAXPLAYERS; i++)
 | 
			
		||||
	{
 | 
			
		||||
		// populate per-client map ...
 | 
			
		||||
		m_RandomMaps[i].resize(length);
 | 
			
		||||
		for (int j = 0; j < length; j++)
 | 
			
		||||
			m_RandomMaps[i][j] = j;
 | 
			
		||||
 | 
			
		||||
		// ... and random shuffle it
 | 
			
		||||
		for (int j = length - 1; j > start; j--)
 | 
			
		||||
		{
 | 
			
		||||
			int x = rand() % (j - start + 1) + start;
 | 
			
		||||
			uint8_t tmp = m_RandomMaps[i][x];
 | 
			
		||||
			m_RandomMaps[i][x] = m_RandomMaps[i][j];
 | 
			
		||||
			m_RandomMaps[i][j] = tmp;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CBaseMenu::SetClientMapping(int client, int *array, int length)
 | 
			
		||||
{
 | 
			
		||||
	length = MIN(length, 255);
 | 
			
		||||
	m_RandomMaps[client].resize(length);
 | 
			
		||||
	for (int i = 0; i < length; i++)
 | 
			
		||||
	{
 | 
			
		||||
		m_RandomMaps[client][i] = array[i];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CBaseMenu::IsPerClientShuffled()
 | 
			
		||||
{
 | 
			
		||||
	for (int i = 1; i <= SM_MAXPLAYERS; i++)
 | 
			
		||||
	{
 | 
			
		||||
		if(m_RandomMaps[i].size() > 0)
 | 
			
		||||
			return true;
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position)
 | 
			
		||||
{
 | 
			
		||||
	if (client > 0 && position < m_RandomMaps[client].size())
 | 
			
		||||
	{
 | 
			
		||||
		position = m_RandomMaps[client][position];
 | 
			
		||||
		return m_items[position].index;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return position;
 | 
			
		||||
	return m_items[position].info.chars();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CBaseMenu::ShufflePerClient(int start, int stop)
 | 
			
		||||
@ -812,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)
 | 
			
		||||
@ -850,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()
 | 
			
		||||
@ -861,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
 | 
			
		||||
@ -885,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,
 | 
			
		||||
@ -942,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,10 +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>
 | 
			
		||||
#elif SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#include <game/shared/vietnam/protobuf/vietnam_usermessages.pb.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
extern const char *g_RadioNumTable[];
 | 
			
		||||
@ -63,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()
 | 
			
		||||
{
 | 
			
		||||
@ -126,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);
 | 
			
		||||
@ -184,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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
	int c = ((CCSUsrMsg_ShowMenu &)msg).display_time();
 | 
			
		||||
#else
 | 
			
		||||
	bf_read br(bf->GetBasePointer(), 3);
 | 
			
		||||
@ -207,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
 | 
			
		||||
@ -472,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()
 | 
			
		||||
@ -502,13 +483,9 @@ void CRadioMenuPlayer::Radio_Refresh()
 | 
			
		||||
		time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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);
 | 
			
		||||
@ -599,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);
 | 
			
		||||
 | 
			
		||||
@ -40,7 +40,6 @@
 | 
			
		||||
#include "UserMessages.h"
 | 
			
		||||
#include "sm_fastlink.h"
 | 
			
		||||
#include <sh_stack.h>
 | 
			
		||||
#include <sh_string.h>
 | 
			
		||||
#include <compat_wrappers.h>
 | 
			
		||||
#include "logic/common_logic.h"
 | 
			
		||||
#include "AutoHandleRooter.h"
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
	{
 | 
			
		||||
@ -109,8 +117,6 @@ bool NextMapManager::SetNextMap(const char *map)
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char g_nextMap[PLATFORM_MAX_PATH];
 | 
			
		||||
 | 
			
		||||
#if SOURCE_ENGINE != SE_DARKMESSIAH
 | 
			
		||||
void NextMapManager::HookChangeLevel(const char *map, const char *unknown)
 | 
			
		||||
#else
 | 
			
		||||
@ -124,16 +130,8 @@ void NextMapManager::HookChangeLevel(const char *map, const char *unknown, const
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const char *newmap = sm_nextmap.GetString();
 | 
			
		||||
	if (newmap[0] != '\0') {
 | 
			
		||||
		ke::SafeStrcpy(g_nextMap, sizeof(g_nextMap), newmap);
 | 
			
		||||
		newmap = g_nextMap;
 | 
			
		||||
 | 
			
		||||
		// Clear the value so that if the map load fails later we don't get stuck in a loop.
 | 
			
		||||
		// This might cause us to go off-cycle for a map, but nextmap will get us back on track.
 | 
			
		||||
		sm_nextmap.SetValue("");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (newmap[0] == '\0' || !g_HL2.IsMapValid(newmap))
 | 
			
		||||
	if (newmap[0] == 0 || !g_HL2.IsMapValid(newmap))
 | 
			
		||||
	{
 | 
			
		||||
		RETURN_META(MRES_IGNORED);
 | 
			
		||||
	}
 | 
			
		||||
@ -152,15 +150,6 @@ void NextMapManager::HookChangeLevel(const char *map, const char *unknown, const
 | 
			
		||||
 | 
			
		||||
void NextMapManager::OnSourceModLevelChange( const char *mapName )
 | 
			
		||||
{
 | 
			
		||||
	// If we were controlling the map change, reset sm_nextmap to be the name of the map we successfully changed to.
 | 
			
		||||
	// This maintains an old API contract on the plugin side. We use the real map name even if it was different from
 | 
			
		||||
	// the expected map name as if the expected map failed to load we let the game take over instead, but the nextmap
 | 
			
		||||
	// plugin compares the sm_nextmap value to the current map to decide if it should advance the mapcycle.
 | 
			
		||||
	if (g_nextMap[0] != '\0') {
 | 
			
		||||
		sm_nextmap.SetValue(mapName);
 | 
			
		||||
		g_nextMap[0] = '\0';
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Skip the first 'mapchange' when the server starts up */
 | 
			
		||||
	if (m_tempChangeInfo.startTime != 0)
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
@ -96,7 +96,7 @@ public:
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	MapChangeData m_tempChangeInfo;
 | 
			
		||||
	char lastMap[PLATFORM_MAX_PATH];
 | 
			
		||||
	char lastMap[32];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern NextMapManager g_NextMap;
 | 
			
		||||
 | 
			
		||||
@ -59,8 +59,6 @@ bool g_OnMapStarted = false;
 | 
			
		||||
IForward *PreAdminCheck = NULL;
 | 
			
		||||
IForward *PostAdminCheck = NULL;
 | 
			
		||||
IForward *PostAdminFilter = NULL;
 | 
			
		||||
IForward *ServerEnterHibernation = NULL;
 | 
			
		||||
IForward *ServerExitHibernation = NULL;
 | 
			
		||||
 | 
			
		||||
const unsigned int *g_NumPlayersToAuth = NULL;
 | 
			
		||||
int lifestate_offset = -1;
 | 
			
		||||
@ -99,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;
 | 
			
		||||
@ -198,15 +196,12 @@ 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);
 | 
			
		||||
 | 
			
		||||
	PreAdminCheck = forwardsys->CreateForward("OnClientPreAdminCheck", ET_Event, 1, p1);
 | 
			
		||||
	PostAdminCheck = forwardsys->CreateForward("OnClientPostAdminCheck", ET_Ignore, 1, p1);
 | 
			
		||||
	PostAdminFilter = forwardsys->CreateForward("OnClientPostAdminFilter", ET_Ignore, 1, p1);
 | 
			
		||||
	ServerEnterHibernation = forwardsys->CreateForward("OnServerEnterHibernation", ET_Ignore, 0, NULL);
 | 
			
		||||
	ServerExitHibernation = forwardsys->CreateForward("OnServerExitHibernation", ET_Ignore, 0, NULL);
 | 
			
		||||
 | 
			
		||||
	m_bIsListenServer = !engine->IsDedicatedServer();
 | 
			
		||||
	m_ListenClient = 0;
 | 
			
		||||
@ -254,15 +249,12 @@ 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);
 | 
			
		||||
 | 
			
		||||
	forwardsys->ReleaseForward(PreAdminCheck);
 | 
			
		||||
	forwardsys->ReleaseForward(PostAdminCheck);
 | 
			
		||||
	forwardsys->ReleaseForward(PostAdminFilter);
 | 
			
		||||
	forwardsys->ReleaseForward(ServerEnterHibernation);
 | 
			
		||||
	forwardsys->ReleaseForward(ServerExitHibernation);
 | 
			
		||||
 | 
			
		||||
	delete [] m_Players;
 | 
			
		||||
 | 
			
		||||
@ -418,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())
 | 
			
		||||
		{
 | 
			
		||||
@ -525,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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
		pPlayer->m_LangId = translator->GetServerLanguage();
 | 
			
		||||
#else
 | 
			
		||||
		const char *name;
 | 
			
		||||
@ -533,13 +525,10 @@ 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();
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
		pPlayer->m_OriginalLangId = pPlayer->m_LangId;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	List<IClientListener *>::iterator iter;
 | 
			
		||||
@ -657,7 +646,7 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
 | 
			
		||||
 | 
			
		||||
		int userId = engine->GetPlayerUserId(pEntity);
 | 
			
		||||
#if (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_PVKII)
 | 
			
		||||
	|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN  || SOURCE_ENGINE == SE_LEFT4DEAD2)
 | 
			
		||||
		static ConVar *tv_name = icvar->FindVar("tv_name");
 | 
			
		||||
#endif
 | 
			
		||||
#if SOURCE_ENGINE == SE_TF2
 | 
			
		||||
@ -680,13 +669,10 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
 | 
			
		||||
			&& ((!m_bIsReplayActive && newCount == 1)
 | 
			
		||||
				|| (m_bIsReplayActive && newCount == 2))
 | 
			
		||||
			&& (m_SourceTVUserId == userId
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
				// It seems likely that MCV will change this at some point, but it's GOTV at the moment.
 | 
			
		||||
#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_PVKII)
 | 
			
		||||
	|| 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)
 | 
			
		||||
#else
 | 
			
		||||
				|| strcmp(playername, "SourceTV") == 0
 | 
			
		||||
@ -728,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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
	else if(m_QueryLang)
 | 
			
		||||
	{
 | 
			
		||||
		// Not a bot
 | 
			
		||||
@ -789,11 +775,6 @@ void PlayerManager::OnSourceModLevelEnd()
 | 
			
		||||
 | 
			
		||||
void PlayerManager::OnServerHibernationUpdate(bool bHibernating)
 | 
			
		||||
{
 | 
			
		||||
	cell_t res;
 | 
			
		||||
	if (bHibernating)
 | 
			
		||||
		ServerEnterHibernation->Execute(&res);
 | 
			
		||||
	else
 | 
			
		||||
		ServerExitHibernation->Execute(&res);
 | 
			
		||||
	/* If bots were added at map start, but not fully inited before hibernation, there will
 | 
			
		||||
	 * be no OnClientDisconnect for them, despite them getting booted right before this.
 | 
			
		||||
	 */
 | 
			
		||||
@ -805,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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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;
 | 
			
		||||
@ -892,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
 | 
			
		||||
@ -910,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);
 | 
			
		||||
	}
 | 
			
		||||
@ -937,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())
 | 
			
		||||
@ -991,6 +972,8 @@ void ClientConsolePrint(edict_t *e, const char *fmt, ...)
 | 
			
		||||
void ListExtensionsToClient(CPlayer *player, const CCommand &args)
 | 
			
		||||
{
 | 
			
		||||
	char buffer[256];
 | 
			
		||||
	unsigned int id = 0;
 | 
			
		||||
	unsigned int start = 0;
 | 
			
		||||
 | 
			
		||||
	AutoExtensionList extensions(extsys);
 | 
			
		||||
	if (!extensions->size())
 | 
			
		||||
@ -999,6 +982,11 @@ void ListExtensionsToClient(CPlayer *player, const CCommand &args)
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (args.ArgC() > 2)
 | 
			
		||||
	{
 | 
			
		||||
		start = atoi(args.Arg(2));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t i = 0;
 | 
			
		||||
	for (; i < extensions->size(); i++)
 | 
			
		||||
	{
 | 
			
		||||
@ -1010,6 +998,17 @@ void ListExtensionsToClient(CPlayer *player, const CCommand &args)
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		id++;
 | 
			
		||||
		if (id < start)
 | 
			
		||||
		{
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (id - start > 10)
 | 
			
		||||
		{
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		IExtensionInterface *api = ext->GetAPI();
 | 
			
		||||
 | 
			
		||||
		const char *name = api->GetExtensionName();
 | 
			
		||||
@ -1034,14 +1033,31 @@ void ListExtensionsToClient(CPlayer *player, const CCommand &args)
 | 
			
		||||
			len += ke::SafeSprintf(&buffer[len], sizeof(buffer)-len, ": %s", description);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		ClientConsolePrint(player->GetEdict(), "%s", buffer);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (; i < extensions->size(); i++)
 | 
			
		||||
	{
 | 
			
		||||
		char error[255];
 | 
			
		||||
		if (extensions->at(i)->IsRunning(error, sizeof(error)))
 | 
			
		||||
		{
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (i < extensions->size())
 | 
			
		||||
	{
 | 
			
		||||
		ClientConsolePrint(player->GetEdict(), "To see more, type \"sm exts %d\"", id);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ListPluginsToClient(CPlayer *player, const CCommand &args)
 | 
			
		||||
{
 | 
			
		||||
	char buffer[256];
 | 
			
		||||
	unsigned int id = 0;
 | 
			
		||||
	edict_t *e = player->GetEdict();
 | 
			
		||||
	unsigned int start = 0;
 | 
			
		||||
 | 
			
		||||
	AutoPluginList plugins(scripts);
 | 
			
		||||
	if (!plugins->size())
 | 
			
		||||
@ -1050,6 +1066,11 @@ void ListPluginsToClient(CPlayer *player, const CCommand &args)
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (args.ArgC() > 2)
 | 
			
		||||
	{
 | 
			
		||||
		start = atoi(args.Arg(2));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SourceHook::List<SMPlugin *> m_FailList;
 | 
			
		||||
 | 
			
		||||
	size_t i = 0;
 | 
			
		||||
@ -1062,6 +1083,18 @@ void ListPluginsToClient(CPlayer *player, const CCommand &args)
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Count valid plugins */
 | 
			
		||||
		id++;
 | 
			
		||||
		if (id < start)
 | 
			
		||||
		{
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (id - start > 10)
 | 
			
		||||
		{
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		size_t len;
 | 
			
		||||
		const sm_plugininfo_t *info = pl->GetPublicInfo();
 | 
			
		||||
		len = ke::SafeSprintf(buffer, sizeof(buffer), " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
 | 
			
		||||
@ -1079,6 +1112,21 @@ void ListPluginsToClient(CPlayer *player, const CCommand &args)
 | 
			
		||||
		}
 | 
			
		||||
		ClientConsolePrint(e, "%s", buffer);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* See if we can get more plugins */
 | 
			
		||||
	for (; i < plugins->size(); i++)
 | 
			
		||||
	{
 | 
			
		||||
		if (plugins->at(i)->GetStatus() == Plugin_Running)
 | 
			
		||||
		{
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Do we actually have more plugins? */
 | 
			
		||||
	if (i < plugins->size())
 | 
			
		||||
	{
 | 
			
		||||
		ClientConsolePrint(e, "To see more, type \"sm plugins %d\"", id);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
 | 
			
		||||
@ -1113,18 +1161,14 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
 | 
			
		||||
		}
 | 
			
		||||
		else if (args.ArgC() > 1 && strcmp(args.Arg(1), "credits") == 0)
 | 
			
		||||
		{
 | 
			
		||||
			ClientConsolePrint(pEntity,
 | 
			
		||||
				"SourceMod would not be possible without:");
 | 
			
		||||
			ClientConsolePrint(pEntity,
 | 
			
		||||
 			ClientConsolePrint(pEntity,
 | 
			
		||||
 				"SourceMod would not be possible without:");
 | 
			
		||||
 			ClientConsolePrint(pEntity,
 | 
			
		||||
				" David \"BAILOPAN\" Anderson, Matt \"pRED\" Woodrow");
 | 
			
		||||
			ClientConsolePrint(pEntity,
 | 
			
		||||
 			ClientConsolePrint(pEntity,
 | 
			
		||||
				" Scott \"DS\" Ehlert, Fyren");
 | 
			
		||||
			ClientConsolePrint(pEntity,
 | 
			
		||||
 			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,
 | 
			
		||||
@ -1139,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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -1164,7 +1208,7 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
 | 
			
		||||
	if (g_ConsoleDetours.IsEnabled())
 | 
			
		||||
	{
 | 
			
		||||
		cell_t res2 = g_ConsoleDetours.InternalDispatch(client, &cargs);
 | 
			
		||||
		if (res2 >= Pl_Handled)
 | 
			
		||||
		if (res2 >= Pl_Stop)
 | 
			
		||||
		{
 | 
			
		||||
			RETURN_META(MRES_SUPERCEDE);
 | 
			
		||||
		}
 | 
			
		||||
@ -1294,69 +1338,65 @@ 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 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
 | 
			
		||||
 | 
			
		||||
	if (strcmp(old_name, new_name) != 0)
 | 
			
		||||
	{
 | 
			
		||||
		if (!pPlayer->IsFakeClient())
 | 
			
		||||
		AdminId id = adminsys->FindAdminByIdentity("name", new_name);
 | 
			
		||||
		if (id != INVALID_ADMIN_ID && pPlayer->GetAdminId() != id)
 | 
			
		||||
		{
 | 
			
		||||
			AdminId id = adminsys->FindAdminByIdentity("name", new_name);
 | 
			
		||||
			if (id != INVALID_ADMIN_ID && pPlayer->GetAdminId() != id)
 | 
			
		||||
			if (!CheckSetAdminName(client, pPlayer, id))
 | 
			
		||||
			{
 | 
			
		||||
				if (!CheckSetAdminName(client, pPlayer, id))
 | 
			
		||||
				{
 | 
			
		||||
					char kickMsg[128];
 | 
			
		||||
					logicore.CoreTranslate(kickMsg, sizeof(kickMsg), "%T", 2, NULL, "Name Reserved", &client);
 | 
			
		||||
					pPlayer->Kick(kickMsg);
 | 
			
		||||
					RETURN_META(MRES_IGNORED);
 | 
			
		||||
				}
 | 
			
		||||
				char kickMsg[128];
 | 
			
		||||
				logicore.CoreTranslate(kickMsg, sizeof(kickMsg), "%T", 2, NULL, "Name Reserved", &client);
 | 
			
		||||
				pPlayer->Kick(kickMsg);
 | 
			
		||||
				RETURN_META(MRES_IGNORED);
 | 
			
		||||
			}
 | 
			
		||||
			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);
 | 
			
		||||
				}
 | 
			
		||||
		} 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)
 | 
			
		||||
	{
 | 
			
		||||
		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());
 | 
			
		||||
		if (strcmp(old_pass, new_pass) != 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());
 | 
			
		||||
			if (strcmp(old_pass, new_pass) != 0)
 | 
			
		||||
			pPlayer->m_LastPassword.assign(new_pass);
 | 
			
		||||
			if (pPlayer->IsInGame() && pPlayer->IsAuthorized())
 | 
			
		||||
			{
 | 
			
		||||
				pPlayer->m_LastPassword.assign(new_pass);
 | 
			
		||||
				if (pPlayer->IsInGame() && pPlayer->IsAuthorized())
 | 
			
		||||
				{
 | 
			
		||||
					/* If there is already an admin id assigned, this will just bail out. */
 | 
			
		||||
					pPlayer->DoBasicAdminChecks();
 | 
			
		||||
				}
 | 
			
		||||
				/* If there is already an admin id assigned, this will just bail out. */
 | 
			
		||||
				pPlayer->DoBasicAdminChecks();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
#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;
 | 
			
		||||
@ -1370,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;
 | 
			
		||||
@ -1542,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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1981,7 +2011,7 @@ void CmdMaxplayersCallback()
 | 
			
		||||
	g_Players.MaxPlayersChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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++)
 | 
			
		||||
@ -1989,10 +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;
 | 
			
		||||
			m_Players[i].m_OriginalLangId = new_langid;
 | 
			
		||||
			OnClientLanguageChanged(i, new_langid);
 | 
			
		||||
			m_Players[i].m_LangId = (translator->GetLanguageByName(cvarValue, &langid)) ? langid : translator->GetServerLanguage();
 | 
			
		||||
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
@ -2041,7 +2068,6 @@ void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
 | 
			
		||||
	m_pEdict = pEntity;
 | 
			
		||||
	m_iIndex = IndexOfEdict(pEntity);
 | 
			
		||||
	m_LangId = translator->GetServerLanguage();
 | 
			
		||||
	m_OriginalLangId = m_LangId;
 | 
			
		||||
 | 
			
		||||
	m_Serial.bits.index = m_iIndex;
 | 
			
		||||
	m_Serial.bits.serial = g_PlayerSerialCount++;
 | 
			
		||||
@ -2062,9 +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_PVKII
 | 
			
		||||
	|| SOURCE_ENGINE == SE_DOI
 | 
			
		||||
	m_pIClient = engine->GetIServer()->GetClient(m_iIndex - 1);
 | 
			
		||||
#else
 | 
			
		||||
  #if SOURCE_ENGINE == SE_SDK2013
 | 
			
		||||
@ -2240,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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
	m_LanguageCookie = InvalidQueryCvarCookie;
 | 
			
		||||
#endif
 | 
			
		||||
	ClearNetchannelQueue();
 | 
			
		||||
@ -2249,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)
 | 
			
		||||
@ -2282,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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2297,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)
 | 
			
		||||
@ -2318,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)
 | 
			
		||||
@ -2328,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();
 | 
			
		||||
	}
 | 
			
		||||
@ -2462,7 +2491,7 @@ void CPlayer::Kick(const char *str)
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
		pClient->Disconnect(str);
 | 
			
		||||
#else
 | 
			
		||||
		pClient->Disconnect("%s", str);
 | 
			
		||||
@ -2595,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))
 | 
			
		||||
		{
 | 
			
		||||
@ -2609,18 +2638,9 @@ unsigned int CPlayer::GetLanguageId()
 | 
			
		||||
	return m_LangId;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int CPlayer::GetOriginalLanguageId()
 | 
			
		||||
{
 | 
			
		||||
	return m_OriginalLangId;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPlayer::SetLanguageId(unsigned int id)
 | 
			
		||||
{
 | 
			
		||||
	if(m_LangId != id)
 | 
			
		||||
	{
 | 
			
		||||
		m_LangId = id;
 | 
			
		||||
		g_Players.OnClientLanguageChanged(m_iIndex, id);
 | 
			
		||||
	}
 | 
			
		||||
	m_LangId = 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.
 | 
			
		||||
@ -96,7 +96,6 @@ public:
 | 
			
		||||
	bool IsInKickQueue();
 | 
			
		||||
	IPlayerInfo *GetPlayerInfo();
 | 
			
		||||
	unsigned int GetLanguageId();
 | 
			
		||||
	unsigned int GetOriginalLanguageId();
 | 
			
		||||
	void SetLanguageId(unsigned int id);
 | 
			
		||||
	int GetUserId();
 | 
			
		||||
	bool RunAdminCacheChecks();
 | 
			
		||||
@ -134,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;
 | 
			
		||||
@ -146,17 +145,16 @@ private:
 | 
			
		||||
	bool m_bAdminCheckSignalled = false;
 | 
			
		||||
	int m_iIndex;
 | 
			
		||||
	unsigned int m_LangId = SOURCEMOD_LANGUAGE_ENGLISH;
 | 
			
		||||
	unsigned int m_OriginalLangId = SOURCEMOD_LANGUAGE_ENGLISH;
 | 
			
		||||
	int m_UserId = -1;
 | 
			
		||||
	bool m_bFakeClient = false;
 | 
			
		||||
	bool m_bIsSourceTV = false;
 | 
			
		||||
	bool m_bIsReplay = false;
 | 
			
		||||
	serial_t m_Serial;
 | 
			
		||||
	CSteamID m_SteamId;
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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 : 
 | 
			
		||||
@ -195,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);
 | 
			
		||||
@ -242,7 +239,7 @@ public:
 | 
			
		||||
	{
 | 
			
		||||
		return m_bInCCKVHook;
 | 
			
		||||
	}
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
	bool HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue);
 | 
			
		||||
#endif
 | 
			
		||||
private:
 | 
			
		||||
@ -260,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,6 +816,9 @@ public:
 | 
			
		||||
 | 
			
		||||
	inline bool GetColor(const char *pszFieldName, Color *out)
 | 
			
		||||
	{
 | 
			
		||||
#if SOURCE_ENGINE != SE_CSGO
 | 
			
		||||
		return false;
 | 
			
		||||
#else
 | 
			
		||||
		GETCHECK_FIELD();
 | 
			
		||||
		CHECK_FIELD_TYPE(MESSAGE);
 | 
			
		||||
		CHECK_FIELD_NOT_REPEATED();
 | 
			
		||||
@ -829,10 +832,14 @@ public:
 | 
			
		||||
			);
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline bool SetColor(const char *pszFieldName, const Color &value)
 | 
			
		||||
	{
 | 
			
		||||
#if SOURCE_ENGINE != SE_CSGO
 | 
			
		||||
		return false;
 | 
			
		||||
#else
 | 
			
		||||
		GETCHECK_FIELD();
 | 
			
		||||
		CHECK_FIELD_TYPE(MESSAGE);
 | 
			
		||||
		CHECK_FIELD_NOT_REPEATED();
 | 
			
		||||
@ -844,10 +851,14 @@ public:
 | 
			
		||||
		msgRGBA->set_a(value.a());
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline bool GetRepeatedColor(const char *pszFieldName, int index, Color *out)
 | 
			
		||||
	{
 | 
			
		||||
#if SOURCE_ENGINE != SE_CSGO
 | 
			
		||||
		return false;
 | 
			
		||||
#else
 | 
			
		||||
		GETCHECK_FIELD();
 | 
			
		||||
		CHECK_FIELD_TYPE(MESSAGE);
 | 
			
		||||
		CHECK_FIELD_REPEATED();
 | 
			
		||||
@ -862,10 +873,14 @@ public:
 | 
			
		||||
			);
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline bool SetRepeatedColor(const char *pszFieldName, int index, const Color &value)
 | 
			
		||||
	{
 | 
			
		||||
#if SOURCE_ENGINE != SE_CSGO
 | 
			
		||||
		return false;
 | 
			
		||||
#else
 | 
			
		||||
		GETCHECK_FIELD();
 | 
			
		||||
		CHECK_FIELD_TYPE(MESSAGE);
 | 
			
		||||
		CHECK_FIELD_REPEATED();
 | 
			
		||||
@ -878,10 +893,14 @@ public:
 | 
			
		||||
		msgRGBA->set_a(value.a());
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline bool AddColor(const char *pszFieldName, const Color &value)
 | 
			
		||||
	{
 | 
			
		||||
#if SOURCE_ENGINE != SE_CSGO
 | 
			
		||||
		return false;
 | 
			
		||||
#else
 | 
			
		||||
		GETCHECK_FIELD();
 | 
			
		||||
		CHECK_FIELD_TYPE(MESSAGE);
 | 
			
		||||
		CHECK_FIELD_REPEATED();
 | 
			
		||||
@ -893,6 +912,7 @@ public:
 | 
			
		||||
		msgRGBA->set_a(value.a());
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline bool GetVector2D(const char *pszFieldName, Vector2D *out)
 | 
			
		||||
 | 
			
		||||
@ -35,16 +35,12 @@
 | 
			
		||||
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
#include <cstrike15_usermessage_helpers.h>
 | 
			
		||||
#elif SOURCE_ENGINE == SE_BLADE
 | 
			
		||||
#include <berimbau_usermessage_helpers.h>
 | 
			
		||||
#elif SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#include <vietnam_usermessage_helpers.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <amtl/am-string.h>
 | 
			
		||||
 | 
			
		||||
UserMessages g_UserMsgs;
 | 
			
		||||
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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
 | 
			
		||||
@ -53,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 || ==SE_MCV
 | 
			
		||||
#endif // ==SE_CSGO
 | 
			
		||||
 | 
			
		||||
UserMessages::UserMessages()
 | 
			
		||||
#ifndef USE_PROTOBUF_USERMESSAGES
 | 
			
		||||
@ -97,7 +93,7 @@ void UserMessages::OnSourceModAllShutdown()
 | 
			
		||||
{
 | 
			
		||||
	if (m_HookCount)
 | 
			
		||||
	{
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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
 | 
			
		||||
@ -115,10 +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);
 | 
			
		||||
#elif SOURCE_ENGINE == SE_MCV
 | 
			
		||||
	return g_VietnamUsermessageHelpers.GetIndex(msg);
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
	int msgid;
 | 
			
		||||
@ -156,10 +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);
 | 
			
		||||
#elif SOURCE_ENGINE == SE_MCV
 | 
			
		||||
	const char *pszName = g_VietnamUsermessageHelpers.GetName(msgid);
 | 
			
		||||
#endif
 | 
			
		||||
	if (!pszName)
 | 
			
		||||
		return false;
 | 
			
		||||
@ -309,7 +297,7 @@ bool UserMessages::EndMessage()
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
	if (m_CurFlags & USERMSG_BLOCKHOOKS)
 | 
			
		||||
	{
 | 
			
		||||
		ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
 | 
			
		||||
@ -339,7 +327,7 @@ bool UserMessages::EndMessage()
 | 
			
		||||
	} else {
 | 
			
		||||
		engine->MessageEnd();
 | 
			
		||||
	}
 | 
			
		||||
#endif // SE_CSGO || SE_BLADE || SE_MCV
 | 
			
		||||
#endif // SE_CSGO
 | 
			
		||||
 | 
			
		||||
	m_InExec = false;
 | 
			
		||||
	m_CurFlags = 0;
 | 
			
		||||
@ -424,7 +412,7 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
 | 
			
		||||
 | 
			
		||||
	if (!m_HookCount++)
 | 
			
		||||
	{
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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
 | 
			
		||||
@ -450,10 +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);
 | 
			
		||||
#elif SOURCE_ENGINE == SE_MCV
 | 
			
		||||
	return g_VietnamUsermessageHelpers.GetPrototype(msg_type);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@ -503,7 +487,7 @@ void UserMessages::_DecRefCounter()
 | 
			
		||||
{
 | 
			
		||||
	if (--m_HookCount == 0)
 | 
			
		||||
	{
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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
 | 
			
		||||
@ -515,19 +499,12 @@ void UserMessages::_DecRefCounter()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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);
 | 
			
		||||
#elif SOURCE_ENGINE == SE_MCV
 | 
			
		||||
	const char *pszName = g_VietnamUsermessageHelpers.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();
 | 
			
		||||
@ -540,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)
 | 
			
		||||
@ -572,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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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)
 | 
			
		||||
@ -612,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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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)
 | 
			
		||||
@ -777,7 +756,7 @@ void UserMessages::OnMessageEnd_Pre()
 | 
			
		||||
 | 
			
		||||
	if (!handled && intercepted)
 | 
			
		||||
	{
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
		ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
 | 
			
		||||
#else
 | 
			
		||||
		bf_write *engine_bfw;
 | 
			
		||||
@ -789,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 || SE_MCV
 | 
			
		||||
#endif // SE_CSGO
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
		int size = m_OrigBuffer->ByteSize();
 | 
			
		||||
		uint8 *data = (uint8 *)stackalloc(size);
 | 
			
		||||
		m_OrigBuffer->SerializePartialToArray(data, size);
 | 
			
		||||
@ -823,7 +802,7 @@ void UserMessages::OnMessageEnd_Pre()
 | 
			
		||||
			iter++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#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 || SOURCE_ENGINE == SE_MCV
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
	void LinkConCommandBase(ConCommandBase *pBase, bool unknown)
 | 
			
		||||
#else
 | 
			
		||||
	void LinkConCommandBase(ConCommandBase *pBase)
 | 
			
		||||
@ -108,20 +108,20 @@ public:
 | 
			
		||||
			listener = listener->next;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		while (iter != tracked_bases.end())
 | 
			
		||||
		{
 | 
			
		||||
		    if ((*iter)->pBase == pBase)
 | 
			
		||||
		    {
 | 
			
		||||
			pInfo = (*iter);
 | 
			
		||||
			iter = tracked_bases.erase(iter);
 | 
			
		||||
			pInfo->cls->OnUnlinkConCommandBase(pBase, pBase->GetName());
 | 
			
		||||
			delete pInfo;
 | 
			
		||||
		    }
 | 
			
		||||
		    else
 | 
			
		||||
		    {
 | 
			
		||||
			iter++;
 | 
			
		||||
		    }
 | 
			
		||||
		}
 | 
			
		||||
        while (iter != tracked_bases.end())
 | 
			
		||||
        {
 | 
			
		||||
            if ((*iter)->pBase == pBase)
 | 
			
		||||
            {
 | 
			
		||||
                pInfo = (*iter);
 | 
			
		||||
                iter = tracked_bases.erase(iter);
 | 
			
		||||
                pInfo->cls->OnUnlinkConCommandBase(pBase, pBase->GetName());
 | 
			
		||||
                delete pInfo;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                iter++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void AddTarget(ConCommandBase *pBase, IConCommandTracker *cls)
 | 
			
		||||
 | 
			
		||||
@ -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++)
 | 
			
		||||
	{
 | 
			
		||||
		ke::RefPtr<ConfDbInfo> current = list->at(i);
 | 
			
		||||
		if (current->realDriver == pDriver)
 | 
			
		||||
		{
 | 
			
		||||
			conf->realDriver = NULL;
 | 
			
		||||
			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,43 +458,46 @@ 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;
 | 
			
		||||
 | 
			
		||||
			// Otherwise, wait for something to happen.
 | 
			
		||||
			m_QueueEvent.wait(lock);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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
 | 
			
		||||
		// items. It's okay if we terminate while unlocked; the main
 | 
			
		||||
		// 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();
 | 
			
		||||
		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.
 | 
			
		||||
		while (true)
 | 
			
		||||
		{
 | 
			
		||||
			std::lock_guard<std::mutex> think_lock(m_ThinkLock);
 | 
			
		||||
			m_ThinkQueue.push(op);
 | 
			
		||||
			Queue<IDBThreadOperation *> &queue = m_OpQueue.GetLikelyQueue();
 | 
			
		||||
			if (queue.empty())
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			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
 | 
			
		||||
			// items. It's okay if we terminate while unlocked; the main
 | 
			
		||||
			// 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.
 | 
			
		||||
			{
 | 
			
		||||
				ke::AutoUnlock unlock(&m_QueueEvent);
 | 
			
		||||
				op->RunThreadPart();
 | 
			
		||||
 | 
			
		||||
				ke::AutoLock lock(&m_ThinkLock);
 | 
			
		||||
				m_ThinkQueue.push(op);
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			
 | 
			
		||||
			if (!m_Terminate)
 | 
			
		||||
			{
 | 
			
		||||
				ke::AutoUnlock unlock(&m_QueueEvent);
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
				Sleep(20);
 | 
			
		||||
#else
 | 
			
		||||
				usleep(20000);
 | 
			
		||||
#endif
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 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);
 | 
			
		||||
		if (m_Terminate)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		lock.lock();
 | 
			
		||||
		// 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,13 +69,13 @@ 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();
 | 
			
		||||
	const char *error = g_pSourcePawn2->GetErrorString(err);
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
			g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
 | 
			
		||||
	if (error)
 | 
			
		||||
	{
 | 
			
		||||
		g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
 | 
			
		||||
	} else {
 | 
			
		||||
		g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_Logger.LogError("[SM] %s", buffer);
 | 
			
		||||
@ -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;
 | 
			
		||||
@ -395,6 +390,11 @@ void CExtension::AddDependency(const IfaceInfo *pInfo)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool operator ==(const IfaceInfo &i1, const IfaceInfo &i2)
 | 
			
		||||
{
 | 
			
		||||
	return (i1.iface == i2.iface) && (i1.owner == i2.owner);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CExtension::AddChildDependent(CExtension *pOther, SMInterface *iface)
 | 
			
		||||
{
 | 
			
		||||
	IfaceInfo info;
 | 
			
		||||
@ -496,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;
 | 
			
		||||
 | 
			
		||||
@ -628,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);
 | 
			
		||||
@ -1177,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);
 | 
			
		||||
@ -1369,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,18 +48,16 @@ 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();
 | 
			
		||||
			FunctionName = it->FunctionName();
 | 
			
		||||
			FilePath = it->FilePath();
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
@ -75,5 +73,5 @@ public:
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	size_t current;
 | 
			
		||||
	std::vector<FrameInfo> frames;
 | 
			
		||||
	ke::Vector<FrameInfo> frames;
 | 
			
		||||
};
 | 
			
		||||
@ -30,7 +30,6 @@
 | 
			
		||||
#include "common_logic.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <sh_list.h>
 | 
			
		||||
#include <sh_string.h>
 | 
			
		||||
#include "GameConfigs.h"
 | 
			
		||||
@ -47,7 +46,6 @@
 | 
			
		||||
#include <am-string.h>
 | 
			
		||||
#include <bridge/include/ILogger.h>
 | 
			
		||||
#include <bridge/include/CoreProvider.h>
 | 
			
		||||
#include <bridge/include/IFileSystemBridge.h>
 | 
			
		||||
 | 
			
		||||
#if defined PLATFORM_POSIX
 | 
			
		||||
#include <dlfcn.h>
 | 
			
		||||
@ -87,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
 | 
			
		||||
@ -105,6 +106,8 @@ struct TempSigInfo
 | 
			
		||||
	char sig[1024];
 | 
			
		||||
	char library[64];
 | 
			
		||||
} s_TempSig;
 | 
			
		||||
unsigned int s_ServerBinCRC;
 | 
			
		||||
bool s_ServerBinCRC_Ok = false;
 | 
			
		||||
 | 
			
		||||
static bool DoesGameMatch(const char *value)
 | 
			
		||||
{
 | 
			
		||||
@ -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;
 | 
			
		||||
@ -303,25 +287,39 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
 | 
			
		||||
		{
 | 
			
		||||
			char error[255];
 | 
			
		||||
			error[0] = '\0';
 | 
			
		||||
			GameBinaryInfo binInfo;
 | 
			
		||||
			if (!g_GameConfigs.TryGetGameBinaryInfo(name, &binInfo))
 | 
			
		||||
			if (strcmp(name, "server") != 0)
 | 
			
		||||
			{
 | 
			
		||||
				ke::SafeSprintf(error, sizeof(error), "Unrecognized library \"%s\"", name);
 | 
			
		||||
			} 
 | 
			
		||||
			else if (!binInfo.m_crcOK)
 | 
			
		||||
			else if (!s_ServerBinCRC_Ok)
 | 
			
		||||
			{
 | 
			
		||||
				ke::SafeSprintf(error, sizeof(error), "Could not get CRC for binary: %s", name);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				bCurrentBinCRC_Ok = binInfo.m_crcOK;
 | 
			
		||||
				bCurrentBinCRC = binInfo.m_crc;
 | 
			
		||||
			}
 | 
			
		||||
				FILE *fp;
 | 
			
		||||
				char path[PLATFORM_MAX_PATH];
 | 
			
		||||
 | 
			
		||||
				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);
 | 
			
		||||
				} else {
 | 
			
		||||
					size_t size;
 | 
			
		||||
					void *buffer;
 | 
			
		||||
 | 
			
		||||
					fseek(fp, 0, SEEK_END);
 | 
			
		||||
					size = ftell(fp);
 | 
			
		||||
					fseek(fp, 0, SEEK_SET);
 | 
			
		||||
 | 
			
		||||
					buffer = malloc(size);
 | 
			
		||||
					fread(buffer, size, 1, fp);
 | 
			
		||||
					s_ServerBinCRC = UTIL_CRC32(buffer, size);
 | 
			
		||||
					free(buffer);
 | 
			
		||||
					s_ServerBinCRC_Ok = true;
 | 
			
		||||
					fclose(fp);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			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;
 | 
			
		||||
@ -336,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;
 | 
			
		||||
@ -357,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;
 | 
			
		||||
@ -394,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)
 | 
			
		||||
@ -444,12 +442,12 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
 | 
			
		||||
		}
 | 
			
		||||
	} else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) {
 | 
			
		||||
		if (DoesPlatformMatch(key)
 | 
			
		||||
			&& bCurrentBinCRC_Ok
 | 
			
		||||
			&& s_ServerBinCRC_Ok
 | 
			
		||||
			&& !bShouldBeReadingDefault)
 | 
			
		||||
		{
 | 
			
		||||
			unsigned int crc = 0;
 | 
			
		||||
			sscanf(value, "%08X", &crc);
 | 
			
		||||
			if (bCurrentBinCRC == crc)
 | 
			
		||||
			if (s_ServerBinCRC == crc)
 | 
			
		||||
			{
 | 
			
		||||
				bShouldBeReadingDefault = true;
 | 
			
		||||
			}
 | 
			
		||||
@ -459,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)
 | 
			
		||||
			{
 | 
			
		||||
@ -467,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);
 | 
			
		||||
@ -531,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);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
@ -586,12 +585,14 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
 | 
			
		||||
				strncopy(s_TempSig.library, "server", sizeof(s_TempSig.library));
 | 
			
		||||
			}
 | 
			
		||||
			void *addrInBase = NULL;
 | 
			
		||||
			GameBinaryInfo binInfo;
 | 
			
		||||
			if (g_GameConfigs.TryGetGameBinaryInfo(s_TempSig.library, &binInfo))
 | 
			
		||||
			if (strcmp(s_TempSig.library, "server") == 0)
 | 
			
		||||
			{
 | 
			
		||||
				addrInBase = binInfo.m_pAddr;
 | 
			
		||||
				addrInBase = bridge->serverFactory;
 | 
			
		||||
			} else if (strcmp(s_TempSig.library, "engine") == 0) {
 | 
			
		||||
				addrInBase = bridge->engineFactory;
 | 
			
		||||
			} else if (strcmp(s_TempSig.library, "matchmaking_ds") == 0) {
 | 
			
		||||
				addrInBase = bridge->matchmakingDSFactory;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			void *final_addr = NULL;
 | 
			
		||||
			if (addrInBase == NULL)
 | 
			
		||||
			{
 | 
			
		||||
@ -654,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;
 | 
			
		||||
@ -670,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;
 | 
			
		||||
@ -791,10 +792,7 @@ public:
 | 
			
		||||
				(!had_game && matched_engine) ||
 | 
			
		||||
				(matched_engine && matched_game))
 | 
			
		||||
			{
 | 
			
		||||
				if (fileList->find(cur_file) == fileList->end())
 | 
			
		||||
				{
 | 
			
		||||
					fileList->push_back(cur_file);
 | 
			
		||||
				}
 | 
			
		||||
				fileList->push_back(cur_file);
 | 
			
		||||
			}
 | 
			
		||||
			state = MSTATE_MAIN;
 | 
			
		||||
		}
 | 
			
		||||
@ -1003,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
 | 
			
		||||
@ -1024,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;
 | 
			
		||||
@ -1057,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);
 | 
			
		||||
 | 
			
		||||
@ -1083,42 +1081,6 @@ bool CGameConfig::GetMemSig(const char *key, void **addr)
 | 
			
		||||
	return m_Sigs.retrieve(key, addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GameBinPathManager::Init()
 | 
			
		||||
{
 | 
			
		||||
	char search_path[PLATFORM_MAX_PATH * 8];
 | 
			
		||||
	bridge->filesystem->GetSearchPath("GAMEBIN", false, search_path, sizeof(search_path));
 | 
			
		||||
 | 
			
		||||
	char addons_folder[12];
 | 
			
		||||
	ke::SafeSprintf(addons_folder, sizeof(addons_folder), "%caddons%c", PLATFORM_SEP_CHAR, PLATFORM_SEP_CHAR);
 | 
			
		||||
 | 
			
		||||
	std::istringstream iss(search_path);
 | 
			
		||||
	for (std::string path; std::getline(iss, path, ';');)
 | 
			
		||||
	{
 | 
			
		||||
		if (path.length() > 0
 | 
			
		||||
			&& path.find(addons_folder) == std::string::npos
 | 
			
		||||
			&& m_lookup.find(path) == m_lookup.cend()
 | 
			
		||||
			)
 | 
			
		||||
		{
 | 
			
		||||
			m_lookup.insert(path);
 | 
			
		||||
			m_ordered.push_back(path);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iss.clear();
 | 
			
		||||
	
 | 
			
		||||
	bridge->filesystem->GetSearchPath("EXECUTABLE_PATH", false, search_path, sizeof(search_path));
 | 
			
		||||
	iss.str(search_path);
 | 
			
		||||
	
 | 
			
		||||
	for (std::string path; std::getline(iss, path, ';');)
 | 
			
		||||
	{
 | 
			
		||||
		if (m_lookup.find(path) == m_lookup.cend())
 | 
			
		||||
		{
 | 
			
		||||
			m_lookup.insert(path);
 | 
			
		||||
			m_ordered.push_back(path);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GameConfigManager::GameConfigManager()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
@ -1129,8 +1091,6 @@ GameConfigManager::~GameConfigManager()
 | 
			
		||||
 | 
			
		||||
void GameConfigManager::OnSourceModStartup(bool late)
 | 
			
		||||
{
 | 
			
		||||
	m_gameBinPathManager.Init();
 | 
			
		||||
	
 | 
			
		||||
	LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0);
 | 
			
		||||
 | 
			
		||||
	strncopy(g_Game, g_pSM->GetGameFolderName(), sizeof(g_Game));
 | 
			
		||||
@ -1172,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);
 | 
			
		||||
@ -1253,75 +1205,3 @@ void GameConfigManager::RemoveCachedConfig(CGameConfig *config)
 | 
			
		||||
{
 | 
			
		||||
	m_Lookup.remove(config->m_File);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GameConfigManager::CacheGameBinaryInfo(const char* pszName)
 | 
			
		||||
{
 | 
			
		||||
	GameBinaryInfo info;
 | 
			
		||||
 | 
			
		||||
	char name[64];
 | 
			
		||||
	bridge->FormatSourceBinaryName(pszName, name, sizeof(name));
 | 
			
		||||
 | 
			
		||||
	char binary_path[PLATFORM_MAX_PATH];
 | 
			
		||||
	for (auto it = m_gameBinPathManager.Paths().begin(); it != m_gameBinPathManager.Paths().end(); ++it)
 | 
			
		||||
	{
 | 
			
		||||
		ke::SafeSprintf(binary_path, sizeof(binary_path), "%s%s%s", it->c_str(), it->back() == PLATFORM_SEP_CHAR ? "" : PLATFORM_SEP, name);
 | 
			
		||||
#if defined PLATFORM_WINDOWS
 | 
			
		||||
		HMODULE hModule = LoadLibraryA(binary_path);
 | 
			
		||||
		if (hModule)
 | 
			
		||||
		{
 | 
			
		||||
			info.m_pAddr = GetProcAddress(hModule, "CreateInterface");
 | 
			
		||||
			FreeLibrary(hModule);
 | 
			
		||||
		}
 | 
			
		||||
#else
 | 
			
		||||
		void *pHandle = dlopen(binary_path, RTLD_NOW);
 | 
			
		||||
		if (pHandle)
 | 
			
		||||
		{
 | 
			
		||||
			info.m_pAddr = dlsym(pHandle, "CreateInterface");
 | 
			
		||||
			dlclose(pHandle);
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
		
 | 
			
		||||
		if (info.m_pAddr)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Don't bother trying to get CRC if we couldn't find the bin loaded
 | 
			
		||||
	if (info.m_pAddr)
 | 
			
		||||
	{
 | 
			
		||||
		FILE *fp;
 | 
			
		||||
 | 
			
		||||
		if ((fp = fopen(binary_path, "rb")) == 0)
 | 
			
		||||
		{
 | 
			
		||||
			info.m_crc = 0;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			size_t size;
 | 
			
		||||
			void* buffer;
 | 
			
		||||
 | 
			
		||||
			fseek(fp, 0, SEEK_END);
 | 
			
		||||
			size = ftell(fp);
 | 
			
		||||
			fseek(fp, 0, SEEK_SET);
 | 
			
		||||
 | 
			
		||||
			buffer = malloc(size);
 | 
			
		||||
			fread(buffer, size, 1, fp);
 | 
			
		||||
			info.m_crc = UTIL_CRC32(buffer, size);
 | 
			
		||||
			free(buffer);
 | 
			
		||||
			info.m_crcOK = true;
 | 
			
		||||
			fclose(fp);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// But insert regardless, to cache the first lookup (even as failed)
 | 
			
		||||
	m_gameBinInfos.insert(pszName, info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GameConfigManager::TryGetGameBinaryInfo(const char* pszName, GameBinaryInfo* pDest)
 | 
			
		||||
{
 | 
			
		||||
	if (m_gameBinInfos.retrieve(pszName, pDest))
 | 
			
		||||
		return pDest->m_pAddr != nullptr;
 | 
			
		||||
 | 
			
		||||
	CacheGameBinaryInfo(pszName);
 | 
			
		||||
 | 
			
		||||
	return m_gameBinInfos.retrieve(pszName, pDest);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -38,7 +38,6 @@
 | 
			
		||||
#include <am-refcounting.h>
 | 
			
		||||
#include <sm_stringhashmap.h>
 | 
			
		||||
#include <sm_namehashset.h>
 | 
			
		||||
#include <unordered_set>
 | 
			
		||||
 | 
			
		||||
using namespace SourceMod;
 | 
			
		||||
 | 
			
		||||
@ -82,18 +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;
 | 
			
		||||
	unsigned int bCurrentBinCRC;
 | 
			
		||||
	bool bCurrentBinCRC_Ok = false;
 | 
			
		||||
	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;
 | 
			
		||||
@ -108,49 +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;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct GameBinaryInfo
 | 
			
		||||
{
 | 
			
		||||
	void *m_pAddr = nullptr;
 | 
			
		||||
	uint32_t m_crc = 0;
 | 
			
		||||
	bool m_crcOK = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class GameBinPathManager
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	GameBinPathManager() {}
 | 
			
		||||
	~GameBinPathManager() {}
 | 
			
		||||
public:
 | 
			
		||||
	void Init();
 | 
			
		||||
 | 
			
		||||
	inline const std::vector<std::string>& Paths() const
 | 
			
		||||
	{
 | 
			
		||||
		return m_ordered;
 | 
			
		||||
	}
 | 
			
		||||
private:
 | 
			
		||||
	std::unordered_set<std::string> m_lookup;
 | 
			
		||||
	std::vector<std::string> m_ordered;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class GameConfigManager : 
 | 
			
		||||
@ -175,16 +147,11 @@ public: //SMGlobalClass
 | 
			
		||||
	void OnSourceModAllInitialized();
 | 
			
		||||
	void OnSourceModAllShutdown();
 | 
			
		||||
public:
 | 
			
		||||
	bool TryGetGameBinaryInfo(const char* pszName, GameBinaryInfo* pDest);
 | 
			
		||||
	void RemoveCachedConfig(CGameConfig *config);
 | 
			
		||||
private:
 | 
			
		||||
	void CacheGameBinaryInfo(const char* pszName);
 | 
			
		||||
private:
 | 
			
		||||
	NameHashSet<CGameConfig *> m_Lookup;
 | 
			
		||||
	StringHashMap<GameBinaryInfo> m_gameBinInfos;
 | 
			
		||||
public:
 | 
			
		||||
	StringHashMap<ITextListener_SMC *> m_customHandlers;
 | 
			
		||||
	GameBinPathManager m_gameBinPathManager;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern GameConfigManager g_GameConfigs;
 | 
			
		||||
 | 
			
		||||
@ -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,12 +1090,12 @@ 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)
 | 
			
		||||
		{
 | 
			
		||||
			IdentityToken_t	*pOwner = m_Handles[i].owner;
 | 
			
		||||
			IdentityToken_t *pOwner = m_Handles[i].owner;
 | 
			
		||||
			if (pOwner == g_pCoreIdent)
 | 
			
		||||
			{
 | 
			
		||||
				owner = "CORE";
 | 
			
		||||
@ -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)
 | 
			
		||||
 | 
			
		||||
@ -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,11 +45,10 @@
 | 
			
		||||
#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>
 | 
			
		||||
 | 
			
		||||
#define SOURCEMOD_PLUGINAPI_VERSION     7
 | 
			
		||||
 | 
			
		||||
CPluginManager g_PluginSys;
 | 
			
		||||
HandleType_t g_PluginType = 0;
 | 
			
		||||
IdentityType_t g_PluginIdent = 0;
 | 
			
		||||
@ -80,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()
 | 
			
		||||
@ -228,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, ...)
 | 
			
		||||
@ -277,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;
 | 
			
		||||
@ -311,12 +310,12 @@ bool CPlugin::ReadInfo()
 | 
			
		||||
 | 
			
		||||
		base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&info);
 | 
			
		||||
		m_FileVersion = info->version;
 | 
			
		||||
		if (m_FileVersion >= 5) {
 | 
			
		||||
		if (m_FileVersion >= 4) {
 | 
			
		||||
			base->LocalToString(info->date, (char **)&pDate);
 | 
			
		||||
			base->LocalToString(info->time, (char **)&pTime);
 | 
			
		||||
			ke::SafeSprintf(m_DateTime, sizeof(m_DateTime), "%s %s", pDate, pTime);
 | 
			
		||||
		}
 | 
			
		||||
		if (m_FileVersion > SOURCEMOD_PLUGINAPI_VERSION) {
 | 
			
		||||
		if (m_FileVersion > 5) {
 | 
			
		||||
			base->LocalToString(info->filevers, (char **)&pFileVers);
 | 
			
		||||
			EvictWithError(Plugin_Failed, "Newer SourceMod required (%s or higher)", pFileVers);
 | 
			
		||||
			return false;
 | 
			
		||||
@ -484,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;
 | 
			
		||||
@ -525,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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -659,7 +658,7 @@ time_t CPlugin::GetFileTimeStamp()
 | 
			
		||||
 | 
			
		||||
IPhraseCollection *CPlugin::GetPhrases()
 | 
			
		||||
{
 | 
			
		||||
	return m_pPhrases.get();
 | 
			
		||||
	return m_pPhrases;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPlugin::DependencyDropped(CPlugin *pOwner)
 | 
			
		||||
@ -675,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]);
 | 
			
		||||
 | 
			
		||||
@ -774,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]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -791,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);
 | 
			
		||||
}
 | 
			
		||||
@ -848,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)
 | 
			
		||||
@ -976,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());
 | 
			
		||||
@ -1044,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();
 | 
			
		||||
@ -1176,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());
 | 
			
		||||
@ -1188,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()))
 | 
			
		||||
@ -1222,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)
 | 
			
		||||
@ -1258,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)
 | 
			
		||||
@ -1501,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())
 | 
			
		||||
@ -1550,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)
 | 
			
		||||
@ -1592,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()
 | 
			
		||||
@ -1607,7 +1592,6 @@ void CPluginManager::OnSourceModShutdown()
 | 
			
		||||
 | 
			
		||||
	forwardsys->ReleaseForward(m_pOnLibraryAdded);
 | 
			
		||||
	forwardsys->ReleaseForward(m_pOnLibraryRemoved);
 | 
			
		||||
	forwardsys->ReleaseForward(m_pOnNotifyPluginUnloaded);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConfigResult CPluginManager::OnSourceModConfigChanged(const char *key,
 | 
			
		||||
@ -1731,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);
 | 
			
		||||
@ -1743,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
 | 
			
		||||
				{
 | 
			
		||||
@ -2049,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);
 | 
			
		||||
@ -2080,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;
 | 
			
		||||
@ -2095,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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2225,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)
 | 
			
		||||
@ -2289,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);
 | 
			
		||||
@ -2367,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,17 +49,15 @@ 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;
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct IfaceInfo
 | 
			
		||||
{
 | 
			
		||||
	bool operator ==(const IfaceInfo &info) const
 | 
			
		||||
	bool operator ==(const IfaceInfo &info)
 | 
			
		||||
	{
 | 
			
		||||
		return (info.iface == iface && info.owner == owner);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
@ -281,19 +277,7 @@ static cell_t GetArrayString(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// the blocknumber is not guaranteed to always be passed
 | 
			
		||||
	size_t blocknumber = 0;
 | 
			
		||||
	if (params[0] >= 5)
 | 
			
		||||
	{
 | 
			
		||||
		blocknumber = (size_t)params[5];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (blocknumber >= array->blocksize())
 | 
			
		||||
	{
 | 
			
		||||
		return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
 | 
			
		||||
	cell_t *blk = array->at(idx);
 | 
			
		||||
	size_t numWritten = 0;
 | 
			
		||||
 | 
			
		||||
	pContext->StringToLocalUTF8(params[3], params[4], (char *)blk, &numWritten);
 | 
			
		||||
@ -319,19 +303,7 @@ static cell_t GetArrayArray(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// the blocknumber is not guaranteed to always be passed
 | 
			
		||||
	size_t blocknumber = 0;
 | 
			
		||||
	if (params[0] >= 5)
 | 
			
		||||
	{
 | 
			
		||||
		blocknumber = (size_t)params[5];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (blocknumber >= array->blocksize())
 | 
			
		||||
	{
 | 
			
		||||
		return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
 | 
			
		||||
	cell_t *blk = array->at(idx);
 | 
			
		||||
	size_t indexes = array->blocksize();
 | 
			
		||||
	if (params[4] != -1 && (size_t)params[4] <= array->blocksize())
 | 
			
		||||
	{
 | 
			
		||||
@ -403,30 +375,12 @@ static cell_t SetArrayString(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// the blocknumber is not guaranteed to always be passed
 | 
			
		||||
	size_t blocknumber = 0;
 | 
			
		||||
	if (params[0] >= 5)
 | 
			
		||||
	{
 | 
			
		||||
		blocknumber = (size_t)params[5];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (blocknumber >= array->blocksize())
 | 
			
		||||
	{
 | 
			
		||||
		return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
 | 
			
		||||
	cell_t *blk = array->at(idx);
 | 
			
		||||
 | 
			
		||||
	char *str;
 | 
			
		||||
	pContext->LocalToString(params[3], &str);
 | 
			
		||||
 | 
			
		||||
	size_t maxlength = array->blocksize() * sizeof(cell_t);
 | 
			
		||||
	if (params[0] >= 4 && params[4] != -1 && (size_t)params[4] <= array->blocksize())
 | 
			
		||||
	{
 | 
			
		||||
		maxlength = (size_t)params[4];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return strncopy((char*)blk, str, maxlength);
 | 
			
		||||
	return strncopy((char *)blk, str, array->blocksize() * sizeof(cell_t));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static cell_t SetArrayArray(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
@ -447,19 +401,7 @@ static cell_t SetArrayArray(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
		return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// the blocknumber is not guaranteed to always be passed
 | 
			
		||||
	size_t blocknumber = 0;
 | 
			
		||||
	if (params[0] >= 5)
 | 
			
		||||
	{
 | 
			
		||||
		blocknumber = (size_t)params[5];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (blocknumber >= array->blocksize())
 | 
			
		||||
	{
 | 
			
		||||
		return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
 | 
			
		||||
	cell_t *blk = array->at(idx);
 | 
			
		||||
	size_t indexes = array->blocksize();
 | 
			
		||||
	if (params[4] != -1 && (size_t)params[4] <= array->blocksize())
 | 
			
		||||
	{
 | 
			
		||||
@ -587,24 +529,12 @@ static cell_t FindStringInArray(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// the blocknumber is not guaranteed to always be passed
 | 
			
		||||
	size_t blocknumber = 0;
 | 
			
		||||
	if (params[0] >= 3)
 | 
			
		||||
	{
 | 
			
		||||
		blocknumber = (size_t)params[3];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (blocknumber >= array->blocksize())
 | 
			
		||||
	{
 | 
			
		||||
		return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	char *str;
 | 
			
		||||
	pContext->LocalToString(params[2], &str);
 | 
			
		||||
 | 
			
		||||
	for (unsigned int i = 0; i < array->size(); i++)
 | 
			
		||||
	{
 | 
			
		||||
		const char *array_str = (const char *)&array->base()[i * array->blocksize() + blocknumber];
 | 
			
		||||
		const char *array_str = (const char *)array->at(i);
 | 
			
		||||
		if (strcmp(str, array_str) == 0)
 | 
			
		||||
		{
 | 
			
		||||
			return (cell_t) i;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
@ -240,9 +198,9 @@ static cell_t PopStackCell(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		if (idx >= array->blocksize() * sizeof(cell_t))
 | 
			
		||||
		if (idx >= array->blocksize() * 4)
 | 
			
		||||
		{
 | 
			
		||||
			return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t));
 | 
			
		||||
			return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4);
 | 
			
		||||
		}
 | 
			
		||||
		*buffer = (cell_t)*((char *)blk + idx);
 | 
			
		||||
	}
 | 
			
		||||
@ -356,8 +314,8 @@ static cell_t ArrayStack_Pop(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
			return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize());
 | 
			
		||||
		rval = blk[idx];
 | 
			
		||||
	} else {
 | 
			
		||||
		if (idx >= array->blocksize() * sizeof(cell_t))
 | 
			
		||||
			return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t));
 | 
			
		||||
		if (idx >= array->blocksize() * 4)
 | 
			
		||||
			return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4);
 | 
			
		||||
		rval = (cell_t)*((char *)blk + idx);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -365,32 +323,6 @@ static cell_t ArrayStack_Pop(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
	return rval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static cell_t ArrayStack_Top(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
{
 | 
			
		||||
	OpenHandle<CellArray> array(pContext, params[1], htCellStack);
 | 
			
		||||
	if (!array.Ok())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (array->size() == 0)
 | 
			
		||||
		return pContext->ThrowNativeError("stack is empty");
 | 
			
		||||
 | 
			
		||||
	cell_t *blk = array->at(array->size() - 1);
 | 
			
		||||
	size_t idx = (size_t)params[2];
 | 
			
		||||
 | 
			
		||||
	cell_t rval;
 | 
			
		||||
	if (params[3] == 0) {
 | 
			
		||||
		if (idx >= array->blocksize())
 | 
			
		||||
			return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize());
 | 
			
		||||
		rval = blk[idx];
 | 
			
		||||
	} else {
 | 
			
		||||
		if (idx >= array->blocksize() * sizeof(cell_t))
 | 
			
		||||
			return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t));
 | 
			
		||||
		rval = (cell_t)*((char *)blk + idx);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static cell_t ArrayStack_PopString(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
{
 | 
			
		||||
	OpenHandle<CellArray> array(pContext, params[1], htCellStack); 
 | 
			
		||||
@ -413,27 +345,6 @@ static cell_t ArrayStack_PopString(IPluginContext *pContext, const cell_t *param
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static cell_t ArrayStack_TopString(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
{
 | 
			
		||||
	OpenHandle<CellArray> array(pContext, params[1], htCellStack);
 | 
			
		||||
	if (!array.Ok())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (array->size() == 0)
 | 
			
		||||
		return pContext->ThrowNativeError("stack is empty");
 | 
			
		||||
 | 
			
		||||
	size_t idx = array->size() - 1;
 | 
			
		||||
	cell_t *blk = array->at(idx);
 | 
			
		||||
 | 
			
		||||
	cell_t *pWritten;
 | 
			
		||||
	pContext->LocalToPhysAddr(params[4], &pWritten);
 | 
			
		||||
 | 
			
		||||
	size_t numWritten;
 | 
			
		||||
	pContext->StringToLocalUTF8(params[2], params[3], (char *)blk, &numWritten);
 | 
			
		||||
	*pWritten = (cell_t)numWritten;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static cell_t ArrayStack_PopArray(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
{
 | 
			
		||||
	OpenHandle<CellArray> array(pContext, params[1], htCellStack); 
 | 
			
		||||
@ -458,29 +369,6 @@ static cell_t ArrayStack_PopArray(IPluginContext *pContext, const cell_t *params
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static cell_t ArrayStack_TopArray(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
{
 | 
			
		||||
	OpenHandle<CellArray> array(pContext, params[1], htCellStack);
 | 
			
		||||
	if (!array.Ok())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (array->size() == 0)
 | 
			
		||||
		return pContext->ThrowNativeError("stack is empty");
 | 
			
		||||
 | 
			
		||||
	cell_t *addr;
 | 
			
		||||
	pContext->LocalToPhysAddr(params[2], &addr);
 | 
			
		||||
 | 
			
		||||
	size_t idx = array->size() - 1;
 | 
			
		||||
	cell_t *blk = array->at(idx);
 | 
			
		||||
	size_t indexes = array->blocksize();
 | 
			
		||||
 | 
			
		||||
	if (params[3] != -1 && (size_t)params[3] <= array->blocksize())
 | 
			
		||||
		indexes = params[3];
 | 
			
		||||
 | 
			
		||||
	memcpy(addr, blk, sizeof(cell_t) * indexes);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
{
 | 
			
		||||
	HandleError err;
 | 
			
		||||
@ -496,25 +384,9 @@ static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
	return array->blocksize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static cell_t GetStackSize(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
{
 | 
			
		||||
	HandleError err;
 | 
			
		||||
	CellArray *array;
 | 
			
		||||
	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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return array->size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
REGISTER_NATIVES(cellStackNatives)
 | 
			
		||||
{
 | 
			
		||||
	{"CreateStack",					CreateStack},
 | 
			
		||||
	{"CloneStack",					CloneStack},
 | 
			
		||||
	{"IsStackEmpty",				IsStackEmpty},
 | 
			
		||||
	{"PopStackArray",				PopStackArray},
 | 
			
		||||
	{"PopStackCell",				PopStackCell},
 | 
			
		||||
@ -526,20 +398,14 @@ REGISTER_NATIVES(cellStackNatives)
 | 
			
		||||
 | 
			
		||||
	// Transitional syntax support.
 | 
			
		||||
	{"ArrayStack.ArrayStack",		CreateStack},
 | 
			
		||||
	{"ArrayStack.Clear",			ClearStack},
 | 
			
		||||
	{"ArrayStack.Clone",			CloneStack},
 | 
			
		||||
	{"ArrayStack.Pop",				ArrayStack_Pop},
 | 
			
		||||
	{"ArrayStack.Top",				ArrayStack_Top},
 | 
			
		||||
	{"ArrayStack.PopString",		ArrayStack_PopString},
 | 
			
		||||
	{"ArrayStack.TopString",		ArrayStack_TopString},
 | 
			
		||||
	{"ArrayStack.PopArray",			ArrayStack_PopArray},
 | 
			
		||||
	{"ArrayStack.TopArray",			ArrayStack_TopArray},
 | 
			
		||||
	{"ArrayStack.Push",				PushStackCell},
 | 
			
		||||
	{"ArrayStack.PushString",		PushStackString},
 | 
			
		||||
	{"ArrayStack.PushArray",		PushStackArray},
 | 
			
		||||
	{"ArrayStack.Empty.get",		IsStackEmpty},
 | 
			
		||||
	{"ArrayStack.BlockSize.get",	GetStackBlockSize},
 | 
			
		||||
	{"ArrayStack.Length.get",		GetStackSize},
 | 
			
		||||
 | 
			
		||||
	{NULL,							NULL},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -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,9 +32,6 @@
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <list>
 | 
			
		||||
#include "common_logic.h"
 | 
			
		||||
#include "Logger.h"
 | 
			
		||||
 | 
			
		||||
@ -48,7 +45,6 @@
 | 
			
		||||
 | 
			
		||||
#if defined PLATFORM_WINDOWS
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#include "sm_invalidparamhandler.h"
 | 
			
		||||
#elif defined PLATFORM_POSIX
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
@ -59,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;
 | 
			
		||||
@ -70,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,
 | 
			
		||||
@ -96,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)
 | 
			
		||||
	{
 | 
			
		||||
@ -118,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())
 | 
			
		||||
@ -215,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];
 | 
			
		||||
 | 
			
		||||
@ -243,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;
 | 
			
		||||
@ -251,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)
 | 
			
		||||
	{
 | 
			
		||||
@ -275,49 +217,6 @@ static cell_t FormatTime(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ParseTime(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
{
 | 
			
		||||
	char *datetime;
 | 
			
		||||
	char *format;
 | 
			
		||||
	pContext->LocalToStringNULL(params[1], &datetime);
 | 
			
		||||
	pContext->LocalToStringNULL(params[2], &format);
 | 
			
		||||
 | 
			
		||||
	if (format == NULL)
 | 
			
		||||
	{
 | 
			
		||||
		format = const_cast<char *>(bridge->GetCvarString(g_datetime_format));
 | 
			
		||||
	}
 | 
			
		||||
	else if (!format[0])
 | 
			
		||||
	{
 | 
			
		||||
		return pContext->ThrowNativeError("Time format string cannot be empty.");
 | 
			
		||||
	}
 | 
			
		||||
	if (!datetime || !datetime[0])
 | 
			
		||||
	{
 | 
			
		||||
		return pContext->ThrowNativeError("Date/time string cannot be empty.");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// https://stackoverflow.com/a/33542189
 | 
			
		||||
	std::tm t{};
 | 
			
		||||
	std::istringstream input(datetime);
 | 
			
		||||
 | 
			
		||||
	auto previousLocale = input.imbue(std::locale::classic());
 | 
			
		||||
	input >> std::get_time(&t, format);
 | 
			
		||||
	bool failed = input.fail();
 | 
			
		||||
	input.imbue(previousLocale);
 | 
			
		||||
 | 
			
		||||
	if (failed)
 | 
			
		||||
	{
 | 
			
		||||
		return pContext->ThrowNativeError("Invalid date/time string or time format.");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if defined PLATFORM_WINDOWS
 | 
			
		||||
	return _mkgmtime(&t);
 | 
			
		||||
#elif defined PLATFORM_LINUX || defined PLATFORM_APPLE
 | 
			
		||||
	return timegm(&t);
 | 
			
		||||
#else
 | 
			
		||||
	return pContext->ThrowNativeError("Platform has no implemented UTC conversion for std::tm to std::time_t");
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static cell_t GetPluginIterator(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
{
 | 
			
		||||
	IPluginIterator *iter = scripts->GetPluginIterator();
 | 
			
		||||
@ -376,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)
 | 
			
		||||
@ -913,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);
 | 
			
		||||
		}
 | 
			
		||||
		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);
 | 
			
		||||
		}
 | 
			
		||||
		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);
 | 
			
		||||
		}
 | 
			
		||||
		SourceHook::SetMemAccess(addr, sizeof(uint32_t), SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC);
 | 
			
		||||
		*reinterpret_cast<uint32_t*>(addr) = data;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
@ -1114,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;
 | 
			
		||||
}
 | 
			
		||||
@ -1133,10 +962,9 @@ REGISTER_NATIVES(coreNatives)
 | 
			
		||||
	{"ThrowError",				ThrowError},
 | 
			
		||||
	{"GetTime",					GetTime},
 | 
			
		||||
	{"FormatTime",				FormatTime},
 | 
			
		||||
	{"ParseTime",				ParseTime},
 | 
			
		||||
	{"GetPluginIterator",		GetPluginIterator},
 | 
			
		||||
	{"MorePlugins",				MorePlugins},
 | 
			
		||||
	{"ReadPlugin", 				ReadPlugin},
 | 
			
		||||
	{"ReadPlugin",				ReadPlugin},
 | 
			
		||||
	{"GetPluginStatus",			GetPluginStatus},
 | 
			
		||||
	{"GetPluginFilename",		GetPluginFilename},
 | 
			
		||||
	{"IsPluginDebugging",		IsPluginDebugging},
 | 
			
		||||
@ -1167,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_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1787,10 +1785,10 @@ static cell_t SQL_ExecuteTransaction(IPluginContext *pContext, const cell_t *par
 | 
			
		||||
 | 
			
		||||
	IPluginFunction *onSuccess = NULL;
 | 
			
		||||
	IPluginFunction *onError = NULL;
 | 
			
		||||
	if (!pContext->GetFunctionByIdOrNull(params[3], &onSuccess))
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (!pContext->GetFunctionByIdOrNull(params[4], &onError))
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (params[3] != -1 && ((onSuccess = pContext->GetFunctionById(params[3])) == NULL))
 | 
			
		||||
		return pContext->ThrowNativeError("Function id %x is invalid", params[3]);
 | 
			
		||||
	if (params[4] != -1 && ((onError = pContext->GetFunctionById(params[4])) == NULL))
 | 
			
		||||
		return pContext->ThrowNativeError("Function id %x is invalid", params[4]);
 | 
			
		||||
 | 
			
		||||
	cell_t data = params[5];
 | 
			
		||||
	PrioQueueLevel priority = PrioQueue_Normal;
 | 
			
		||||
 | 
			
		||||
@ -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]);
 | 
			
		||||
@ -244,19 +188,7 @@ static cell_t smn_WritePackFunction(IPluginContext *pContext, const cell_t *para
 | 
			
		||||
		pDataPack->RemoveItem();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cell_t funcid = params[2];
 | 
			
		||||
	if (pContext->IsNullFunctionId(funcid))
 | 
			
		||||
	{
 | 
			
		||||
		pDataPack->PackFunction(0);
 | 
			
		||||
	} 
 | 
			
		||||
	else if (funcid <= 0)
 | 
			
		||||
	{
 | 
			
		||||
		return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		pDataPack->PackFunction(funcid);
 | 
			
		||||
	}
 | 
			
		||||
	pDataPack->PackFunction(params[2]);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
@ -377,114 +309,7 @@ static cell_t smn_ReadPackFunction(IPluginContext *pContext, const cell_t *param
 | 
			
		||||
		return pContext->ThrowNativeError("Invalid data pack type (got %d / expected %d).", pDataPack->GetCurrentType(), CDataPackType::Function);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cell_t funcid = pDataPack->ReadFunction();
 | 
			
		||||
	if (!funcid)
 | 
			
		||||
	{
 | 
			
		||||
		return pContext->GetNullFunctionValue();
 | 
			
		||||
	}
 | 
			
		||||
	return funcid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
	return pDataPack->ReadFunction();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static cell_t smn_ResetPack(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
@ -601,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},
 | 
			
		||||
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user