Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
935c9cd80a
|
|
@ -20,7 +20,7 @@ jobs:
|
|||
|
||||
include:
|
||||
- profile: ubuntu-bionic-double-standard-unity-makefile
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04
|
||||
config: Standard
|
||||
unity: YES
|
||||
generator: Unix Makefiles
|
||||
|
|
@ -29,9 +29,10 @@ jobs:
|
|||
python: YES
|
||||
eigen: NO
|
||||
double: YES
|
||||
asan: YES
|
||||
|
||||
- profile: ubuntu-bionic-coverage-ninja
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04
|
||||
config: Coverage
|
||||
unity: NO
|
||||
generator: Ninja
|
||||
|
|
@ -40,9 +41,10 @@ jobs:
|
|||
python: YES
|
||||
eigen: NO
|
||||
double: NO
|
||||
asan: YES
|
||||
|
||||
#- profile: macos-coverage-unity-xcode
|
||||
# os: macOS-13
|
||||
# os: macOS-15
|
||||
# config: Coverage
|
||||
# unity: YES
|
||||
# generator: Xcode
|
||||
|
|
@ -53,7 +55,7 @@ jobs:
|
|||
# double: NO
|
||||
|
||||
- profile: macos-nometa-standard-makefile
|
||||
os: macOS-13
|
||||
os: macOS-15
|
||||
config: Standard
|
||||
unity: NO
|
||||
generator: Unix Makefiles
|
||||
|
|
@ -62,6 +64,7 @@ jobs:
|
|||
python: YES
|
||||
eigen: NO
|
||||
double: NO
|
||||
asan: YES
|
||||
|
||||
- profile: windows-standard-unity-msvc
|
||||
os: windows-2022
|
||||
|
|
@ -88,7 +91,7 @@ jobs:
|
|||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 10
|
||||
|
||||
|
|
@ -110,7 +113,7 @@ jobs:
|
|||
|
||||
- name: Set up XCode (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: sudo xcode-select -s /Applications/Xcode_14.3.1.app/Contents/Developer
|
||||
run: sudo xcode-select -s /Applications/Xcode_16.app/Contents/Developer
|
||||
|
||||
- name: Install dependencies (Ubuntu)
|
||||
if: startsWith(matrix.os, 'ubuntu')
|
||||
|
|
@ -127,7 +130,7 @@ jobs:
|
|||
|
||||
- name: Cache dependencies (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: thirdparty
|
||||
key: ci-cmake-${{ runner.OS }}-thirdparty-v1.10.15-r1
|
||||
|
|
@ -144,7 +147,7 @@ jobs:
|
|||
|
||||
- name: ccache (non-Windows)
|
||||
if: runner.os != 'Windows'
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ccache
|
||||
key: ci-cmake-ccache-${{ matrix.profile }}
|
||||
|
|
@ -182,8 +185,13 @@ jobs:
|
|||
-D HAVE_PYTHON=${{ runner.os != 'Windows' && matrix.python || 'NO' }}
|
||||
-D HAVE_EIGEN=${{ matrix.eigen }}
|
||||
-D STDFLOAT_DOUBLE=${{ matrix.double }}
|
||||
-D ENABLE_ASAN=${{ matrix.asan || 'NO' }}
|
||||
..
|
||||
|
||||
echo "$PWD/${{ matrix.config }}/bin" >> $GITHUB_PATH
|
||||
|
||||
echo "$PWD/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Build (no Python)
|
||||
if: contains(matrix.python, 'NO')
|
||||
# BEGIN A
|
||||
|
|
@ -193,7 +201,7 @@ jobs:
|
|||
|
||||
- name: Setup Python (Python 3.8)
|
||||
if: contains(matrix.python, 'YES')
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.8'
|
||||
- name: Configure (Python 3.8)
|
||||
|
|
@ -216,16 +224,17 @@ jobs:
|
|||
shell: bash
|
||||
env:
|
||||
PYTHONPATH: ${{ matrix.config }}
|
||||
ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0:log_path=asan.log.py38
|
||||
run: |
|
||||
PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//')
|
||||
$PYTHON_EXECUTABLE -m pip install -r ../requirements-test.txt
|
||||
export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw
|
||||
$PYTHON_EXECUTABLE -m pytest ../tests --cov=.
|
||||
run_pytest ../tests --cov=.
|
||||
# END B
|
||||
|
||||
- name: Setup Python (Python 3.9)
|
||||
if: contains(matrix.python, 'YES')
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: Configure (Python 3.9)
|
||||
|
|
@ -248,16 +257,17 @@ jobs:
|
|||
shell: bash
|
||||
env:
|
||||
PYTHONPATH: ${{ matrix.config }}
|
||||
ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0:log_path=asan.log.py39
|
||||
run: |
|
||||
PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//')
|
||||
$PYTHON_EXECUTABLE -m pip install -r ../requirements-test.txt
|
||||
export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw
|
||||
$PYTHON_EXECUTABLE -m pytest ../tests --cov=.
|
||||
run_pytest ../tests --cov=.
|
||||
# END B
|
||||
|
||||
- name: Setup Python (Python 3.10)
|
||||
if: contains(matrix.python, 'YES')
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: Configure (Python 3.10)
|
||||
|
|
@ -280,16 +290,17 @@ jobs:
|
|||
shell: bash
|
||||
env:
|
||||
PYTHONPATH: ${{ matrix.config }}
|
||||
ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0:log_path=asan.log.py310
|
||||
run: |
|
||||
PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//')
|
||||
$PYTHON_EXECUTABLE -m pip install -r ../requirements-test.txt
|
||||
export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw
|
||||
$PYTHON_EXECUTABLE -m pytest ../tests --cov=.
|
||||
run_pytest ../tests --cov=.
|
||||
# END B
|
||||
|
||||
- name: Setup Python (Python 3.11)
|
||||
if: contains(matrix.python, 'YES')
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Configure (Python 3.11)
|
||||
|
|
@ -312,16 +323,17 @@ jobs:
|
|||
shell: bash
|
||||
env:
|
||||
PYTHONPATH: ${{ matrix.config }}
|
||||
ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0:log_path=asan.log.py311
|
||||
run: |
|
||||
PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//')
|
||||
$PYTHON_EXECUTABLE -m pip install -r ../requirements-test.txt
|
||||
export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw
|
||||
$PYTHON_EXECUTABLE -m pytest ../tests --cov=.
|
||||
run_pytest ../tests --cov=.
|
||||
# END B
|
||||
|
||||
- name: Setup Python (Python 3.12)
|
||||
if: contains(matrix.python, 'YES')
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Configure (Python 3.12)
|
||||
|
|
@ -344,13 +356,26 @@ jobs:
|
|||
shell: bash
|
||||
env:
|
||||
PYTHONPATH: ${{ matrix.config }}
|
||||
ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0:log_path=asan.log.py312
|
||||
run: |
|
||||
PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//')
|
||||
$PYTHON_EXECUTABLE -m pip install -r ../requirements-test.txt
|
||||
export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw
|
||||
$PYTHON_EXECUTABLE -m pytest ../tests --cov=.
|
||||
run_pytest ../tests --cov=.
|
||||
# END B
|
||||
|
||||
- name: Show ASan errors
|
||||
if: failure() && contains(matrix.asan, 'YES')
|
||||
working-directory: build
|
||||
run: |
|
||||
ls -lAh asan.log.* || true
|
||||
if cat asan.log.* 2>/dev/null | grep -q .; then
|
||||
echo '### Address Sanitizer Report' >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
cat asan.log.* >> $GITHUB_STEP_SUMMARY 2>/dev/null || echo "No ASan errors found"
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
- name: Upload coverage reports
|
||||
if: always() && matrix.config == 'Coverage'
|
||||
working-directory: build
|
||||
|
|
@ -364,6 +389,13 @@ jobs:
|
|||
python -m pip install coverage
|
||||
python -m coverage combine $(find . -name '.coverage.*')
|
||||
|
||||
TOTAL=$(python -m coverage report --format=total)
|
||||
echo '### Coverage Report' >> $GITHUB_STEP_SUMMARY
|
||||
echo "<details><summary>Coverage: <b>${TOTAL}%</b></summary>" >> $GITHUB_STEP_SUMMARY
|
||||
echo '' >> $GITHUB_STEP_SUMMARY
|
||||
python -m coverage report --format=markdown >> $GITHUB_STEP_SUMMARY
|
||||
echo '</details>' >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
llvm-profdata merge pid-*.profraw -o coverage.profdata
|
||||
llvm-cov show $(grep -Rl LLVM_PROFILE_FILE . | sed 's/^/-object /') -instr-profile=coverage.profdata > coverage.txt
|
||||
bash <(curl -s https://codecov.io/bash) -y ../.github/codecov.yml
|
||||
|
|
@ -372,12 +404,12 @@ jobs:
|
|||
if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')"
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, windows-2019, macOS-13]
|
||||
os: [ubuntu-22.04, windows-2022, macOS-15]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- name: Install dependencies (Ubuntu)
|
||||
if: matrix.os == 'ubuntu-20.04'
|
||||
if: matrix.os == 'ubuntu-22.04'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install build-essential bison flex libfreetype6-dev libgl1-mesa-dev libjpeg-dev libode-dev libopenal-dev libpng-dev libssl-dev libvorbis-dev libx11-dev libxcursor-dev libxrandr-dev nvidia-cg-toolkit zlib1g-dev
|
||||
|
|
@ -386,30 +418,30 @@ jobs:
|
|||
shell: powershell
|
||||
run: |
|
||||
$wc = New-Object System.Net.WebClient
|
||||
$wc.DownloadFile("https://www.panda3d.org/download/panda3d-1.10.15/panda3d-1.10.15-tools-win64.zip", "thirdparty-tools.zip")
|
||||
$wc.DownloadFile("https://www.panda3d.org/download/panda3d-1.10.16/panda3d-1.10.16-tools-win64.zip", "thirdparty-tools.zip")
|
||||
Expand-Archive -Path thirdparty-tools.zip
|
||||
Move-Item -Path thirdparty-tools/panda3d-1.10.15/thirdparty -Destination .
|
||||
Move-Item -Path thirdparty-tools/panda3d-1.10.16/thirdparty -Destination .
|
||||
- name: Get thirdparty packages (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
curl -O https://www.panda3d.org/download/panda3d-1.10.15/panda3d-1.10.15-tools-mac.tar.gz
|
||||
tar -xf panda3d-1.10.15-tools-mac.tar.gz
|
||||
mv panda3d-1.10.15/thirdparty thirdparty
|
||||
rmdir panda3d-1.10.15
|
||||
curl -O https://www.panda3d.org/download/panda3d-1.10.16/panda3d-1.10.16-tools-mac.tar.gz
|
||||
tar -xf panda3d-1.10.16-tools-mac.tar.gz
|
||||
mv panda3d-1.10.16/thirdparty thirdparty
|
||||
rmdir panda3d-1.10.16
|
||||
(cd thirdparty/darwin-libs-a && rm -rf rocket)
|
||||
|
||||
- name: Set up XCode (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: sudo xcode-select -s /Applications/Xcode_14.3.1.app/Contents/Developer
|
||||
run: sudo xcode-select -s /Applications/Xcode_16.app/Contents/Developer
|
||||
|
||||
- name: Set up Python 3.13
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.13'
|
||||
- name: Build Python 3.13
|
||||
shell: bash
|
||||
run: |
|
||||
python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.2
|
||||
python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.3
|
||||
- name: Test Python 3.13
|
||||
shell: bash
|
||||
run: |
|
||||
|
|
@ -417,13 +449,13 @@ jobs:
|
|||
PYTHONPATH=built LD_LIBRARY_PATH=built/lib:$pythonLocation/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
|
||||
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Build Python 3.12 (double)
|
||||
shell: bash
|
||||
run: |
|
||||
python makepanda/makepanda.py --override STDFLOAT_DOUBLE=1 --git-commit=${{github.sha}} --outputdir=built_dbl --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.2
|
||||
python makepanda/makepanda.py --override STDFLOAT_DOUBLE=1 --git-commit=${{github.sha}} --outputdir=built_dbl --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.3
|
||||
- name: Test Python 3.12 (double)
|
||||
shell: bash
|
||||
run: |
|
||||
|
|
@ -435,13 +467,13 @@ jobs:
|
|||
python makepanda/makepackage.py --verbose --lzma --outputdir=built_dbl
|
||||
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Build Python 3.11
|
||||
shell: bash
|
||||
run: |
|
||||
python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.2
|
||||
python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.3
|
||||
- name: Test Python 3.11
|
||||
shell: bash
|
||||
run: |
|
||||
|
|
@ -449,13 +481,13 @@ jobs:
|
|||
PYTHONPATH=built LD_LIBRARY_PATH=built/lib:$pythonLocation/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
|
||||
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: Build Python 3.10
|
||||
shell: bash
|
||||
run: |
|
||||
python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.2
|
||||
python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.3
|
||||
- name: Test Python 3.10
|
||||
shell: bash
|
||||
run: |
|
||||
|
|
@ -463,13 +495,13 @@ jobs:
|
|||
PYTHONPATH=built LD_LIBRARY_PATH=built/lib:$pythonLocation/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
|
||||
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: Build Python 3.9
|
||||
shell: bash
|
||||
run: |
|
||||
python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.2
|
||||
python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.3
|
||||
- name: Test Python 3.9
|
||||
shell: bash
|
||||
run: |
|
||||
|
|
@ -477,13 +509,13 @@ jobs:
|
|||
PYTHONPATH=built LD_LIBRARY_PATH=built/lib:$pythonLocation/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
|
||||
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.8'
|
||||
- name: Build Python 3.8
|
||||
shell: bash
|
||||
run: |
|
||||
python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.2
|
||||
python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.3
|
||||
- name: Test Python 3.8
|
||||
shell: bash
|
||||
run: |
|
||||
|
|
@ -498,7 +530,7 @@ jobs:
|
|||
if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')"
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
|
@ -508,32 +540,32 @@ jobs:
|
|||
- name: Setup emsdk
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
with:
|
||||
version: 3.1.70
|
||||
version: 4.0.2
|
||||
actions-cache-folder: 'emsdk-cache'
|
||||
|
||||
- name: Restore Python build cache
|
||||
id: cache-emscripten-python-restore
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: ~/python
|
||||
key: cache-emscripten-python-3.12.7
|
||||
key: cache-emscripten-python-3.12.8
|
||||
|
||||
- name: Build Python 3.12
|
||||
if: steps.cache-emscripten-python-restore.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
wget https://www.python.org/ftp/python/3.12.7/Python-3.12.7.tar.xz
|
||||
tar -xJf Python-3.12.7.tar.xz
|
||||
(cd Python-3.12.7 && EM_CONFIG=$EMSDK/.emscripten python3 Tools/wasm/wasm_build.py emscripten-browser)
|
||||
(cd Python-3.12.7/builddir/emscripten-browser && make install DESTDIR=~/python)
|
||||
cp Python-3.12.7/builddir/emscripten-browser/Modules/_hacl/libHacl_Hash_SHA2.a ~/python/usr/local/lib
|
||||
cp Python-3.12.7/builddir/emscripten-browser/Modules/_decimal/libmpdec/libmpdec.a ~/python/usr/local/lib
|
||||
cp Python-3.12.7/builddir/emscripten-browser/Modules/expat/libexpat.a ~/python/usr/local/lib
|
||||
rm -rf Python-3.12.7
|
||||
wget https://www.python.org/ftp/python/3.12.8/Python-3.12.8.tar.xz
|
||||
tar -xJf Python-3.12.8.tar.xz
|
||||
(cd Python-3.12.8 && EM_CONFIG=$EMSDK/.emscripten python3 Tools/wasm/wasm_build.py emscripten-browser)
|
||||
(cd Python-3.12.8/builddir/emscripten-browser && make install DESTDIR=~/python)
|
||||
cp Python-3.12.8/builddir/emscripten-browser/Modules/_hacl/libHacl_Hash_SHA2.a ~/python/usr/local/lib
|
||||
cp Python-3.12.8/builddir/emscripten-browser/Modules/_decimal/libmpdec/libmpdec.a ~/python/usr/local/lib
|
||||
cp Python-3.12.8/builddir/emscripten-browser/Modules/expat/libexpat.a ~/python/usr/local/lib
|
||||
rm -rf Python-3.12.8
|
||||
|
||||
- name: Save Python build cache
|
||||
id: cache-emscripten-python-save
|
||||
if: steps.cache-emscripten-python-restore.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: ~/python
|
||||
key: ${{ steps.cache-emscripten-python-restore.outputs.cache-primary-key }}
|
||||
|
|
@ -552,3 +584,156 @@ jobs:
|
|||
shell: bash
|
||||
run: |
|
||||
PYTHONHOME=~/python/usr/local PYTHONPATH=built node built/bin/run_tests.js tests
|
||||
|
||||
android:
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')"
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- android-abi: arm64-v8a
|
||||
android-arch: arm64
|
||||
android-triple: aarch64-linux-android
|
||||
ndk-version: 29.0.14206865
|
||||
runner: ubuntu-latest
|
||||
|
||||
- android-abi: armeabi-v7a
|
||||
android-arch: arm
|
||||
android-triple: arm-linux-androideabi
|
||||
ndk-version: 29.0.14206865
|
||||
runner: ubuntu-latest
|
||||
|
||||
- android-abi: x86_64
|
||||
android-arch: x86_64
|
||||
android-triple: x86_64-linux-android
|
||||
ndk-version: 29.0.14206865
|
||||
runner: ubuntu-latest
|
||||
|
||||
- android-abi: x86
|
||||
android-arch: x86
|
||||
android-triple: i686-linux-android
|
||||
ndk-version: 29.0.14206865
|
||||
runner: ubuntu-latest
|
||||
|
||||
runs-on: ${{ matrix.runner }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Android SDK
|
||||
uses: android-actions/setup-android@v3
|
||||
with:
|
||||
packages: 'tools platform-tools platforms;android-21 ndk;${{ matrix.ndk-version }}'
|
||||
|
||||
- name: Set up Android NDK
|
||||
run: |
|
||||
echo "ANDROID_NDK_ROOT=$ANDROID_SDK_ROOT/ndk/${{ matrix.ndk-version }}" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.13'
|
||||
|
||||
- name: Restore Python build cache
|
||||
id: cache-android-python-restore
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: ~/python-prefix
|
||||
key: cache-android-python-3.13.9-${{ matrix.android-abi }}-ndk${{ matrix.ndk-version }}
|
||||
|
||||
- name: Build Python 3.13
|
||||
if: steps.cache-android-python-restore.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
wget https://www.python.org/ftp/python/3.13.9/Python-3.13.9.tar.xz
|
||||
tar -xJf Python-3.13.9.tar.xz
|
||||
sed -i.bak "s/aarch64-linux-android/${{ matrix.android-triple }}/" Python-3.13.9/Android/android.py
|
||||
sed -i.bak "s/ndk_version=[0-9.]\{1,\}/ndk_version=${{ matrix.ndk-version }}/" Python-3.13.9/Android/android-env.sh
|
||||
(cd Python-3.13.9/Android && python3 android.py build ${{ matrix.android-triple }})
|
||||
cp -R Python-3.13.9/cross-build/${{ matrix.android-triple }}/prefix ~/python-prefix
|
||||
rm -rf Python-3.13.9
|
||||
|
||||
- name: Save Python build cache
|
||||
id: cache-android-python-save
|
||||
if: steps.cache-android-python-restore.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: ~/python-prefix
|
||||
key: ${{ steps.cache-android-python-restore.outputs.cache-primary-key }}
|
||||
|
||||
- name: Restore thirdparty build cache
|
||||
id: cache-android-thirdparty-restore
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: ./thirdparty
|
||||
key: cache-android-thirdparty-935c80380ca171e08587c570e9dad678d29db3c8-${{ matrix.android-abi }}-ndk${{ matrix.ndk-version }}
|
||||
|
||||
- name: Install yasm
|
||||
if: steps.cache-android-thirdparty-restore.outputs.cache-hit != 'true'
|
||||
run: ${{runner.os == 'macOS' && 'brew' || 'sudo apt-get'}} install yasm
|
||||
|
||||
- name: Build thirdparty packages
|
||||
if: steps.cache-android-thirdparty-restore.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git clone --revision=935c80380ca171e08587c570e9dad678d29db3c8 --depth=1 https://github.com/rdb/panda3d-thirdparty.git thirdparty
|
||||
cd thirdparty
|
||||
cmake -B build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake \
|
||||
-DCMAKE_ANDROID_ARCH_ABI=${{ matrix.android-abi }} \
|
||||
-DCMAKE_ANDROID_ARCH=${{ matrix.android-arch }} \
|
||||
-DCMAKE_SYSTEM_VERSION=21 \
|
||||
-DANDROID_ABI=${{ matrix.android-abi }} \
|
||||
-DANDROID_PLATFORM=android-21 \
|
||||
-DBUILD_FCOLLADA=OFF \
|
||||
-DBUILD_OPENSSL=OFF \
|
||||
-DBUILD_VRPN=OFF \
|
||||
-DBUILD_ARTOOLKIT=OFF
|
||||
cmake --build build --config Release -j4
|
||||
rm -rf build
|
||||
|
||||
- name: Save thirdparty build cache
|
||||
id: cache-android-thirdparty-save
|
||||
if: steps.cache-android-thirdparty-restore.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: ./thirdparty
|
||||
key: ${{ steps.cache-android-thirdparty-restore.outputs.cache-primary-key }}
|
||||
|
||||
- name: Build for Android
|
||||
shell: bash
|
||||
run: |
|
||||
python makepanda/makepanda.py --git-commit=${{github.sha}} --target android-21 --python-incdir=~/python-prefix/include --python-libdir=~/python-prefix/lib --arch ${{ matrix.android-arch }} --everything --no-openssl --no-tinydisplay --no-pandatool --verbose --threads=4
|
||||
|
||||
- name: Install test dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
python -m pip install -t ~/python-prefix/lib/python3.13/site-packages -r requirements-test.txt
|
||||
|
||||
- name: Enable KVM group perms
|
||||
if: startsWith(matrix.runner, 'ubuntu')
|
||||
run: |
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: Setup Android Emulator and Run Tests
|
||||
if: startsWith(matrix.android-abi, 'x86')
|
||||
uses: reactivecircus/android-emulator-runner@v2
|
||||
with:
|
||||
api-level: 27
|
||||
arch: ${{ matrix.android-abi }}
|
||||
target: default
|
||||
profile: pixel_6
|
||||
script: |
|
||||
adb shell "rm -rf /data/local/tmp/panda3d-tests"
|
||||
adb push built/bin/run_tests /data/local/tmp/panda3d-tests/run_tests
|
||||
adb shell "mkdir /data/local/tmp/panda3d-tests/lib"
|
||||
adb push built/lib/*.so /data/local/tmp/panda3d-tests/lib
|
||||
adb push ~/python-prefix/lib/*.so /data/local/tmp/panda3d-tests/lib
|
||||
adb push ~/python-prefix/lib/python3.13 /data/local/tmp/panda3d-tests/lib/python3.13
|
||||
adb push built/panda3d /data/local/tmp/panda3d-tests/lib/python3.13/site-packages/
|
||||
adb push built/direct /data/local/tmp/panda3d-tests/lib/python3.13/site-packages/
|
||||
adb push built/models /data/local/tmp/panda3d-tests/models
|
||||
adb push built/etc /data/local/tmp/panda3d-tests/etc
|
||||
adb push tests /data/local/tmp/panda3d-tests/tests
|
||||
adb shell "cd /data/local/tmp/panda3d-tests && LD_LIBRARY_PATH=/data/local/tmp/panda3d-tests/lib PYTHONPATH=/data/local/tmp/panda3d-tests/lib/python3.13/site-packages ./run_tests -v tests"
|
||||
|
|
|
|||
|
|
@ -7,17 +7,17 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
python-version: ['3.8', '3.11']
|
||||
python-version: ['3.9', '3.13']
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install mypy==1.4.0
|
||||
pip install mypy==1.14.1
|
||||
- name: Run mypy on direct
|
||||
run: python tests/run_mypy.py
|
||||
|
|
|
|||
|
|
@ -5,10 +5,12 @@ This is a list of all the people who are contributing financially to Panda3D. I
|
|||
## Bronze Sponsors
|
||||
|
||||
[<img src="https://www.panda3d.org/wp-content/uploads/2024/08/Route4MeLogo1185x300-2-1-1024x259.png" alt="Route4Me" height="48">](https://route4me.com/)
|
||||
[<img src="https://www.panda3d.org/wp-content/uploads/2026/01/black-logo-1-e1768931551108.png" alt="TestMu AI" height="48">](https://www.testmu.ai/?utm_source=panda3d&utm_medium=sponsor)
|
||||
|
||||
* [Daniel Stokes](https://opencollective.com/daniel-stokes)
|
||||
* [David Rose](https://opencollective.com/david-rose)
|
||||
* [Route4Me](https://route4me.com/)
|
||||
* [TestMu AI](https://www.testmu.ai/?utm_source=panda3d&utm_medium=sponsor)
|
||||
|
||||
## Benefactors
|
||||
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ option(BUILD_DIRECT "Build the direct source tree." ON)
|
|||
option(BUILD_PANDATOOL "Build the pandatool source tree." ON)
|
||||
option(BUILD_CONTRIB "Build the contrib source tree." ON)
|
||||
option(BUILD_MODELS "Build/install the built-in models." ON)
|
||||
option(BUILD_TESTS "Build unit test runner." ON)
|
||||
option(BUILD_TOOLS "Build binary tools." ON)
|
||||
|
||||
# Include Panda3D packages
|
||||
|
|
@ -166,17 +167,8 @@ if(BUILD_MODELS)
|
|||
COMPONENT Models DESTINATION ${CMAKE_INSTALL_DATADIR}/panda3d)
|
||||
endif()
|
||||
|
||||
if(INTERROGATE_PYTHON_INTERFACE)
|
||||
# If we built the Python interface, run the test suite. Note, we do NOT test
|
||||
# for pytest before adding this test. If the user doesn't have pytest, we'd
|
||||
# like for the tests to fail.
|
||||
|
||||
# In the Coverage configuration, we also require pytest-cov
|
||||
|
||||
add_test(NAME pytest
|
||||
COMMAND "${PYTHON_EXECUTABLE}" -m pytest "${PROJECT_SOURCE_DIR}/tests"
|
||||
$<$<CONFIG:Coverage>:--cov=.>
|
||||
WORKING_DIRECTORY "${PANDA_OUTPUT_DIR}")
|
||||
if(BUILD_TESTS)
|
||||
add_subdirectory(tests "${CMAKE_BINARY_DIR}/tests")
|
||||
endif()
|
||||
|
||||
# Generate the Panda3DConfig.cmake file so find_package(Panda3D) works, and
|
||||
|
|
|
|||
38
README.md
38
README.md
|
|
@ -24,7 +24,7 @@ Installing Panda3D
|
|||
==================
|
||||
|
||||
The latest Panda3D SDK can be downloaded from
|
||||
[this page](https://www.panda3d.org/download/sdk-1-10-15/).
|
||||
[this page](https://www.panda3d.org/download/sdk-1-10-16/).
|
||||
If you are familiar with installing Python packages, you can use
|
||||
the following command:
|
||||
|
||||
|
|
@ -64,8 +64,8 @@ depending on whether you are on a 32-bit or 64-bit system, or you can
|
|||
[click here](https://github.com/rdb/panda3d-thirdparty) for instructions on
|
||||
building them from source.
|
||||
|
||||
- https://www.panda3d.org/download/panda3d-1.10.15/panda3d-1.10.15-tools-win64.zip
|
||||
- https://www.panda3d.org/download/panda3d-1.10.15/panda3d-1.10.15-tools-win32.zip
|
||||
- https://www.panda3d.org/download/panda3d-1.10.16/panda3d-1.10.16-tools-win64.zip
|
||||
- https://www.panda3d.org/download/panda3d-1.10.16/panda3d-1.10.16-tools-win32.zip
|
||||
|
||||
After acquiring these dependencies, you can build Panda3D from the command
|
||||
prompt using the following command. Change the `--msvc-version` option based
|
||||
|
|
@ -136,7 +136,7 @@ macOS
|
|||
-----
|
||||
|
||||
On macOS, you will need to download a set of precompiled thirdparty packages in order to
|
||||
compile Panda3D, which can be acquired from [here](https://www.panda3d.org/download/panda3d-1.10.15/panda3d-1.10.15-tools-mac.tar.gz).
|
||||
compile Panda3D, which can be acquired from [here](https://www.panda3d.org/download/panda3d-1.10.16/panda3d-1.10.16-tools-mac.tar.gz).
|
||||
|
||||
After placing the thirdparty directory inside the panda3d source directory,
|
||||
you may build Panda3D using a command like the following:
|
||||
|
|
@ -181,22 +181,21 @@ Although it's possible to build Panda3D on an Android device using the
|
|||
[termux](https://termux.com/) shell, the recommended route is to cross-compile
|
||||
.whl files using the SDK and NDK, which can then be used by the `build_apps`
|
||||
command to build a Python application into an .apk or .aab bundle. You will
|
||||
need to get the latest thirdparty packages, which can be obtained from the
|
||||
artifacts page of the last successful run here:
|
||||
need to get the latest thirdparty packages, which can be obtained from here:
|
||||
|
||||
https://github.com/rdb/panda3d-thirdparty/actions?query=branch%3Amain+is%3Asuccess+event%3Apush
|
||||
https://rdb.name/thirdparty-android.tar.gz
|
||||
|
||||
This does not include Python at the moment, which can be extracted from
|
||||
[this archive](https://rdb.name/thirdparty-android.tar.gz) instead.
|
||||
This includes a copy of Python 3.13 compiled for Android. You will need to
|
||||
use Python 3.13 on the host as well.
|
||||
|
||||
These commands show how to compile wheels for the supported Android ABIs:
|
||||
|
||||
```bash
|
||||
export ANDROID_SDK_ROOT=/home/rdb/local/android
|
||||
python3.8 makepanda/makepanda.py --everything --outputdir built-droid-arm64 --arch arm64 --target android-21 --threads 6 --wheel
|
||||
python3.8 makepanda/makepanda.py --everything --outputdir built-droid-armv7a --arch armv7a --target android-19 --threads 6 --wheel
|
||||
python3.8 makepanda/makepanda.py --everything --outputdir built-droid-x86_64 --arch x86_64 --target android-21 --threads 6 --wheel
|
||||
python3.8 makepanda/makepanda.py --everything --outputdir built-droid-x86 --arch x86 --target android-19 --threads 6 --wheel
|
||||
python3.13 makepanda/makepanda.py --everything --outputdir built-droid-arm64 --arch arm64 --target android-21 --threads 6 --wheel
|
||||
python3.13 makepanda/makepanda.py --everything --outputdir built-droid-armv7a --arch arm --target android-21 --threads 6 --wheel
|
||||
python3.13 makepanda/makepanda.py --everything --outputdir built-droid-x86_64 --arch x86_64 --target android-21 --threads 6 --wheel
|
||||
python3.13 makepanda/makepanda.py --everything --outputdir built-droid-x86 --arch x86 --target android-21 --threads 6 --wheel
|
||||
```
|
||||
|
||||
It is now possible to use the generated wheels with `build_apps`, as explained
|
||||
|
|
@ -229,8 +228,8 @@ information as possible to help the developers track down the issue, such as
|
|||
your version of Panda3D, operating system, architecture, and any code and
|
||||
models that are necessary for the developers to reproduce the issue.
|
||||
|
||||
If you're not sure whether you've encountered a bug, feel free to ask about
|
||||
it in the forums or the IRC channel first.
|
||||
If you're unsure whether you've encountered a bug, feel free to ask in the [forums](https://discourse.panda3d.org) or the [IRC channel](https://web.libera.chat/#panda3d) before opening an issue.
|
||||
|
||||
|
||||
Supporting the Project
|
||||
======================
|
||||
|
|
@ -239,9 +238,12 @@ If you would like to support the project financially, visit
|
|||
[our campaign on OpenCollective](https://opencollective.com/panda3d). Your
|
||||
contributions help us accelerate the development of Panda3D.
|
||||
|
||||
For the list of backers, see the [BACKERS.md](BACKERS.md) file or visit the
|
||||
[Sponsors page](https://www.panda3d.org/sponsors) on our web site. Thank you
|
||||
to everyone who has donated!
|
||||
For the complete list of backers, see the [BACKERS.md](BACKERS.md) file or
|
||||
visit the [Sponsors page](https://www.panda3d.org/sponsors) on our web site.
|
||||
Thank you to everyone who has donated!
|
||||
|
||||
[<img src="https://www.panda3d.org/wp-content/uploads/2024/08/Route4MeLogo1185x300-2-1-1024x259.png" alt="Route4Me" height="48">](https://route4me.com/)
|
||||
[<img src="https://www.panda3d.org/wp-content/uploads/2026/01/black-logo-1-e1768931551108.png" alt="TestMu AI" height="48">](https://www.testmu.ai/?utm_source=panda3d&utm_medium=sponsor)
|
||||
|
||||
<a href="https://opencollective.com/panda3d" target="_blank">
|
||||
<img src="https://opencollective.com/panda3d/contribute/button@2x.png?color=blue" width=300 />
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ endfunction(interrogate_sources)
|
|||
|
||||
#
|
||||
# Function: add_python_module(module [lib1 [lib2 ...]] [LINK lib1 ...]
|
||||
# [IMPORT mod1 ...])
|
||||
# [IMPORT mod1 ...] [INIT func1 ...])
|
||||
# Uses interrogate to create a Python module. If the LINK keyword is specified,
|
||||
# the Python module is linked against the specified libraries instead of those
|
||||
# listed before. The IMPORT keyword makes the output module import another
|
||||
|
|
@ -305,7 +305,7 @@ function(add_python_module module)
|
|||
|
||||
set(keyword)
|
||||
foreach(arg ${ARGN})
|
||||
if(arg STREQUAL "LINK" OR arg STREQUAL "IMPORT" OR arg STREQUAL "COMPONENT")
|
||||
if(arg STREQUAL "LINK" OR arg STREQUAL "IMPORT" OR arg STREQUAL "INIT" OR arg STREQUAL "COMPONENT")
|
||||
set(keyword "${arg}")
|
||||
|
||||
elseif(keyword STREQUAL "LINK")
|
||||
|
|
@ -316,6 +316,10 @@ function(add_python_module module)
|
|||
list(APPEND import_flags "-import" "${arg}")
|
||||
set(keyword)
|
||||
|
||||
elseif(keyword STREQUAL "INIT")
|
||||
list(APPEND import_flags "-init" "${arg}")
|
||||
set(keyword)
|
||||
|
||||
elseif(keyword STREQUAL "COMPONENT")
|
||||
set(component "${arg}")
|
||||
set(keyword)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"""PANDA3D Particle Panel"""
|
||||
|
||||
# Import Tkinter, Pmw, and the floater code from this directory tree.
|
||||
from panda3d.core import ConfigVariableSearchPath, Point2, Point3, Vec3, Vec4
|
||||
from direct.tkwidgets.AppShell import AppShell
|
||||
import os, Pmw
|
||||
from direct.tkwidgets.Dial import AngleDial
|
||||
|
|
@ -17,6 +18,10 @@ from tkinter.filedialog import *
|
|||
from tkinter.simpledialog import askstring
|
||||
|
||||
|
||||
particlePath = ConfigVariableSearchPath("particle-path",
|
||||
"The directories to search for particle files to be loaded.")
|
||||
|
||||
|
||||
class ParticlePanel(AppShell):
|
||||
# Override class variables
|
||||
appname = 'Particle Panel'
|
||||
|
|
@ -1041,7 +1046,7 @@ class ParticlePanel(AppShell):
|
|||
|
||||
def loadParticleEffectFromFile(self):
|
||||
# Find path to particle directory
|
||||
pPath = getParticlePath()
|
||||
pPath = particlePath
|
||||
if pPath.getNumDirectories() > 0:
|
||||
if repr(pPath.getDirectory(0)) == '.':
|
||||
path = '.'
|
||||
|
|
@ -1070,7 +1075,7 @@ class ParticlePanel(AppShell):
|
|||
|
||||
def saveParticleEffectToFile(self):
|
||||
# Find path to particle directory
|
||||
pPath = getParticlePath()
|
||||
pPath = particlePath
|
||||
if pPath.getNumDirectories() > 0:
|
||||
if repr(pPath.getDirectory(0)) == '.':
|
||||
path = '.'
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ receive_update(PyObject *distobj, DatagramIterator &di) const {
|
|||
int field_id = packer.raw_unpack_uint16();
|
||||
DCField *field = _this->get_field_by_index(field_id);
|
||||
if (field == nullptr) {
|
||||
ostringstream strm;
|
||||
std::ostringstream strm;
|
||||
strm
|
||||
<< "Received update for field " << field_id << ", not in class "
|
||||
<< _this->get_name();
|
||||
|
|
|
|||
|
|
@ -42,25 +42,25 @@ class DirectNotify:
|
|||
"""
|
||||
return list(self.__categories.keys())
|
||||
|
||||
def getCategory(self, categoryName: str) -> Notifier.Notifier | None:
|
||||
def getCategory(self, name: str) -> Notifier.Notifier | None:
|
||||
"""getCategory(self, string)
|
||||
Return the category with given name if present, None otherwise
|
||||
"""
|
||||
return self.__categories.get(categoryName, None)
|
||||
return self.__categories.get(name, None)
|
||||
|
||||
def newCategory(self, categoryName: str, logger: Logger.Logger | None = None) -> Notifier.Notifier:
|
||||
def newCategory(self, name: str, logger: Logger.Logger | None = None) -> Notifier.Notifier:
|
||||
"""newCategory(self, string)
|
||||
Make a new notify category named categoryName. Return new category
|
||||
Make a new notify category named name. Return new category
|
||||
if no such category exists, else return existing category
|
||||
"""
|
||||
if categoryName not in self.__categories:
|
||||
self.__categories[categoryName] = Notifier.Notifier(categoryName, logger)
|
||||
self.setDconfigLevel(categoryName)
|
||||
notifier = self.getCategory(categoryName)
|
||||
if name not in self.__categories:
|
||||
self.__categories[name] = Notifier.Notifier(name, logger)
|
||||
self.setDconfigLevel(name)
|
||||
notifier = self.getCategory(name)
|
||||
assert notifier is not None
|
||||
return notifier
|
||||
|
||||
def setDconfigLevel(self, categoryName: str) -> None:
|
||||
def setDconfigLevel(self, name: str) -> None:
|
||||
"""
|
||||
Check to see if this category has a dconfig variable
|
||||
to set the notify severity and then set that level. You cannot
|
||||
|
|
@ -71,7 +71,7 @@ class DirectNotify:
|
|||
# we're running before ShowBase has finished initializing
|
||||
from panda3d.core import ConfigVariableString
|
||||
|
||||
dconfigParam = ("notify-level-" + categoryName)
|
||||
dconfigParam = ("notify-level-" + name)
|
||||
cvar = ConfigVariableString(dconfigParam, "")
|
||||
level = cvar.getValue()
|
||||
|
||||
|
|
@ -82,11 +82,11 @@ class DirectNotify:
|
|||
if not level:
|
||||
level = 'error'
|
||||
|
||||
category = self.getCategory(categoryName)
|
||||
assert category is not None, f'failed to find category: {categoryName!r}'
|
||||
category = self.getCategory(name)
|
||||
assert category is not None, f'failed to find category: {name!r}'
|
||||
# Note - this print statement is making it difficult to
|
||||
# achieve "no output unless there's an error" operation - Josh
|
||||
# print ("Setting DirectNotify category: " + categoryName +
|
||||
# print ("Setting DirectNotify category: " + name +
|
||||
# " to severity: " + level)
|
||||
if level == "error":
|
||||
category.setWarning(False)
|
||||
|
|
@ -106,7 +106,7 @@ class DirectNotify:
|
|||
category.setDebug(True)
|
||||
else:
|
||||
print("DirectNotify: unknown notify level: " + str(level)
|
||||
+ " for category: " + str(categoryName))
|
||||
+ " for category: " + str(name))
|
||||
|
||||
def setDconfigLevels(self) -> None:
|
||||
for categoryName in self.getCategories():
|
||||
|
|
@ -129,3 +129,12 @@ class DirectNotify:
|
|||
|
||||
def giveNotify(self, cls) -> None:
|
||||
cls.notify = self.newCategory(cls.__name__)
|
||||
|
||||
get_categories = getCategories
|
||||
get_category = getCategory
|
||||
new_category = newCategory
|
||||
set_dconfig_level = setDconfigLevel
|
||||
set_dconfig_levels = setDconfigLevels
|
||||
set_verbose = setVerbose
|
||||
popup_controls = popupControls
|
||||
give_notify = giveNotify
|
||||
|
|
|
|||
|
|
@ -79,8 +79,8 @@ class LineNodePath(NodePath):
|
|||
def getVertex(self, index):
|
||||
return self.lineSegs.getVertex(index)
|
||||
|
||||
def getVertexColor(self):
|
||||
return self.lineSegs.getVertexColor()
|
||||
def getVertexColor(self, index):
|
||||
return self.lineSegs.getVertexColor(index)
|
||||
|
||||
def drawArrow(self, sv, ev, arrowAngle, arrowLength):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class DirectGrid(NodePath, DirectObject):
|
|||
|
||||
self.centerLines = LineNodePath(self.lines)
|
||||
self.centerLines.lineNode.setName('centerLines')
|
||||
self.centerLines.setColor(VBase4(1, 0, 0, 0))
|
||||
self.centerLines.setColor(VBase4(1, 0, 0, 1))
|
||||
self.centerLines.setThickness(3)
|
||||
|
||||
# Small marker to hilight snap-to-grid point
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from panda3d.core import VBase4
|
||||
from panda3d.core import NodePath, VBase4
|
||||
from direct.task.Task import Task
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ def lerpBackgroundColor(r, g, b, duration):
|
|||
|
||||
# Set direct drawing style for an object
|
||||
# Never light object or draw in wireframe
|
||||
def useDirectRenderStyle(nodePath, priority = 0):
|
||||
def useDirectRenderStyle(nodePath: NodePath, priority: int = 0) -> None:
|
||||
"""
|
||||
Function to force a node path to use direct render style:
|
||||
no lighting, and no wireframe
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ defaultHiddenImports = {
|
|||
'numpy.core._dtype_ctypes',
|
||||
'numpy.core._methods',
|
||||
],
|
||||
'panda3d.core': ['enum'],
|
||||
'pandas.compat': ['lzma', 'cmath'],
|
||||
'pandas._libs.tslibs.conversion': ['pandas._libs.tslibs.base'],
|
||||
'plyer': ['plyer.platforms'],
|
||||
|
|
@ -101,6 +102,7 @@ defaultHiddenImports = {
|
|||
'scipy.stats._stats': ['scipy.special.cython_special'],
|
||||
'setuptools.monkey': ['setuptools.msvc'],
|
||||
'shapely._geometry_helpers': ['shapely._geos'],
|
||||
'jnius': ['jnius_config'],
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -113,7 +115,7 @@ ignoreImports = {
|
|||
'toml.encoder': ['numpy'],
|
||||
'py._builtin': ['__builtin__'],
|
||||
|
||||
'site': ['android_log'],
|
||||
'site': ['android_support'],
|
||||
}
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
|
|
@ -138,12 +140,23 @@ def getline(filename, lineno, module_globals=None):
|
|||
return ''
|
||||
|
||||
def clearcache():
|
||||
global cache
|
||||
cache = {}
|
||||
cache.clear()
|
||||
|
||||
def getlines(filename, module_globals=None):
|
||||
return []
|
||||
|
||||
def _getline_from_code(filename, lineno):
|
||||
return ''
|
||||
|
||||
def _make_key(code):
|
||||
return (code.co_filename, code.co_qualname, code.co_firstlineno)
|
||||
|
||||
def _getlines_from_code(code):
|
||||
return []
|
||||
|
||||
def _source_unavailable(filename):
|
||||
return True
|
||||
|
||||
def checkcache(filename=None):
|
||||
pass
|
||||
|
||||
|
|
@ -1236,8 +1249,12 @@ class Freezer:
|
|||
pass
|
||||
|
||||
# Check if any new modules we found have "hidden" imports
|
||||
for origName in list(self.mf.modules.keys()):
|
||||
checkHiddenImports = set(self.mf.modules.keys())
|
||||
while checkHiddenImports:
|
||||
origName = next(iter(checkHiddenImports))
|
||||
checkHiddenImports.discard(origName)
|
||||
hidden = self.hiddenImports.get(origName, [])
|
||||
preModules = frozenset(self.mf.modules.keys())
|
||||
for modname in hidden:
|
||||
if modname.endswith('.*'):
|
||||
mdefs = self._gatherSubmodules(modname, implicit = True)
|
||||
|
|
@ -1251,6 +1268,9 @@ class Freezer:
|
|||
self.__loadModule(self.ModuleDef(modname, implicit = True))
|
||||
except ImportError:
|
||||
pass
|
||||
addedModules = set(self.mf.modules.keys())
|
||||
addedModules -= preModules
|
||||
checkHiddenImports |= addedModules
|
||||
|
||||
# Special case for sysconfig, which depends on a platform-specific
|
||||
# sysconfigdata module on POSIX systems.
|
||||
|
|
@ -1834,7 +1854,8 @@ class Freezer:
|
|||
return target
|
||||
|
||||
def generateRuntimeFromStub(self, target, stub_file, use_console, fields={},
|
||||
log_append=False, log_filename_strftime=False):
|
||||
log_append=False, log_filename_strftime=False,
|
||||
blob_path=None):
|
||||
self.__replacePaths()
|
||||
|
||||
# We must have a __main__ module to make an exe file.
|
||||
|
|
@ -1969,6 +1990,9 @@ class Freezer:
|
|||
elif self.platform.endswith('_aarch64') or self.platform.endswith('_arm64'):
|
||||
# Most arm64 operating systems are configured with 16 KiB pages.
|
||||
blob_align = 16384
|
||||
elif self.platform.replace('-', '_') == 'android_x86_64':
|
||||
# Android nowadays requires 16 KiB pages on 64-bit Intel as well.
|
||||
blob_align = 16384
|
||||
else:
|
||||
# Align to page size, so that it can be mmapped.
|
||||
blob_align = 4096
|
||||
|
|
@ -1979,29 +2003,33 @@ class Freezer:
|
|||
pad = (blob_align - (blob_size & (blob_align - 1)))
|
||||
blob_size += pad
|
||||
|
||||
# TODO: Support creating custom sections in universal binaries.
|
||||
append_blob = True
|
||||
if self.platform.startswith('macosx') and len(bitnesses) == 1:
|
||||
# If our deploy-stub has a __PANDA segment, we know we're meant to
|
||||
# put our blob there rather than attach it to the end.
|
||||
load_commands = self._parse_macho_load_commands(stub_data)
|
||||
if b'__PANDA' in load_commands.keys():
|
||||
append_blob = False
|
||||
|
||||
if self.platform.startswith("macosx") and not append_blob:
|
||||
# Take this time to shift any Mach-O structures around to fit our
|
||||
# blob. We don't need to worry about aligning the offset since the
|
||||
# compiler already took care of that when creating the segment.
|
||||
blob_offset = self._shift_macho_structures(stub_data, load_commands, blob_size)
|
||||
if blob_path is not None:
|
||||
# We'll be writing the blob to a separate location.
|
||||
blob_offset = 0
|
||||
else:
|
||||
# Add padding before the blob if necessary.
|
||||
blob_offset = len(stub_data)
|
||||
if (blob_offset & (blob_align - 1)) != 0:
|
||||
pad = (blob_align - (blob_offset & (blob_align - 1)))
|
||||
stub_data += (b'\0' * pad)
|
||||
blob_offset += pad
|
||||
assert (blob_offset % blob_align) == 0
|
||||
assert blob_offset == len(stub_data)
|
||||
# TODO: Support creating custom sections in universal binaries.
|
||||
append_blob = True
|
||||
if self.platform.startswith('macosx') and len(bitnesses) == 1:
|
||||
# If our deploy-stub has a __PANDA segment, we know we're meant to
|
||||
# put our blob there rather than attach it to the end.
|
||||
load_commands = self._parse_macho_load_commands(stub_data)
|
||||
if b'__PANDA' in load_commands.keys():
|
||||
append_blob = False
|
||||
|
||||
if self.platform.startswith("macosx") and not append_blob:
|
||||
# Take this time to shift any Mach-O structures around to fit our
|
||||
# blob. We don't need to worry about aligning the offset since the
|
||||
# compiler already took care of that when creating the segment.
|
||||
blob_offset = self._shift_macho_structures(stub_data, load_commands, blob_size)
|
||||
else:
|
||||
# Add padding before the blob if necessary.
|
||||
blob_offset = len(stub_data)
|
||||
if (blob_offset & (blob_align - 1)) != 0:
|
||||
pad = (blob_align - (blob_offset & (blob_align - 1)))
|
||||
stub_data += (b'\0' * pad)
|
||||
blob_offset += pad
|
||||
assert (blob_offset % blob_align) == 0
|
||||
assert blob_offset == len(stub_data)
|
||||
|
||||
# Calculate the offsets for the variables. These are pointers,
|
||||
# relative to the beginning of the blob.
|
||||
|
|
@ -2087,7 +2115,9 @@ class Freezer:
|
|||
blob += struct.pack('<Q', blob_offset)
|
||||
|
||||
with open(target, 'wb') as f:
|
||||
if append_blob:
|
||||
if blob_path is not None:
|
||||
f.write(stub_data)
|
||||
elif append_blob:
|
||||
f.write(stub_data)
|
||||
assert f.tell() == blob_offset
|
||||
f.write(blob)
|
||||
|
|
@ -2095,6 +2125,10 @@ class Freezer:
|
|||
stub_data[blob_offset:blob_offset + blob_size] = blob
|
||||
f.write(stub_data)
|
||||
|
||||
if blob_path is not None:
|
||||
with open(blob_path, 'wb') as f:
|
||||
f.write(blob)
|
||||
|
||||
os.chmod(target, 0o755)
|
||||
return target
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import xml.etree.ElementTree as ET
|
||||
|
||||
from ._proto.targeting_pb2 import Abi
|
||||
from ._proto.config_pb2 import BundleConfig # pylint: disable=unused-import
|
||||
from ._proto.config_pb2 import BundleConfig, UncompressNativeLibraries # pylint: disable=unused-import
|
||||
from ._proto.files_pb2 import NativeLibraries # pylint: disable=unused-import
|
||||
from ._proto.Resources_pb2 import ResourceTable # pylint: disable=unused-import
|
||||
from ._proto.Resources_pb2 import XmlNode
|
||||
|
|
@ -174,6 +174,7 @@ ANDROID_ATTRIBUTES = {
|
|||
'debuggable': bool_resource(0x0101000f),
|
||||
'documentLaunchMode': enum_resource(0x1010445, "none", "intoExisting", "always", "never"),
|
||||
'enabled': bool_resource(0x101000e),
|
||||
'enableOnBackInvokedCallback': bool_resource(0x0101066c),
|
||||
'excludeFromRecents': bool_resource(0x1010017),
|
||||
'exported': bool_resource(0x1010010),
|
||||
'extractNativeLibs': bool_resource(0x10104ea),
|
||||
|
|
@ -195,8 +196,10 @@ ANDROID_ATTRIBUTES = {
|
|||
'multiprocess': bool_resource(0x1010013),
|
||||
'name': str_resource(0x1010003),
|
||||
'noHistory': bool_resource(0x101022d),
|
||||
'pageSizeCompat': bool_resource(0x010106ab),
|
||||
'pathPattern': str_resource(0x101002c),
|
||||
'preferMinimalPostProcessing': bool_resource(0x101060c),
|
||||
'resource': ref_resource(0x01010025),
|
||||
'required': bool_resource(0x101028e),
|
||||
'resizeableActivity': bool_resource(0x10104f6),
|
||||
'scheme': str_resource(0x1010027),
|
||||
|
|
@ -220,6 +223,7 @@ class AndroidManifest:
|
|||
self.root = XmlNode()
|
||||
self.resource_types = []
|
||||
self.resources = {}
|
||||
self.extract_native_libs = None
|
||||
|
||||
def parse_xml(self, data):
|
||||
parser = ET.XMLParser(target=self)
|
||||
|
|
@ -240,6 +244,15 @@ class AndroidManifest:
|
|||
element = node.element
|
||||
element.name = tag
|
||||
|
||||
if tag == 'application':
|
||||
value = attribs.get('{http://schemas.android.com/apk/res/android}extractNativeLibs')
|
||||
if value == 'false':
|
||||
self.extract_native_libs = False
|
||||
elif value == 'true':
|
||||
self.extract_native_libs = True
|
||||
else:
|
||||
print(f'Warning: invalid value for android:extractNativeLibs: {value}')
|
||||
|
||||
self._stack.append(element)
|
||||
|
||||
for key, value in attribs.items():
|
||||
|
|
|
|||
|
|
@ -1,11 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# NO CHECKED-IN PROTOBUF GENCODE
|
||||
# source: frameworks/base/tools/aapt2/Configuration.proto
|
||||
# Protobuf Python Version: 6.33.0
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import runtime_version as _runtime_version
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
_runtime_version.ValidateProtobufRuntimeVersion(
|
||||
_runtime_version.Domain.PUBLIC,
|
||||
6,
|
||||
33,
|
||||
0,
|
||||
'',
|
||||
'frameworks/base/tools/aapt2/Configuration.proto'
|
||||
)
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
|
@ -13,754 +24,44 @@ _sym_db = _symbol_database.Default()
|
|||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='frameworks/base/tools/aapt2/Configuration.proto',
|
||||
package='aapt.pb',
|
||||
syntax='proto3',
|
||||
serialized_options=b'\n\020com.android.aapt',
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=b'\n/frameworks/base/tools/aapt2/Configuration.proto\x12\x07\x61\x61pt.pb\"\xd9\x14\n\rConfiguration\x12\x0b\n\x03mcc\x18\x01 \x01(\r\x12\x0b\n\x03mnc\x18\x02 \x01(\r\x12\x0e\n\x06locale\x18\x03 \x01(\t\x12@\n\x10layout_direction\x18\x04 \x01(\x0e\x32&.aapt.pb.Configuration.LayoutDirection\x12\x14\n\x0cscreen_width\x18\x05 \x01(\r\x12\x15\n\rscreen_height\x18\x06 \x01(\r\x12\x17\n\x0fscreen_width_dp\x18\x07 \x01(\r\x12\x18\n\x10screen_height_dp\x18\x08 \x01(\r\x12 \n\x18smallest_screen_width_dp\x18\t \x01(\r\x12\x43\n\x12screen_layout_size\x18\n \x01(\x0e\x32\'.aapt.pb.Configuration.ScreenLayoutSize\x12\x43\n\x12screen_layout_long\x18\x0b \x01(\x0e\x32\'.aapt.pb.Configuration.ScreenLayoutLong\x12\x38\n\x0cscreen_round\x18\x0c \x01(\x0e\x32\".aapt.pb.Configuration.ScreenRound\x12?\n\x10wide_color_gamut\x18\r \x01(\x0e\x32%.aapt.pb.Configuration.WideColorGamut\x12\'\n\x03hdr\x18\x0e \x01(\x0e\x32\x1a.aapt.pb.Configuration.Hdr\x12\x37\n\x0borientation\x18\x0f \x01(\x0e\x32\".aapt.pb.Configuration.Orientation\x12\x37\n\x0cui_mode_type\x18\x10 \x01(\x0e\x32!.aapt.pb.Configuration.UiModeType\x12\x39\n\rui_mode_night\x18\x11 \x01(\x0e\x32\".aapt.pb.Configuration.UiModeNight\x12\x0f\n\x07\x64\x65nsity\x18\x12 \x01(\r\x12\x37\n\x0btouchscreen\x18\x13 \x01(\x0e\x32\".aapt.pb.Configuration.Touchscreen\x12\x36\n\x0bkeys_hidden\x18\x14 \x01(\x0e\x32!.aapt.pb.Configuration.KeysHidden\x12\x31\n\x08keyboard\x18\x15 \x01(\x0e\x32\x1f.aapt.pb.Configuration.Keyboard\x12\x34\n\nnav_hidden\x18\x16 \x01(\x0e\x32 .aapt.pb.Configuration.NavHidden\x12\x35\n\nnavigation\x18\x17 \x01(\x0e\x32!.aapt.pb.Configuration.Navigation\x12\x13\n\x0bsdk_version\x18\x18 \x01(\r\x12\x0f\n\x07product\x18\x19 \x01(\t\"a\n\x0fLayoutDirection\x12\x1a\n\x16LAYOUT_DIRECTION_UNSET\x10\x00\x12\x18\n\x14LAYOUT_DIRECTION_LTR\x10\x01\x12\x18\n\x14LAYOUT_DIRECTION_RTL\x10\x02\"\xaa\x01\n\x10ScreenLayoutSize\x12\x1c\n\x18SCREEN_LAYOUT_SIZE_UNSET\x10\x00\x12\x1c\n\x18SCREEN_LAYOUT_SIZE_SMALL\x10\x01\x12\x1d\n\x19SCREEN_LAYOUT_SIZE_NORMAL\x10\x02\x12\x1c\n\x18SCREEN_LAYOUT_SIZE_LARGE\x10\x03\x12\x1d\n\x19SCREEN_LAYOUT_SIZE_XLARGE\x10\x04\"m\n\x10ScreenLayoutLong\x12\x1c\n\x18SCREEN_LAYOUT_LONG_UNSET\x10\x00\x12\x1b\n\x17SCREEN_LAYOUT_LONG_LONG\x10\x01\x12\x1e\n\x1aSCREEN_LAYOUT_LONG_NOTLONG\x10\x02\"X\n\x0bScreenRound\x12\x16\n\x12SCREEN_ROUND_UNSET\x10\x00\x12\x16\n\x12SCREEN_ROUND_ROUND\x10\x01\x12\x19\n\x15SCREEN_ROUND_NOTROUND\x10\x02\"h\n\x0eWideColorGamut\x12\x1a\n\x16WIDE_COLOR_GAMUT_UNSET\x10\x00\x12\x1b\n\x17WIDE_COLOR_GAMUT_WIDECG\x10\x01\x12\x1d\n\x19WIDE_COLOR_GAMUT_NOWIDECG\x10\x02\"3\n\x03Hdr\x12\r\n\tHDR_UNSET\x10\x00\x12\x0e\n\nHDR_HIGHDR\x10\x01\x12\r\n\tHDR_LOWDR\x10\x02\"h\n\x0bOrientation\x12\x15\n\x11ORIENTATION_UNSET\x10\x00\x12\x14\n\x10ORIENTATION_PORT\x10\x01\x12\x14\n\x10ORIENTATION_LAND\x10\x02\x12\x16\n\x12ORIENTATION_SQUARE\x10\x03\"\xd7\x01\n\nUiModeType\x12\x16\n\x12UI_MODE_TYPE_UNSET\x10\x00\x12\x17\n\x13UI_MODE_TYPE_NORMAL\x10\x01\x12\x15\n\x11UI_MODE_TYPE_DESK\x10\x02\x12\x14\n\x10UI_MODE_TYPE_CAR\x10\x03\x12\x1b\n\x17UI_MODE_TYPE_TELEVISION\x10\x04\x12\x1a\n\x16UI_MODE_TYPE_APPLIANCE\x10\x05\x12\x16\n\x12UI_MODE_TYPE_WATCH\x10\x06\x12\x1a\n\x16UI_MODE_TYPE_VRHEADSET\x10\x07\"[\n\x0bUiModeNight\x12\x17\n\x13UI_MODE_NIGHT_UNSET\x10\x00\x12\x17\n\x13UI_MODE_NIGHT_NIGHT\x10\x01\x12\x1a\n\x16UI_MODE_NIGHT_NOTNIGHT\x10\x02\"m\n\x0bTouchscreen\x12\x15\n\x11TOUCHSCREEN_UNSET\x10\x00\x12\x17\n\x13TOUCHSCREEN_NOTOUCH\x10\x01\x12\x16\n\x12TOUCHSCREEN_STYLUS\x10\x02\x12\x16\n\x12TOUCHSCREEN_FINGER\x10\x03\"v\n\nKeysHidden\x12\x15\n\x11KEYS_HIDDEN_UNSET\x10\x00\x12\x1b\n\x17KEYS_HIDDEN_KEYSEXPOSED\x10\x01\x12\x1a\n\x16KEYS_HIDDEN_KEYSHIDDEN\x10\x02\x12\x18\n\x14KEYS_HIDDEN_KEYSSOFT\x10\x03\"`\n\x08Keyboard\x12\x12\n\x0eKEYBOARD_UNSET\x10\x00\x12\x13\n\x0fKEYBOARD_NOKEYS\x10\x01\x12\x13\n\x0fKEYBOARD_QWERTY\x10\x02\x12\x16\n\x12KEYBOARD_TWELVEKEY\x10\x03\"V\n\tNavHidden\x12\x14\n\x10NAV_HIDDEN_UNSET\x10\x00\x12\x19\n\x15NAV_HIDDEN_NAVEXPOSED\x10\x01\x12\x18\n\x14NAV_HIDDEN_NAVHIDDEN\x10\x02\"}\n\nNavigation\x12\x14\n\x10NAVIGATION_UNSET\x10\x00\x12\x14\n\x10NAVIGATION_NONAV\x10\x01\x12\x13\n\x0fNAVIGATION_DPAD\x10\x02\x12\x18\n\x14NAVIGATION_TRACKBALL\x10\x03\x12\x14\n\x10NAVIGATION_WHEEL\x10\x04\x42\x12\n\x10\x63om.android.aaptb\x06proto3'
|
||||
)
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n/frameworks/base/tools/aapt2/Configuration.proto\x12\x07\x61\x61pt.pb\"\x97\x16\n\rConfiguration\x12\x0b\n\x03mcc\x18\x01 \x01(\r\x12\x0b\n\x03mnc\x18\x02 \x01(\r\x12\x0e\n\x06locale\x18\x03 \x01(\t\x12@\n\x10layout_direction\x18\x04 \x01(\x0e\x32&.aapt.pb.Configuration.LayoutDirection\x12\x14\n\x0cscreen_width\x18\x05 \x01(\r\x12\x15\n\rscreen_height\x18\x06 \x01(\r\x12\x17\n\x0fscreen_width_dp\x18\x07 \x01(\r\x12\x18\n\x10screen_height_dp\x18\x08 \x01(\r\x12 \n\x18smallest_screen_width_dp\x18\t \x01(\r\x12\x43\n\x12screen_layout_size\x18\n \x01(\x0e\x32\'.aapt.pb.Configuration.ScreenLayoutSize\x12\x43\n\x12screen_layout_long\x18\x0b \x01(\x0e\x32\'.aapt.pb.Configuration.ScreenLayoutLong\x12\x38\n\x0cscreen_round\x18\x0c \x01(\x0e\x32\".aapt.pb.Configuration.ScreenRound\x12?\n\x10wide_color_gamut\x18\r \x01(\x0e\x32%.aapt.pb.Configuration.WideColorGamut\x12\'\n\x03hdr\x18\x0e \x01(\x0e\x32\x1a.aapt.pb.Configuration.Hdr\x12\x37\n\x0borientation\x18\x0f \x01(\x0e\x32\".aapt.pb.Configuration.Orientation\x12\x37\n\x0cui_mode_type\x18\x10 \x01(\x0e\x32!.aapt.pb.Configuration.UiModeType\x12\x39\n\rui_mode_night\x18\x11 \x01(\x0e\x32\".aapt.pb.Configuration.UiModeNight\x12\x0f\n\x07\x64\x65nsity\x18\x12 \x01(\r\x12\x37\n\x0btouchscreen\x18\x13 \x01(\x0e\x32\".aapt.pb.Configuration.Touchscreen\x12\x36\n\x0bkeys_hidden\x18\x14 \x01(\x0e\x32!.aapt.pb.Configuration.KeysHidden\x12\x31\n\x08keyboard\x18\x15 \x01(\x0e\x32\x1f.aapt.pb.Configuration.Keyboard\x12\x34\n\nnav_hidden\x18\x16 \x01(\x0e\x32 .aapt.pb.Configuration.NavHidden\x12\x35\n\nnavigation\x18\x17 \x01(\x0e\x32!.aapt.pb.Configuration.Navigation\x12\x13\n\x0bsdk_version\x18\x18 \x01(\r\x12\x44\n\x12grammatical_gender\x18\x1a \x01(\x0e\x32(.aapt.pb.Configuration.GrammaticalGender\x12\x0f\n\x07product\x18\x19 \x01(\t\"a\n\x0fLayoutDirection\x12\x1a\n\x16LAYOUT_DIRECTION_UNSET\x10\x00\x12\x18\n\x14LAYOUT_DIRECTION_LTR\x10\x01\x12\x18\n\x14LAYOUT_DIRECTION_RTL\x10\x02\"\xaa\x01\n\x10ScreenLayoutSize\x12\x1c\n\x18SCREEN_LAYOUT_SIZE_UNSET\x10\x00\x12\x1c\n\x18SCREEN_LAYOUT_SIZE_SMALL\x10\x01\x12\x1d\n\x19SCREEN_LAYOUT_SIZE_NORMAL\x10\x02\x12\x1c\n\x18SCREEN_LAYOUT_SIZE_LARGE\x10\x03\x12\x1d\n\x19SCREEN_LAYOUT_SIZE_XLARGE\x10\x04\"m\n\x10ScreenLayoutLong\x12\x1c\n\x18SCREEN_LAYOUT_LONG_UNSET\x10\x00\x12\x1b\n\x17SCREEN_LAYOUT_LONG_LONG\x10\x01\x12\x1e\n\x1aSCREEN_LAYOUT_LONG_NOTLONG\x10\x02\"X\n\x0bScreenRound\x12\x16\n\x12SCREEN_ROUND_UNSET\x10\x00\x12\x16\n\x12SCREEN_ROUND_ROUND\x10\x01\x12\x19\n\x15SCREEN_ROUND_NOTROUND\x10\x02\"h\n\x0eWideColorGamut\x12\x1a\n\x16WIDE_COLOR_GAMUT_UNSET\x10\x00\x12\x1b\n\x17WIDE_COLOR_GAMUT_WIDECG\x10\x01\x12\x1d\n\x19WIDE_COLOR_GAMUT_NOWIDECG\x10\x02\"3\n\x03Hdr\x12\r\n\tHDR_UNSET\x10\x00\x12\x0e\n\nHDR_HIGHDR\x10\x01\x12\r\n\tHDR_LOWDR\x10\x02\"h\n\x0bOrientation\x12\x15\n\x11ORIENTATION_UNSET\x10\x00\x12\x14\n\x10ORIENTATION_PORT\x10\x01\x12\x14\n\x10ORIENTATION_LAND\x10\x02\x12\x16\n\x12ORIENTATION_SQUARE\x10\x03\"\xd7\x01\n\nUiModeType\x12\x16\n\x12UI_MODE_TYPE_UNSET\x10\x00\x12\x17\n\x13UI_MODE_TYPE_NORMAL\x10\x01\x12\x15\n\x11UI_MODE_TYPE_DESK\x10\x02\x12\x14\n\x10UI_MODE_TYPE_CAR\x10\x03\x12\x1b\n\x17UI_MODE_TYPE_TELEVISION\x10\x04\x12\x1a\n\x16UI_MODE_TYPE_APPLIANCE\x10\x05\x12\x16\n\x12UI_MODE_TYPE_WATCH\x10\x06\x12\x1a\n\x16UI_MODE_TYPE_VRHEADSET\x10\x07\"[\n\x0bUiModeNight\x12\x17\n\x13UI_MODE_NIGHT_UNSET\x10\x00\x12\x17\n\x13UI_MODE_NIGHT_NIGHT\x10\x01\x12\x1a\n\x16UI_MODE_NIGHT_NOTNIGHT\x10\x02\"m\n\x0bTouchscreen\x12\x15\n\x11TOUCHSCREEN_UNSET\x10\x00\x12\x17\n\x13TOUCHSCREEN_NOTOUCH\x10\x01\x12\x16\n\x12TOUCHSCREEN_STYLUS\x10\x02\x12\x16\n\x12TOUCHSCREEN_FINGER\x10\x03\"v\n\nKeysHidden\x12\x15\n\x11KEYS_HIDDEN_UNSET\x10\x00\x12\x1b\n\x17KEYS_HIDDEN_KEYSEXPOSED\x10\x01\x12\x1a\n\x16KEYS_HIDDEN_KEYSHIDDEN\x10\x02\x12\x18\n\x14KEYS_HIDDEN_KEYSSOFT\x10\x03\"`\n\x08Keyboard\x12\x12\n\x0eKEYBOARD_UNSET\x10\x00\x12\x13\n\x0fKEYBOARD_NOKEYS\x10\x01\x12\x13\n\x0fKEYBOARD_QWERTY\x10\x02\x12\x16\n\x12KEYBOARD_TWELVEKEY\x10\x03\"V\n\tNavHidden\x12\x14\n\x10NAV_HIDDEN_UNSET\x10\x00\x12\x19\n\x15NAV_HIDDEN_NAVEXPOSED\x10\x01\x12\x18\n\x14NAV_HIDDEN_NAVHIDDEN\x10\x02\"}\n\nNavigation\x12\x14\n\x10NAVIGATION_UNSET\x10\x00\x12\x14\n\x10NAVIGATION_NONAV\x10\x01\x12\x13\n\x0fNAVIGATION_DPAD\x10\x02\x12\x18\n\x14NAVIGATION_TRACKBALL\x10\x03\x12\x14\n\x10NAVIGATION_WHEEL\x10\x04\"v\n\x11GrammaticalGender\x12\x14\n\x10GRAM_GENDER_USET\x10\x00\x12\x16\n\x12GRAM_GENDER_NEUTER\x10\x01\x12\x18\n\x14GRAM_GENDER_FEMININE\x10\x02\x12\x19\n\x15GRAM_GENDER_MASCULINE\x10\x03\x42\x12\n\x10\x63om.android.aaptb\x06proto3')
|
||||
|
||||
|
||||
|
||||
_CONFIGURATION_LAYOUTDIRECTION = _descriptor.EnumDescriptor(
|
||||
name='LayoutDirection',
|
||||
full_name='aapt.pb.Configuration.LayoutDirection',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='LAYOUT_DIRECTION_UNSET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='LAYOUT_DIRECTION_LTR', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='LAYOUT_DIRECTION_RTL', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=1119,
|
||||
serialized_end=1216,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_LAYOUTDIRECTION)
|
||||
|
||||
_CONFIGURATION_SCREENLAYOUTSIZE = _descriptor.EnumDescriptor(
|
||||
name='ScreenLayoutSize',
|
||||
full_name='aapt.pb.Configuration.ScreenLayoutSize',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SCREEN_LAYOUT_SIZE_UNSET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SCREEN_LAYOUT_SIZE_SMALL', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SCREEN_LAYOUT_SIZE_NORMAL', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SCREEN_LAYOUT_SIZE_LARGE', index=3, number=3,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SCREEN_LAYOUT_SIZE_XLARGE', index=4, number=4,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=1219,
|
||||
serialized_end=1389,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_SCREENLAYOUTSIZE)
|
||||
|
||||
_CONFIGURATION_SCREENLAYOUTLONG = _descriptor.EnumDescriptor(
|
||||
name='ScreenLayoutLong',
|
||||
full_name='aapt.pb.Configuration.ScreenLayoutLong',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SCREEN_LAYOUT_LONG_UNSET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SCREEN_LAYOUT_LONG_LONG', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SCREEN_LAYOUT_LONG_NOTLONG', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=1391,
|
||||
serialized_end=1500,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_SCREENLAYOUTLONG)
|
||||
|
||||
_CONFIGURATION_SCREENROUND = _descriptor.EnumDescriptor(
|
||||
name='ScreenRound',
|
||||
full_name='aapt.pb.Configuration.ScreenRound',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SCREEN_ROUND_UNSET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SCREEN_ROUND_ROUND', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SCREEN_ROUND_NOTROUND', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=1502,
|
||||
serialized_end=1590,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_SCREENROUND)
|
||||
|
||||
_CONFIGURATION_WIDECOLORGAMUT = _descriptor.EnumDescriptor(
|
||||
name='WideColorGamut',
|
||||
full_name='aapt.pb.Configuration.WideColorGamut',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='WIDE_COLOR_GAMUT_UNSET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='WIDE_COLOR_GAMUT_WIDECG', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='WIDE_COLOR_GAMUT_NOWIDECG', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=1592,
|
||||
serialized_end=1696,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_WIDECOLORGAMUT)
|
||||
|
||||
_CONFIGURATION_HDR = _descriptor.EnumDescriptor(
|
||||
name='Hdr',
|
||||
full_name='aapt.pb.Configuration.Hdr',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='HDR_UNSET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='HDR_HIGHDR', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='HDR_LOWDR', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=1698,
|
||||
serialized_end=1749,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_HDR)
|
||||
|
||||
_CONFIGURATION_ORIENTATION = _descriptor.EnumDescriptor(
|
||||
name='Orientation',
|
||||
full_name='aapt.pb.Configuration.Orientation',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='ORIENTATION_UNSET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='ORIENTATION_PORT', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='ORIENTATION_LAND', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='ORIENTATION_SQUARE', index=3, number=3,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=1751,
|
||||
serialized_end=1855,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_ORIENTATION)
|
||||
|
||||
_CONFIGURATION_UIMODETYPE = _descriptor.EnumDescriptor(
|
||||
name='UiModeType',
|
||||
full_name='aapt.pb.Configuration.UiModeType',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='UI_MODE_TYPE_UNSET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='UI_MODE_TYPE_NORMAL', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='UI_MODE_TYPE_DESK', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='UI_MODE_TYPE_CAR', index=3, number=3,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='UI_MODE_TYPE_TELEVISION', index=4, number=4,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='UI_MODE_TYPE_APPLIANCE', index=5, number=5,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='UI_MODE_TYPE_WATCH', index=6, number=6,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='UI_MODE_TYPE_VRHEADSET', index=7, number=7,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=1858,
|
||||
serialized_end=2073,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_UIMODETYPE)
|
||||
|
||||
_CONFIGURATION_UIMODENIGHT = _descriptor.EnumDescriptor(
|
||||
name='UiModeNight',
|
||||
full_name='aapt.pb.Configuration.UiModeNight',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='UI_MODE_NIGHT_UNSET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='UI_MODE_NIGHT_NIGHT', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='UI_MODE_NIGHT_NOTNIGHT', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=2075,
|
||||
serialized_end=2166,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_UIMODENIGHT)
|
||||
|
||||
_CONFIGURATION_TOUCHSCREEN = _descriptor.EnumDescriptor(
|
||||
name='Touchscreen',
|
||||
full_name='aapt.pb.Configuration.Touchscreen',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='TOUCHSCREEN_UNSET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='TOUCHSCREEN_NOTOUCH', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='TOUCHSCREEN_STYLUS', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='TOUCHSCREEN_FINGER', index=3, number=3,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=2168,
|
||||
serialized_end=2277,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_TOUCHSCREEN)
|
||||
|
||||
_CONFIGURATION_KEYSHIDDEN = _descriptor.EnumDescriptor(
|
||||
name='KeysHidden',
|
||||
full_name='aapt.pb.Configuration.KeysHidden',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='KEYS_HIDDEN_UNSET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='KEYS_HIDDEN_KEYSEXPOSED', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='KEYS_HIDDEN_KEYSHIDDEN', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='KEYS_HIDDEN_KEYSSOFT', index=3, number=3,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=2279,
|
||||
serialized_end=2397,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_KEYSHIDDEN)
|
||||
|
||||
_CONFIGURATION_KEYBOARD = _descriptor.EnumDescriptor(
|
||||
name='Keyboard',
|
||||
full_name='aapt.pb.Configuration.Keyboard',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='KEYBOARD_UNSET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='KEYBOARD_NOKEYS', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='KEYBOARD_QWERTY', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='KEYBOARD_TWELVEKEY', index=3, number=3,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=2399,
|
||||
serialized_end=2495,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_KEYBOARD)
|
||||
|
||||
_CONFIGURATION_NAVHIDDEN = _descriptor.EnumDescriptor(
|
||||
name='NavHidden',
|
||||
full_name='aapt.pb.Configuration.NavHidden',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='NAV_HIDDEN_UNSET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='NAV_HIDDEN_NAVEXPOSED', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='NAV_HIDDEN_NAVHIDDEN', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=2497,
|
||||
serialized_end=2583,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_NAVHIDDEN)
|
||||
|
||||
_CONFIGURATION_NAVIGATION = _descriptor.EnumDescriptor(
|
||||
name='Navigation',
|
||||
full_name='aapt.pb.Configuration.Navigation',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='NAVIGATION_UNSET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='NAVIGATION_NONAV', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='NAVIGATION_DPAD', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='NAVIGATION_TRACKBALL', index=3, number=3,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='NAVIGATION_WHEEL', index=4, number=4,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=2585,
|
||||
serialized_end=2710,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CONFIGURATION_NAVIGATION)
|
||||
|
||||
|
||||
_CONFIGURATION = _descriptor.Descriptor(
|
||||
name='Configuration',
|
||||
full_name='aapt.pb.Configuration',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='mcc', full_name='aapt.pb.Configuration.mcc', index=0,
|
||||
number=1, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='mnc', full_name='aapt.pb.Configuration.mnc', index=1,
|
||||
number=2, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='locale', full_name='aapt.pb.Configuration.locale', index=2,
|
||||
number=3, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=b"".decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='layout_direction', full_name='aapt.pb.Configuration.layout_direction', index=3,
|
||||
number=4, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='screen_width', full_name='aapt.pb.Configuration.screen_width', index=4,
|
||||
number=5, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='screen_height', full_name='aapt.pb.Configuration.screen_height', index=5,
|
||||
number=6, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='screen_width_dp', full_name='aapt.pb.Configuration.screen_width_dp', index=6,
|
||||
number=7, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='screen_height_dp', full_name='aapt.pb.Configuration.screen_height_dp', index=7,
|
||||
number=8, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='smallest_screen_width_dp', full_name='aapt.pb.Configuration.smallest_screen_width_dp', index=8,
|
||||
number=9, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='screen_layout_size', full_name='aapt.pb.Configuration.screen_layout_size', index=9,
|
||||
number=10, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='screen_layout_long', full_name='aapt.pb.Configuration.screen_layout_long', index=10,
|
||||
number=11, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='screen_round', full_name='aapt.pb.Configuration.screen_round', index=11,
|
||||
number=12, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='wide_color_gamut', full_name='aapt.pb.Configuration.wide_color_gamut', index=12,
|
||||
number=13, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='hdr', full_name='aapt.pb.Configuration.hdr', index=13,
|
||||
number=14, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='orientation', full_name='aapt.pb.Configuration.orientation', index=14,
|
||||
number=15, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='ui_mode_type', full_name='aapt.pb.Configuration.ui_mode_type', index=15,
|
||||
number=16, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='ui_mode_night', full_name='aapt.pb.Configuration.ui_mode_night', index=16,
|
||||
number=17, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='density', full_name='aapt.pb.Configuration.density', index=17,
|
||||
number=18, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='touchscreen', full_name='aapt.pb.Configuration.touchscreen', index=18,
|
||||
number=19, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='keys_hidden', full_name='aapt.pb.Configuration.keys_hidden', index=19,
|
||||
number=20, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='keyboard', full_name='aapt.pb.Configuration.keyboard', index=20,
|
||||
number=21, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='nav_hidden', full_name='aapt.pb.Configuration.nav_hidden', index=21,
|
||||
number=22, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='navigation', full_name='aapt.pb.Configuration.navigation', index=22,
|
||||
number=23, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='sdk_version', full_name='aapt.pb.Configuration.sdk_version', index=23,
|
||||
number=24, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='product', full_name='aapt.pb.Configuration.product', index=24,
|
||||
number=25, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=b"".decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
_CONFIGURATION_LAYOUTDIRECTION,
|
||||
_CONFIGURATION_SCREENLAYOUTSIZE,
|
||||
_CONFIGURATION_SCREENLAYOUTLONG,
|
||||
_CONFIGURATION_SCREENROUND,
|
||||
_CONFIGURATION_WIDECOLORGAMUT,
|
||||
_CONFIGURATION_HDR,
|
||||
_CONFIGURATION_ORIENTATION,
|
||||
_CONFIGURATION_UIMODETYPE,
|
||||
_CONFIGURATION_UIMODENIGHT,
|
||||
_CONFIGURATION_TOUCHSCREEN,
|
||||
_CONFIGURATION_KEYSHIDDEN,
|
||||
_CONFIGURATION_KEYBOARD,
|
||||
_CONFIGURATION_NAVHIDDEN,
|
||||
_CONFIGURATION_NAVIGATION,
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=61,
|
||||
serialized_end=2710,
|
||||
)
|
||||
|
||||
_CONFIGURATION.fields_by_name['layout_direction'].enum_type = _CONFIGURATION_LAYOUTDIRECTION
|
||||
_CONFIGURATION.fields_by_name['screen_layout_size'].enum_type = _CONFIGURATION_SCREENLAYOUTSIZE
|
||||
_CONFIGURATION.fields_by_name['screen_layout_long'].enum_type = _CONFIGURATION_SCREENLAYOUTLONG
|
||||
_CONFIGURATION.fields_by_name['screen_round'].enum_type = _CONFIGURATION_SCREENROUND
|
||||
_CONFIGURATION.fields_by_name['wide_color_gamut'].enum_type = _CONFIGURATION_WIDECOLORGAMUT
|
||||
_CONFIGURATION.fields_by_name['hdr'].enum_type = _CONFIGURATION_HDR
|
||||
_CONFIGURATION.fields_by_name['orientation'].enum_type = _CONFIGURATION_ORIENTATION
|
||||
_CONFIGURATION.fields_by_name['ui_mode_type'].enum_type = _CONFIGURATION_UIMODETYPE
|
||||
_CONFIGURATION.fields_by_name['ui_mode_night'].enum_type = _CONFIGURATION_UIMODENIGHT
|
||||
_CONFIGURATION.fields_by_name['touchscreen'].enum_type = _CONFIGURATION_TOUCHSCREEN
|
||||
_CONFIGURATION.fields_by_name['keys_hidden'].enum_type = _CONFIGURATION_KEYSHIDDEN
|
||||
_CONFIGURATION.fields_by_name['keyboard'].enum_type = _CONFIGURATION_KEYBOARD
|
||||
_CONFIGURATION.fields_by_name['nav_hidden'].enum_type = _CONFIGURATION_NAVHIDDEN
|
||||
_CONFIGURATION.fields_by_name['navigation'].enum_type = _CONFIGURATION_NAVIGATION
|
||||
_CONFIGURATION_LAYOUTDIRECTION.containing_type = _CONFIGURATION
|
||||
_CONFIGURATION_SCREENLAYOUTSIZE.containing_type = _CONFIGURATION
|
||||
_CONFIGURATION_SCREENLAYOUTLONG.containing_type = _CONFIGURATION
|
||||
_CONFIGURATION_SCREENROUND.containing_type = _CONFIGURATION
|
||||
_CONFIGURATION_WIDECOLORGAMUT.containing_type = _CONFIGURATION
|
||||
_CONFIGURATION_HDR.containing_type = _CONFIGURATION
|
||||
_CONFIGURATION_ORIENTATION.containing_type = _CONFIGURATION
|
||||
_CONFIGURATION_UIMODETYPE.containing_type = _CONFIGURATION
|
||||
_CONFIGURATION_UIMODENIGHT.containing_type = _CONFIGURATION
|
||||
_CONFIGURATION_TOUCHSCREEN.containing_type = _CONFIGURATION
|
||||
_CONFIGURATION_KEYSHIDDEN.containing_type = _CONFIGURATION
|
||||
_CONFIGURATION_KEYBOARD.containing_type = _CONFIGURATION
|
||||
_CONFIGURATION_NAVHIDDEN.containing_type = _CONFIGURATION
|
||||
_CONFIGURATION_NAVIGATION.containing_type = _CONFIGURATION
|
||||
DESCRIPTOR.message_types_by_name['Configuration'] = _CONFIGURATION
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
Configuration = _reflection.GeneratedProtocolMessageType('Configuration', (_message.Message,), {
|
||||
'DESCRIPTOR' : _CONFIGURATION,
|
||||
'__module__' : 'frameworks.base.tools.aapt2.Configuration_pb2'
|
||||
# @@protoc_insertion_point(class_scope:aapt.pb.Configuration)
|
||||
})
|
||||
_sym_db.RegisterMessage(Configuration)
|
||||
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'frameworks.base.tools.aapt2.Configuration_pb2', _globals)
|
||||
if not _descriptor._USE_C_DESCRIPTORS:
|
||||
_globals['DESCRIPTOR']._loaded_options = None
|
||||
_globals['DESCRIPTOR']._serialized_options = b'\n\020com.android.aapt'
|
||||
_globals['_CONFIGURATION']._serialized_start=61
|
||||
_globals['_CONFIGURATION']._serialized_end=2900
|
||||
_globals['_CONFIGURATION_LAYOUTDIRECTION']._serialized_start=1189
|
||||
_globals['_CONFIGURATION_LAYOUTDIRECTION']._serialized_end=1286
|
||||
_globals['_CONFIGURATION_SCREENLAYOUTSIZE']._serialized_start=1289
|
||||
_globals['_CONFIGURATION_SCREENLAYOUTSIZE']._serialized_end=1459
|
||||
_globals['_CONFIGURATION_SCREENLAYOUTLONG']._serialized_start=1461
|
||||
_globals['_CONFIGURATION_SCREENLAYOUTLONG']._serialized_end=1570
|
||||
_globals['_CONFIGURATION_SCREENROUND']._serialized_start=1572
|
||||
_globals['_CONFIGURATION_SCREENROUND']._serialized_end=1660
|
||||
_globals['_CONFIGURATION_WIDECOLORGAMUT']._serialized_start=1662
|
||||
_globals['_CONFIGURATION_WIDECOLORGAMUT']._serialized_end=1766
|
||||
_globals['_CONFIGURATION_HDR']._serialized_start=1768
|
||||
_globals['_CONFIGURATION_HDR']._serialized_end=1819
|
||||
_globals['_CONFIGURATION_ORIENTATION']._serialized_start=1821
|
||||
_globals['_CONFIGURATION_ORIENTATION']._serialized_end=1925
|
||||
_globals['_CONFIGURATION_UIMODETYPE']._serialized_start=1928
|
||||
_globals['_CONFIGURATION_UIMODETYPE']._serialized_end=2143
|
||||
_globals['_CONFIGURATION_UIMODENIGHT']._serialized_start=2145
|
||||
_globals['_CONFIGURATION_UIMODENIGHT']._serialized_end=2236
|
||||
_globals['_CONFIGURATION_TOUCHSCREEN']._serialized_start=2238
|
||||
_globals['_CONFIGURATION_TOUCHSCREEN']._serialized_end=2347
|
||||
_globals['_CONFIGURATION_KEYSHIDDEN']._serialized_start=2349
|
||||
_globals['_CONFIGURATION_KEYSHIDDEN']._serialized_end=2467
|
||||
_globals['_CONFIGURATION_KEYBOARD']._serialized_start=2469
|
||||
_globals['_CONFIGURATION_KEYBOARD']._serialized_end=2565
|
||||
_globals['_CONFIGURATION_NAVHIDDEN']._serialized_start=2567
|
||||
_globals['_CONFIGURATION_NAVHIDDEN']._serialized_end=2653
|
||||
_globals['_CONFIGURATION_NAVIGATION']._serialized_start=2655
|
||||
_globals['_CONFIGURATION_NAVIGATION']._serialized_end=2780
|
||||
_globals['_CONFIGURATION_GRAMMATICALGENDER']._serialized_start=2782
|
||||
_globals['_CONFIGURATION_GRAMMATICALGENDER']._serialized_end=2900
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,11 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# NO CHECKED-IN PROTOBUF GENCODE
|
||||
# source: files.proto
|
||||
# Protobuf Python Version: 6.33.0
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import runtime_version as _runtime_version
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
_runtime_version.ValidateProtobufRuntimeVersion(
|
||||
_runtime_version.Domain.PUBLIC,
|
||||
6,
|
||||
33,
|
||||
0,
|
||||
'',
|
||||
'files.proto'
|
||||
)
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
|
@ -14,294 +25,24 @@ _sym_db = _symbol_database.Default()
|
|||
from . import targeting_pb2 as targeting__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='files.proto',
|
||||
package='android.bundle',
|
||||
syntax='proto3',
|
||||
serialized_options=b'\n\022com.android.bundle',
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=b'\n\x0b\x66iles.proto\x12\x0e\x61ndroid.bundle\x1a\x0ftargeting.proto\"D\n\x06\x41ssets\x12:\n\tdirectory\x18\x01 \x03(\x0b\x32\'.android.bundle.TargetedAssetsDirectory\"M\n\x0fNativeLibraries\x12:\n\tdirectory\x18\x01 \x03(\x0b\x32\'.android.bundle.TargetedNativeDirectory\"D\n\nApexImages\x12\x30\n\x05image\x18\x01 \x03(\x0b\x32!.android.bundle.TargetedApexImageJ\x04\x08\x02\x10\x03\"d\n\x17TargetedAssetsDirectory\x12\x0c\n\x04path\x18\x01 \x01(\t\x12;\n\ttargeting\x18\x02 \x01(\x0b\x32(.android.bundle.AssetsDirectoryTargeting\"d\n\x17TargetedNativeDirectory\x12\x0c\n\x04path\x18\x01 \x01(\t\x12;\n\ttargeting\x18\x02 \x01(\x0b\x32(.android.bundle.NativeDirectoryTargeting\"q\n\x11TargetedApexImage\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x17\n\x0f\x62uild_info_path\x18\x03 \x01(\t\x12\x35\n\ttargeting\x18\x02 \x01(\x0b\x32\".android.bundle.ApexImageTargetingB\x14\n\x12\x63om.android.bundleb\x06proto3'
|
||||
,
|
||||
dependencies=[targeting__pb2.DESCRIPTOR,])
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0b\x66iles.proto\x12\x0e\x61ndroid.bundle\x1a\x0ftargeting.proto\"D\n\x06\x41ssets\x12:\n\tdirectory\x18\x01 \x03(\x0b\x32\'.android.bundle.TargetedAssetsDirectory\"M\n\x0fNativeLibraries\x12:\n\tdirectory\x18\x01 \x03(\x0b\x32\'.android.bundle.TargetedNativeDirectory\"D\n\nApexImages\x12\x30\n\x05image\x18\x01 \x03(\x0b\x32!.android.bundle.TargetedApexImageJ\x04\x08\x02\x10\x03\"d\n\x17TargetedAssetsDirectory\x12\x0c\n\x04path\x18\x01 \x01(\t\x12;\n\ttargeting\x18\x02 \x01(\x0b\x32(.android.bundle.AssetsDirectoryTargeting\"d\n\x17TargetedNativeDirectory\x12\x0c\n\x04path\x18\x01 \x01(\t\x12;\n\ttargeting\x18\x02 \x01(\x0b\x32(.android.bundle.NativeDirectoryTargeting\"q\n\x11TargetedApexImage\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x17\n\x0f\x62uild_info_path\x18\x03 \x01(\t\x12\x35\n\ttargeting\x18\x02 \x01(\x0b\x32\".android.bundle.ApexImageTargetingB\x14\n\x12\x63om.android.bundleb\x06proto3')
|
||||
|
||||
|
||||
|
||||
|
||||
_ASSETS = _descriptor.Descriptor(
|
||||
name='Assets',
|
||||
full_name='android.bundle.Assets',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='directory', full_name='android.bundle.Assets.directory', index=0,
|
||||
number=1, type=11, cpp_type=10, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=48,
|
||||
serialized_end=116,
|
||||
)
|
||||
|
||||
|
||||
_NATIVELIBRARIES = _descriptor.Descriptor(
|
||||
name='NativeLibraries',
|
||||
full_name='android.bundle.NativeLibraries',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='directory', full_name='android.bundle.NativeLibraries.directory', index=0,
|
||||
number=1, type=11, cpp_type=10, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=118,
|
||||
serialized_end=195,
|
||||
)
|
||||
|
||||
|
||||
_APEXIMAGES = _descriptor.Descriptor(
|
||||
name='ApexImages',
|
||||
full_name='android.bundle.ApexImages',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='image', full_name='android.bundle.ApexImages.image', index=0,
|
||||
number=1, type=11, cpp_type=10, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=197,
|
||||
serialized_end=265,
|
||||
)
|
||||
|
||||
|
||||
_TARGETEDASSETSDIRECTORY = _descriptor.Descriptor(
|
||||
name='TargetedAssetsDirectory',
|
||||
full_name='android.bundle.TargetedAssetsDirectory',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='path', full_name='android.bundle.TargetedAssetsDirectory.path', index=0,
|
||||
number=1, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=b"".decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='targeting', full_name='android.bundle.TargetedAssetsDirectory.targeting', index=1,
|
||||
number=2, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=267,
|
||||
serialized_end=367,
|
||||
)
|
||||
|
||||
|
||||
_TARGETEDNATIVEDIRECTORY = _descriptor.Descriptor(
|
||||
name='TargetedNativeDirectory',
|
||||
full_name='android.bundle.TargetedNativeDirectory',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='path', full_name='android.bundle.TargetedNativeDirectory.path', index=0,
|
||||
number=1, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=b"".decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='targeting', full_name='android.bundle.TargetedNativeDirectory.targeting', index=1,
|
||||
number=2, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=369,
|
||||
serialized_end=469,
|
||||
)
|
||||
|
||||
|
||||
_TARGETEDAPEXIMAGE = _descriptor.Descriptor(
|
||||
name='TargetedApexImage',
|
||||
full_name='android.bundle.TargetedApexImage',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='path', full_name='android.bundle.TargetedApexImage.path', index=0,
|
||||
number=1, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=b"".decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='build_info_path', full_name='android.bundle.TargetedApexImage.build_info_path', index=1,
|
||||
number=3, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=b"".decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='targeting', full_name='android.bundle.TargetedApexImage.targeting', index=2,
|
||||
number=2, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=471,
|
||||
serialized_end=584,
|
||||
)
|
||||
|
||||
_ASSETS.fields_by_name['directory'].message_type = _TARGETEDASSETSDIRECTORY
|
||||
_NATIVELIBRARIES.fields_by_name['directory'].message_type = _TARGETEDNATIVEDIRECTORY
|
||||
_APEXIMAGES.fields_by_name['image'].message_type = _TARGETEDAPEXIMAGE
|
||||
_TARGETEDASSETSDIRECTORY.fields_by_name['targeting'].message_type = targeting__pb2._ASSETSDIRECTORYTARGETING
|
||||
_TARGETEDNATIVEDIRECTORY.fields_by_name['targeting'].message_type = targeting__pb2._NATIVEDIRECTORYTARGETING
|
||||
_TARGETEDAPEXIMAGE.fields_by_name['targeting'].message_type = targeting__pb2._APEXIMAGETARGETING
|
||||
DESCRIPTOR.message_types_by_name['Assets'] = _ASSETS
|
||||
DESCRIPTOR.message_types_by_name['NativeLibraries'] = _NATIVELIBRARIES
|
||||
DESCRIPTOR.message_types_by_name['ApexImages'] = _APEXIMAGES
|
||||
DESCRIPTOR.message_types_by_name['TargetedAssetsDirectory'] = _TARGETEDASSETSDIRECTORY
|
||||
DESCRIPTOR.message_types_by_name['TargetedNativeDirectory'] = _TARGETEDNATIVEDIRECTORY
|
||||
DESCRIPTOR.message_types_by_name['TargetedApexImage'] = _TARGETEDAPEXIMAGE
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
Assets = _reflection.GeneratedProtocolMessageType('Assets', (_message.Message,), {
|
||||
'DESCRIPTOR' : _ASSETS,
|
||||
'__module__' : 'files_pb2'
|
||||
# @@protoc_insertion_point(class_scope:android.bundle.Assets)
|
||||
})
|
||||
_sym_db.RegisterMessage(Assets)
|
||||
|
||||
NativeLibraries = _reflection.GeneratedProtocolMessageType('NativeLibraries', (_message.Message,), {
|
||||
'DESCRIPTOR' : _NATIVELIBRARIES,
|
||||
'__module__' : 'files_pb2'
|
||||
# @@protoc_insertion_point(class_scope:android.bundle.NativeLibraries)
|
||||
})
|
||||
_sym_db.RegisterMessage(NativeLibraries)
|
||||
|
||||
ApexImages = _reflection.GeneratedProtocolMessageType('ApexImages', (_message.Message,), {
|
||||
'DESCRIPTOR' : _APEXIMAGES,
|
||||
'__module__' : 'files_pb2'
|
||||
# @@protoc_insertion_point(class_scope:android.bundle.ApexImages)
|
||||
})
|
||||
_sym_db.RegisterMessage(ApexImages)
|
||||
|
||||
TargetedAssetsDirectory = _reflection.GeneratedProtocolMessageType('TargetedAssetsDirectory', (_message.Message,), {
|
||||
'DESCRIPTOR' : _TARGETEDASSETSDIRECTORY,
|
||||
'__module__' : 'files_pb2'
|
||||
# @@protoc_insertion_point(class_scope:android.bundle.TargetedAssetsDirectory)
|
||||
})
|
||||
_sym_db.RegisterMessage(TargetedAssetsDirectory)
|
||||
|
||||
TargetedNativeDirectory = _reflection.GeneratedProtocolMessageType('TargetedNativeDirectory', (_message.Message,), {
|
||||
'DESCRIPTOR' : _TARGETEDNATIVEDIRECTORY,
|
||||
'__module__' : 'files_pb2'
|
||||
# @@protoc_insertion_point(class_scope:android.bundle.TargetedNativeDirectory)
|
||||
})
|
||||
_sym_db.RegisterMessage(TargetedNativeDirectory)
|
||||
|
||||
TargetedApexImage = _reflection.GeneratedProtocolMessageType('TargetedApexImage', (_message.Message,), {
|
||||
'DESCRIPTOR' : _TARGETEDAPEXIMAGE,
|
||||
'__module__' : 'files_pb2'
|
||||
# @@protoc_insertion_point(class_scope:android.bundle.TargetedApexImage)
|
||||
})
|
||||
_sym_db.RegisterMessage(TargetedApexImage)
|
||||
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'files_pb2', _globals)
|
||||
if not _descriptor._USE_C_DESCRIPTORS:
|
||||
_globals['DESCRIPTOR']._loaded_options = None
|
||||
_globals['DESCRIPTOR']._serialized_options = b'\n\022com.android.bundle'
|
||||
_globals['_ASSETS']._serialized_start=48
|
||||
_globals['_ASSETS']._serialized_end=116
|
||||
_globals['_NATIVELIBRARIES']._serialized_start=118
|
||||
_globals['_NATIVELIBRARIES']._serialized_end=195
|
||||
_globals['_APEXIMAGES']._serialized_start=197
|
||||
_globals['_APEXIMAGES']._serialized_end=265
|
||||
_globals['_TARGETEDASSETSDIRECTORY']._serialized_start=267
|
||||
_globals['_TARGETEDASSETSDIRECTORY']._serialized_end=367
|
||||
_globals['_TARGETEDNATIVEDIRECTORY']._serialized_start=369
|
||||
_globals['_TARGETEDNATIVEDIRECTORY']._serialized_end=469
|
||||
_globals['_TARGETEDAPEXIMAGE']._serialized_start=471
|
||||
_globals['_TARGETEDAPEXIMAGE']._serialized_end=584
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -79,6 +79,10 @@ def _model_to_bam(_build_cmd, srcpath, dstpath):
|
|||
|
||||
_register_python_loaders()
|
||||
|
||||
if src_fn.get_extension() == 'egg' and zipfile.is_zipfile(src_fn.to_os_specific()):
|
||||
_build_cmd.warn('Skipping %s as it appears to be a Python .egg archive, was this included by mistake?' % (src_fn.to_os_specific()))
|
||||
return
|
||||
|
||||
loader = p3d.Loader.get_global_ptr()
|
||||
options = p3d.LoaderOptions(p3d.LoaderOptions.LF_report_errors |
|
||||
p3d.LoaderOptions.LF_no_ram_cache)
|
||||
|
|
@ -192,14 +196,14 @@ SITE_PY_ANDROID = """
|
|||
# module.
|
||||
import sys, os
|
||||
from importlib import _bootstrap, _bootstrap_external
|
||||
from android_support import log_write as android_log_write
|
||||
from android_support import find_library
|
||||
|
||||
class AndroidExtensionFinder:
|
||||
@classmethod
|
||||
def find_spec(cls, fullname, path=None, target=None):
|
||||
soname = 'libpy.' + fullname + '.so'
|
||||
path = os.path.join(sys.platlibdir, soname)
|
||||
|
||||
if os.path.exists(path):
|
||||
path = find_library('py.' + fullname)
|
||||
if path:
|
||||
loader = _bootstrap_external.ExtensionFileLoader(fullname, path)
|
||||
return _bootstrap.ModuleSpec(fullname, loader, origin=path)
|
||||
|
||||
|
|
@ -210,8 +214,6 @@ sys.meta_path.append(AndroidExtensionFinder)
|
|||
from _frozen_importlib import _imp, FrozenImporter
|
||||
from io import RawIOBase, TextIOWrapper
|
||||
|
||||
from android_log import write as android_log_write
|
||||
|
||||
|
||||
sys.frozen = True
|
||||
|
||||
|
|
@ -300,7 +302,8 @@ class build_apps(setuptools.Command):
|
|||
self.android_version_code = 1
|
||||
self.android_min_sdk_version = 21
|
||||
self.android_max_sdk_version = None
|
||||
self.android_target_sdk_version = 30
|
||||
self.android_target_sdk_version = 35
|
||||
self.android_manifest_file = None
|
||||
self.gui_apps = {}
|
||||
self.console_apps = {}
|
||||
self.macos_main_app = None
|
||||
|
|
@ -316,7 +319,10 @@ class build_apps(setuptools.Command):
|
|||
'win_amd64',
|
||||
]
|
||||
|
||||
if sys.version_info >= (3, 13):
|
||||
if sys.version_info >= (3, 14):
|
||||
# This version of Python is only available for 10.15+.
|
||||
self.platforms[1] = 'macosx_10_15_x86_64'
|
||||
elif sys.version_info >= (3, 13):
|
||||
# This version of Python is only available for 10.13+.
|
||||
self.platforms[1] = 'macosx_10_13_x86_64'
|
||||
|
||||
|
|
@ -586,6 +592,10 @@ class build_apps(setuptools.Command):
|
|||
data_dir = os.path.join(build_dir, 'assets')
|
||||
os.makedirs(data_dir, exist_ok=True)
|
||||
|
||||
res_dir = os.path.join(build_dir, 'res')
|
||||
res_raw_dir = os.path.join(res_dir, 'raw')
|
||||
os.makedirs(res_raw_dir, exist_ok=True)
|
||||
|
||||
for abi in self.android_abis:
|
||||
lib_dir = os.path.join(build_dir, 'lib', abi)
|
||||
os.makedirs(lib_dir, exist_ok=True)
|
||||
|
|
@ -602,7 +612,7 @@ class build_apps(setuptools.Command):
|
|||
|
||||
# We end up copying the data multiple times to the same
|
||||
# directory, but that's probably fine for now.
|
||||
self.build_binaries(platform + suffix, lib_dir, data_dir)
|
||||
self.build_binaries(platform + suffix, lib_dir, data_dir, res_raw_dir)
|
||||
|
||||
# Write out the icons to the res directory.
|
||||
for appname, icon in self.icon_objects.items():
|
||||
|
|
@ -610,9 +620,9 @@ class build_apps(setuptools.Command):
|
|||
# Conventional name for icon on Android.
|
||||
basename = 'ic_launcher.png'
|
||||
else:
|
||||
basename = f'ic_{appname}.png'
|
||||
appname_sane = appname.replace(' ', '_')
|
||||
basename = f'ic_{appname_sane}.png'
|
||||
|
||||
res_dir = os.path.join(build_dir, 'res')
|
||||
icon.writeSize(48, os.path.join(res_dir, 'mipmap-mdpi-v4', basename))
|
||||
icon.writeSize(72, os.path.join(res_dir, 'mipmap-hdpi-v4', basename))
|
||||
icon.writeSize(96, os.path.join(res_dir, 'mipmap-xhdpi-v4', basename))
|
||||
|
|
@ -623,8 +633,17 @@ class build_apps(setuptools.Command):
|
|||
|
||||
self.build_assets(platform, data_dir)
|
||||
|
||||
# Generate an AndroidManifest.xml
|
||||
self.generate_android_manifest(os.path.join(build_dir, 'AndroidManifest.xml'))
|
||||
# Generate an AndroidManifest.xml if none was provided
|
||||
manifest_path = os.path.join(build_dir, 'AndroidManifest.xml')
|
||||
if self.android_manifest_file:
|
||||
try:
|
||||
self.check_android_manifest(self.android_manifest_file)
|
||||
except Exception as e:
|
||||
self.announce(f"Failed to use provided manifest file from {self.android_manifest_file}", distutils.log.FATAL)
|
||||
raise
|
||||
self.copy(self.android_manifest_file, manifest_path)
|
||||
else:
|
||||
self.generate_android_manifest(manifest_path)
|
||||
else:
|
||||
self.build_binaries(platform, build_dir, build_dir)
|
||||
self.build_assets(platform, build_dir)
|
||||
|
|
@ -691,8 +710,14 @@ class build_apps(setuptools.Command):
|
|||
subprocess.check_call([sys.executable, '-m', 'pip'] + pip_args)
|
||||
except:
|
||||
# Display a more helpful message for these common issues.
|
||||
if platform.startswith('macosx_10_9_') and sys.version_info >= (3, 13):
|
||||
new_platform = platform.replace('macosx_10_9_', 'macosx_10_13_')
|
||||
if platform.startswith('macosx_10_13_') and sys.version_info >= (3, 14):
|
||||
new_platform = platform.replace('macosx_10_13_', 'macosx_10_15_')
|
||||
self.announce('This error likely occurs because {} is not a supported target as of Python 3.14.\nChange the target platform to {} instead.'.format(platform, new_platform), distutils.log.ERROR)
|
||||
elif platform.startswith('macosx_10_9_') and sys.version_info >= (3, 13):
|
||||
if sys.version_info >= (3, 14):
|
||||
new_platform = platform.replace('macosx_10_9_', 'macosx_10_15_')
|
||||
else:
|
||||
new_platform = platform.replace('macosx_10_9_', 'macosx_10_13_')
|
||||
self.announce('This error likely occurs because {} is not a supported target as of Python 3.13.\nChange the target platform to {} instead.'.format(platform, new_platform), distutils.log.ERROR)
|
||||
elif platform.startswith('manylinux2010_') and sys.version_info >= (3, 11):
|
||||
new_platform = platform.replace('manylinux2010_', 'manylinux2014_')
|
||||
|
|
@ -701,7 +726,9 @@ class build_apps(setuptools.Command):
|
|||
new_platform = platform.replace('manylinux1_', 'manylinux2014_')
|
||||
self.announce('This error likely occurs because {} is not a supported target as of Python 3.10.\nChange the target platform to {} instead.'.format(platform, new_platform), distutils.log.ERROR)
|
||||
elif platform.startswith('macosx_10_6_') and sys.version_info >= (3, 8):
|
||||
if sys.version_info >= (3, 13):
|
||||
if sys.version_info >= (3, 14):
|
||||
new_platform = platform.replace('macosx_10_6_', 'macosx_10_15_')
|
||||
elif sys.version_info >= (3, 13):
|
||||
new_platform = platform.replace('macosx_10_6_', 'macosx_10_13_')
|
||||
else:
|
||||
new_platform = platform.replace('macosx_10_6_', 'macosx_10_9_')
|
||||
|
|
@ -855,7 +882,7 @@ class build_apps(setuptools.Command):
|
|||
if category:
|
||||
application.set('android:appCategory', category)
|
||||
application.set('android:debuggable', ('false', 'true')[self.android_debuggable])
|
||||
application.set('android:extractNativeLibs', 'true')
|
||||
application.set('android:extractNativeLibs', 'false')
|
||||
application.set('android:hardwareAccelerated', 'true')
|
||||
|
||||
app_icon = self.icon_objects.get('*', self.icon_objects.get(self.macos_main_app))
|
||||
|
|
@ -863,6 +890,8 @@ class build_apps(setuptools.Command):
|
|||
application.set('android:icon', '@mipmap/ic_launcher')
|
||||
|
||||
for appname in self.gui_apps:
|
||||
appname_sane = appname.replace(' ', '_')
|
||||
|
||||
activity = ET.SubElement(application, 'activity')
|
||||
activity.set('android:name', 'org.panda3d.android.PythonActivity')
|
||||
activity.set('android:label', appname)
|
||||
|
|
@ -871,14 +900,19 @@ class build_apps(setuptools.Command):
|
|||
activity.set('android:configChanges', 'layoutDirection|locale|grammaticalGender|fontScale|fontWeightAdjustment|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation')
|
||||
activity.set('android:launchMode', 'singleInstance')
|
||||
activity.set('android:preferMinimalPostProcessing', 'true')
|
||||
activity.set('android:exported', 'true')
|
||||
|
||||
act_icon = self.icon_objects.get(appname)
|
||||
if act_icon and act_icon is not app_icon:
|
||||
activity.set('android:icon', '@mipmap/ic_' + appname)
|
||||
activity.set('android:icon', '@mipmap/ic_' + appname_sane)
|
||||
|
||||
meta_data = ET.SubElement(activity, 'meta-data')
|
||||
meta_data.set('android:name', 'android.app.lib_name')
|
||||
meta_data.set('android:value', appname)
|
||||
meta_data.set('android:value', appname_sane)
|
||||
|
||||
meta_data = ET.SubElement(activity, 'meta-data')
|
||||
meta_data.set('android:name', 'org.panda3d.android.BLOB_RESOURCE')
|
||||
meta_data.set('android:resource', '@raw/' + appname_sane + '.so')
|
||||
|
||||
intent_filter = ET.SubElement(activity, 'intent-filter')
|
||||
ET.SubElement(intent_filter, 'action').set('android:name', 'android.intent.action.MAIN')
|
||||
|
|
@ -886,10 +920,44 @@ class build_apps(setuptools.Command):
|
|||
ET.SubElement(intent_filter, 'category').set('android:name', 'android.intent.category.LEANBACK_LAUNCHER')
|
||||
|
||||
tree = ET.ElementTree(manifest)
|
||||
if sys.version_info >= (3, 9):
|
||||
ET.indent(tree)
|
||||
with open(path, 'wb') as fh:
|
||||
tree.write(fh, encoding='utf-8', xml_declaration=True)
|
||||
|
||||
def build_binaries(self, platform, binary_dir, data_dir=None):
|
||||
def check_android_manifest(self, path):
|
||||
""" Checks that the user-provided manifest file seems OK. """
|
||||
|
||||
# This function doesn't aim to check everything as it's the user's
|
||||
# responsibility, just a basic sanity check, but if we change anything
|
||||
# in our own generation logic then it would be good to check those
|
||||
# things here and warn if anything needs to be updated.
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
android = '{http://schemas.android.com/apk/res/android}'
|
||||
|
||||
tree = ET.parse(path)
|
||||
root = tree.getroot()
|
||||
if root.tag != 'manifest':
|
||||
raise RuntimeError(f"Expected <manifest> in {path}")
|
||||
|
||||
if root.attrib['package'] != self.application_id:
|
||||
raise RuntimeError(f"<manifest> package attribute does not match given application_id {self.application_id}")
|
||||
|
||||
apps = root.findall('application')
|
||||
if len(apps) != 1:
|
||||
raise RuntimeError("<manifest> must contain exactly one <application>")
|
||||
|
||||
application = apps[0]
|
||||
for activity in application.iter('activity'):
|
||||
if f'{android}name' not in activity.attrib:
|
||||
raise RuntimeError("<activity> element must have android:name attribute")
|
||||
|
||||
if self.android_target_sdk_version >= 31 and f'{android}exported' not in activity.attrib:
|
||||
raise RuntimeError("<activity> element must have android:exported attribute when targeting Android API 31+")
|
||||
|
||||
def build_binaries(self, platform, binary_dir, data_dir=None, blob_dir=None):
|
||||
""" Builds the binary data for the given platform. """
|
||||
|
||||
use_wheels = True
|
||||
|
|
@ -1085,13 +1153,26 @@ class build_apps(setuptools.Command):
|
|||
|
||||
stub_name = 'deploy-stub'
|
||||
target_name = appname
|
||||
appname_sane = appname
|
||||
if platform.startswith('win') or 'macosx' in platform:
|
||||
if not use_console:
|
||||
stub_name = 'deploy-stubw'
|
||||
elif platform.startswith('android'):
|
||||
if not use_console:
|
||||
stub_name = 'libdeploy-stubw.so'
|
||||
target_name = 'lib' + target_name + '.so'
|
||||
appname_sane = appname.replace(' ', '_')
|
||||
target_name = 'lib' + appname_sane + '.so'
|
||||
|
||||
if use_wheels:
|
||||
dexfile = os.path.join(binary_dir, '..', '..', 'classes.dex')
|
||||
self.copy(os.path.join(p3dwhlfn, 'deploy_libs', 'classes.dex'), dexfile)
|
||||
|
||||
# Can this wheel load the blob as a raw resource?
|
||||
with open(dexfile, 'rb') as fh:
|
||||
supports_blob_resource = b'org.panda3d.android.BLOB_RESOURCE' in fh.read()
|
||||
|
||||
assert supports_blob_resource, \
|
||||
"Please use a newer Panda3D wheel to build for Android using this version of build_apps"
|
||||
|
||||
if platform.startswith('win'):
|
||||
stub_name += '.exe'
|
||||
|
|
@ -1123,6 +1204,14 @@ class build_apps(setuptools.Command):
|
|||
if not self.log_filename or '%' not in self.log_filename:
|
||||
use_strftime = False
|
||||
|
||||
blob_path = None
|
||||
if blob_dir is not None:
|
||||
if platform.startswith('android'):
|
||||
# Not really a .so file, but it forces bundletool to align it
|
||||
blob_path = os.path.join(blob_dir, appname_sane + '.so')
|
||||
else:
|
||||
blob_path = os.path.join(blob_dir, appname_sane)
|
||||
|
||||
target_path = os.path.join(binary_dir, target_name)
|
||||
freezer.generateRuntimeFromStub(target_path, stub_file, use_console, {
|
||||
'prc_data': prcexport if self.embed_prc_data else None,
|
||||
|
|
@ -1136,7 +1225,7 @@ class build_apps(setuptools.Command):
|
|||
'prc_executable_args_envvar': None,
|
||||
'main_dir': None,
|
||||
'log_filename': self.expand_path(self.log_filename, platform),
|
||||
}, self.log_append, use_strftime)
|
||||
}, self.log_append, use_strftime, blob_path)
|
||||
stub_file.close()
|
||||
|
||||
if temp_file:
|
||||
|
|
@ -1251,11 +1340,6 @@ class build_apps(setuptools.Command):
|
|||
search_path = get_search_path_for(source_path)
|
||||
self.copy_with_dependencies(source_path, target_path, search_path)
|
||||
|
||||
# Copy classes.dex on Android
|
||||
if use_wheels and platform.startswith('android'):
|
||||
self.copy(os.path.join(p3dwhlfn, 'deploy_libs', 'classes.dex'),
|
||||
os.path.join(binary_dir, '..', '..', 'classes.dex'))
|
||||
|
||||
# Extract any other data files from dependency packages.
|
||||
if data_dir is None:
|
||||
return
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ def create_aab(command, basename, build_dir):
|
|||
and use it to convert an .aab into an .apk.
|
||||
"""
|
||||
|
||||
from ._android import AndroidManifest, AbiAlias, BundleConfig, NativeLibraries, ResourceTable
|
||||
from ._android import AndroidManifest, AbiAlias, BundleConfig, NativeLibraries, ResourceTable, UncompressNativeLibraries
|
||||
|
||||
bundle_fn = p3d.Filename.from_os_specific(command.dist_dir) / (basename + '.aab')
|
||||
build_dir_fn = p3d.Filename.from_os_specific(build_dir)
|
||||
|
|
@ -230,7 +230,13 @@ def create_aab(command, basename, build_dir):
|
|||
config = BundleConfig()
|
||||
config.bundletool.version = '1.1.0'
|
||||
config.optimizations.splits_config.Clear()
|
||||
config.optimizations.uncompress_native_libraries.enabled = False
|
||||
if axml.extract_native_libs:
|
||||
config.optimizations.uncompress_native_libraries.enabled = False
|
||||
else:
|
||||
config.optimizations.uncompress_native_libraries.enabled = True
|
||||
config.optimizations.uncompress_native_libraries.alignment = \
|
||||
UncompressNativeLibraries.PageAlignment.PAGE_ALIGNMENT_16K
|
||||
config.compression.uncompressed_glob.append('res/raw/**')
|
||||
bundle.add_subfile('BundleConfig.pb', p3d.StringStream(config.SerializeToString()), 9)
|
||||
|
||||
resources = ResourceTable()
|
||||
|
|
@ -251,13 +257,25 @@ def create_aab(command, basename, build_dir):
|
|||
entry.entry_id.id = entry_id
|
||||
entry.name = res_name
|
||||
|
||||
for density, tag in (160, 'mdpi'), (240, 'hdpi'), (320, 'xhdpi'), (480, 'xxhdpi'), (640, 'xxxhdpi'):
|
||||
path = f'res/mipmap-{tag}-v4/{res_name}.png'
|
||||
if (build_dir_fn / path).exists():
|
||||
bundle.add_subfile('base/' + path, build_dir_fn / path, 0)
|
||||
config_value = entry.config_value.add()
|
||||
config_value.config.density = density
|
||||
config_value.value.item.file.path = path
|
||||
if type_name == 'raw':
|
||||
path = f'res/raw/{res_name}'
|
||||
if not (build_dir_fn / path).exists():
|
||||
command.announce(
|
||||
f'\tRaw resource {path} was not found on disk', distutils.log.ERROR)
|
||||
return
|
||||
|
||||
# These are aligned to page size for mmap.
|
||||
bundle.add_subfile('base/' + path, build_dir_fn / path, 0, 16384)
|
||||
config_value = entry.config_value.add()
|
||||
config_value.value.item.file.path = path
|
||||
else:
|
||||
for density, tag in (120, 'ldpi'), (160, 'mdpi'), (240, 'hdpi'), (320, 'xhdpi'), (480, 'xxhdpi'), (640, 'xxxhdpi'):
|
||||
path = f'res/mipmap-{tag}-v4/{res_name}.png'
|
||||
if (build_dir_fn / path).exists():
|
||||
bundle.add_subfile('base/' + path, build_dir_fn / path, 0)
|
||||
config_value = entry.config_value.add()
|
||||
config_value.config.density = density
|
||||
config_value.value.item.file.path = path
|
||||
|
||||
bundle.add_subfile('base/resources.pb', p3d.StringStream(resources.SerializeToString()), 9)
|
||||
|
||||
|
|
@ -273,13 +291,25 @@ def create_aab(command, basename, build_dir):
|
|||
# Add the classes.dex.
|
||||
bundle.add_subfile('base/dex/classes.dex', build_dir_fn / 'classes.dex', 9)
|
||||
|
||||
# Add libraries, compressed.
|
||||
# Add libraries, compressed, unless extractNativeLibs is false, in which
|
||||
# case they have to be aligned to page boundaries (16 KiB on 64-bit).
|
||||
lib_compress = 9 if axml.extract_native_libs else 0
|
||||
|
||||
for abi in os.listdir(os.path.join(build_dir, 'lib')):
|
||||
abi_dir = os.path.join(build_dir, 'lib', abi)
|
||||
|
||||
if axml.extract_native_libs:
|
||||
lib_align = 0
|
||||
elif '64' in abi:
|
||||
lib_align = 16384
|
||||
else:
|
||||
lib_align = 4096
|
||||
|
||||
for lib in os.listdir(abi_dir):
|
||||
if lib.startswith('lib') and lib.endswith('.so'):
|
||||
bundle.add_subfile(f'base/lib/{abi}/{lib}', build_dir_fn / 'lib' / abi / lib, 9)
|
||||
bundle.add_subfile(f'base/lib/{abi}/{lib}',
|
||||
build_dir_fn / 'lib' / abi / lib,
|
||||
lib_compress, lib_align)
|
||||
|
||||
# Add assets, compressed.
|
||||
assets_dir = os.path.join(build_dir, 'assets')
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class ClockDelta(DirectObject.DirectObject):
|
|||
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('ClockDelta')
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
self.globalClock = ClockObject.getGlobalClock()
|
||||
|
||||
# self.delta is the relative delta from our clock to the
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from panda3d.core import DocumentSpec, Filename, HTTPClient, VirtualFileSystem, getModelPath
|
||||
from panda3d.core import DocumentSpec, Filename, VirtualFileSystem, getModelPath
|
||||
from panda3d.direct import CConnectionRepository, DCPacker
|
||||
from direct.task import Task
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
|
|
@ -590,6 +590,7 @@ class ConnectionRepository(
|
|||
|
||||
if self.http is None:
|
||||
try:
|
||||
from panda3d.core import HTTPClient
|
||||
self.http = HTTPClient()
|
||||
except Exception:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ class DistributedObjectAI(DistributedObjectBase):
|
|||
# setLocation destroys self._zoneData if we move away to
|
||||
# a different zone
|
||||
if self._zoneData is None:
|
||||
from otp.ai.AIZoneData import AIZoneData # type: ignore[import]
|
||||
from otp.ai.AIZoneData import AIZoneData # type: ignore[import-not-found]
|
||||
self._zoneData = AIZoneData(self.air, self.parentId, self.zoneId)
|
||||
return self._zoneData
|
||||
|
||||
|
|
@ -515,7 +515,7 @@ class DistributedObjectAI(DistributedObjectBase):
|
|||
# simultaneously on different lists of avatars, although they
|
||||
# should have different names.
|
||||
|
||||
from otp.ai import Barrier # type: ignore[import]
|
||||
from otp.ai import Barrier # type: ignore[import-not-found]
|
||||
context = self.__nextBarrierContext
|
||||
# We assume the context number is passed as a uint16.
|
||||
self.__nextBarrierContext = (self.__nextBarrierContext + 1) & 0xffff
|
||||
|
|
|
|||
|
|
@ -432,7 +432,7 @@ class DistributedObjectUD(DistributedObjectBase):
|
|||
# simultaneously on different lists of avatars, although they
|
||||
# should have different names.
|
||||
|
||||
from otp.ai import Barrier # type: ignore[import]
|
||||
from otp.ai import Barrier # type: ignore[import-not-found]
|
||||
context = self.__nextBarrierContext
|
||||
# We assume the context number is passed as a uint16.
|
||||
self.__nextBarrierContext = (self.__nextBarrierContext + 1) & 0xffff
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@ dclass DistributedSmoothNode: DistributedNode {
|
|||
|
||||
suggestResync(uint32 avId, int16 timestampA, int16 timestampB,
|
||||
int32 serverTimeSec, uint16 serverTimeUSec,
|
||||
uint16 / 100 uncertainty);
|
||||
int16 / 100 uncertainty);
|
||||
returnResync(uint32 avId, int16 timestampB,
|
||||
int32 serverTimeSec, uint16 serverTimeUSec,
|
||||
uint16 / 100 uncertainty);
|
||||
int16 / 100 uncertainty);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
from __future__ import annotations
|
||||
|
||||
__all__ = ["Dtool_ObjectToDict", "Dtool_funcToMethod"]
|
||||
|
||||
from collections.abc import Callable
|
||||
|
||||
|
||||
def Dtool_ObjectToDict(cls, name, obj):
|
||||
cls.DtoolClassDict[name] = obj
|
||||
|
||||
|
||||
def Dtool_funcToMethod(func, cls, method_name=None):
|
||||
def Dtool_funcToMethod(func: Callable, cls, method_name: str | None = None) -> None:
|
||||
"""Adds func to class so it is an accessible method; use method_name to specify the name to be used for calling the method.
|
||||
The new method is accessible to any instance immediately."""
|
||||
func.__func__ = func
|
||||
func.__self__ = None
|
||||
func.__func__ = func # type: ignore[attr-defined]
|
||||
func.__self__ = None # type: ignore[attr-defined]
|
||||
if not method_name:
|
||||
method_name = func.__name__
|
||||
cls.DtoolClassDict[method_name] = func
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ class DirectButton(DirectFrame):
|
|||
# Sounds to be used for button events
|
||||
('rolloverSound', DGG.getDefaultRolloverSound(), self.setRolloverSound),
|
||||
('clickSound', DGG.getDefaultClickSound(), self.setClickSound),
|
||||
('releaseSound', DGG.getDefaultReleaseSound(), self.setReleaseSound),
|
||||
# Can only be specified at time of widget contruction
|
||||
# Do the text/graphics appear to move when the button is clicked
|
||||
('pressEffect', 1, DGG.INITOPT),
|
||||
|
|
@ -108,6 +109,13 @@ class DirectButton(DirectFrame):
|
|||
# Pass any extra args to command
|
||||
self['command'](*self['extraArgs'])
|
||||
|
||||
def setRolloverSound(self):
|
||||
rolloverSound = self['rolloverSound']
|
||||
if rolloverSound:
|
||||
self.guiItem.setSound(DGG.ENTER + self.guiId, rolloverSound)
|
||||
else:
|
||||
self.guiItem.clearSound(DGG.ENTER + self.guiId)
|
||||
|
||||
def setClickSound(self):
|
||||
clickSound = self['clickSound']
|
||||
# Clear out sounds
|
||||
|
|
@ -122,9 +130,16 @@ class DirectButton(DirectFrame):
|
|||
if DGG.RMB in self['commandButtons']:
|
||||
self.guiItem.setSound(DGG.B3PRESS + self.guiId, clickSound)
|
||||
|
||||
def setRolloverSound(self):
|
||||
rolloverSound = self['rolloverSound']
|
||||
if rolloverSound:
|
||||
self.guiItem.setSound(DGG.ENTER + self.guiId, rolloverSound)
|
||||
else:
|
||||
self.guiItem.clearSound(DGG.ENTER + self.guiId)
|
||||
def setReleaseSound(self):
|
||||
releaseSound = self['releaseSound']
|
||||
# Clear out sounds
|
||||
self.guiItem.clearSound(DGG.B1RELEASE + self.guiId)
|
||||
self.guiItem.clearSound(DGG.B2RELEASE + self.guiId)
|
||||
self.guiItem.clearSound(DGG.B3RELEASE + self.guiId)
|
||||
if releaseSound:
|
||||
if DGG.LMB in self['commandButtons']:
|
||||
self.guiItem.setSound(DGG.B1RELEASE + self.guiId, releaseSound)
|
||||
if DGG.MMB in self['commandButtons']:
|
||||
self.guiItem.setSound(DGG.B2RELEASE + self.guiId, releaseSound)
|
||||
if DGG.RMB in self['commandButtons']:
|
||||
self.guiItem.setSound(DGG.B3RELEASE + self.guiId, releaseSound)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ class DirectCheckBox(DirectButton):
|
|||
# Sounds to be used for button events
|
||||
('rolloverSound', DGG.getDefaultRolloverSound(), self.setRolloverSound),
|
||||
('clickSound', DGG.getDefaultClickSound(), self.setClickSound),
|
||||
('releaseSound', DGG.getDefaultReleaseSound(), self.setReleaseSound),
|
||||
# Can only be specified at time of widget contruction
|
||||
# Do the text/graphics appear to move when the button is clicked
|
||||
('pressEffect', 1, DGG.INITOPT),
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@ from panda3d.core import (
|
|||
|
||||
defaultFont = None
|
||||
defaultFontFunc = TextNode.getDefaultFont
|
||||
defaultClickSound = None
|
||||
defaultRolloverSound = None
|
||||
defaultClickSound = None
|
||||
defaultReleaseSound = None
|
||||
defaultDialogGeom = None
|
||||
defaultDialogRelief = PGFrameStyle.TBevelOut
|
||||
drawOrder = 100
|
||||
|
|
@ -129,6 +130,13 @@ def setDefaultClickSound(newSound):
|
|||
global defaultClickSound
|
||||
defaultClickSound = newSound
|
||||
|
||||
def getDefaultReleaseSound():
|
||||
return defaultReleaseSound
|
||||
|
||||
def setDefaultReleaseSound(newSound):
|
||||
global defaultReleaseSound
|
||||
defaultReleaseSound = newSound
|
||||
|
||||
def getDefaultFont():
|
||||
global defaultFont
|
||||
if defaultFont is None:
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
"""Defines the IntervalManager class as well as the global instance of
|
||||
this class, ivalMgr."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = ['IntervalManager', 'ivalMgr']
|
||||
|
||||
from panda3d.core import EventQueue
|
||||
from panda3d.direct import CIntervalManager, Dtool_BorrowThisReference
|
||||
from panda3d.direct import CInterval, CIntervalManager, Dtool_BorrowThisReference
|
||||
from direct.showbase import EventManager
|
||||
from . import Interval
|
||||
import fnmatch
|
||||
|
||||
class IntervalManager(CIntervalManager):
|
||||
|
|
@ -15,7 +18,7 @@ class IntervalManager(CIntervalManager):
|
|||
# the Python extensions is to add support for Python-based
|
||||
# intervals (like MetaIntervals).
|
||||
|
||||
def __init__(self, globalPtr = 0):
|
||||
def __init__(self, globalPtr: bool = False) -> None:
|
||||
# Pass globalPtr == 1 to the constructor to trick it into
|
||||
# "constructing" a Python wrapper around the global
|
||||
# CIntervalManager object.
|
||||
|
|
@ -28,8 +31,8 @@ class IntervalManager(CIntervalManager):
|
|||
self.eventQueue = EventQueue()
|
||||
self.MyEventmanager = EventManager.EventManager(self.eventQueue)
|
||||
self.setEventQueue(self.eventQueue)
|
||||
self.ivals = []
|
||||
self.removedIvals = {}
|
||||
self.ivals: list[Interval.Interval | CInterval | None] = []
|
||||
self.removedIvals: dict = {}
|
||||
|
||||
def addInterval(self, interval):
|
||||
index = self.addCInterval(interval, 1)
|
||||
|
|
@ -86,7 +89,7 @@ class IntervalManager(CIntervalManager):
|
|||
ival.pause()
|
||||
return len(ivals)
|
||||
|
||||
def step(self):
|
||||
def step(self) -> None:
|
||||
# This method should be called once per frame to perform all
|
||||
# of the per-frame processing on the active intervals.
|
||||
# Call C++ step, then do the Python stuff.
|
||||
|
|
@ -101,7 +104,7 @@ class IntervalManager(CIntervalManager):
|
|||
CIntervalManager.interrupt(self)
|
||||
self.__doPythonCallbacks()
|
||||
|
||||
def __doPythonCallbacks(self):
|
||||
def __doPythonCallbacks(self) -> None:
|
||||
# This method does all of the required Python post-processing
|
||||
# after performing some C++-level action.
|
||||
# It is important to call all of the python callbacks on the
|
||||
|
|
@ -137,4 +140,4 @@ class IntervalManager(CIntervalManager):
|
|||
self.ivals[index] = interval
|
||||
|
||||
#: The global IntervalManager object.
|
||||
ivalMgr = IntervalManager(1)
|
||||
ivalMgr = IntervalManager(True)
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ class LerpPosInterval(LerpNodePathInterval):
|
|||
def privDoEvent(self, t, event):
|
||||
# This function is only used if Python functors were passed in
|
||||
# for some of the input parameters.
|
||||
if self.paramSetup and event == CInterval.ETInitialize:
|
||||
if self.paramSetup and (event == CInterval.ETInitialize or event == CInterval.ETInstant):
|
||||
self.setupParam(self.setEndPos, self.endPos)
|
||||
self.setupParam(self.setStartPos, self.startPos)
|
||||
LerpNodePathInterval.privDoEvent(self, t, event)
|
||||
|
|
@ -153,7 +153,7 @@ class LerpHprInterval(LerpNodePathInterval):
|
|||
def privDoEvent(self, t, event):
|
||||
# This function is only used if Python functors were passed in
|
||||
# for some of the input parameters.
|
||||
if self.paramSetup and event == CInterval.ETInitialize:
|
||||
if self.paramSetup and (event == CInterval.ETInitialize or event == CInterval.ETInstant):
|
||||
self.setupParam(self.setEndHpr, self.endHpr)
|
||||
self.setupParam(self.setStartHpr, self.startHpr)
|
||||
self.setupParam(self.setStartQuat, self.startQuat)
|
||||
|
|
@ -192,7 +192,7 @@ class LerpQuatInterval(LerpNodePathInterval):
|
|||
def privDoEvent(self, t, event):
|
||||
# This function is only used if Python functors were passed in
|
||||
# for some of the input parameters.
|
||||
if self.paramSetup and event == CInterval.ETInitialize:
|
||||
if self.paramSetup and (event == CInterval.ETInitialize or event == CInterval.ETInstant):
|
||||
self.setupParam(self.setEndQuat, self.endQuat)
|
||||
self.setupParam(self.setStartHpr, self.startHpr)
|
||||
self.setupParam(self.setStartQuat, self.startQuat)
|
||||
|
|
@ -219,7 +219,7 @@ class LerpScaleInterval(LerpNodePathInterval):
|
|||
def privDoEvent(self, t, event):
|
||||
# This function is only used if Python functors were passed in
|
||||
# for some of the input parameters.
|
||||
if self.paramSetup and event == CInterval.ETInitialize:
|
||||
if self.paramSetup and (event == CInterval.ETInitialize or event == CInterval.ETInstant):
|
||||
self.setupParam(self.setEndScale, self.endScale)
|
||||
self.setupParam(self.setStartScale, self.startScale)
|
||||
LerpNodePathInterval.privDoEvent(self, t, event)
|
||||
|
|
@ -245,7 +245,7 @@ class LerpShearInterval(LerpNodePathInterval):
|
|||
def privDoEvent(self, t, event):
|
||||
# This function is only used if Python functors were passed in
|
||||
# for some of the input parameters.
|
||||
if self.paramSetup and event == CInterval.ETInitialize:
|
||||
if self.paramSetup and (event == CInterval.ETInitialize or event == CInterval.ETInstant):
|
||||
self.setupParam(self.setEndShear, self.endShear)
|
||||
self.setupParam(self.setStartShear, self.startShear)
|
||||
LerpNodePathInterval.privDoEvent(self, t, event)
|
||||
|
|
@ -280,7 +280,7 @@ class LerpPosHprInterval(LerpNodePathInterval):
|
|||
def privDoEvent(self, t, event):
|
||||
# This function is only used if Python functors were passed in
|
||||
# for some of the input parameters.
|
||||
if self.paramSetup and event == CInterval.ETInitialize:
|
||||
if self.paramSetup and (event == CInterval.ETInitialize or event == CInterval.ETInstant):
|
||||
self.setupParam(self.setEndPos, self.endPos)
|
||||
self.setupParam(self.setStartPos, self.startPos)
|
||||
self.setupParam(self.setEndHpr, self.endHpr)
|
||||
|
|
@ -326,7 +326,7 @@ class LerpPosQuatInterval(LerpNodePathInterval):
|
|||
def privDoEvent(self, t, event):
|
||||
# This function is only used if Python functors were passed in
|
||||
# for some of the input parameters.
|
||||
if self.paramSetup and event == CInterval.ETInitialize:
|
||||
if self.paramSetup and (event == CInterval.ETInitialize or event == CInterval.ETInstant):
|
||||
self.setupParam(self.setEndPos, self.endPos)
|
||||
self.setupParam(self.setStartPos, self.startPos)
|
||||
self.setupParam(self.setEndQuat, self.endQuat)
|
||||
|
|
@ -365,7 +365,7 @@ class LerpHprScaleInterval(LerpNodePathInterval):
|
|||
def privDoEvent(self, t, event):
|
||||
# This function is only used if Python functors were passed in
|
||||
# for some of the input parameters.
|
||||
if self.paramSetup and event == CInterval.ETInitialize:
|
||||
if self.paramSetup and (event == CInterval.ETInitialize or event == CInterval.ETInstant):
|
||||
self.setupParam(self.setEndHpr, self.endHpr)
|
||||
self.setupParam(self.setStartHpr, self.startHpr)
|
||||
self.setupParam(self.setStartQuat, self.startQuat)
|
||||
|
|
@ -414,7 +414,7 @@ class LerpQuatScaleInterval(LerpNodePathInterval):
|
|||
def privDoEvent(self, t, event):
|
||||
# This function is only used if Python functors were passed in
|
||||
# for some of the input parameters.
|
||||
if self.paramSetup and event == CInterval.ETInitialize:
|
||||
if self.paramSetup and (event == CInterval.ETInitialize or event == CInterval.ETInstant):
|
||||
self.setupParam(self.setEndQuat, self.endQuat)
|
||||
self.setupParam(self.setStartHpr, self.startHpr)
|
||||
self.setupParam(self.setStartQuat, self.startQuat)
|
||||
|
|
@ -459,7 +459,7 @@ class LerpPosHprScaleInterval(LerpNodePathInterval):
|
|||
def privDoEvent(self, t, event):
|
||||
# This function is only used if Python functors were passed in
|
||||
# for some of the input parameters.
|
||||
if self.paramSetup and event == CInterval.ETInitialize:
|
||||
if self.paramSetup and (event == CInterval.ETInitialize or event == CInterval.ETInstant):
|
||||
self.setupParam(self.setEndPos, self.endPos)
|
||||
self.setupParam(self.setStartPos, self.startPos)
|
||||
self.setupParam(self.setEndHpr, self.endHpr)
|
||||
|
|
@ -516,7 +516,7 @@ class LerpPosQuatScaleInterval(LerpNodePathInterval):
|
|||
def privDoEvent(self, t, event):
|
||||
# This function is only used if Python functors were passed in
|
||||
# for some of the input parameters.
|
||||
if self.paramSetup and event == CInterval.ETInitialize:
|
||||
if self.paramSetup and (event == CInterval.ETInitialize or event == CInterval.ETInstant):
|
||||
self.setupParam(self.setEndPos, self.endPos)
|
||||
self.setupParam(self.setStartPos, self.startPos)
|
||||
self.setupParam(self.setEndQuat, self.endQuat)
|
||||
|
|
@ -569,7 +569,7 @@ class LerpPosHprScaleShearInterval(LerpNodePathInterval):
|
|||
def privDoEvent(self, t, event):
|
||||
# This function is only used if Python functors were passed in
|
||||
# for some of the input parameters.
|
||||
if self.paramSetup and event == CInterval.ETInitialize:
|
||||
if self.paramSetup and (event == CInterval.ETInitialize or event == CInterval.ETInstant):
|
||||
self.setupParam(self.setEndPos, self.endPos)
|
||||
self.setupParam(self.setStartPos, self.startPos)
|
||||
self.setupParam(self.setEndHpr, self.endHpr)
|
||||
|
|
@ -636,7 +636,7 @@ class LerpPosQuatScaleShearInterval(LerpNodePathInterval):
|
|||
def privDoEvent(self, t, event):
|
||||
# This function is only used if Python functors were passed in
|
||||
# for some of the input parameters.
|
||||
if self.paramSetup and event == CInterval.ETInitialize:
|
||||
if self.paramSetup and (event == CInterval.ETInitialize or event == CInterval.ETInstant):
|
||||
self.setupParam(self.setEndPos, self.endPos)
|
||||
self.setupParam(self.setStartPos, self.startPos)
|
||||
self.setupParam(self.setEndQuat, self.endQuat)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ Or, you can enable the following variable in your Config.prc::
|
|||
show-buffers true
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = ['BufferViewer']
|
||||
|
||||
from panda3d.core import (
|
||||
|
|
@ -39,14 +41,19 @@ from direct.task.TaskManagerGlobal import taskMgr
|
|||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
import math
|
||||
from typing import Literal, Union
|
||||
|
||||
# The following variables are typing constructs used in annotations
|
||||
# to succinctly express complex type structures.
|
||||
_Texture = Union[Texture, GraphicsOutput, Literal['all']]
|
||||
|
||||
|
||||
class BufferViewer(DirectObject):
|
||||
notify = directNotify.newCategory('BufferViewer')
|
||||
|
||||
def __init__(self, win, parent):
|
||||
def __init__(self, win: GraphicsOutput | None, parent: NodePath) -> None:
|
||||
"""Access: private. Constructor."""
|
||||
self.enabled = 0
|
||||
self.enabled = False
|
||||
size = ConfigVariableDouble('buffer-viewer-size', '0 0')
|
||||
self.sizex = size[0]
|
||||
self.sizey = size[1]
|
||||
|
|
@ -59,23 +66,23 @@ class BufferViewer(DirectObject):
|
|||
self.win = win
|
||||
self.engine = GraphicsEngine.getGlobalPtr()
|
||||
self.renderParent = parent
|
||||
self.cards = []
|
||||
self.cards: list[NodePath] = []
|
||||
self.cardindex = 0
|
||||
self.cardmaker = CardMaker("cubemaker")
|
||||
self.cardmaker.setFrame(-1,1,-1,1)
|
||||
self.task = 0
|
||||
self.dirty = 1
|
||||
self.dirty = True
|
||||
self.accept("render-texture-targets-changed", self.refreshReadout)
|
||||
if ConfigVariableBool("show-buffers", 0):
|
||||
self.enable(1)
|
||||
self.enable(True)
|
||||
|
||||
def refreshReadout(self):
|
||||
def refreshReadout(self) -> None:
|
||||
"""Force the readout to be refreshed. This is usually invoked
|
||||
by GraphicsOutput::add_render_texture (via an event handler).
|
||||
However, it is also possible to invoke it manually. Currently,
|
||||
the only time I know of that this is necessary is after a
|
||||
window resize (and I ought to fix that)."""
|
||||
self.dirty = 1
|
||||
self.dirty = True
|
||||
|
||||
# Call enabled again, mainly to ensure that the task has been
|
||||
# started.
|
||||
|
|
@ -95,14 +102,14 @@ class BufferViewer(DirectObject):
|
|||
"""Returns true if the buffer viewer is currently enabled."""
|
||||
return self.enabled
|
||||
|
||||
def enable(self, x):
|
||||
def enable(self, x: bool) -> None:
|
||||
"""Turn the buffer viewer on or off. The initial state of the
|
||||
buffer viewer depends on the Config variable 'show-buffers'."""
|
||||
if x != 0 and x != 1:
|
||||
BufferViewer.notify.error('invalid parameter to BufferViewer.enable')
|
||||
return
|
||||
self.enabled = x
|
||||
self.dirty = 1
|
||||
self.dirty = True
|
||||
if (x and self.task == 0):
|
||||
self.task = taskMgr.add(self.maintainReadout, "buffer-viewer-maintain-readout",
|
||||
priority=1)
|
||||
|
|
@ -218,7 +225,11 @@ class BufferViewer(DirectObject):
|
|||
self.renderParent = renderParent
|
||||
self.dirty = 1
|
||||
|
||||
def analyzeTextureSet(self, x, set):
|
||||
def analyzeTextureSet(
|
||||
self,
|
||||
x: _Texture | GraphicsEngine | list[_Texture | GraphicsEngine],
|
||||
set: dict[Texture, int],
|
||||
) -> None:
|
||||
"""Access: private. Converts a list of GraphicsObject,
|
||||
GraphicsEngine, and Texture into a table of Textures."""
|
||||
|
||||
|
|
@ -240,7 +251,7 @@ class BufferViewer(DirectObject):
|
|||
else:
|
||||
return
|
||||
|
||||
def makeFrame(self, sizex, sizey):
|
||||
def makeFrame(self, sizex: int, sizey: int) -> NodePath:
|
||||
"""Access: private. Each texture card is displayed with
|
||||
a two-pixel wide frame (a ring of black and a ring of white).
|
||||
This routine builds the frame geometry. It is necessary to
|
||||
|
|
@ -287,7 +298,7 @@ class BufferViewer(DirectObject):
|
|||
geomnode.addGeom(geom)
|
||||
return NodePath(geomnode)
|
||||
|
||||
def maintainReadout(self, task):
|
||||
def maintainReadout(self, task: object) -> int:
|
||||
"""Access: private. Whenever necessary, rebuilds the entire
|
||||
display from scratch. This is only done when the configuration
|
||||
parameters have changed."""
|
||||
|
|
@ -295,7 +306,7 @@ class BufferViewer(DirectObject):
|
|||
# If nothing has changed, don't update.
|
||||
if not self.dirty:
|
||||
return Task.cont
|
||||
self.dirty = 0
|
||||
self.dirty = False
|
||||
|
||||
# Delete the old set of cards.
|
||||
for card in self.cards:
|
||||
|
|
@ -308,8 +319,8 @@ class BufferViewer(DirectObject):
|
|||
return Task.done
|
||||
|
||||
# Generate the include and exclude sets.
|
||||
exclude = {}
|
||||
include = {}
|
||||
exclude: dict[Texture, int] = {}
|
||||
include: dict[Texture, int] = {}
|
||||
self.analyzeTextureSet(self.exclude, exclude)
|
||||
self.analyzeTextureSet(self.include, include)
|
||||
|
||||
|
|
@ -407,6 +418,7 @@ class BufferViewer(DirectObject):
|
|||
|
||||
bordersize = 4.0
|
||||
|
||||
assert self.win is not None
|
||||
if float(self.sizex) == 0.0 and float(self.sizey) == 0.0:
|
||||
sizey = int(0.4266666667 * self.win.getYSize())
|
||||
sizex = (sizey * aspectx) // aspecty
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
"""Defines the DirectObject class, a convenient class to inherit from if the
|
||||
object needs to be able to respond to events."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = ['DirectObject']
|
||||
|
||||
from typing import Callable
|
||||
|
||||
from panda3d.core import AsyncTask
|
||||
|
||||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
from .MessengerGlobal import messenger
|
||||
|
|
@ -12,6 +18,9 @@ class DirectObject:
|
|||
"""
|
||||
This is the class that all Direct/SAL classes should inherit from
|
||||
"""
|
||||
_MSGRmessengerId: tuple[str, int]
|
||||
_taskList: dict[int, AsyncTask]
|
||||
|
||||
#def __del__(self):
|
||||
# This next line is useful for debugging leaks
|
||||
#print "Destructing: ", self.__class__.__name__
|
||||
|
|
@ -19,16 +28,16 @@ class DirectObject:
|
|||
# Wrapper functions to have a cleaner, more object oriented approach to
|
||||
# the messenger functionality.
|
||||
|
||||
def accept(self, event, method, extraArgs=[]):
|
||||
return messenger.accept(event, self, method, extraArgs, 1)
|
||||
def accept(self, event: str, method: Callable, extraArgs: list = []) -> None:
|
||||
return messenger.accept(event, self, method, extraArgs, True)
|
||||
|
||||
def acceptOnce(self, event, method, extraArgs=[]):
|
||||
return messenger.accept(event, self, method, extraArgs, 0)
|
||||
|
||||
def ignore(self, event):
|
||||
def ignore(self, event: str) -> None:
|
||||
return messenger.ignore(event, self)
|
||||
|
||||
def ignoreAll(self):
|
||||
def ignoreAll(self) -> None:
|
||||
return messenger.ignoreAll(self)
|
||||
|
||||
def isAccepting(self, event):
|
||||
|
|
@ -41,7 +50,7 @@ class DirectObject:
|
|||
return messenger.isIgnoring(event, self)
|
||||
|
||||
#This function must be used if you want a managed task
|
||||
def addTask(self, *args, **kwargs):
|
||||
def addTask(self, *args, **kwargs) -> AsyncTask:
|
||||
if not hasattr(self, "_taskList"):
|
||||
self._taskList = {}
|
||||
kwargs['owner'] = self
|
||||
|
|
|
|||
|
|
@ -1,21 +1,33 @@
|
|||
"""Contains the EventManager class. See :mod:`.EventManagerGlobal` for the
|
||||
global eventMgr instance."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = ['EventManager']
|
||||
|
||||
|
||||
from typing import Any
|
||||
|
||||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||
from direct.directnotify.Notifier import Notifier
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
from direct.showbase.MessengerGlobal import messenger
|
||||
from panda3d.core import PStatCollector, EventQueue, EventHandler
|
||||
from panda3d.core import ConfigVariableBool
|
||||
from panda3d.core import (
|
||||
ConfigVariableBool,
|
||||
Event,
|
||||
EventHandler,
|
||||
EventParameter,
|
||||
EventQueue,
|
||||
PStatCollector,
|
||||
PythonTask,
|
||||
)
|
||||
|
||||
|
||||
class EventManager:
|
||||
|
||||
notify = None
|
||||
notify: Notifier | None = None
|
||||
|
||||
def __init__(self, eventQueue = None):
|
||||
def __init__(self, eventQueue: EventQueue | None = None) -> None:
|
||||
"""
|
||||
Create a C++ event queue and handler
|
||||
"""
|
||||
|
|
@ -24,11 +36,11 @@ class EventManager:
|
|||
EventManager.notify = directNotify.newCategory("EventManager")
|
||||
|
||||
self.eventQueue = eventQueue
|
||||
self.eventHandler = None
|
||||
self.eventHandler: EventHandler | None = None
|
||||
|
||||
self._wantPstats = ConfigVariableBool('pstats-eventmanager', False)
|
||||
|
||||
def doEvents(self):
|
||||
def doEvents(self) -> None:
|
||||
"""
|
||||
Process all the events on the C++ event queue
|
||||
"""
|
||||
|
|
@ -38,12 +50,13 @@ class EventManager:
|
|||
processFunc = self.processEventPstats
|
||||
else:
|
||||
processFunc = self.processEvent
|
||||
assert self.eventQueue is not None
|
||||
isEmptyFunc = self.eventQueue.isQueueEmpty
|
||||
dequeueFunc = self.eventQueue.dequeueEvent
|
||||
while not isEmptyFunc():
|
||||
processFunc(dequeueFunc())
|
||||
|
||||
def eventLoopTask(self, task):
|
||||
def eventLoopTask(self, task: PythonTask) -> int:
|
||||
"""
|
||||
Process all the events on the C++ event queue
|
||||
"""
|
||||
|
|
@ -51,7 +64,7 @@ class EventManager:
|
|||
messenger.send("event-loop-done")
|
||||
return task.cont
|
||||
|
||||
def parseEventParameter(self, eventParameter):
|
||||
def parseEventParameter(self, eventParameter: EventParameter) -> Any:
|
||||
"""
|
||||
Extract the actual data from the eventParameter
|
||||
"""
|
||||
|
|
@ -63,6 +76,8 @@ class EventManager:
|
|||
return eventParameter.getStringValue()
|
||||
elif eventParameter.isWstring():
|
||||
return eventParameter.getWstringValue()
|
||||
elif hasattr(eventParameter, 'isBytes') and eventParameter.isBytes():
|
||||
return eventParameter.getBytesValue()
|
||||
elif eventParameter.isTypedRefCount():
|
||||
return eventParameter.getTypedRefCountValue()
|
||||
elif eventParameter.isEmpty():
|
||||
|
|
@ -72,7 +87,7 @@ class EventManager:
|
|||
# which will be downcast to that type.
|
||||
return eventParameter.getPtr()
|
||||
|
||||
def processEvent(self, event):
|
||||
def processEvent(self, event: Event) -> None:
|
||||
"""
|
||||
Process a C++ event
|
||||
Duplicate any changes in processEventPstats
|
||||
|
|
@ -89,6 +104,7 @@ class EventManager:
|
|||
paramList.append(eventParameterData)
|
||||
|
||||
# Do not print the new frame debug, it is too noisy!
|
||||
assert EventManager.notify is not None
|
||||
if EventManager.notify.getDebug() and eventName != 'NewFrame':
|
||||
EventManager.notify.debug('received C++ event named: ' + eventName +
|
||||
' parameters: ' + repr(paramList))
|
||||
|
|
@ -106,9 +122,10 @@ class EventManager:
|
|||
|
||||
else:
|
||||
# An unnamed event from C++ is probably a bad thing
|
||||
assert EventManager.notify is not None
|
||||
EventManager.notify.warning('unnamed event in processEvent')
|
||||
|
||||
def processEventPstats(self, event):
|
||||
def processEventPstats(self, event: Event) -> None:
|
||||
"""
|
||||
Process a C++ event with pstats tracking
|
||||
Duplicate any changes in processEvent
|
||||
|
|
@ -125,6 +142,7 @@ class EventManager:
|
|||
paramList.append(eventParameterData)
|
||||
|
||||
# Do not print the new frame debug, it is too noisy!
|
||||
assert EventManager.notify is not None
|
||||
if EventManager.notify.getDebug() and eventName != 'NewFrame':
|
||||
EventManager.notify.debug('received C++ event named: ' + eventName +
|
||||
' parameters: ' + repr(paramList))
|
||||
|
|
@ -156,9 +174,10 @@ class EventManager:
|
|||
|
||||
else:
|
||||
# An unnamed event from C++ is probably a bad thing
|
||||
assert EventManager.notify is not None
|
||||
EventManager.notify.warning('unnamed event in processEvent')
|
||||
|
||||
def restart(self):
|
||||
def restart(self) -> None:
|
||||
if self.eventQueue is None:
|
||||
self.eventQueue = EventQueue.getGlobalEventQueue()
|
||||
|
||||
|
|
@ -173,7 +192,7 @@ class EventManager:
|
|||
|
||||
taskMgr.add(self.eventLoopTask, 'eventManager')
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
taskMgr.remove('eventManager')
|
||||
|
||||
# Flush the event queue. We do this after removing the task
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ def _varDump__init__(self, *args, **kArgs):
|
|||
sReentry = 0
|
||||
|
||||
|
||||
def _varDump__print(exc):
|
||||
def _varDump__print(exc) -> None:
|
||||
global sReentry
|
||||
global notify
|
||||
if sReentry > 0:
|
||||
|
|
@ -176,7 +176,7 @@ def _excepthookDumpVars(eType, eValue, tb):
|
|||
oldExcepthook(eType, eValue, origTb)
|
||||
|
||||
|
||||
def install(log, upload):
|
||||
def install(log: bool, upload: bool) -> None:
|
||||
"""Installs the exception hook."""
|
||||
global oldExcepthook
|
||||
global wantStackDumpLog
|
||||
|
|
@ -192,8 +192,8 @@ def install(log, upload):
|
|||
# thrown by the interpreter don't get created until the
|
||||
# stack has been unwound and an except block has been reached
|
||||
if not hasattr(Exception, '_moved__init__'):
|
||||
Exception._moved__init__ = Exception.__init__
|
||||
Exception.__init__ = _varDump__init__
|
||||
Exception._moved__init__ = Exception.__init__ # type: ignore[attr-defined]
|
||||
Exception.__init__ = _varDump__init__ # type: ignore[method-assign]
|
||||
else:
|
||||
if sys.excepthook is not _excepthookDumpVars:
|
||||
oldExcepthook = sys.excepthook
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
"""Contains utility classes for debugging memory leaks."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = ['FakeObject', '_createGarbage', 'GarbageReport', 'GarbageLogger']
|
||||
|
||||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||
|
|
@ -10,6 +12,7 @@ from direct.showbase.JobManagerGlobal import jobMgr
|
|||
from direct.showbase.MessengerGlobal import messenger
|
||||
from panda3d.core import ConfigVariableBool
|
||||
import gc
|
||||
from collections.abc import Callable
|
||||
|
||||
GarbageCycleCountAnnounceEvent = 'announceGarbageCycleDesc2num'
|
||||
|
||||
|
|
@ -41,9 +44,21 @@ class GarbageReport(Job):
|
|||
If you just want to dump the report to the log, use GarbageLogger."""
|
||||
notify = directNotify.newCategory("GarbageReport")
|
||||
|
||||
def __init__(self, name, log=True, verbose=False, fullReport=False, findCycles=True,
|
||||
threaded=False, doneCallback=None, autoDestroy=False, priority=None,
|
||||
safeMode=False, delOnly=False, collect=True):
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
log: bool = True,
|
||||
verbose: bool = False,
|
||||
fullReport: bool = False,
|
||||
findCycles: bool = True,
|
||||
threaded: bool = False,
|
||||
doneCallback: Callable[[GarbageReport], object] | None = None,
|
||||
autoDestroy: bool = False,
|
||||
priority: int | None = None,
|
||||
safeMode: bool = False,
|
||||
delOnly: bool = False,
|
||||
collect: bool = True
|
||||
) -> None:
|
||||
# if autoDestroy is True, GarbageReport will self-destroy after logging
|
||||
# if false, caller is responsible for calling destroy()
|
||||
# if threaded is True, processing will be performed over multiple frames
|
||||
|
|
@ -399,7 +414,7 @@ class GarbageReport(Job):
|
|||
if self._args.autoDestroy:
|
||||
self.destroy()
|
||||
|
||||
def destroy(self):
|
||||
def destroy(self) -> None:
|
||||
#print 'GarbageReport.destroy'
|
||||
del self._args
|
||||
del self.garbage
|
||||
|
|
@ -417,13 +432,13 @@ class GarbageReport(Job):
|
|||
del self._reportStr
|
||||
Job.destroy(self)
|
||||
|
||||
def getNumCycles(self):
|
||||
def getNumCycles(self) -> int:
|
||||
# if the job hasn't run yet, we don't have a numCycles yet
|
||||
return self.numCycles
|
||||
|
||||
def getDesc2numDict(self):
|
||||
def getDesc2numDict(self) -> dict[str, int]:
|
||||
# dict of python-syntax leak -> number of that type of leak
|
||||
desc2num = {}
|
||||
desc2num: dict[str, int] = {}
|
||||
for cycleBySyntax in self.cyclesBySyntax:
|
||||
desc2num.setdefault(cycleBySyntax, 0)
|
||||
desc2num[cycleBySyntax] += 1
|
||||
|
|
@ -563,7 +578,7 @@ class _CFGLGlobals:
|
|||
LastNumCycles = 0
|
||||
|
||||
|
||||
def checkForGarbageLeaks():
|
||||
def checkForGarbageLeaks() -> int:
|
||||
gc.collect()
|
||||
numGarbage = len(gc.garbage)
|
||||
if numGarbage > 0 and ConfigVariableBool('auto-garbage-logging', False):
|
||||
|
|
@ -576,6 +591,7 @@ def checkForGarbageLeaks():
|
|||
messenger.send(GarbageCycleCountAnnounceEvent, [gr.getDesc2numDict()])
|
||||
gr.destroy()
|
||||
notify = directNotify.newCategory("GarbageDetect")
|
||||
func: Callable[[str], object]
|
||||
if ConfigVariableBool('allow-garbage-cycles', True):
|
||||
func = notify.warning
|
||||
else:
|
||||
|
|
@ -584,7 +600,8 @@ def checkForGarbageLeaks():
|
|||
return numGarbage
|
||||
|
||||
|
||||
def b_checkForGarbageLeaks(wantReply=False):
|
||||
def b_checkForGarbageLeaks(wantReply: bool = False) -> int:
|
||||
from direct.showbase.ShowBaseGlobal import base, __dev__
|
||||
if not __dev__:
|
||||
return 0
|
||||
# does a garbage collect on the client and the AI
|
||||
|
|
@ -592,10 +609,10 @@ def b_checkForGarbageLeaks(wantReply=False):
|
|||
# logs leak info and terminates (if configured to do so)
|
||||
try:
|
||||
# if this is the client, tell the AI to check for leaks too
|
||||
base.cr.timeManager
|
||||
base.cr.timeManager # type: ignore[attr-defined]
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
if base.cr.timeManager:
|
||||
base.cr.timeManager.d_checkForGarbageLeaks(wantReply=wantReply)
|
||||
if base.cr.timeManager: # type: ignore[attr-defined]
|
||||
base.cr.timeManager.d_checkForGarbageLeaks(wantReply=wantReply) # type: ignore[attr-defined]
|
||||
return checkForGarbageLeaks()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Iterator
|
||||
|
||||
from panda3d.core import ConfigVariableBool, ConfigVariableDouble, ClockObject
|
||||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
|
|
@ -17,28 +21,28 @@ class JobManager:
|
|||
# there's one task for the JobManager, all jobs run in this task
|
||||
TaskName = 'jobManager'
|
||||
|
||||
def __init__(self, timeslice=None):
|
||||
def __init__(self, timeslice: float | None = None) -> None:
|
||||
# how long do we run per frame
|
||||
self._timeslice = timeslice
|
||||
# store the jobs in these structures to allow fast lookup by various keys
|
||||
# priority -> jobId -> job
|
||||
self._pri2jobId2job = {}
|
||||
self._pri2jobId2job: dict[int, dict[int, Job]] = {}
|
||||
# priority -> chronological list of jobIds
|
||||
self._pri2jobIds = {}
|
||||
self._pri2jobIds: dict[int, list[int]] = {}
|
||||
# jobId -> priority
|
||||
self._jobId2pri = {}
|
||||
self._jobId2pri: dict[int, int] = {}
|
||||
# how many timeslices to give each job; this is used to efficiently implement
|
||||
# the relative job priorities
|
||||
self._jobId2timeslices = {}
|
||||
self._jobId2timeslices: dict[int, int] = {}
|
||||
# how much time did the job use beyond the allotted timeslice, used to balance
|
||||
# out CPU usage
|
||||
self._jobId2overflowTime = {}
|
||||
self._useOverflowTime = None
|
||||
self._jobId2overflowTime: dict[int, float] = {}
|
||||
self._useOverflowTime: bool | None = None
|
||||
# this is a generator that we use to give high-priority jobs more timeslices,
|
||||
# it yields jobIds in a sequence that includes high-priority jobIds more often
|
||||
# than low-priority
|
||||
self._jobIdGenerator = None
|
||||
self._highestPriority = Job.Priorities.Normal
|
||||
self._jobIdGenerator: Iterator[int] | None = None
|
||||
self._highestPriority: int = Job.Priorities.Normal # type: ignore[attr-defined]
|
||||
|
||||
def destroy(self):
|
||||
taskMgr.remove(JobManager.TaskName)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,13 @@
|
|||
sound, music, shaders and fonts from disk.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = ['Loader']
|
||||
|
||||
from panda3d.core import (
|
||||
AsyncTask,
|
||||
AudioManager,
|
||||
ConfigVariableBool,
|
||||
Filename,
|
||||
FontPool,
|
||||
|
|
@ -13,6 +17,7 @@ from panda3d.core import (
|
|||
ModelFlattenRequest,
|
||||
ModelNode,
|
||||
ModelPool,
|
||||
MovieAudio,
|
||||
NodePath,
|
||||
PandaNode,
|
||||
SamplerState,
|
||||
|
|
@ -24,13 +29,20 @@ from panda3d.core import (
|
|||
from panda3d.core import Loader as PandaLoader
|
||||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from . import ShowBase
|
||||
import warnings
|
||||
import sys
|
||||
import os
|
||||
from typing import Any, Callable, Iterable, Union
|
||||
|
||||
# Type aliases for loadModel, loadSound, etc. annotations
|
||||
_ModelPath = Union[str, Filename, os.PathLike]
|
||||
_SoundPath = Union[str, Filename, os.PathLike, MovieAudio]
|
||||
|
||||
# You can specify a phaseChecker callback to check
|
||||
# a modelPath to see if it is being loaded in the correct
|
||||
# phase
|
||||
phaseChecker = None
|
||||
phaseChecker: Callable[[_ModelPath, LoaderOptions], object] | None = None
|
||||
|
||||
|
||||
class Loader(DirectObject):
|
||||
|
|
@ -49,16 +61,23 @@ class Loader(DirectObject):
|
|||
# This indicates that this class behaves like a Future.
|
||||
_asyncio_future_blocking = False
|
||||
|
||||
def __init__(self, loader, numObjects, gotList, callback, extraArgs):
|
||||
def __init__(
|
||||
self,
|
||||
loader: Loader | None,
|
||||
numObjects: int,
|
||||
gotList: bool,
|
||||
callback: Callable[..., object] | None,
|
||||
extraArgs: list,
|
||||
) -> None:
|
||||
self._loader = loader
|
||||
self.objects = [None] * numObjects
|
||||
self.objects: list[Any | None] = [None] * numObjects
|
||||
self.gotList = gotList
|
||||
self.callback = callback
|
||||
self.extraArgs = extraArgs
|
||||
self.requests = set()
|
||||
self.requestList = []
|
||||
self.requests: set[AsyncTask] = set()
|
||||
self.requestList: list[AsyncTask] = []
|
||||
|
||||
def gotObject(self, index, object):
|
||||
def gotObject(self, index: int, object) -> None:
|
||||
self.objects[index] = object
|
||||
|
||||
if not self.requests:
|
||||
|
|
@ -79,7 +98,7 @@ class Loader(DirectObject):
|
|||
self.requests = None
|
||||
self.requestList = None
|
||||
|
||||
def cancelled(self):
|
||||
def cancelled(self) -> bool:
|
||||
"Returns true if the request was cancelled."
|
||||
return self.requestList is None
|
||||
|
||||
|
|
@ -87,7 +106,7 @@ class Loader(DirectObject):
|
|||
"Returns true if all the requests were finished or cancelled."
|
||||
return not self.requests
|
||||
|
||||
def result(self):
|
||||
def result(self) -> Any:
|
||||
"Returns the results, suspending the thread to wait if necessary."
|
||||
for r in list(self.requests):
|
||||
r.wait()
|
||||
|
|
@ -126,26 +145,26 @@ class Loader(DirectObject):
|
|||
yield await req
|
||||
|
||||
# special methods
|
||||
def __init__(self, base):
|
||||
def __init__(self, base: ShowBase.ShowBase | None = None) -> None:
|
||||
self.base = base
|
||||
self.loader = PandaLoader.getGlobalPtr()
|
||||
|
||||
self._requests = {}
|
||||
self._requests: dict[AsyncTask, tuple[Loader._Callback, int]] = {}
|
||||
|
||||
self.hook = "async_loader_%s" % (Loader.loaderIndex)
|
||||
Loader.loaderIndex += 1
|
||||
self.accept(self.hook, self.__gotAsyncObject)
|
||||
|
||||
self._loadPythonFileTypes()
|
||||
|
||||
def destroy(self):
|
||||
def destroy(self) -> None:
|
||||
self.ignore(self.hook)
|
||||
self.loader.stopThreads()
|
||||
del self.base
|
||||
del self.loader
|
||||
|
||||
def _init_base(self, base: ShowBase.ShowBase) -> None:
|
||||
self.base = base
|
||||
self.accept(self.hook, self.__gotAsyncObject)
|
||||
|
||||
@classmethod
|
||||
def _loadPythonFileTypes(cls):
|
||||
def _loadPythonFileTypes(cls) -> None:
|
||||
if cls._loadedPythonFileTypes:
|
||||
return
|
||||
|
||||
|
|
@ -168,10 +187,18 @@ class Loader(DirectObject):
|
|||
cls._loadedPythonFileTypes = True
|
||||
|
||||
# model loading funcs
|
||||
def loadModel(self, modelPath, loaderOptions = None, noCache = None,
|
||||
allowInstance = False, okMissing = None,
|
||||
callback = None, extraArgs = [], priority = None,
|
||||
blocking = None):
|
||||
def loadModel(
|
||||
self,
|
||||
modelPath: _ModelPath | list[_ModelPath] | tuple[_ModelPath, ...] | set[_ModelPath],
|
||||
loaderOptions: LoaderOptions | None = None,
|
||||
noCache: bool | None = None,
|
||||
allowInstance: bool = False,
|
||||
okMissing: bool | None = None,
|
||||
callback: Callable[..., object] | None = None,
|
||||
extraArgs: list = [],
|
||||
priority: int | None = None,
|
||||
blocking: bool | None = None,
|
||||
) -> Any:
|
||||
"""
|
||||
Attempts to load a model or models from one or more relative
|
||||
pathnames. If the input modelPath is a string (a single model
|
||||
|
|
@ -229,6 +256,10 @@ class Loader(DirectObject):
|
|||
"""
|
||||
|
||||
assert Loader.notify.debug("Loading model: %s" % (modelPath,))
|
||||
|
||||
if not self._loadedPythonFileTypes:
|
||||
self._loadPythonFileTypes()
|
||||
|
||||
if loaderOptions is None:
|
||||
loaderOptions = LoaderOptions()
|
||||
else:
|
||||
|
|
@ -251,6 +282,7 @@ class Loader(DirectObject):
|
|||
if allowInstance:
|
||||
loaderOptions.setFlags(loaderOptions.getFlags() | LoaderOptions.LFAllowInstance)
|
||||
|
||||
modelList: Iterable[_ModelPath]
|
||||
if not isinstance(modelPath, (tuple, list, set)):
|
||||
# We were given a single model pathname.
|
||||
modelList = [modelPath]
|
||||
|
|
@ -416,6 +448,9 @@ class Loader(DirectObject):
|
|||
a callback is used, the model is saved asynchronously, and the
|
||||
true/false status is passed to the callback function. """
|
||||
|
||||
if not self._loadedPythonFileTypes:
|
||||
self._loadPythonFileTypes()
|
||||
|
||||
if loaderOptions is None:
|
||||
loaderOptions = LoaderOptions()
|
||||
else:
|
||||
|
|
@ -942,7 +977,13 @@ class Loader(DirectObject):
|
|||
TexturePool.releaseTexture(texture)
|
||||
|
||||
# sound loading funcs
|
||||
def loadSfx(self, *args, **kw):
|
||||
def loadSfx(
|
||||
self,
|
||||
soundPath: _SoundPath | tuple[_SoundPath, ...] | list[_SoundPath] | set[_SoundPath],
|
||||
positional: bool = False,
|
||||
callback: Callable[..., object] | None = None,
|
||||
extraArgs: list = [],
|
||||
) -> Any:
|
||||
"""Loads one or more sound files, specifically designated as a
|
||||
"sound effect" file (that is, uses the sfxManager to load the
|
||||
sound). There is no distinction between sound effect files
|
||||
|
|
@ -952,11 +993,18 @@ class Loader(DirectObject):
|
|||
independently of the other group."""
|
||||
|
||||
# showbase-created sfxManager should always be at front of list
|
||||
assert self.base is not None
|
||||
if self.base.sfxManagerList:
|
||||
return self.loadSound(self.base.sfxManagerList[0], *args, **kw)
|
||||
return self.loadSound(self.base.sfxManagerList[0], soundPath, positional, callback, extraArgs)
|
||||
return None
|
||||
|
||||
def loadMusic(self, *args, **kw):
|
||||
def loadMusic(
|
||||
self,
|
||||
soundPath: _SoundPath | tuple[_SoundPath, ...] | list[_SoundPath] | set[_SoundPath],
|
||||
positional: bool = False,
|
||||
callback: Callable[..., object] | None = None,
|
||||
extraArgs: list = [],
|
||||
) -> Any:
|
||||
"""Loads one or more sound files, specifically designated as a
|
||||
"music" file (that is, uses the musicManager to load the
|
||||
sound). There is no distinction between sound effect files
|
||||
|
|
@ -964,13 +1012,20 @@ class Loader(DirectObject):
|
|||
to load the sound file, but this distinction allows the sound
|
||||
effects and/or the music files to be adjusted as a group,
|
||||
independently of the other group."""
|
||||
assert self.base is not None
|
||||
if self.base.musicManager:
|
||||
return self.loadSound(self.base.musicManager, *args, **kw)
|
||||
return self.loadSound(self.base.musicManager, soundPath, positional, callback, extraArgs)
|
||||
else:
|
||||
return None
|
||||
|
||||
def loadSound(self, manager, soundPath, positional = False,
|
||||
callback = None, extraArgs = []):
|
||||
def loadSound(
|
||||
self,
|
||||
manager: AudioManager,
|
||||
soundPath: _SoundPath | tuple[_SoundPath, ...] | list[_SoundPath] | set[_SoundPath],
|
||||
positional: bool = False,
|
||||
callback: Callable[..., object] | None = None,
|
||||
extraArgs: list = [],
|
||||
) -> Any:
|
||||
"""Loads one or more sound files, specifying the particular
|
||||
AudioManager that should be used to load them. The soundPath
|
||||
may be either a single filename, or a list of filenames. If a
|
||||
|
|
@ -980,6 +1035,7 @@ class Loader(DirectObject):
|
|||
|
||||
from panda3d.core import AudioLoadRequest
|
||||
|
||||
soundList: Iterable[_SoundPath]
|
||||
if not isinstance(soundPath, (tuple, list, set)):
|
||||
# We were given a single sound pathname or a MovieAudio instance.
|
||||
soundList = [soundPath]
|
||||
|
|
@ -1105,7 +1161,7 @@ class Loader(DirectObject):
|
|||
else:
|
||||
callback(*(origModelList + extraArgs))
|
||||
|
||||
def __gotAsyncObject(self, request):
|
||||
def __gotAsyncObject(self, request: AsyncTask) -> None:
|
||||
"""A model or sound file or some such thing has just been
|
||||
loaded asynchronously by the sub-thread. Add it to the list
|
||||
of loaded objects, and call the appropriate callback when it's
|
||||
|
|
|
|||
|
|
@ -2,19 +2,40 @@
|
|||
:ref:`event handling <event-handlers>` that happens on the Python side.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = ['Messenger']
|
||||
|
||||
import types
|
||||
from collections.abc import Callable
|
||||
from typing import Protocol
|
||||
# These can be replaced with their builtin counterparts once support for Python 3.8 is dropped.
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from panda3d.core import AsyncTask
|
||||
|
||||
from direct.stdpy.threading import Lock
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from .PythonUtil import safeRepr
|
||||
import types
|
||||
|
||||
# The following variables are typing constructs used in annotations
|
||||
# to succinctly express complex type structures.
|
||||
_ObjMsgrId = Tuple[str, int]
|
||||
_CallbackInfo = list # [Callable, list, bool]
|
||||
_ListenerObject = list # [int, DirectObject]
|
||||
_AcceptorDict = Dict[_ObjMsgrId, _CallbackInfo]
|
||||
_EventTuple = Tuple[_AcceptorDict, str, list, bool]
|
||||
|
||||
|
||||
class _HasMessengerID(Protocol):
|
||||
_MSGRmessengerId: _ObjMsgrId
|
||||
|
||||
|
||||
class Messenger:
|
||||
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("Messenger")
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
"""
|
||||
One is keyed off the event name. It has the following structure::
|
||||
|
||||
|
|
@ -34,16 +55,16 @@ class Messenger:
|
|||
{'mouseDown': {avatar: [avatar.jump, [2.0], 1]}}
|
||||
"""
|
||||
# eventName->objMsgrId->callbackInfo
|
||||
self.__callbacks = {}
|
||||
self.__callbacks: dict[str, _AcceptorDict] = {}
|
||||
# objMsgrId->set(eventName)
|
||||
self.__objectEvents = {}
|
||||
self.__objectEvents: dict[_ObjMsgrId, dict[str, None]] = {}
|
||||
self._messengerIdGen = 0
|
||||
# objMsgrId->listenerObject
|
||||
self._id2object = {}
|
||||
self._id2object: dict[_ObjMsgrId, _ListenerObject] = {}
|
||||
|
||||
# A mapping of taskChain -> eventList, used for sending events
|
||||
# across task chains (and therefore across threads).
|
||||
self._eventQueuesByTaskChain = {}
|
||||
self._eventQueuesByTaskChain: dict[str, list[_EventTuple]] = {}
|
||||
|
||||
# This protects the data structures within this object from
|
||||
# multithreaded access.
|
||||
|
|
@ -51,7 +72,7 @@ class Messenger:
|
|||
|
||||
if __debug__:
|
||||
self.__isWatching=0
|
||||
self.__watching={}
|
||||
self.__watching: dict[str, bool] = {}
|
||||
# I'd like this to be in the __debug__, but I fear that someone will
|
||||
# want this in a release build. If you're sure that that will not be
|
||||
# then please remove this comment and put the quiet/verbose stuff
|
||||
|
|
@ -62,7 +83,7 @@ class Messenger:
|
|||
'collisionLoopFinished':1,
|
||||
} # see def quiet()
|
||||
|
||||
def _getMessengerId(self, object):
|
||||
def _getMessengerId(self, object: _HasMessengerID) -> _ObjMsgrId:
|
||||
# TODO: allocate this id in DirectObject.__init__ and get derived
|
||||
# classes to call down (speed optimization, assuming objects
|
||||
# accept/ignore more than once over their lifetime)
|
||||
|
|
@ -73,7 +94,7 @@ class Messenger:
|
|||
self._messengerIdGen += 1
|
||||
return object._MSGRmessengerId
|
||||
|
||||
def _storeObject(self, object):
|
||||
def _storeObject(self, object: _HasMessengerID) -> None:
|
||||
# store reference-counted reference to object in case we need to
|
||||
# retrieve it later. assumes lock is held.
|
||||
id = self._getMessengerId(object)
|
||||
|
|
@ -82,7 +103,7 @@ class Messenger:
|
|||
else:
|
||||
self._id2object[id][0] += 1
|
||||
|
||||
def _getObject(self, id):
|
||||
def _getObject(self, id: _ObjMsgrId) -> _HasMessengerID:
|
||||
return self._id2object[id][1]
|
||||
|
||||
def _getObjects(self):
|
||||
|
|
@ -101,7 +122,7 @@ class Messenger:
|
|||
def _getEvents(self):
|
||||
return list(self.__callbacks.keys())
|
||||
|
||||
def _releaseObject(self, object):
|
||||
def _releaseObject(self, object: _HasMessengerID) -> None:
|
||||
# assumes lock is held.
|
||||
id = self._getMessengerId(object)
|
||||
if id in self._id2object:
|
||||
|
|
@ -117,7 +138,14 @@ class Messenger:
|
|||
from .EventManagerGlobal import eventMgr
|
||||
return eventMgr.eventHandler.get_future(event)
|
||||
|
||||
def accept(self, event, object, method, extraArgs=[], persistent=1):
|
||||
def accept(
|
||||
self,
|
||||
event: str,
|
||||
object: _HasMessengerID,
|
||||
method: Callable,
|
||||
extraArgs: list = [],
|
||||
persistent: bool = True,
|
||||
) -> None:
|
||||
""" accept(self, string, DirectObject, Function, List, Boolean)
|
||||
|
||||
Make this object accept this event. When the event is
|
||||
|
|
@ -174,7 +202,7 @@ class Messenger:
|
|||
finally:
|
||||
self.lock.release()
|
||||
|
||||
def ignore(self, event, object):
|
||||
def ignore(self, event: str, object: _HasMessengerID) -> None:
|
||||
""" ignore(self, string, DirectObject)
|
||||
Make this object no longer respond to this event.
|
||||
It is safe to call even if it was not already accepting
|
||||
|
|
@ -208,7 +236,7 @@ class Messenger:
|
|||
finally:
|
||||
self.lock.release()
|
||||
|
||||
def ignoreAll(self, object):
|
||||
def ignoreAll(self, object: _HasMessengerID) -> None:
|
||||
"""
|
||||
Make this object no longer respond to any events it was accepting
|
||||
Useful for cleanup
|
||||
|
|
@ -283,7 +311,7 @@ class Messenger:
|
|||
"""
|
||||
return not self.isAccepting(event, object)
|
||||
|
||||
def send(self, event, sentArgs=[], taskChain=None):
|
||||
def send(self, event: str, sentArgs: list = [], taskChain: str | None = None) -> None:
|
||||
"""
|
||||
Send this event, optionally passing in arguments.
|
||||
|
||||
|
|
@ -305,12 +333,12 @@ class Messenger:
|
|||
|
||||
self.lock.acquire()
|
||||
try:
|
||||
foundWatch = 0
|
||||
foundWatch = False
|
||||
if __debug__:
|
||||
if self.__isWatching:
|
||||
for i in self.__watching:
|
||||
if str(event).find(i) >= 0:
|
||||
foundWatch = 1
|
||||
foundWatch = True
|
||||
break
|
||||
acceptorDict = self.__callbacks.get(event)
|
||||
if not acceptorDict:
|
||||
|
|
@ -336,7 +364,7 @@ class Messenger:
|
|||
finally:
|
||||
self.lock.release()
|
||||
|
||||
def __taskChainDispatch(self, taskChain, task):
|
||||
def __taskChainDispatch(self, taskChain: str, task: AsyncTask) -> int:
|
||||
""" This task is spawned each time an event is sent across
|
||||
task chains. Its job is to empty the task events on the queue
|
||||
for this particular task chain. This guarantees that events
|
||||
|
|
@ -365,7 +393,13 @@ class Messenger:
|
|||
|
||||
return task.done
|
||||
|
||||
def __dispatch(self, acceptorDict, event, sentArgs, foundWatch):
|
||||
def __dispatch(
|
||||
self,
|
||||
acceptorDict: _AcceptorDict,
|
||||
event: str,
|
||||
sentArgs: list,
|
||||
foundWatch: bool,
|
||||
) -> None:
|
||||
for id in list(acceptorDict.keys()):
|
||||
# We have to make this apparently redundant check, because
|
||||
# it is possible that one object removes its own hooks
|
||||
|
|
@ -562,7 +596,7 @@ class Messenger:
|
|||
break
|
||||
return matches
|
||||
|
||||
def __methodRepr(self, method):
|
||||
def __methodRepr(self, method: object) -> str:
|
||||
"""
|
||||
return string version of class.method or method.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
"""Contains the OnScreenDebug class."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = ['OnScreenDebug']
|
||||
|
||||
from typing import Any
|
||||
|
||||
from panda3d.core import (
|
||||
ConfigVariableBool,
|
||||
ConfigVariableDouble,
|
||||
|
|
@ -18,13 +22,13 @@ class OnScreenDebug:
|
|||
|
||||
enabled = ConfigVariableBool("on-screen-debug-enabled", False)
|
||||
|
||||
def __init__(self):
|
||||
self.onScreenText = None
|
||||
def __init__(self) -> None:
|
||||
self.onScreenText: OnscreenText.OnscreenText | None = None
|
||||
self.frame = 0
|
||||
self.text = ""
|
||||
self.data = {}
|
||||
self.data: dict[str, tuple[int, Any]] = {}
|
||||
|
||||
def load(self):
|
||||
def load(self) -> None:
|
||||
if self.onScreenText:
|
||||
return
|
||||
|
||||
|
|
@ -40,6 +44,7 @@ class OnScreenDebug:
|
|||
fgColor.setW(ConfigVariableDouble("on-screen-debug-fg-alpha", 0.85).value)
|
||||
bgColor.setW(ConfigVariableDouble("on-screen-debug-bg-alpha", 0.85).value)
|
||||
|
||||
from direct.showbase.ShowBaseGlobal import base
|
||||
font = base.loader.loadFont(fontPath)
|
||||
if not font.isValid():
|
||||
print("failed to load OnScreenDebug font %s" % fontPath)
|
||||
|
|
@ -47,15 +52,16 @@ class OnScreenDebug:
|
|||
self.onScreenText = OnscreenText.OnscreenText(
|
||||
parent = base.a2dTopLeft, pos = (0.0, -0.1),
|
||||
fg=fgColor, bg=bgColor, scale = (fontScale, fontScale, 0.0),
|
||||
align = TextNode.ALeft, mayChange = 1, font = font)
|
||||
align = TextNode.ALeft, mayChange = True, font = font)
|
||||
# Make sure readout is never lit or drawn in wireframe
|
||||
DirectUtil.useDirectRenderStyle(self.onScreenText)
|
||||
|
||||
def render(self):
|
||||
def render(self) -> None:
|
||||
if not self.enabled:
|
||||
return
|
||||
if not self.onScreenText:
|
||||
self.load()
|
||||
assert self.onScreenText is not None
|
||||
self.onScreenText.clearText()
|
||||
for k, v in sorted(self.data.items()):
|
||||
if v[0] == self.frame:
|
||||
|
|
@ -75,7 +81,7 @@ class OnScreenDebug:
|
|||
self.onScreenText.appendText(self.text)
|
||||
self.frame += 1
|
||||
|
||||
def clear(self):
|
||||
def clear(self) -> None:
|
||||
self.text = ""
|
||||
if self.onScreenText:
|
||||
self.onScreenText.clearText()
|
||||
|
|
|
|||
|
|
@ -41,13 +41,17 @@ import time
|
|||
import builtins
|
||||
import importlib
|
||||
import functools
|
||||
from typing import Callable
|
||||
from collections.abc import Callable, Container, Iterable, Mapping
|
||||
from typing import Any, Generic, TypeVar
|
||||
|
||||
__report_indent = 3
|
||||
|
||||
from panda3d.core import ConfigVariableBool, ConfigVariableString, ConfigFlags
|
||||
from panda3d.core import ClockObject
|
||||
|
||||
_T = TypeVar('_T')
|
||||
_KT = TypeVar('_KT')
|
||||
_VT = TypeVar('_VT')
|
||||
|
||||
## with one integer positional arg, this uses about 4/5 of the memory of the Functor class below
|
||||
#def Functor(function, *args, **kArgs):
|
||||
|
|
@ -100,9 +104,9 @@ class Functor:
|
|||
return s
|
||||
|
||||
|
||||
class Stack:
|
||||
def __init__(self):
|
||||
self.__list = []
|
||||
class Stack(Generic[_T]):
|
||||
def __init__(self) -> None:
|
||||
self.__list: list[_T] = []
|
||||
|
||||
def push(self, item):
|
||||
self.__list.append(item)
|
||||
|
|
@ -229,7 +233,7 @@ if __debug__:
|
|||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def traceFunctionCall(frame):
|
||||
def traceFunctionCall(frame: types.FrameType) -> str:
|
||||
"""
|
||||
return a string that shows the call frame with calling arguments.
|
||||
e.g.
|
||||
|
|
@ -270,7 +274,7 @@ if __debug__:
|
|||
r+="*** undefined ***"
|
||||
return r+')'
|
||||
|
||||
def traceParentCall():
|
||||
def traceParentCall() -> str:
|
||||
return traceFunctionCall(sys._getframe(2))
|
||||
|
||||
def printThisCall():
|
||||
|
|
@ -411,7 +415,7 @@ def list2dict(L, value=None):
|
|||
return dict([(k, value) for k in L])
|
||||
|
||||
|
||||
def listToIndex2item(L):
|
||||
def listToIndex2item(L: Iterable[_VT]) -> dict[int, _VT]:
|
||||
"""converts list to dict of list index->list item"""
|
||||
d = {}
|
||||
for i, item in enumerate(L):
|
||||
|
|
@ -422,7 +426,7 @@ def listToIndex2item(L):
|
|||
assert listToIndex2item(['a','b']) == {0: 'a', 1: 'b',}
|
||||
|
||||
|
||||
def listToItem2index(L):
|
||||
def listToItem2index(L: Iterable[_KT]) -> dict[_KT, int]:
|
||||
"""converts list to dict of list item->list index
|
||||
This is lossy if there are duplicate list items"""
|
||||
d = {}
|
||||
|
|
@ -451,7 +455,7 @@ def invertDict(D, lossy=False):
|
|||
return n
|
||||
|
||||
|
||||
def invertDictLossless(D):
|
||||
def invertDictLossless(D: Mapping[_KT, _VT]) -> dict[_VT, list[_KT]]:
|
||||
"""similar to invertDict, but values of new dict are lists of keys from
|
||||
old dict. No information is lost.
|
||||
|
||||
|
|
@ -459,7 +463,7 @@ def invertDictLossless(D):
|
|||
>>> invertDictLossless(old)
|
||||
{1: ['key1'], 2: ['key2', 'keyA']}
|
||||
"""
|
||||
n = {}
|
||||
n: dict[_VT, list[_KT]] = {}
|
||||
for key, value in D.items():
|
||||
n.setdefault(value, [])
|
||||
n[value].append(key)
|
||||
|
|
@ -706,7 +710,7 @@ if __debug__:
|
|||
movedDumpFuncs: list[Callable] = []
|
||||
movedLoadFuncs: list[Callable] = []
|
||||
profileFilenames = set()
|
||||
profileFilenameList = Stack()
|
||||
profileFilenameList = Stack[str]()
|
||||
profileFilename2file = {}
|
||||
profileFilename2marshalData = {}
|
||||
|
||||
|
|
@ -998,7 +1002,7 @@ def lineupPos(i, num, spacing):
|
|||
return pos - ((float(spacing) * (num-1))/2.)
|
||||
|
||||
|
||||
def formatElapsedSeconds(seconds):
|
||||
def formatElapsedSeconds(seconds: float) -> str:
|
||||
"""
|
||||
Returns a string of the form "mm:ss" or "hh:mm:ss" or "n days",
|
||||
representing the indicated elapsed time in seconds.
|
||||
|
|
@ -1278,7 +1282,7 @@ def randInt32(rng=random.random):
|
|||
class SerialNumGen:
|
||||
"""generates serial numbers"""
|
||||
|
||||
def __init__(self, start=None):
|
||||
def __init__(self, start: int | None = None) -> None:
|
||||
if start is None:
|
||||
start = 0
|
||||
self.__counter = start-1
|
||||
|
|
@ -1305,7 +1309,7 @@ class SerialMaskedGen(SerialNumGen):
|
|||
_serialGen = SerialNumGen()
|
||||
|
||||
|
||||
def serialNum():
|
||||
def serialNum() -> int:
|
||||
return _serialGen.next()
|
||||
|
||||
|
||||
|
|
@ -1404,14 +1408,16 @@ def _getSafeReprNotify():
|
|||
return safeReprNotify
|
||||
|
||||
|
||||
def safeRepr(obj):
|
||||
def safeRepr(obj: object) -> str:
|
||||
global dtoolSuperBase
|
||||
if dtoolSuperBase is None:
|
||||
_getDtoolSuperBase()
|
||||
assert dtoolSuperBase is not None
|
||||
|
||||
global safeReprNotify
|
||||
if safeReprNotify is None:
|
||||
_getSafeReprNotify()
|
||||
assert safeReprNotify is not None
|
||||
|
||||
if isinstance(obj, dtoolSuperBase):
|
||||
# repr of C++ object could crash, particularly if the object has been deleted
|
||||
|
|
@ -1443,7 +1449,12 @@ def safeReprTypeOnFail(obj):
|
|||
return '<** FAILED REPR OF %s instance at %s **>' % (obj.__class__.__name__, hex(id(obj)))
|
||||
|
||||
|
||||
def fastRepr(obj, maxLen=200, strFactor=10, _visitedIds=None):
|
||||
def fastRepr(
|
||||
obj: object,
|
||||
maxLen: int = 200,
|
||||
strFactor: int = 10,
|
||||
_visitedIds: set[int] | None = None,
|
||||
) -> str:
|
||||
""" caps the length of iterable types, so very large objects will print faster.
|
||||
also prevents infinite recursion """
|
||||
try:
|
||||
|
|
@ -1452,9 +1463,9 @@ def fastRepr(obj, maxLen=200, strFactor=10, _visitedIds=None):
|
|||
if id(obj) in _visitedIds:
|
||||
return '<ALREADY-VISITED %s>' % itype(obj)
|
||||
if type(obj) in (tuple, list):
|
||||
assert isinstance(obj, (tuple, list))
|
||||
s = ''
|
||||
s += {tuple: '(',
|
||||
list: '[',}[type(obj)]
|
||||
s += '(' if type(obj) == tuple else '['
|
||||
if maxLen is not None and len(obj) > maxLen:
|
||||
o = obj[:maxLen]
|
||||
ellips = '...'
|
||||
|
|
@ -1467,8 +1478,7 @@ def fastRepr(obj, maxLen=200, strFactor=10, _visitedIds=None):
|
|||
s += ', '
|
||||
_visitedIds.remove(id(obj))
|
||||
s += ellips
|
||||
s += {tuple: ')',
|
||||
list: ']',}[type(obj)]
|
||||
s += ')' if type(obj) == tuple else ']'
|
||||
return s
|
||||
elif type(obj) is dict:
|
||||
s = '{'
|
||||
|
|
@ -1588,7 +1598,7 @@ class ScratchPad:
|
|||
class Sync:
|
||||
_SeriesGen = SerialNumGen()
|
||||
|
||||
def __init__(self, name, other=None):
|
||||
def __init__(self, name: str, other: Sync | None = None) -> None:
|
||||
self._name = name
|
||||
if other is None:
|
||||
self._series = self._SeriesGen.next()
|
||||
|
|
@ -1620,7 +1630,7 @@ class Sync:
|
|||
self._name, self._series, self._value)
|
||||
|
||||
|
||||
def itype(obj):
|
||||
def itype(obj: object) -> type | str:
|
||||
# version of type that gives more complete information about instance types
|
||||
global dtoolSuperBase
|
||||
t = type(obj)
|
||||
|
|
@ -1628,6 +1638,7 @@ def itype(obj):
|
|||
# check if this is a C++ object
|
||||
if dtoolSuperBase is None:
|
||||
_getDtoolSuperBase()
|
||||
assert dtoolSuperBase is not None
|
||||
if isinstance(obj, dtoolSuperBase):
|
||||
return "<type 'instance' of %s>" % (obj.__class__)
|
||||
return t
|
||||
|
|
@ -1972,7 +1983,13 @@ def pstatcollect(scope, level = None):
|
|||
__report_indent = 0
|
||||
|
||||
|
||||
def report(types = [], prefix = '', xform = None, notifyFunc = None, dConfigParam = []):
|
||||
def report(
|
||||
types: Container[str] = [],
|
||||
prefix: str = '',
|
||||
xform: Callable[[Any], object] | None = None,
|
||||
notifyFunc: Callable[[str], object] | None = None,
|
||||
dConfigParam: str | list[str] | tuple[str, ...] = [],
|
||||
) -> Callable[[_T], _T]:
|
||||
"""
|
||||
This is a decorator generating function. Use is similar to
|
||||
a @decorator, except you must be sure to call it as a function.
|
||||
|
|
@ -2031,7 +2048,7 @@ def report(types = [], prefix = '', xform = None, notifyFunc = None, dConfigPara
|
|||
return f
|
||||
|
||||
try:
|
||||
if not __dev__ and not ConfigVariableBool('force-reports', False):
|
||||
if not __dev__ and not ConfigVariableBool('force-reports', False): # type: ignore[name-defined]
|
||||
return decorator
|
||||
|
||||
# determine whether we should use the decorator
|
||||
|
|
@ -2041,6 +2058,7 @@ def report(types = [], prefix = '', xform = None, notifyFunc = None, dConfigPara
|
|||
if not dConfigParam:
|
||||
doPrint = True
|
||||
else:
|
||||
dConfigParams: list[str] | tuple[str, ...]
|
||||
if not isinstance(dConfigParam, (list,tuple)):
|
||||
dConfigParams = (dConfigParam,)
|
||||
else:
|
||||
|
|
@ -2070,7 +2088,7 @@ def report(types = [], prefix = '', xform = None, notifyFunc = None, dConfigPara
|
|||
|
||||
globalClockDelta = importlib.import_module("direct.distributed.ClockDelta").globalClockDelta
|
||||
|
||||
def decorator(f):
|
||||
def decorator(f): # type: ignore[no-redef]
|
||||
def wrap(*args, **kwargs):
|
||||
if args:
|
||||
rArgs = [args[0].__class__.__name__ + ', ']
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ from panda3d.core import (
|
|||
DepthTestAttrib,
|
||||
DepthWriteAttrib,
|
||||
DriveInterface,
|
||||
EventQueue,
|
||||
ExecutionEnvironment,
|
||||
Filename,
|
||||
FisheyeMaker,
|
||||
|
|
@ -114,7 +115,7 @@ from panda3d.core import (
|
|||
WindowProperties,
|
||||
getModelPath,
|
||||
)
|
||||
from panda3d.direct import throw_new_frame, init_app_for_gui
|
||||
from panda3d.direct import init_app_for_gui
|
||||
from panda3d.direct import storeAccessibilityShortcutKeys, allowAccessibilityShortcutKeys
|
||||
from . import DConfig
|
||||
|
||||
|
|
@ -177,6 +178,10 @@ class ShowBase(DirectObject.DirectObject):
|
|||
aspect2d: NodePath
|
||||
pixel2d: NodePath
|
||||
|
||||
a2dTopLeft: NodePath
|
||||
|
||||
cluster: Any | None
|
||||
|
||||
def __init__(self, fStartDirect: bool = True, windowType: str | None = None) -> None:
|
||||
"""Opens a window, sets up a 3-D and several 2-D scene graphs, and
|
||||
everything else needed to render the scene graph to the window.
|
||||
|
|
@ -380,7 +385,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
#: yourself every frame.
|
||||
self.cTrav: CollisionTraverser | Literal[0] = 0
|
||||
self.shadowTrav: CollisionTraverser | Literal[0] = 0
|
||||
self.cTravStack = Stack()
|
||||
self.cTravStack = Stack[CollisionTraverser]()
|
||||
# Ditto for an AppTraverser.
|
||||
self.appTrav: Any | Literal[0] = 0
|
||||
|
||||
|
|
@ -436,9 +441,9 @@ class ShowBase(DirectObject.DirectObject):
|
|||
self.useTrackball()
|
||||
|
||||
#: `.Loader.Loader` object.
|
||||
self.loader = Loader.Loader(self)
|
||||
self.loader: Loader.Loader = ShowBaseGlobal.loader
|
||||
self.loader._init_base(self)
|
||||
self.graphicsEngine.setDefaultLoader(self.loader.loader)
|
||||
ShowBaseGlobal.loader = self.loader
|
||||
|
||||
#: The global event manager, as imported from `.EventManagerGlobal`.
|
||||
self.eventMgr = eventMgr
|
||||
|
|
@ -652,7 +657,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
def getExitErrorCode(self):
|
||||
return 0
|
||||
|
||||
def printEnvDebugInfo(self):
|
||||
def printEnvDebugInfo(self) -> None:
|
||||
"""Print some information about the environment that we are running
|
||||
in. Stuff like the model paths and other paths. Feel free to
|
||||
add stuff to this.
|
||||
|
|
@ -706,7 +711,8 @@ class ShowBase(DirectObject.DirectObject):
|
|||
allowAccessibilityShortcutKeys(True)
|
||||
self.__disabledStickyKeys = False
|
||||
|
||||
self.__directObject.ignoreAll()
|
||||
if hasattr(self, '__directObject'):
|
||||
self.__directObject.ignoreAll()
|
||||
self.ignoreAll()
|
||||
self.shutdown()
|
||||
|
||||
|
|
@ -1208,7 +1214,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
self.taskMgr.remove('clientSleep')
|
||||
self.taskMgr.add(self.__sleepCycleTask, 'clientSleep', sort = 55)
|
||||
|
||||
def __sleepCycleTask(self, task):
|
||||
def __sleepCycleTask(self, task: object) -> int:
|
||||
Thread.sleep(self.clientSleep)
|
||||
#time.sleep(self.clientSleep)
|
||||
return Task.cont
|
||||
|
|
@ -1444,7 +1450,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
self.__configAspectRatio = aspectRatio
|
||||
self.adjustWindowAspectRatio(self.getAspectRatio())
|
||||
|
||||
def getAspectRatio(self, win = None):
|
||||
def getAspectRatio(self, win: GraphicsOutput | None = None) -> float:
|
||||
# Returns the actual aspect ratio of the indicated (or main
|
||||
# window), or the default aspect ratio if there is not yet a
|
||||
# main window.
|
||||
|
|
@ -1453,7 +1459,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
if self.__configAspectRatio:
|
||||
return self.__configAspectRatio
|
||||
|
||||
aspectRatio = 1
|
||||
aspectRatio: float = 1
|
||||
|
||||
if win is None:
|
||||
win = self.win
|
||||
|
|
@ -1476,7 +1482,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
|
||||
return aspectRatio
|
||||
|
||||
def getSize(self, win = None):
|
||||
def getSize(self, win: GraphicsOutput | None = None) -> tuple[int, int]:
|
||||
"""
|
||||
Returns the actual size of the indicated (or main window), or the
|
||||
default size if there is not yet a main window.
|
||||
|
|
@ -2176,7 +2182,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
music.setLoop(looping)
|
||||
music.play()
|
||||
|
||||
def __resetPrevTransform(self, state):
|
||||
def __resetPrevTransform(self, state: object) -> int:
|
||||
# Clear out the previous velocity deltas now, after we have
|
||||
# rendered (the previous frame). We do this after the render,
|
||||
# so that we have a chance to draw a representation of spheres
|
||||
|
|
@ -2187,7 +2193,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
PandaNode.resetAllPrevTransform()
|
||||
return Task.cont
|
||||
|
||||
def __dataLoop(self, state):
|
||||
def __dataLoop(self, state: object) -> int:
|
||||
# Check if there were newly connected devices.
|
||||
self.devices.update()
|
||||
|
||||
|
|
@ -2197,7 +2203,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
self.dgTrav.traverse(self.dataRootNode)
|
||||
return Task.cont
|
||||
|
||||
def __ivalLoop(self, state):
|
||||
def __ivalLoop(self, state: object) -> int:
|
||||
# Execute all intervals in the global ivalMgr.
|
||||
IntervalManager.ivalMgr.step()
|
||||
return Task.cont
|
||||
|
|
@ -2215,7 +2221,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
self.shadowTrav.traverse(self.render)
|
||||
return Task.cont
|
||||
|
||||
def __collisionLoop(self, state):
|
||||
def __collisionLoop(self, state: object) -> int:
|
||||
# run the collision traversal if we have a
|
||||
# CollisionTraverser set.
|
||||
if self.cTrav:
|
||||
|
|
@ -2227,14 +2233,14 @@ class ShowBase(DirectObject.DirectObject):
|
|||
messenger.send("collisionLoopFinished")
|
||||
return Task.cont
|
||||
|
||||
def __audioLoop(self, state):
|
||||
def __audioLoop(self, state: object) -> int:
|
||||
if self.musicManager is not None:
|
||||
self.musicManager.update()
|
||||
for x in self.sfxManagerList:
|
||||
x.update()
|
||||
return Task.cont
|
||||
|
||||
def __garbageCollectStates(self, state):
|
||||
def __garbageCollectStates(self, state: object) -> int:
|
||||
""" This task is started only when we have
|
||||
garbage-collect-states set in the Config.prc file, in which
|
||||
case we're responsible for taking out Panda's garbage from
|
||||
|
|
@ -2245,7 +2251,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
RenderState.garbageCollect()
|
||||
return Task.cont
|
||||
|
||||
def __igLoop(self, state):
|
||||
def __igLoop(self, state: object) -> int:
|
||||
if __debug__:
|
||||
# We render the watch variables for the onScreenDebug as soon
|
||||
# as we reasonably can before the renderFrame().
|
||||
|
|
@ -2280,12 +2286,11 @@ class ShowBase(DirectObject.DirectObject):
|
|||
# now until someone complains.
|
||||
time.sleep(0.1)
|
||||
|
||||
# Lerp stuff needs this event, and it must be generated in
|
||||
# C++, not in Python.
|
||||
throw_new_frame()
|
||||
# Lerp stuff needs this event, thrown directly on the C++ queue.
|
||||
EventQueue.getGlobalEventQueue().queueEvent("NewFrame")
|
||||
return Task.cont
|
||||
|
||||
def __igLoopSync(self, state):
|
||||
def __igLoopSync(self, state: object) -> int:
|
||||
if __debug__:
|
||||
# We render the watch variables for the onScreenDebug as soon
|
||||
# as we reasonably can before the renderFrame().
|
||||
|
|
@ -2294,6 +2299,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
if self.recorder:
|
||||
self.recorder.recordFrame()
|
||||
|
||||
assert self.cluster is not None
|
||||
self.cluster.collectData()
|
||||
|
||||
# Finally, render the frame.
|
||||
|
|
@ -2323,12 +2329,12 @@ class ShowBase(DirectObject.DirectObject):
|
|||
time.sleep(0.1)
|
||||
|
||||
self.graphicsEngine.readyFlip()
|
||||
assert self.cluster is not None
|
||||
self.cluster.waitForFlipCommand()
|
||||
self.graphicsEngine.flipFrame()
|
||||
|
||||
# Lerp stuff needs this event, and it must be generated in
|
||||
# C++, not in Python.
|
||||
throw_new_frame()
|
||||
# Lerp stuff needs this event, thrown directly on the C++ queue.
|
||||
EventQueue.getGlobalEventQueue().queueEvent("NewFrame")
|
||||
return Task.cont
|
||||
|
||||
def restart(self, clusterSync: bool = False, cluster=None) -> None:
|
||||
|
|
@ -2753,7 +2759,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
self.oobeVis.reparentTo(self.camera)
|
||||
self.oobeMode = 1
|
||||
|
||||
def __oobeButton(self, suffix, button):
|
||||
def __oobeButton(self, suffix: str, button: str) -> None:
|
||||
if button.startswith('mouse'):
|
||||
# Eat mouse buttons.
|
||||
return
|
||||
|
|
@ -3073,7 +3079,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
else:
|
||||
return Task.cont
|
||||
|
||||
def windowEvent(self, win):
|
||||
def windowEvent(self, win: GraphicsOutput) -> None:
|
||||
if win != self.win:
|
||||
# This event isn't about our window.
|
||||
return
|
||||
|
|
@ -3092,9 +3098,9 @@ class ShowBase(DirectObject.DirectObject):
|
|||
self.userExit()
|
||||
|
||||
if properties.getForeground() and not self.mainWinForeground:
|
||||
self.mainWinForeground = 1
|
||||
self.mainWinForeground = True
|
||||
elif not properties.getForeground() and self.mainWinForeground:
|
||||
self.mainWinForeground = 0
|
||||
self.mainWinForeground = False
|
||||
if __debug__:
|
||||
if self.__autoGarbageLogging:
|
||||
GarbageReport.b_checkForGarbageLeaks()
|
||||
|
|
@ -3102,12 +3108,12 @@ class ShowBase(DirectObject.DirectObject):
|
|||
if properties.getMinimized() and not self.mainWinMinimized:
|
||||
# If the main window is minimized, throw an event to
|
||||
# stop the music.
|
||||
self.mainWinMinimized = 1
|
||||
self.mainWinMinimized = True
|
||||
messenger.send('PandaPaused')
|
||||
elif not properties.getMinimized() and self.mainWinMinimized:
|
||||
# If the main window is restored, throw an event to
|
||||
# restart the music.
|
||||
self.mainWinMinimized = 0
|
||||
self.mainWinMinimized = False
|
||||
messenger.send('PandaRestarted')
|
||||
|
||||
# If we have not forced the aspect ratio, let's see if it has
|
||||
|
|
@ -3125,7 +3131,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
if self.wantRender2dp:
|
||||
self.pixel2dp.setScale(2.0 / xsize, 1.0, 2.0 / ysize)
|
||||
|
||||
def adjustWindowAspectRatio(self, aspectRatio):
|
||||
def adjustWindowAspectRatio(self, aspectRatio: float) -> None:
|
||||
""" This function is normally called internally by
|
||||
`windowEvent()`, but it may also be called to explicitly adjust
|
||||
the aspect ratio of the render/render2d DisplayRegion, by a
|
||||
|
|
@ -3512,6 +3518,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
remove_camera_frustum = removeCameraFrustum
|
||||
save_cube_map = saveCubeMap
|
||||
save_sphere_map = saveSphereMap
|
||||
user_exit = userExit
|
||||
start_wx = startWx
|
||||
start_tk = startTk
|
||||
start_direct = startDirect
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ aspect2d = render2d.attachNewNode(PGTop("aspect2d"))
|
|||
#: A dummy scene graph that is not being rendered by anything.
|
||||
hidden = NodePath("hidden")
|
||||
|
||||
loader: Loader
|
||||
#: The global Loader instance for models, textures, etc.
|
||||
loader = Loader()
|
||||
|
||||
# Set direct notify categories now that we have config
|
||||
directNotify.setDconfigLevels()
|
||||
|
|
|
|||
|
|
@ -5,477 +5,267 @@ Calling the :func:`register()` function to register the import hooks should be
|
|||
sufficient to enable this functionality.
|
||||
"""
|
||||
|
||||
__all__ = ['register', 'sharedPackages',
|
||||
'reloadSharedPackage', 'reloadSharedPackages']
|
||||
from __future__ import annotations
|
||||
|
||||
from panda3d.core import Filename, VirtualFileSystem, VirtualFileMountSystem, OFileStream, copyStream
|
||||
from direct.stdpy.file import open
|
||||
__all__ = ['register']
|
||||
|
||||
from panda3d.core import Filename, VirtualFile, VirtualFileSystem, VirtualFileMountSystem
|
||||
from panda3d.core import OFileStream, copy_stream
|
||||
import sys
|
||||
import marshal
|
||||
import imp
|
||||
import types
|
||||
import _imp
|
||||
import atexit
|
||||
from importlib.abc import Loader, SourceLoader
|
||||
from importlib.util import MAGIC_NUMBER, decode_source
|
||||
from importlib.machinery import ModuleSpec, EXTENSION_SUFFIXES, BYTECODE_SUFFIXES
|
||||
from types import ModuleType
|
||||
from typing import Any
|
||||
|
||||
#: The sharedPackages dictionary lists all of the "shared packages",
|
||||
#: special Python packages that automatically span multiple directories
|
||||
#: via magic in the VFSImporter. You can make a package "shared"
|
||||
#: simply by adding its name into this dictionary (and then calling
|
||||
#: reloadSharedPackages() if it's already been imported).
|
||||
#:
|
||||
#: When a package name is in this dictionary at import time, *all*
|
||||
#: instances of the package are located along sys.path, and merged into
|
||||
#: a single Python module with a __path__ setting that represents the
|
||||
#: union. Thus, you can have a direct.showbase.foo in your own
|
||||
#: application, and loading it won't shadow the system
|
||||
#: direct.showbase.ShowBase which is in a different directory on disk.
|
||||
sharedPackages = {}
|
||||
|
||||
vfs = VirtualFileSystem.getGlobalPtr()
|
||||
|
||||
compiledExtensions = ['pyc', 'pyo']
|
||||
if not __debug__:
|
||||
# In optimized mode, we prefer loading .pyo files over .pyc files.
|
||||
# We implement that by reversing the extension names.
|
||||
compiledExtensions = ['pyo', 'pyc']
|
||||
vfs = VirtualFileSystem.get_global_ptr()
|
||||
|
||||
|
||||
class VFSImporter:
|
||||
def _make_spec(fullname: str, loader: VFSLoader, *, is_package: bool) -> ModuleSpec:
|
||||
filename = loader._vfile.get_filename()
|
||||
spec = ModuleSpec(fullname, loader, origin=filename.to_os_specific(), is_package=is_package)
|
||||
if is_package:
|
||||
assert spec.submodule_search_locations is not None
|
||||
spec.submodule_search_locations.append(Filename(filename.get_dirname()).to_os_specific())
|
||||
spec.has_location = True
|
||||
return spec
|
||||
|
||||
|
||||
class VFSFinder:
|
||||
""" This class serves as a Python importer to support loading
|
||||
Python .py and .pyc/.pyo files from Panda's Virtual File System,
|
||||
which allows loading Python source files from mounted .mf files
|
||||
(among other places). """
|
||||
|
||||
def __init__(self, path):
|
||||
if isinstance(path, Filename):
|
||||
self.dir_path = Filename(path)
|
||||
else:
|
||||
self.dir_path = Filename.fromOsSpecific(path)
|
||||
def __init__(self, path: str) -> None:
|
||||
self.path = path
|
||||
|
||||
def find_module(self, fullname, path = None):
|
||||
if path is None:
|
||||
dir_path = self.dir_path
|
||||
else:
|
||||
dir_path = path
|
||||
#print >>sys.stderr, "find_module(%s), dir_path = %s" % (fullname, dir_path)
|
||||
def find_spec(self, fullname: str, target: ModuleType | None = None) -> ModuleSpec | None:
|
||||
#print(f"find_spec({fullname}), dir_path = {dir_path}", file=sys.stderr)
|
||||
basename = fullname.split('.')[-1]
|
||||
path = Filename(dir_path, basename)
|
||||
filename = Filename(Filename.from_os_specific(self.path), basename)
|
||||
|
||||
loader: VFSLoader
|
||||
|
||||
# First, look for Python files.
|
||||
filename = Filename(path)
|
||||
filename.setExtension('py')
|
||||
vfile = vfs.getFile(filename, True)
|
||||
vfile = vfs.get_file(filename + '.py', True)
|
||||
if vfile:
|
||||
return VFSLoader(dir_path, vfile, filename,
|
||||
desc=('.py', 'r', imp.PY_SOURCE))
|
||||
loader = VFSSourceLoader(fullname, vfile)
|
||||
return _make_spec(fullname, loader, is_package=False)
|
||||
|
||||
# If there's no .py file, but there's a .pyc file, load that
|
||||
# anyway.
|
||||
for ext in compiledExtensions:
|
||||
filename = Filename(path)
|
||||
filename.setExtension(ext)
|
||||
vfile = vfs.getFile(filename, True)
|
||||
for suffix in BYTECODE_SUFFIXES:
|
||||
vfile = vfs.get_file(filename + suffix, True)
|
||||
if vfile:
|
||||
return VFSLoader(dir_path, vfile, filename,
|
||||
desc=('.'+ext, 'rb', imp.PY_COMPILED))
|
||||
loader = VFSCompiledLoader(fullname, vfile)
|
||||
return _make_spec(fullname, loader, is_package=False)
|
||||
|
||||
# Look for a C/C++ extension module.
|
||||
for desc in imp.get_suffixes():
|
||||
if desc[2] != imp.C_EXTENSION:
|
||||
continue
|
||||
|
||||
filename = Filename(path + desc[0])
|
||||
vfile = vfs.getFile(filename, True)
|
||||
for suffix in EXTENSION_SUFFIXES:
|
||||
vfile = vfs.get_file(filename + suffix, True)
|
||||
if vfile:
|
||||
return VFSLoader(dir_path, vfile, filename, desc=desc)
|
||||
loader = VFSExtensionLoader(fullname, vfile)
|
||||
return _make_spec(fullname, loader, is_package=False)
|
||||
|
||||
# Finally, consider a package, i.e. a directory containing
|
||||
# __init__.py.
|
||||
filename = Filename(path, '__init__.py')
|
||||
vfile = vfs.getFile(filename, True)
|
||||
# Consider a package, i.e. a directory containing __init__.py.
|
||||
init_filename = Filename(filename, '__init__.py')
|
||||
vfile = vfs.get_file(init_filename, True)
|
||||
if vfile:
|
||||
return VFSLoader(dir_path, vfile, filename, packagePath=path,
|
||||
desc=('.py', 'r', imp.PY_SOURCE))
|
||||
for ext in compiledExtensions:
|
||||
filename = Filename(path, '__init__.' + ext)
|
||||
vfile = vfs.getFile(filename, True)
|
||||
if vfile:
|
||||
return VFSLoader(dir_path, vfile, filename, packagePath=path,
|
||||
desc=('.'+ext, 'rb', imp.PY_COMPILED))
|
||||
loader = VFSSourceLoader(fullname, vfile)
|
||||
return _make_spec(fullname, loader, is_package=True)
|
||||
|
||||
#print >>sys.stderr, "not found."
|
||||
for suffix in BYTECODE_SUFFIXES:
|
||||
init_filename = Filename(filename, '__init__' + suffix)
|
||||
vfile = vfs.get_file(init_filename, True)
|
||||
if vfile:
|
||||
loader = VFSCompiledLoader(fullname, vfile)
|
||||
return _make_spec(fullname, loader, is_package=True)
|
||||
|
||||
# Consider a namespace package.
|
||||
if vfs.is_directory(filename):
|
||||
spec = ModuleSpec(fullname, VFSNamespaceLoader(), is_package=True)
|
||||
assert spec.submodule_search_locations is not None
|
||||
spec.submodule_search_locations.append(filename.to_os_specific())
|
||||
return spec
|
||||
|
||||
#print("not found.", file=sys.stderr)
|
||||
return None
|
||||
|
||||
|
||||
class VFSLoader:
|
||||
""" The second part of VFSImporter, this is created for a
|
||||
particular .py file or directory. """
|
||||
|
||||
def __init__(self, dir_path, vfile, filename, desc, packagePath=None):
|
||||
self.dir_path = dir_path
|
||||
self.timestamp = None
|
||||
if vfile:
|
||||
self.timestamp = vfile.getTimestamp()
|
||||
self.filename = filename
|
||||
self.desc = desc
|
||||
self.packagePath = packagePath
|
||||
|
||||
def load_module(self, fullname, loadingShared = False):
|
||||
#print >>sys.stderr, "load_module(%s), dir_path = %s, filename = %s" % (fullname, self.dir_path, self.filename)
|
||||
if self.desc[2] == imp.PY_FROZEN:
|
||||
return self._import_frozen_module(fullname)
|
||||
if self.desc[2] == imp.C_EXTENSION:
|
||||
return self._import_extension_module(fullname)
|
||||
|
||||
# Check if this is a child of a shared package.
|
||||
if not loadingShared and self.packagePath and '.' in fullname:
|
||||
parentname = fullname.rsplit('.', 1)[0]
|
||||
if parentname in sharedPackages:
|
||||
# It is. That means it's a shared package too.
|
||||
parent = sys.modules[parentname]
|
||||
path = getattr(parent, '__path__', None)
|
||||
importer = VFSSharedImporter()
|
||||
sharedPackages[fullname] = True
|
||||
loader = importer.find_module(fullname, path = path)
|
||||
assert loader
|
||||
return loader.load_module(fullname)
|
||||
|
||||
code = self._read_code()
|
||||
if not code:
|
||||
raise ImportError('No Python code in %s' % (fullname))
|
||||
|
||||
mod = sys.modules.setdefault(fullname, imp.new_module(fullname))
|
||||
mod.__file__ = self.filename.toOsSpecific()
|
||||
mod.__loader__ = self
|
||||
if self.packagePath:
|
||||
mod.__path__ = [self.packagePath.toOsSpecific()]
|
||||
#print >> sys.stderr, "loaded %s, path = %s" % (fullname, mod.__path__)
|
||||
|
||||
exec(code, mod.__dict__)
|
||||
return sys.modules[fullname]
|
||||
|
||||
def getdata(self, path):
|
||||
path = Filename(self.dir_path, Filename.fromOsSpecific(path))
|
||||
vfile = vfs.getFile(path)
|
||||
if not vfile:
|
||||
raise IOError("Could not find '%s'" % (path))
|
||||
return vfile.readFile(True)
|
||||
class VFSLoader(Loader):
|
||||
def __init__(self, fullname: str, vfile: VirtualFile) -> None:
|
||||
self.name = fullname
|
||||
self._vfile = vfile
|
||||
|
||||
def is_package(self, fullname):
|
||||
return bool(self.packagePath)
|
||||
if fullname is not None and self.name != fullname:
|
||||
raise ImportError
|
||||
|
||||
filename = self._vfile.get_filename().get_basename()
|
||||
filename_base = filename.rsplit('.', 1)[0]
|
||||
tail_name = fullname.rpartition('.')[2]
|
||||
return filename_base == '__init__' and tail_name != '__init__'
|
||||
|
||||
def create_module(self, spec: ModuleSpec) -> ModuleType | None:
|
||||
"""Use default semantics for module creation."""
|
||||
|
||||
def exec_module(self, module: ModuleType) -> None:
|
||||
"""Execute the module."""
|
||||
code = self.get_code(module.__name__) # type: ignore[attr-defined]
|
||||
exec(code, module.__dict__)
|
||||
|
||||
def get_filename(self, fullname: str) -> str:
|
||||
if fullname is not None and self.name != fullname:
|
||||
raise ImportError
|
||||
|
||||
return self._vfile.get_filename().to_os_specific()
|
||||
|
||||
@staticmethod
|
||||
def get_data(path: str) -> bytes:
|
||||
vfile = vfs.get_file(Filename.from_os_specific(path))
|
||||
if vfile:
|
||||
return vfile.read_file(True)
|
||||
else:
|
||||
raise OSError
|
||||
|
||||
@staticmethod
|
||||
def path_stats(path: str) -> dict[str, Any]:
|
||||
vfile = vfs.get_file(Filename.from_os_specific(path))
|
||||
if vfile:
|
||||
return {'mtime': vfile.get_timestamp(), 'size': vfile.get_file_size()}
|
||||
else:
|
||||
raise OSError
|
||||
|
||||
@staticmethod
|
||||
def path_mtime(path):
|
||||
vfile = vfs.get_file(Filename.from_os_specific(path))
|
||||
if vfile:
|
||||
return vfile.get_timestamp()
|
||||
else:
|
||||
raise OSError
|
||||
|
||||
|
||||
class VFSSourceLoader(VFSLoader, SourceLoader): # type: ignore[misc]
|
||||
def get_source(self, fullname):
|
||||
if fullname is not None and self.name != fullname:
|
||||
raise ImportError
|
||||
|
||||
return decode_source(self._vfile.read_file(True))
|
||||
|
||||
|
||||
class VFSCompiledLoader(VFSLoader):
|
||||
def get_code(self, fullname):
|
||||
return self._read_code()
|
||||
if fullname is not None and self.name != fullname:
|
||||
raise ImportError
|
||||
|
||||
vfile = self._vfile
|
||||
data = vfile.read_file(True)
|
||||
if data[:4] != MAGIC_NUMBER:
|
||||
raise ImportError("Bad magic number in %s" % (vfile))
|
||||
|
||||
return marshal.loads(data[16:])
|
||||
|
||||
def get_source(self, fullname):
|
||||
return self._read_source()
|
||||
return None
|
||||
|
||||
def get_filename(self, fullname):
|
||||
return self.filename.toOsSpecific()
|
||||
|
||||
def _read_source(self):
|
||||
""" Returns the Python source for this file, if it is
|
||||
available, or None if it is not. May raise IOError. """
|
||||
|
||||
if self.desc[2] == imp.PY_COMPILED or \
|
||||
self.desc[2] == imp.C_EXTENSION:
|
||||
return None
|
||||
|
||||
filename = Filename(self.filename)
|
||||
filename.setExtension('py')
|
||||
filename.setText()
|
||||
|
||||
# Use the tokenize module to detect the encoding.
|
||||
import tokenize
|
||||
fh = open(self.filename, 'rb')
|
||||
encoding, lines = tokenize.detect_encoding(fh.readline)
|
||||
return (b''.join(lines) + fh.read()).decode(encoding)
|
||||
|
||||
def _import_extension_module(self, fullname):
|
||||
""" Loads the binary shared object as a Python module, and
|
||||
returns it. """
|
||||
|
||||
vfile = vfs.getFile(self.filename, False)
|
||||
class VFSExtensionLoader(VFSLoader):
|
||||
def create_module(self, spec):
|
||||
vfile = self._vfile
|
||||
filename = vfile.get_filename()
|
||||
|
||||
# We can only import an extension module if it already exists on
|
||||
# disk. This means if it's a truly virtual file that has no
|
||||
# on-disk equivalent, we have to write it to a temporary file
|
||||
# first.
|
||||
if hasattr(vfile, 'getMount') and \
|
||||
isinstance(vfile.getMount(), VirtualFileMountSystem):
|
||||
if isinstance(vfile.get_mount(), VirtualFileMountSystem):
|
||||
# It's a real file.
|
||||
filename = self.filename
|
||||
elif self.filename.exists():
|
||||
pass
|
||||
elif filename.exists():
|
||||
# It's a virtual file, but it's shadowing a real file in
|
||||
# the same directory. Assume they're the same, and load
|
||||
# the real one.
|
||||
filename = self.filename
|
||||
else:
|
||||
# It's a virtual file with no real-world existence. Dump
|
||||
# it to disk. TODO: clean up this filename.
|
||||
filename = Filename.temporary('', self.filename.getBasenameWoExtension(),
|
||||
'.' + self.filename.getExtension(),
|
||||
type = Filename.TDso)
|
||||
filename.setExtension(self.filename.getExtension())
|
||||
filename.setBinary()
|
||||
sin = vfile.openReadFile(True)
|
||||
sout = OFileStream()
|
||||
if not filename.openWrite(sout):
|
||||
raise IOError
|
||||
if not copyStream(sin, sout):
|
||||
raise IOError
|
||||
vfile.closeReadFile(sin)
|
||||
del sout
|
||||
|
||||
module = imp.load_module(fullname, None, filename.toOsSpecific(),
|
||||
self.desc)
|
||||
module.__file__ = self.filename.toOsSpecific()
|
||||
return module
|
||||
|
||||
def _import_frozen_module(self, fullname):
|
||||
""" Imports the frozen module without messing around with
|
||||
searching any more. """
|
||||
#print >>sys.stderr, "importing frozen %s" % (fullname)
|
||||
module = imp.load_module(fullname, None, fullname,
|
||||
('', '', imp.PY_FROZEN))
|
||||
module.__path__ = []
|
||||
return module
|
||||
|
||||
def _read_code(self):
|
||||
""" Returns the Python compiled code object for this file, if
|
||||
it is available, or None if it is not. May raise IOError,
|
||||
ValueError, SyntaxError, or a number of other errors generated
|
||||
by the low-level system. """
|
||||
|
||||
if self.desc[2] == imp.PY_COMPILED:
|
||||
# It's a pyc file; just read it directly.
|
||||
pycVfile = vfs.getFile(self.filename, False)
|
||||
if pycVfile:
|
||||
return self._loadPyc(pycVfile, None)
|
||||
raise IOError('Could not read %s' % (self.filename))
|
||||
|
||||
elif self.desc[2] == imp.C_EXTENSION:
|
||||
return None
|
||||
|
||||
# It's a .py file (or an __init__.py file; same thing). Read
|
||||
# the .pyc file if it is available and current; otherwise read
|
||||
# the .py file and compile it.
|
||||
t_pyc = None
|
||||
for ext in compiledExtensions:
|
||||
pycFilename = Filename(self.filename)
|
||||
pycFilename.setExtension(ext)
|
||||
pycVfile = vfs.getFile(pycFilename, False)
|
||||
if pycVfile:
|
||||
t_pyc = pycVfile.getTimestamp()
|
||||
break
|
||||
|
||||
code = None
|
||||
if t_pyc and t_pyc >= self.timestamp:
|
||||
try:
|
||||
code = self._loadPyc(pycVfile, self.timestamp)
|
||||
except ValueError:
|
||||
code = None
|
||||
|
||||
if not code:
|
||||
source = self._read_source()
|
||||
filename = Filename(self.filename)
|
||||
filename.setExtension('py')
|
||||
code = self._compile(filename, source)
|
||||
|
||||
return code
|
||||
|
||||
def _loadPyc(self, vfile, timestamp):
|
||||
""" Reads and returns the marshal data from a .pyc file.
|
||||
Raises ValueError if there is a problem. """
|
||||
|
||||
code = None
|
||||
data = vfile.readFile(True)
|
||||
if data[:4] != imp.get_magic():
|
||||
raise ValueError("Bad magic number in %s" % (vfile))
|
||||
|
||||
t = int.from_bytes(data[4:8], 'little')
|
||||
data = data[12:]
|
||||
|
||||
if not timestamp or t == timestamp:
|
||||
return marshal.loads(data)
|
||||
else:
|
||||
raise ValueError("Timestamp wrong on %s" % (vfile))
|
||||
|
||||
def _compile(self, filename, source):
|
||||
""" Compiles the Python source code to a code object and
|
||||
attempts to write it to an appropriate .pyc file. May raise
|
||||
SyntaxError or other errors generated by the compiler. """
|
||||
|
||||
if source and source[-1] != '\n':
|
||||
source = source + '\n'
|
||||
code = compile(source, filename.toOsSpecific(), 'exec')
|
||||
|
||||
# try to cache the compiled code
|
||||
pycFilename = Filename(filename)
|
||||
pycFilename.setExtension(compiledExtensions[0])
|
||||
try:
|
||||
f = open(pycFilename.toOsSpecific(), 'wb')
|
||||
except IOError:
|
||||
pass
|
||||
else:
|
||||
f.write(imp.get_magic())
|
||||
f.write((self.timestamp & 0xffffffff).to_bytes(4, 'little'))
|
||||
f.write(b'\0\0\0\0')
|
||||
f.write(marshal.dumps(code))
|
||||
f.close()
|
||||
|
||||
return code
|
||||
|
||||
|
||||
class VFSSharedImporter:
|
||||
""" This is a special importer that is added onto the meta_path
|
||||
list, so that it is called before sys.path is traversed. It uses
|
||||
special logic to load one of the "shared" packages, by searching
|
||||
the entire sys.path for all instances of this shared package, and
|
||||
merging them. """
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def find_module(self, fullname, path = None, reload = False):
|
||||
#print >>sys.stderr, "shared find_module(%s), path = %s" % (fullname, path)
|
||||
|
||||
if fullname not in sharedPackages:
|
||||
# Not a shared package; fall back to normal import.
|
||||
return None
|
||||
|
||||
if path is None:
|
||||
path = sys.path
|
||||
|
||||
excludePaths = []
|
||||
if reload:
|
||||
# If reload is true, we are simply reloading the module,
|
||||
# looking for new paths to add.
|
||||
mod = sys.modules[fullname]
|
||||
excludePaths = getattr(mod, '_vfs_shared_path', None)
|
||||
if excludePaths is None:
|
||||
# If there isn't a _vfs_shared_path symbol already,
|
||||
# the module must have been loaded through
|
||||
# conventional means. Try to guess which path it was
|
||||
# found on.
|
||||
d = self.getLoadedDirname(mod)
|
||||
excludePaths = [d]
|
||||
|
||||
loaders = []
|
||||
for dir in path:
|
||||
if dir in excludePaths:
|
||||
continue
|
||||
|
||||
importer = sys.path_importer_cache.get(dir, None)
|
||||
if importer is None:
|
||||
try:
|
||||
importer = VFSImporter(dir)
|
||||
except ImportError:
|
||||
continue
|
||||
|
||||
sys.path_importer_cache[dir] = importer
|
||||
|
||||
# It's a virtual file with no real-world existence. Dump
|
||||
# it to disk.
|
||||
ext = filename.get_extension()
|
||||
tmp_filename = Filename.temporary('', filename.get_basename_wo_extension(),
|
||||
'.' + ext,
|
||||
type = Filename.T_dso)
|
||||
tmp_filename.set_extension(ext)
|
||||
tmp_filename.set_binary()
|
||||
sin = vfile.open_read_file(True)
|
||||
try:
|
||||
loader = importer.find_module(fullname)
|
||||
if not loader:
|
||||
continue
|
||||
except ImportError:
|
||||
continue
|
||||
sout = OFileStream()
|
||||
if not tmp_filename.open_write(sout):
|
||||
raise IOError
|
||||
if not copy_stream(sin, sout):
|
||||
raise IOError
|
||||
finally:
|
||||
vfile.close_read_file(sin)
|
||||
del sout
|
||||
|
||||
loaders.append(loader)
|
||||
# Delete when the process ends.
|
||||
atexit.register(tmp_filename.unlink)
|
||||
|
||||
if not loaders:
|
||||
return None
|
||||
return VFSSharedLoader(loaders, reload = reload)
|
||||
# Make a dummy spec to pass to create_dynamic with the path to
|
||||
# our temporary file.
|
||||
spec = ModuleSpec(spec.name, spec.loader,
|
||||
origin=tmp_filename.to_os_specific(),
|
||||
is_package=False)
|
||||
|
||||
def getLoadedDirname(self, mod):
|
||||
""" Returns the directory name that the indicated
|
||||
conventionally-loaded module must have been loaded from. """
|
||||
module = _imp.create_dynamic(spec)
|
||||
module.__file__ = filename.to_os_specific()
|
||||
return module
|
||||
|
||||
if not getattr(mod, '__file__', None):
|
||||
return None
|
||||
def exec_module(self, module):
|
||||
_imp.exec_dynamic(module)
|
||||
|
||||
fullname = mod.__name__
|
||||
dirname = Filename.fromOsSpecific(mod.__file__).getDirname()
|
||||
def is_package(self, fullname):
|
||||
return False
|
||||
|
||||
parentname = None
|
||||
basename = fullname
|
||||
if '.' in fullname:
|
||||
parentname, basename = fullname.rsplit('.', 1)
|
||||
def get_code(self, fullname):
|
||||
return None
|
||||
|
||||
path = None
|
||||
if parentname:
|
||||
parent = sys.modules[parentname]
|
||||
path = parent.__path__
|
||||
if path is None:
|
||||
path = sys.path
|
||||
|
||||
for dir in path:
|
||||
pdir = str(Filename.fromOsSpecific(dir))
|
||||
if pdir + '/' + basename == dirname:
|
||||
# We found it!
|
||||
return dir
|
||||
|
||||
# Couldn't figure it out.
|
||||
def get_source(self, fullname):
|
||||
return None
|
||||
|
||||
|
||||
class VFSSharedLoader:
|
||||
""" The second part of VFSSharedImporter, this imports a list of
|
||||
packages and combines them. """
|
||||
class VFSNamespaceLoader(Loader):
|
||||
def create_module(self, spec: ModuleSpec) -> ModuleType | None:
|
||||
"""Use default semantics for module creation."""
|
||||
|
||||
def __init__(self, loaders, reload):
|
||||
self.loaders = loaders
|
||||
self.reload = reload
|
||||
def exec_module(self, module: ModuleType) -> None:
|
||||
pass
|
||||
|
||||
def load_module(self, fullname):
|
||||
#print >>sys.stderr, "shared load_module(%s), loaders = %s" % (fullname, map(lambda l: l.dir_path, self.loaders))
|
||||
def is_package(self, fullname):
|
||||
return True
|
||||
|
||||
mod = None
|
||||
message = None
|
||||
path = []
|
||||
vfs_shared_path = []
|
||||
if self.reload:
|
||||
mod = sys.modules[fullname]
|
||||
path = mod.__path__ or []
|
||||
if path == fullname:
|
||||
# Work around Python bug setting __path__ of frozen modules.
|
||||
path = []
|
||||
vfs_shared_path = getattr(mod, '_vfs_shared_path', [])
|
||||
def get_source(self, fullname):
|
||||
return ''
|
||||
|
||||
for loader in self.loaders:
|
||||
try:
|
||||
mod = loader.load_module(fullname, loadingShared = True)
|
||||
except ImportError:
|
||||
etype, evalue, etraceback = sys.exc_info()
|
||||
print("%s on %s: %s" % (etype.__name__, fullname, evalue))
|
||||
if not message:
|
||||
message = '%s: %s' % (fullname, evalue)
|
||||
continue
|
||||
for dir in getattr(mod, '__path__', []):
|
||||
if dir not in path:
|
||||
path.append(dir)
|
||||
def get_code(self, fullname):
|
||||
return compile('', '<string>', 'exec', dont_inherit=True)
|
||||
|
||||
if mod is None:
|
||||
# If all of them failed to load, raise ImportError.
|
||||
raise ImportError(message)
|
||||
|
||||
# If at least one of them loaded successfully, return the
|
||||
# union of loaded modules.
|
||||
mod.__path__ = path
|
||||
mod.__package__ = fullname
|
||||
|
||||
# Also set this special symbol, which records that this is a
|
||||
# shared package, and also lists the paths we have already
|
||||
# loaded.
|
||||
mod._vfs_shared_path = vfs_shared_path + [l.dir_path for l in self.loaders]
|
||||
|
||||
return mod
|
||||
def _path_hook(entry: str) -> VFSFinder:
|
||||
# If this is a directory in the VFS, create a VFSFinder for this entry.
|
||||
vfile = vfs.get_file(Filename.from_os_specific(entry), False)
|
||||
if vfile and vfile.is_directory() and not isinstance(vfile.get_mount(), VirtualFileMountSystem):
|
||||
return VFSFinder(entry)
|
||||
else:
|
||||
raise ImportError
|
||||
|
||||
|
||||
_registered = False
|
||||
|
||||
|
||||
def register():
|
||||
""" Register the VFSImporter on the path_hooks, if it has not
|
||||
def register() -> None:
|
||||
""" Register the VFSFinder on the path_hooks, if it has not
|
||||
already been registered, so that future Python import statements
|
||||
will vector through here (and therefore will take advantage of
|
||||
Panda's virtual file system). """
|
||||
|
|
@ -483,55 +273,9 @@ def register():
|
|||
global _registered
|
||||
if not _registered:
|
||||
_registered = True
|
||||
sys.path_hooks.insert(0, VFSImporter)
|
||||
sys.meta_path.insert(0, VFSSharedImporter())
|
||||
sys.path_hooks.insert(0, _path_hook)
|
||||
|
||||
# Blow away the importer cache, so we'll come back through the
|
||||
# VFSImporter for every folder in the future, even those
|
||||
# VFSFinder for every folder in the future, even those
|
||||
# folders that previously were loaded directly.
|
||||
sys.path_importer_cache = {}
|
||||
|
||||
|
||||
def reloadSharedPackage(mod):
|
||||
""" Reloads the specific module as a shared package, adding any
|
||||
new directories that might have appeared on the search path. """
|
||||
|
||||
fullname = mod.__name__
|
||||
path = None
|
||||
if '.' in fullname:
|
||||
parentname = fullname.rsplit('.', 1)[0]
|
||||
parent = sys.modules[parentname]
|
||||
path = parent.__path__
|
||||
|
||||
importer = VFSSharedImporter()
|
||||
loader = importer.find_module(fullname, path = path, reload = True)
|
||||
if loader:
|
||||
loader.load_module(fullname)
|
||||
|
||||
# Also force any child packages to become shared packages, if
|
||||
# they aren't already.
|
||||
for basename, child in list(mod.__dict__.items()):
|
||||
if isinstance(child, types.ModuleType):
|
||||
childname = child.__name__
|
||||
if childname == fullname + '.' + basename and \
|
||||
hasattr(child, '__path__') and \
|
||||
childname not in sharedPackages:
|
||||
sharedPackages[childname] = True
|
||||
reloadSharedPackage(child)
|
||||
|
||||
|
||||
def reloadSharedPackages():
|
||||
""" Walks through the sharedPackages list, and forces a reload of
|
||||
any modules on that list that have already been loaded. This
|
||||
allows new directories to be added to the search path. """
|
||||
|
||||
#print >> sys.stderr, "reloadSharedPackages, path = %s, sharedPackages = %s" % (sys.path, sharedPackages.keys())
|
||||
|
||||
# Sort the list, just to make sure parent packages are reloaded
|
||||
# before child packages are.
|
||||
for fullname in sorted(sharedPackages.keys()):
|
||||
mod = sys.modules.get(fullname, None)
|
||||
if not mod:
|
||||
continue
|
||||
|
||||
reloadSharedPackage(mod)
|
||||
|
|
|
|||
|
|
@ -45,15 +45,6 @@ ConfigureDef(config_showbase);
|
|||
ConfigureFn(config_showbase) {
|
||||
}
|
||||
|
||||
ConfigVariableSearchPath particle_path
|
||||
("particle-path",
|
||||
PRC_DESC("The directories to search for particle files to be loaded."));
|
||||
|
||||
ConfigVariableSearchPath &
|
||||
get_particle_path() {
|
||||
return particle_path;
|
||||
}
|
||||
|
||||
// Throw the "NewFrame" event in the C++ world. Some of the lerp code depends
|
||||
// on receiving this.
|
||||
void
|
||||
|
|
|
|||
|
|
@ -22,8 +22,6 @@
|
|||
#include "animControl.h"
|
||||
#include "pointerTo.h"
|
||||
#include "dconfig.h"
|
||||
#include "dSearchPath.h"
|
||||
#include "configVariableSearchPath.h"
|
||||
#include "nodePath.h"
|
||||
|
||||
ConfigureDecl(config_showbase, EXPCL_DIRECT_SHOWBASE, EXPTP_DIRECT_SHOWBASE);
|
||||
|
|
@ -34,8 +32,6 @@ class GraphicsEngine;
|
|||
|
||||
BEGIN_PUBLISH
|
||||
|
||||
EXPCL_DIRECT_SHOWBASE ConfigVariableSearchPath &get_particle_path();
|
||||
|
||||
EXPCL_DIRECT_SHOWBASE void throw_new_frame();
|
||||
|
||||
EXPCL_DIRECT_SHOWBASE void init_app_for_gui();
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ in some compilation models, Panda's threading constructs are
|
|||
incompatible with the OS-provided threads used by Python's thread
|
||||
module. """
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = [
|
||||
'error', 'LockType',
|
||||
'start_new_thread',
|
||||
|
|
@ -19,6 +21,9 @@ __all__ = [
|
|||
from panda3d import core
|
||||
import sys
|
||||
|
||||
from collections.abc import Callable, Iterable, Mapping
|
||||
from typing import Any
|
||||
|
||||
if sys.platform == "win32":
|
||||
TIMEOUT_MAX = float(0xffffffff // 1000)
|
||||
else:
|
||||
|
|
@ -41,12 +46,12 @@ class LockType:
|
|||
allows a different thread to release the lock than the one that
|
||||
acquired it. """
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
self.__lock = core.Mutex('PythonLock')
|
||||
self.__cvar = core.ConditionVar(self.__lock)
|
||||
self.__locked = False
|
||||
|
||||
def acquire(self, waitflag = 1, timeout = -1):
|
||||
def acquire(self, waitflag: bool = True, timeout: float = -1) -> bool:
|
||||
self.__lock.acquire()
|
||||
try:
|
||||
if self.__locked and not waitflag:
|
||||
|
|
@ -65,7 +70,7 @@ class LockType:
|
|||
finally:
|
||||
self.__lock.release()
|
||||
|
||||
def release(self):
|
||||
def release(self) -> None:
|
||||
self.__lock.acquire()
|
||||
try:
|
||||
if not self.__locked:
|
||||
|
|
@ -90,18 +95,23 @@ class LockType:
|
|||
_counter = 0
|
||||
|
||||
|
||||
def _newname(template="Thread-%d"):
|
||||
def _newname(template: str = "Thread-%d") -> str:
|
||||
global _counter
|
||||
_counter = _counter + 1
|
||||
return template % _counter
|
||||
|
||||
|
||||
_threads = {}
|
||||
_threads: dict[int, tuple[core.Thread, dict[int, dict[str, Any]], Any | None]] = {}
|
||||
_nextThreadId = 0
|
||||
_threadsLock = core.Mutex('thread._threadsLock')
|
||||
|
||||
|
||||
def start_new_thread(function, args, kwargs = {}, name = None):
|
||||
def start_new_thread(
|
||||
function: Callable[..., object],
|
||||
args: Iterable[Any],
|
||||
kwargs: Mapping[str, Any] = {},
|
||||
name: str | None = None,
|
||||
) -> int:
|
||||
def threadFunc(threadId, function = function, args = args, kwargs = kwargs):
|
||||
try:
|
||||
try:
|
||||
|
|
@ -132,7 +142,7 @@ def start_new_thread(function, args, kwargs = {}, name = None):
|
|||
_threadsLock.release()
|
||||
|
||||
|
||||
def _add_thread(thread, wrapper):
|
||||
def _add_thread(thread: core.Thread, wrapper: Any) -> int:
|
||||
""" Adds the indicated core.Thread object, with the indicated Python
|
||||
wrapper, to the thread list. Returns the new thread ID. """
|
||||
|
||||
|
|
@ -150,7 +160,7 @@ def _add_thread(thread, wrapper):
|
|||
_threadsLock.release()
|
||||
|
||||
|
||||
def _get_thread_wrapper(thread, wrapperClass):
|
||||
def _get_thread_wrapper(thread: core.Thread, wrapperClass: Callable[[core.Thread, int], Any]) -> Any:
|
||||
""" Returns the thread wrapper for the indicated thread. If there
|
||||
is not one, creates an instance of the indicated wrapperClass
|
||||
instead. """
|
||||
|
|
@ -222,7 +232,7 @@ def _get_thread_locals(thread, i):
|
|||
_threadsLock.release()
|
||||
|
||||
|
||||
def _remove_thread_id(threadId):
|
||||
def _remove_thread_id(threadId: int) -> None:
|
||||
""" Removes the thread with the indicated ID from the thread list. """
|
||||
|
||||
# On interpreter shutdown, Python may set module globals to None.
|
||||
|
|
@ -250,11 +260,11 @@ def exit():
|
|||
raise SystemExit
|
||||
|
||||
|
||||
def allocate_lock():
|
||||
def allocate_lock() -> LockType:
|
||||
return LockType()
|
||||
|
||||
|
||||
def get_ident():
|
||||
def get_ident() -> int:
|
||||
return core.Thread.getCurrentThread().this
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,12 +21,17 @@ easier to use and understand.
|
|||
It is permissible to mix-and-match both threading and threading2
|
||||
within the same application. """
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from panda3d import core
|
||||
from direct.stdpy import thread as _thread
|
||||
import sys as _sys
|
||||
|
||||
import weakref
|
||||
|
||||
from collections.abc import Callable, Iterable, Mapping
|
||||
from typing import Any, NoReturn
|
||||
|
||||
__all__ = [
|
||||
'Thread',
|
||||
'Lock', 'RLock',
|
||||
|
|
@ -54,10 +59,14 @@ class ThreadBase:
|
|||
""" A base class for both Thread and ExternalThread in this
|
||||
module. """
|
||||
|
||||
def __init__(self):
|
||||
name: str
|
||||
ident: int
|
||||
daemon: bool
|
||||
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
def getName(self):
|
||||
def getName(self) -> str:
|
||||
return self.name
|
||||
|
||||
def isDaemon(self):
|
||||
|
|
@ -92,7 +101,15 @@ class Thread(ThreadBase):
|
|||
object. The wrapper is designed to emulate Python's own
|
||||
threading.Thread object. """
|
||||
|
||||
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}, daemon=None):
|
||||
def __init__(
|
||||
self,
|
||||
group: None = None,
|
||||
target: Callable[..., object] | None = None,
|
||||
name: str | None = None,
|
||||
args: Iterable[Any] = (),
|
||||
kwargs: Mapping[str, Any] = {},
|
||||
daemon: bool | None = None,
|
||||
) -> None:
|
||||
ThreadBase.__init__(self)
|
||||
|
||||
assert group is None
|
||||
|
|
@ -131,7 +148,7 @@ class Thread(ThreadBase):
|
|||
|
||||
isAlive = is_alive
|
||||
|
||||
def start(self):
|
||||
def start(self) -> None:
|
||||
thread = self.__thread
|
||||
if thread is None or thread.is_started():
|
||||
raise RuntimeError
|
||||
|
|
@ -147,7 +164,7 @@ class Thread(ThreadBase):
|
|||
|
||||
self.__target(*self.__args, **self.__kwargs)
|
||||
|
||||
def join(self, timeout = None):
|
||||
def join(self, timeout: float | None = None) -> None:
|
||||
# We don't support a timed join here, sorry.
|
||||
assert timeout is None
|
||||
thread = self.__thread
|
||||
|
|
@ -157,7 +174,7 @@ class Thread(ThreadBase):
|
|||
self.__thread = None
|
||||
_thread._remove_thread_id(self.ident)
|
||||
|
||||
def setName(self, name):
|
||||
def setName(self, name: str) -> None:
|
||||
self.__dict__['name'] = name
|
||||
self.__thread.setName(name)
|
||||
|
||||
|
|
@ -166,7 +183,7 @@ class ExternalThread(ThreadBase):
|
|||
""" Returned for a Thread object that wasn't created by this
|
||||
interface. """
|
||||
|
||||
def __init__(self, extThread, threadId):
|
||||
def __init__(self, extThread: core.Thread, threadId: int) -> None:
|
||||
ThreadBase.__init__(self)
|
||||
|
||||
self.__thread = extThread
|
||||
|
|
@ -196,7 +213,7 @@ class ExternalThread(ThreadBase):
|
|||
class MainThread(ExternalThread):
|
||||
""" Returned for the MainThread object. """
|
||||
|
||||
def __init__(self, extThread, threadId):
|
||||
def __init__(self, extThread: core.Thread, threadId: int) -> None:
|
||||
ExternalThread.__init__(self, extThread, threadId)
|
||||
self.__dict__['daemon'] = False
|
||||
|
||||
|
|
@ -206,7 +223,7 @@ class Lock(core.Mutex):
|
|||
The wrapper is designed to emulate Python's own threading.Lock
|
||||
object. """
|
||||
|
||||
def __init__(self, name = "PythonLock"):
|
||||
def __init__(self, name: str = "PythonLock") -> None:
|
||||
core.Mutex.__init__(self, name)
|
||||
|
||||
|
||||
|
|
@ -224,7 +241,7 @@ class Condition(core.ConditionVar):
|
|||
object. The wrapper is designed to emulate Python's own
|
||||
threading.Condition object. """
|
||||
|
||||
def __init__(self, lock = None):
|
||||
def __init__(self, lock: Lock | RLock | None = None) -> None:
|
||||
if not lock:
|
||||
lock = Lock()
|
||||
|
||||
|
|
@ -241,7 +258,7 @@ class Condition(core.ConditionVar):
|
|||
def release(self):
|
||||
self.__lock.release()
|
||||
|
||||
def wait(self, timeout = None):
|
||||
def wait(self, timeout: float | None = None) -> None:
|
||||
if timeout is None:
|
||||
core.ConditionVar.wait(self)
|
||||
else:
|
||||
|
|
@ -373,8 +390,9 @@ class Timer(Thread):
|
|||
self.finished.set()
|
||||
|
||||
|
||||
def _create_thread_wrapper(t, threadId):
|
||||
def _create_thread_wrapper(t: core.Thread, threadId: int) -> ExternalThread:
|
||||
""" Creates a thread wrapper for the indicated external thread. """
|
||||
pyt: ExternalThread
|
||||
if isinstance(t, core.MainThread):
|
||||
pyt = MainThread(t, threadId)
|
||||
else:
|
||||
|
|
@ -383,7 +401,7 @@ def _create_thread_wrapper(t, threadId):
|
|||
return pyt
|
||||
|
||||
|
||||
def current_thread():
|
||||
def current_thread() -> ThreadBase:
|
||||
t = core.Thread.getCurrentThread()
|
||||
return _thread._get_thread_wrapper(t, _create_thread_wrapper)
|
||||
|
||||
|
|
@ -430,5 +448,5 @@ def setprofile(func):
|
|||
_setprofile_func = func
|
||||
|
||||
|
||||
def stack_size(size = None):
|
||||
def stack_size(size: object = None) -> NoReturn:
|
||||
raise ThreadError
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ to import Panda's thread reimplementation instead of the system thread
|
|||
module, and so it is therefore layered on top of Panda's thread
|
||||
implementation. """
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys as _sys
|
||||
import atexit as _atexit
|
||||
|
||||
|
|
@ -21,8 +23,10 @@ from direct.stdpy.thread import stack_size, _newname, _local as local
|
|||
from panda3d import core
|
||||
_sleep = core.Thread.sleep
|
||||
|
||||
from collections.abc import Callable, Iterable, Mapping
|
||||
from time import time as _time
|
||||
from traceback import format_exc as _format_exc
|
||||
from typing import Any
|
||||
|
||||
__all__ = ['get_ident', 'active_count', 'Condition', 'current_thread',
|
||||
'enumerate', 'main_thread', 'TIMEOUT_MAX',
|
||||
|
|
@ -51,12 +55,12 @@ if __debug__:
|
|||
|
||||
class _Verbose(object):
|
||||
|
||||
def __init__(self, verbose=None):
|
||||
def __init__(self, verbose: bool | None = None) -> None:
|
||||
if verbose is None:
|
||||
verbose = _VERBOSE
|
||||
self.__verbose = verbose
|
||||
|
||||
def _note(self, format, *args):
|
||||
def _note(self, format: str, *args: Any) -> None:
|
||||
if self.__verbose:
|
||||
format = format % args
|
||||
format = "%s: %s\n" % (
|
||||
|
|
@ -66,9 +70,9 @@ if __debug__:
|
|||
else:
|
||||
# Disable this when using "python -O"
|
||||
class _Verbose(object): # type: ignore[no-redef]
|
||||
def __init__(self, verbose=None):
|
||||
def __init__(self, verbose: bool | None = None) -> None:
|
||||
pass
|
||||
def _note(self, *args):
|
||||
def _note(self, *args) -> None:
|
||||
pass
|
||||
|
||||
# Support for profile and trace hooks
|
||||
|
|
@ -88,15 +92,15 @@ def settrace(func):
|
|||
|
||||
Lock = _allocate_lock
|
||||
|
||||
def RLock(*args, **kwargs):
|
||||
return _RLock(*args, **kwargs)
|
||||
def RLock(verbose: bool | None = None) -> _RLock:
|
||||
return _RLock(verbose)
|
||||
|
||||
class _RLock(_Verbose):
|
||||
|
||||
def __init__(self, verbose=None):
|
||||
def __init__(self, verbose: bool | None = None) -> None:
|
||||
_Verbose.__init__(self, verbose)
|
||||
self.__block = _allocate_lock()
|
||||
self.__owner = None
|
||||
self.__owner: Thread | None = None
|
||||
self.__count = 0
|
||||
|
||||
def __repr__(self):
|
||||
|
|
@ -105,13 +109,13 @@ class _RLock(_Verbose):
|
|||
self.__owner and self.__owner.getName(),
|
||||
self.__count)
|
||||
|
||||
def acquire(self, blocking=1):
|
||||
def acquire(self, blocking: bool = True) -> bool:
|
||||
me = currentThread()
|
||||
if self.__owner is me:
|
||||
self.__count = self.__count + 1
|
||||
if __debug__:
|
||||
self._note("%s.acquire(%s): recursive success", self, blocking)
|
||||
return 1
|
||||
return True
|
||||
rc = self.__block.acquire(blocking)
|
||||
if rc:
|
||||
self.__owner = me
|
||||
|
|
@ -125,7 +129,7 @@ class _RLock(_Verbose):
|
|||
|
||||
__enter__ = acquire
|
||||
|
||||
def release(self):
|
||||
def release(self) -> None:
|
||||
me = currentThread()
|
||||
assert self.__owner is me, "release() of un-acquire()d lock"
|
||||
self.__count = count = self.__count - 1
|
||||
|
|
@ -163,12 +167,12 @@ class _RLock(_Verbose):
|
|||
return self.__owner is currentThread()
|
||||
|
||||
|
||||
def Condition(*args, **kwargs):
|
||||
return _Condition(*args, **kwargs)
|
||||
def Condition(lock: _thread.LockType | _RLock | None = None, verbose: bool | None = None) -> _Condition:
|
||||
return _Condition(lock, verbose)
|
||||
|
||||
class _Condition(_Verbose):
|
||||
|
||||
def __init__(self, lock=None, verbose=None):
|
||||
def __init__(self, lock: _thread.LockType | _RLock | None = None, verbose: bool | None = None) -> None:
|
||||
_Verbose.__init__(self, verbose)
|
||||
if lock is None:
|
||||
lock = RLock()
|
||||
|
|
@ -180,18 +184,18 @@ class _Condition(_Verbose):
|
|||
# these override the default implementations (which just call
|
||||
# release() and acquire() on the lock). Ditto for _is_owned().
|
||||
try:
|
||||
self._release_save = lock._release_save
|
||||
self._release_save = lock._release_save # type: ignore[method-assign, union-attr]
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
self._acquire_restore = lock._acquire_restore
|
||||
self._acquire_restore = lock._acquire_restore # type: ignore[method-assign, union-attr]
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
self._is_owned = lock._is_owned
|
||||
self._is_owned = lock._is_owned # type: ignore[method-assign, union-attr]
|
||||
except AttributeError:
|
||||
pass
|
||||
self.__waiters = []
|
||||
self.__waiters: list[_thread.LockType] = []
|
||||
|
||||
def __enter__(self):
|
||||
return self.__lock.__enter__()
|
||||
|
|
@ -202,22 +206,22 @@ class _Condition(_Verbose):
|
|||
def __repr__(self):
|
||||
return "<Condition(%s, %d)>" % (self.__lock, len(self.__waiters))
|
||||
|
||||
def _release_save(self): # pylint: disable=method-hidden
|
||||
def _release_save(self) -> Any: # pylint: disable=method-hidden
|
||||
self.__lock.release() # No state to save
|
||||
|
||||
def _acquire_restore(self, x): # pylint: disable=method-hidden
|
||||
def _acquire_restore(self, x) -> None: # pylint: disable=method-hidden
|
||||
self.__lock.acquire() # Ignore saved state
|
||||
|
||||
def _is_owned(self): # pylint: disable=method-hidden
|
||||
def _is_owned(self) -> bool: # pylint: disable=method-hidden
|
||||
# Return True if lock is owned by currentThread.
|
||||
# This method is called only if __lock doesn't have _is_owned().
|
||||
if self.__lock.acquire(0):
|
||||
if self.__lock.acquire(False):
|
||||
self.__lock.release()
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def wait(self, timeout=None):
|
||||
def wait(self, timeout: float | None = None) -> None:
|
||||
assert self._is_owned(), "wait() of un-acquire()d lock"
|
||||
waiter = _allocate_lock()
|
||||
waiter.acquire()
|
||||
|
|
@ -237,7 +241,7 @@ class _Condition(_Verbose):
|
|||
endtime = _time() + timeout
|
||||
delay = 0.0005 # 500 us -> initial delay of 1 ms
|
||||
while True:
|
||||
gotit = waiter.acquire(0)
|
||||
gotit = waiter.acquire(False)
|
||||
if gotit:
|
||||
break
|
||||
remaining = endtime - _time()
|
||||
|
|
@ -258,7 +262,7 @@ class _Condition(_Verbose):
|
|||
finally:
|
||||
self._acquire_restore(saved_state)
|
||||
|
||||
def notify(self, n=1):
|
||||
def notify(self, n: int = 1) -> None:
|
||||
assert self._is_owned(), "notify() of un-acquire()d lock"
|
||||
__waiters = self.__waiters
|
||||
waiters = __waiters[:n]
|
||||
|
|
@ -275,7 +279,7 @@ class _Condition(_Verbose):
|
|||
except ValueError:
|
||||
pass
|
||||
|
||||
def notifyAll(self):
|
||||
def notifyAll(self) -> None:
|
||||
self.notify(len(self.__waiters))
|
||||
|
||||
|
||||
|
|
@ -381,7 +385,7 @@ class _Event(_Verbose):
|
|||
|
||||
# Active thread administration
|
||||
_active_limbo_lock = _allocate_lock()
|
||||
_active = {} # maps thread id to Thread object
|
||||
_active: dict[int, Thread] = {} # maps thread id to Thread object
|
||||
_limbo = {}
|
||||
|
||||
|
||||
|
|
@ -400,8 +404,16 @@ class Thread(_Verbose):
|
|||
# Protected by _active_limbo_lock.
|
||||
__registered_atexit = False
|
||||
|
||||
def __init__(self, group=None, target=None, name=None,
|
||||
args=(), kwargs=None, verbose=None, daemon=None):
|
||||
def __init__(
|
||||
self,
|
||||
group: None = None,
|
||||
target: Callable[..., object] | None = None,
|
||||
name: object = None,
|
||||
args: Iterable[Any] = (),
|
||||
kwargs: Mapping[str, Any] | None = None,
|
||||
verbose: bool | None = None,
|
||||
daemon: bool | None = None,
|
||||
) -> None:
|
||||
assert group is None, "group argument must be None for now"
|
||||
_Verbose.__init__(self, verbose)
|
||||
if kwargs is None:
|
||||
|
|
@ -422,7 +434,7 @@ class Thread(_Verbose):
|
|||
# sys.exc_info since it can be changed between instances
|
||||
self.__stderr = _sys.stderr
|
||||
|
||||
def _set_daemon(self):
|
||||
def _set_daemon(self) -> bool:
|
||||
# Overridden in _MainThread and _DummyThread
|
||||
return currentThread().isDaemon()
|
||||
|
||||
|
|
@ -437,7 +449,7 @@ class Thread(_Verbose):
|
|||
status = status + " daemon"
|
||||
return "<%s(%s, %s)>" % (self.__class__.__name__, self.__name, status)
|
||||
|
||||
def start(self):
|
||||
def start(self) -> None:
|
||||
assert self.__initialized, "Thread.__init__() not called"
|
||||
assert not self.__started, "thread already started"
|
||||
if __debug__:
|
||||
|
|
@ -457,11 +469,11 @@ class Thread(_Verbose):
|
|||
self.__started = True
|
||||
_sleep(0.000001) # 1 usec, to let the thread run (Solaris hack)
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
if self.__target:
|
||||
self.__target(*self.__args, **self.__kwargs)
|
||||
|
||||
def __bootstrap(self):
|
||||
def __bootstrap(self) -> None:
|
||||
try:
|
||||
self.__started = True
|
||||
_active_limbo_lock.acquire()
|
||||
|
|
@ -497,7 +509,7 @@ class Thread(_Verbose):
|
|||
# Do the best job possible w/o a huge amt. of code to
|
||||
# approximate a traceback (code ideas from
|
||||
# Lib/traceback.py)
|
||||
exc_type, exc_value, exc_tb = self.__exc_info()
|
||||
exc_type, exc_value, exc_tb = self.__exc_info() # type: ignore[misc]
|
||||
try:
|
||||
self.__stderr.write("Exception in thread " + self.getName() +
|
||||
" (most likely raised during interpreter shutdown):\n")
|
||||
|
|
@ -523,13 +535,13 @@ class Thread(_Verbose):
|
|||
except:
|
||||
pass
|
||||
|
||||
def __stop(self):
|
||||
def __stop(self) -> None:
|
||||
self.__block.acquire()
|
||||
self.__stopped = True
|
||||
self.__block.notifyAll()
|
||||
self.__block.release()
|
||||
|
||||
def __delete(self):
|
||||
def __delete(self) -> None:
|
||||
"Remove current thread from the dict of currently running threads."
|
||||
|
||||
# Notes about running with dummy_thread:
|
||||
|
|
@ -563,7 +575,7 @@ class Thread(_Verbose):
|
|||
finally:
|
||||
_active_limbo_lock.release()
|
||||
|
||||
def join(self, timeout=None):
|
||||
def join(self, timeout: float | None = None) -> None:
|
||||
assert self.__initialized, "Thread.__init__() not called"
|
||||
assert self.__started, "cannot join thread before it is started"
|
||||
assert self is not currentThread(), "cannot join current thread"
|
||||
|
|
@ -592,11 +604,11 @@ class Thread(_Verbose):
|
|||
finally:
|
||||
self.__block.release()
|
||||
|
||||
def getName(self):
|
||||
def getName(self) -> str:
|
||||
assert self.__initialized, "Thread.__init__() not called"
|
||||
return self.__name
|
||||
|
||||
def setName(self, name):
|
||||
def setName(self, name: object) -> None:
|
||||
assert self.__initialized, "Thread.__init__() not called"
|
||||
self.__name = str(name)
|
||||
|
||||
|
|
@ -606,7 +618,7 @@ class Thread(_Verbose):
|
|||
|
||||
isAlive = is_alive
|
||||
|
||||
def isDaemon(self):
|
||||
def isDaemon(self) -> bool:
|
||||
assert self.__initialized, "Thread.__init__() not called"
|
||||
return self.__daemonic
|
||||
|
||||
|
|
@ -654,7 +666,7 @@ class _Timer(Thread):
|
|||
|
||||
class _MainThread(Thread):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
Thread.__init__(self, name="MainThread")
|
||||
self._Thread__started = True
|
||||
_active_limbo_lock.acquire()
|
||||
|
|
@ -688,13 +700,13 @@ class _MainThread(Thread):
|
|||
|
||||
class _DummyThread(Thread):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
Thread.__init__(self, name=_newname("Dummy-%d"), daemon=True)
|
||||
|
||||
# Thread.__block consumes an OS-level locking primitive, which
|
||||
# can never be used by a _DummyThread. Since a _DummyThread
|
||||
# instance is immortal, that's bad, so release this resource.
|
||||
del self._Thread__block
|
||||
del self._Thread__block # type: ignore[attr-defined]
|
||||
|
||||
self._Thread__started = True
|
||||
_active_limbo_lock.acquire()
|
||||
|
|
@ -710,7 +722,7 @@ class _DummyThread(Thread):
|
|||
|
||||
# Global API functions
|
||||
|
||||
def current_thread():
|
||||
def current_thread() -> Thread:
|
||||
try:
|
||||
return _active[get_ident()]
|
||||
except KeyError:
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ if hasattr(sys, 'getandroidapilevel'):
|
|||
signal = None
|
||||
else:
|
||||
try:
|
||||
import _signal as signal # type: ignore[import, no-redef]
|
||||
import _signal as signal # type: ignore[import-not-found, no-redef]
|
||||
except ImportError:
|
||||
signal = None
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ def inspectorFor(anObject):
|
|||
|
||||
### initializing
|
||||
|
||||
def initializeInspectorMap():
|
||||
def initializeInspectorMap() -> None:
|
||||
global _InspectorMap
|
||||
notFinishedTypes = ['BufferType', 'EllipsisType', 'FrameType', 'TracebackType', 'XRangeType']
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
__all__ = ['ParticlePanel']
|
||||
|
||||
# Import Tkinter, Pmw, and the floater code from this directory tree.
|
||||
from panda3d.core import ColorBlendAttrib, Filename, Point2, Point3, Vec3, Vec4, getModelPath
|
||||
from panda3d.core import ColorBlendAttrib, ConfigVariableSearchPath, Filename, Point2, Point3, Vec3, Vec4, getModelPath
|
||||
from panda3d.physics import (
|
||||
BaseParticleEmitter,
|
||||
BaseParticleRenderer,
|
||||
|
|
@ -36,7 +36,6 @@ from panda3d.physics import (
|
|||
SpriteParticleRenderer,
|
||||
TangentRingEmitter,
|
||||
)
|
||||
from panda3d.direct import getParticlePath
|
||||
from direct.tkwidgets.AppShell import AppShell
|
||||
from direct.tkwidgets import Dial
|
||||
from direct.tkwidgets import Floater
|
||||
|
|
@ -53,6 +52,10 @@ import os
|
|||
import tkinter as tk
|
||||
|
||||
|
||||
particlePath = ConfigVariableSearchPath("particle-path",
|
||||
"The directories to search for particle files to be loaded.")
|
||||
|
||||
|
||||
class ParticlePanel(AppShell):
|
||||
# Override class variables
|
||||
appname = 'Particle Panel'
|
||||
|
|
@ -1275,7 +1278,7 @@ class ParticlePanel(AppShell):
|
|||
|
||||
def loadParticleEffectFromFile(self):
|
||||
# Find path to particle directory
|
||||
pPath = getParticlePath()
|
||||
pPath = particlePath
|
||||
if pPath.getNumDirectories() > 0:
|
||||
if repr(pPath.getDirectory(0)) == '.':
|
||||
path = '.'
|
||||
|
|
@ -1303,7 +1306,7 @@ class ParticlePanel(AppShell):
|
|||
|
||||
def saveParticleEffectToFile(self):
|
||||
# Find path to particle directory
|
||||
pPath = getParticlePath()
|
||||
pPath = particlePath
|
||||
if pPath.getNumDirectories() > 0:
|
||||
if repr(pPath.getDirectory(0)) == '.':
|
||||
path = '.'
|
||||
|
|
@ -2872,6 +2875,12 @@ class ParticlePanel(AppShell):
|
|||
if type == 'FT_ONE_OVER_R_CUBED':
|
||||
#f.setFalloffType(LinearDistanceForce.FTONEOVERRCUBED)
|
||||
f.setFalloffType(2)
|
||||
if type == 'FT_ONE_OVER_R_OVER_DISTANCE':
|
||||
f.setFalloffType(3)
|
||||
if type == 'FT_ONE_OVER_R_OVER_DISTANCE_SQUARED':
|
||||
f.setFalloffType(4)
|
||||
if type == 'FT_ONE_OVER_R_OVER_DISTANCE_CUBED':
|
||||
f.setFalloffType(5)
|
||||
|
||||
def setForceCenter(vec, f = force):
|
||||
f.setForceCenter(Point3(vec[0], vec[1], vec[2]))
|
||||
|
|
@ -2886,7 +2895,10 @@ class ParticlePanel(AppShell):
|
|||
'Set force falloff type',
|
||||
('FT_ONE_OVER_R',
|
||||
'FT_ONE_OVER_R_SQUARED',
|
||||
'FT_ONE_OVER_R_CUBED'),
|
||||
'FT_ONE_OVER_R_CUBED',
|
||||
'FT_ONE_OVER_R_OVER_DISTANCE',
|
||||
'FT_ONE_OVER_R_OVER_DISTANCE_SQUARED',
|
||||
'FT_ONE_OVER_R_OVER_DISTANCE_CUBED'),
|
||||
command = setFalloffType)
|
||||
self.getWidget(pageName, forceName + ' Falloff').configure(
|
||||
label_width = 16)
|
||||
|
|
@ -2897,6 +2909,12 @@ class ParticlePanel(AppShell):
|
|||
var.set('FT_ONE_OVER_R_SQUARED')
|
||||
elif falloff == LinearDistanceForce.FTONEOVERRCUBED:
|
||||
var.set('FT_ONE_OVER_R_CUBED')
|
||||
elif falloff == LinearDistanceForce.FTONEOVERROVERDISTANCE:
|
||||
var.set('FT_ONE_OVER_R_OVER_DISTANCE')
|
||||
elif falloff == LinearDistanceForce.FTONEOVERROVERDISTANCESQUARED:
|
||||
var.set('FT_ONE_OVER_R_OVER_DISTANCE_SQUARED')
|
||||
elif falloff == LinearDistanceForce.FTONEOVERROVERDISTANCECUBED:
|
||||
var.set('FT_ONE_OVER_R_OVER_DISTANCE_CUBED')
|
||||
vec = force.getForceCenter()
|
||||
self.createVector3Entry(frame, pageName, forceName + ' Center',
|
||||
'Set center of force',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,32 @@
|
|||
----------------------- RELEASE 1.10.16 -----------------------
|
||||
|
||||
This maintenance release fixes some minor defects and stability issues.
|
||||
|
||||
* OpenAL: Support non-default coordinate systems when playing 3D audio
|
||||
* Tasks: Coroutine detect now also handles coroutine subclass to support Nuitka
|
||||
* Tasks: Now properly handles generators without send()
|
||||
* Windows: Fixes a hang when adjusting Z-order in some situations
|
||||
* Fix SparseArray methods get_lowest_off_bit() and get_lowest_on_bit()
|
||||
* Fix linecache error when distributing for newer Python versions
|
||||
* Fix `await AsyncFuture.gather()` returning first item instead of tuple (#1738)
|
||||
* Fix use-after-free in collision system with transform cache disabled (#1733)
|
||||
* Egg: Add limited forward compatibility for metallic-roughness textures
|
||||
* OpenGL: fix error blitting depth texture on macOS (#1719)
|
||||
* OpenGL: fix SSBO not being rebound if deleted and recreated immediately
|
||||
* OpenGL: fix SSBO support not being detected in certain situations
|
||||
* GLSL: Add p3d_MetallicRoughnessTexture input mapped to M_metallic_roughness
|
||||
* X11: Add config variable to enable detection of autorepeat key events (#1735)
|
||||
* GUI: Fix bug with PGSliderBar dragging (#1722)
|
||||
* Minor thread safety things for free-threaded Python builds
|
||||
* Add forward compatibility for bam version 6.46
|
||||
* Fixes a harmless buffer overflow in pdtoa
|
||||
* Fix compilation issues with SDL version of tinydisplay (#1708)
|
||||
* bam2egg: Fix issue when having more than two tags (#1725)
|
||||
* Fix "Detected leak for ... which interrogate cannot delete." error (#1743)
|
||||
* Fix PythonCallbackObject crash upon destruction in some cases
|
||||
* PStats: Fix crash when receiving frames out of order
|
||||
* PandaFramework::close_framework() now clears task manager of tasks
|
||||
|
||||
----------------------- RELEASE 1.10.15 -----------------------
|
||||
|
||||
This release adds support for Python 3.13, and fixes some significant bugs.
|
||||
|
|
|
|||
|
|
@ -51,6 +51,16 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GCC")
|
|||
|
||||
endif()
|
||||
|
||||
# AddressSanitizer
|
||||
if(ENABLE_ASAN)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "(AppleClang|Clang|GNU)")
|
||||
add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
|
||||
add_link_options(-fsanitize=address)
|
||||
else()
|
||||
message(FATAL_ERROR "ENABLE_ASAN requires GCC or Clang")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Panda3D is now a C++14 project.
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ if(BUILD_INTERROGATE)
|
|||
panda3d-interrogate
|
||||
|
||||
GIT_REPOSITORY https://github.com/panda3d/interrogate.git
|
||||
GIT_TAG 03418d6d7ddda7fb99abf27230aa42d1d8bd607e
|
||||
GIT_TAG 7cf2550d2c8d95b8c268aa4bb0b5602e85a086dc
|
||||
|
||||
PREFIX ${_interrogate_dir}
|
||||
CMAKE_ARGS
|
||||
|
|
@ -425,6 +425,14 @@ endif()
|
|||
|
||||
unset(_prefer_mimalloc)
|
||||
|
||||
#
|
||||
# Sanitizers
|
||||
#
|
||||
|
||||
option(ENABLE_ASAN
|
||||
"Enable AddressSanitizer for detecting memory errors such as
|
||||
buffer overflows, use-after-free, etc. Requires GCC or Clang." OFF)
|
||||
|
||||
#
|
||||
# This section relates to mobile-device/phone support and options
|
||||
#
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ check_include_file_cxx(dirent.h PHAVE_DIRENT_H)
|
|||
check_include_file_cxx(ucontext.h PHAVE_UCONTEXT_H) #TODO doesn't work on OSX, use sys/ucontext.h
|
||||
check_include_file_cxx(linux/input.h PHAVE_LINUX_INPUT_H)
|
||||
check_include_file_cxx(stdint.h PHAVE_STDINT_H)
|
||||
check_include_file_cxx(execinfo.h PHAVE_EXECINFO_H)
|
||||
|
||||
# Do we have Posix threads?
|
||||
#set(HAVE_POSIX_THREADS ${CMAKE_USE_PTHREADS_INIT})
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ struct AtomicAdjust {
|
|||
#include "atomicAdjustDummyImpl.h"
|
||||
typedef AtomicAdjustDummyImpl AtomicAdjust;
|
||||
|
||||
#elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) || (defined(__clang__) && (__clang_major__ >= 3))
|
||||
#elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) || (defined(__clang__) && (__clang_major__ >= 3) && !defined(WIN32_VC) )
|
||||
// GCC 4.7 and above has built-in __atomic functions for atomic operations.
|
||||
// Clang 3.0 and above also supports them.
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,14 @@ allocate(size_t size, TypeHandle type_handle) {
|
|||
return ptr;
|
||||
|
||||
#else // USE_DELETED_CHAIN
|
||||
return PANDA_MALLOC_SINGLE(_buffer_size);
|
||||
void *ptr = PANDA_MALLOC_SINGLE(_buffer_size);
|
||||
|
||||
#ifdef DO_MEMORY_USAGE
|
||||
type_handle.inc_memory_usage(TypeHandle::MC_singleton, _buffer_size);
|
||||
#endif // DO_MEMORY_USAGE
|
||||
|
||||
return ptr;
|
||||
|
||||
#endif // USE_DELETED_CHAIN
|
||||
}
|
||||
|
||||
|
|
@ -133,6 +140,11 @@ deallocate(void *ptr, TypeHandle type_handle) {
|
|||
_lock.unlock();
|
||||
|
||||
#else // USE_DELETED_CHAIN
|
||||
|
||||
#ifdef DO_MEMORY_USAGE
|
||||
type_handle.dec_memory_usage(TypeHandle::MC_singleton, _buffer_size);
|
||||
#endif // DO_MEMORY_USAGE
|
||||
|
||||
PANDA_FREE_SINGLE(ptr);
|
||||
#endif // USE_DELETED_CHAIN
|
||||
}
|
||||
|
|
@ -155,8 +167,9 @@ get_deleted_chain(size_t buffer_size) {
|
|||
|
||||
static MutexImpl lock;
|
||||
lock.lock();
|
||||
static std::set<DeletedBufferChain> deleted_chains;
|
||||
DeletedBufferChain *result = (DeletedBufferChain *)&*deleted_chains.insert(DeletedBufferChain(buffer_size)).first;
|
||||
alignas(std::set<DeletedBufferChain>) static char storage[sizeof(std::set<DeletedBufferChain>)];
|
||||
static auto *deleted_chains = new (storage) std::set<DeletedBufferChain>;
|
||||
DeletedBufferChain *result = (DeletedBufferChain *)&*deleted_chains->insert(DeletedBufferChain(buffer_size)).first;
|
||||
lock.unlock();
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,6 +122,50 @@ public:
|
|||
#define ALLOC_DELETED_CHAIN_DEF(Type) \
|
||||
DeletedChain< Type > Type::_deleted_chain;
|
||||
|
||||
#elif defined(DO_MEMORY_USAGE)
|
||||
|
||||
#define ALLOC_DELETED_CHAIN(Type) \
|
||||
inline void *operator new(size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT) { \
|
||||
void *ptr = PANDA_MALLOC_SINGLE(size); \
|
||||
get_type_handle(Type).inc_memory_usage(TypeHandle::MC_singleton, sizeof(Type)); \
|
||||
return ptr; \
|
||||
} \
|
||||
inline void *operator new(size_t size, void *ptr) { \
|
||||
(void) size; \
|
||||
return ptr; \
|
||||
} \
|
||||
inline void operator delete(void *ptr) { \
|
||||
if (ptr != nullptr) { \
|
||||
get_type_handle(Type).dec_memory_usage(TypeHandle::MC_singleton, sizeof(Type)); \
|
||||
PANDA_FREE_SINGLE(ptr); \
|
||||
} \
|
||||
} \
|
||||
inline void operator delete(void *, void *) { \
|
||||
} \
|
||||
inline void *operator new[](size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT) { \
|
||||
void *ptr = PANDA_MALLOC_SINGLE(size); \
|
||||
get_type_handle(Type).inc_memory_usage(TypeHandle::MC_array, sizeof(Type)); \
|
||||
return ptr; \
|
||||
} \
|
||||
inline void *operator new[](size_t size, void *ptr) { \
|
||||
(void) size; \
|
||||
return ptr; \
|
||||
} \
|
||||
inline void operator delete[](void *ptr) { \
|
||||
if (ptr != nullptr) { \
|
||||
get_type_handle(Type).dec_memory_usage(TypeHandle::MC_array, sizeof(Type)); \
|
||||
PANDA_FREE_SINGLE(ptr); \
|
||||
} \
|
||||
} \
|
||||
inline void operator delete[](void *, void *) { \
|
||||
} \
|
||||
inline static bool validate_ptr(const void *ptr) { \
|
||||
return (ptr != nullptr); \
|
||||
}
|
||||
|
||||
#define ALLOC_DELETED_CHAIN_DECL(Type) ALLOC_DELETED_CHAIN(Type)
|
||||
#define ALLOC_DELETED_CHAIN_DEF(Type)
|
||||
|
||||
#else // USE_DELETED_CHAIN
|
||||
|
||||
#define ALLOC_DELETED_CHAIN(Type) \
|
||||
|
|
|
|||
|
|
@ -96,6 +96,9 @@
|
|||
#elif defined(__arm__)
|
||||
#define DTOOL_PLATFORM "linux_arm"
|
||||
|
||||
#elif defined(__riscv)
|
||||
#define DTOOL_PLATFORM "linux_riscv"
|
||||
|
||||
#elif defined(__ppc__)
|
||||
#define DTOOL_PLATFORM "linux_ppc"
|
||||
|
||||
|
|
|
|||
|
|
@ -618,6 +618,9 @@ determine_page_size() const {
|
|||
|
||||
_page_size = (size_t)sysinfo.dwPageSize;
|
||||
|
||||
#elif defined(ANDROID)
|
||||
_page_size = getpagesize();
|
||||
|
||||
#else
|
||||
// Posix case.
|
||||
_page_size = sysconf(_SC_PAGESIZE);
|
||||
|
|
|
|||
|
|
@ -454,6 +454,12 @@ patomic_notify_one(volatile uint32_t *value) {
|
|||
#elif defined(_WIN32)
|
||||
_patomic_wake_one_func((void *)value);
|
||||
#elif defined(__APPLE__)
|
||||
#ifndef __arm64__
|
||||
if (UNLIKELY(__ulock_wake == nullptr || __ulock_wait == nullptr)) {
|
||||
_patomic_notify_all(value);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
__ulock_wake(UL_COMPARE_AND_WAIT, (void *)value, 0);
|
||||
#elif defined(HAVE_POSIX_THREADS)
|
||||
_patomic_notify_all(value);
|
||||
|
|
@ -472,6 +478,12 @@ patomic_notify_all(volatile uint32_t *value) {
|
|||
#elif defined(_WIN32)
|
||||
_patomic_wake_all_func((void *)value);
|
||||
#elif defined(__APPLE__)
|
||||
#ifndef __arm64__
|
||||
if (UNLIKELY(__ulock_wake == nullptr || __ulock_wait == nullptr)) {
|
||||
_patomic_notify_all(value);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
__ulock_wake(UL_COMPARE_AND_WAIT | ULF_WAKE_ALL, (void *)value, 0);
|
||||
#elif defined(HAVE_POSIX_THREADS)
|
||||
_patomic_notify_all(value);
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ initialize_wait(volatile VOID *addr, PVOID cmp, SIZE_T size, DWORD timeout) {
|
|||
return emulated_wait(addr, cmp, size, timeout);
|
||||
}
|
||||
|
||||
#elif !defined(CPPPARSER) && !defined(__linux__) && !defined(__APPLE__) && defined(HAVE_POSIX_THREADS)
|
||||
#elif !defined(CPPPARSER) && !defined(__linux__) && (!defined(__APPLE__) || !defined(__arm64__)) && defined(HAVE_POSIX_THREADS)
|
||||
|
||||
// Same as above, but using pthreads.
|
||||
struct alignas(64) WaitTableEntry {
|
||||
|
|
|
|||
|
|
@ -36,9 +36,6 @@
|
|||
// Undocumented API, see https://outerproduct.net/futex-dictionary.html
|
||||
#define UL_COMPARE_AND_WAIT 1
|
||||
#define ULF_WAKE_ALL 0x00000100
|
||||
|
||||
extern "C" int __ulock_wait(uint32_t op, void *addr, uint64_t value, uint32_t timeout);
|
||||
extern "C" int __ulock_wake(uint32_t op, void *addr, uint64_t wake_value);
|
||||
#endif
|
||||
|
||||
#if defined(THREAD_DUMMY_IMPL) || defined(THREAD_SIMPLE_IMPL)
|
||||
|
|
@ -173,9 +170,17 @@ ALWAYS_INLINE void patomic_notify_all(volatile uint32_t *value);
|
|||
EXPCL_DTOOL_DTOOLBASE extern BOOL (__stdcall *_patomic_wait_func)(volatile VOID *, PVOID, SIZE_T, DWORD);
|
||||
EXPCL_DTOOL_DTOOLBASE extern void (__stdcall *_patomic_wake_one_func)(PVOID);
|
||||
EXPCL_DTOOL_DTOOLBASE extern void (__stdcall *_patomic_wake_all_func)(PVOID);
|
||||
#elif !defined(__linux__) && !defined(__APPLE__) && defined(HAVE_POSIX_THREADS)
|
||||
#elif defined(__APPLE__) && defined(__arm64__)
|
||||
extern "C" int __ulock_wait(uint32_t op, void *addr, uint64_t value, uint32_t timeout);
|
||||
extern "C" int __ulock_wake(uint32_t op, void *addr, uint64_t wake_value);
|
||||
#elif !defined(__linux__) && defined(HAVE_POSIX_THREADS)
|
||||
EXPCL_DTOOL_DTOOLBASE void _patomic_wait(const volatile uint32_t *value, uint32_t old);
|
||||
EXPCL_DTOOL_DTOOLBASE void _patomic_notify_all(volatile uint32_t *value);
|
||||
#ifdef __APPLE__
|
||||
// Use conditionally since we can't count on support before 10.12.
|
||||
extern "C" int __ulock_wait(uint32_t op, void *addr, uint64_t value, uint32_t timeout) __attribute__((weak_import));
|
||||
extern "C" int __ulock_wake(uint32_t op, void *addr, uint64_t wake_value) __attribute__((weak_import));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "patomic.I"
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ inline static unsigned CountDecimalDigit32(uint32_t n) {
|
|||
}
|
||||
|
||||
inline static void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
|
||||
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0, 0, 0, 0, 0 };
|
||||
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0, 0, 0, 0, 0, 0 };
|
||||
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
|
||||
const DiyFp wp_w = Mp - W;
|
||||
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
|
||||
|
|
|
|||
|
|
@ -46,13 +46,16 @@ public:
|
|||
typedef std::vector<Type, allocator> base_class;
|
||||
typedef typename base_class::size_type size_type;
|
||||
|
||||
explicit pvector(TypeHandle type_handle = pvector_type_handle) : base_class(allocator(type_handle)) { }
|
||||
pvector() : base_class(allocator(get_type_handle(pvector<Type>))) { }
|
||||
explicit pvector(TypeHandle type_handle) : base_class(allocator(type_handle)) { }
|
||||
pvector(const pvector<Type> ©) : base_class(copy) { }
|
||||
pvector(pvector<Type> &&from) noexcept : base_class(std::move(from)) {};
|
||||
explicit pvector(size_type n, TypeHandle type_handle = pvector_type_handle) : base_class(n, Type(), allocator(type_handle)) { }
|
||||
explicit pvector(size_type n, const Type &value, TypeHandle type_handle = pvector_type_handle) : base_class(n, value, allocator(type_handle)) { }
|
||||
pvector(const Type *begin, const Type *end, TypeHandle type_handle = pvector_type_handle) : base_class(begin, end, allocator(type_handle)) { }
|
||||
pvector(std::initializer_list<Type> init, TypeHandle type_handle = pvector_type_handle) : base_class(std::move(init), allocator(type_handle)) { }
|
||||
explicit pvector(size_type n, TypeHandle type_handle = get_type_handle(pvector<Type>)) : base_class(n, Type(), allocator(type_handle)) { }
|
||||
explicit pvector(size_type n, const Type &value, TypeHandle type_handle = get_type_handle(pvector<Type>)) : base_class(n, value, allocator(type_handle)) { }
|
||||
pvector(const Type *begin, const Type *end, TypeHandle type_handle = get_type_handle(pvector<Type>)) : base_class(allocator(type_handle)) {
|
||||
this->insert(this->end(), begin, end);
|
||||
}
|
||||
pvector(std::initializer_list<Type> init, TypeHandle type_handle = get_type_handle(pvector<Type>)) : base_class(std::move(init), allocator(type_handle)) { }
|
||||
|
||||
pvector<Type> &operator =(const pvector<Type> ©) {
|
||||
base_class::operator =(copy);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ TypeHandle double_type_handle;
|
|||
TypeHandle float_type_handle;
|
||||
TypeHandle string_type_handle;
|
||||
TypeHandle wstring_type_handle;
|
||||
TypeHandle vector_uchar_type_handle;
|
||||
|
||||
TypeHandle long_p_type_handle;
|
||||
TypeHandle int_p_type_handle;
|
||||
|
|
@ -59,6 +60,7 @@ void init_system_type_handles() {
|
|||
register_type(float_type_handle, "float");
|
||||
register_type(string_type_handle, "string");
|
||||
register_type(wstring_type_handle, "wstring");
|
||||
register_type(vector_uchar_type_handle, "vector_uchar");
|
||||
|
||||
register_type(int_p_type_handle, "int*");
|
||||
register_type(short_p_type_handle, "short*");
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@
|
|||
#include "typeHandle.h"
|
||||
#include "typeRegistry.h"
|
||||
|
||||
template<class T>
|
||||
class pvector;
|
||||
|
||||
/**
|
||||
* This inline function is just a convenient way to call
|
||||
* TypeRegistry::register_type(), along with zero to four
|
||||
|
|
@ -88,6 +91,7 @@ extern TypeHandle EXPCL_DTOOL_DTOOLBASE double_type_handle;
|
|||
extern TypeHandle EXPCL_DTOOL_DTOOLBASE float_type_handle;
|
||||
extern TypeHandle EXPCL_DTOOL_DTOOLBASE string_type_handle;
|
||||
extern TypeHandle EXPCL_DTOOL_DTOOLBASE wstring_type_handle;
|
||||
extern TypeHandle EXPCL_DTOOL_DTOOLBASE vector_uchar_type_handle;
|
||||
|
||||
extern TypeHandle long_p_type_handle;
|
||||
extern TypeHandle int_p_type_handle;
|
||||
|
|
@ -175,6 +179,16 @@ INLINE TypeHandle _get_type_handle(const std::wstring *) {
|
|||
return wstring_type_handle;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
INLINE TypeHandle _get_type_handle(const pvector<T> *) {
|
||||
return pvector_type_handle;
|
||||
}
|
||||
|
||||
template<>
|
||||
INLINE TypeHandle _get_type_handle(const pvector<unsigned char> *) {
|
||||
return vector_uchar_type_handle;
|
||||
}
|
||||
|
||||
template<>
|
||||
INLINE TypeHandle _get_type_handle(const long * const *) {
|
||||
return long_p_type_handle;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ set(P3DTOOLUTIL_IGATEEXT
|
|||
globPattern_ext.h
|
||||
iostream_ext.cxx
|
||||
iostream_ext.h
|
||||
pyenv_init.cxx
|
||||
pyenv_init.h
|
||||
textEncoder_ext.cxx
|
||||
textEncoder_ext.h
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* @file console_preamble.js
|
||||
* @author rdb
|
||||
* @date 2025-02-03
|
||||
*/
|
||||
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
Module["preInit"] = Module["preInit"] || [];
|
||||
Module["preInit"].push(function() {
|
||||
if (typeof process === "object" && typeof process.env === "object") {
|
||||
// These are made up by emscripten if we don't set them to undefined
|
||||
ENV['USER'] = undefined;
|
||||
ENV['LOGNAME'] = undefined;
|
||||
ENV['PATH'] = undefined;
|
||||
ENV['PWD'] = undefined;
|
||||
ENV['HOME'] = undefined;
|
||||
ENV['LANG'] = undefined;
|
||||
ENV['_'] = undefined;
|
||||
for (var variable in process.env) {
|
||||
ENV[variable] = process.env[variable];
|
||||
}
|
||||
}
|
||||
|
||||
addOnPreMain(function preloadNodeEnv() {
|
||||
var sp = stackSave();
|
||||
var set_binary_name = wasmExports["_set_binary_name"];
|
||||
if (set_binary_name && typeof __filename === "string") {
|
||||
set_binary_name(stringToUTF8OnStack(__filename));
|
||||
}
|
||||
|
||||
var set_env_var = wasmExports["_set_env_var"];
|
||||
if (set_env_var) {
|
||||
for (var variable in ENV) {
|
||||
var value = ENV[variable];
|
||||
if (value !== undefined) {
|
||||
set_env_var(stringToUTF8OnStack(variable), stringToUTF8OnStack(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
stackRestore(sp);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -125,12 +125,18 @@ static const char *const libp3dtool_filenames[] = {
|
|||
|
||||
#if defined(__EMSCRIPTEN__) && !defined(CPPPARSER)
|
||||
extern "C" void EMSCRIPTEN_KEEPALIVE
|
||||
_set_env_var(ExecutionEnvironment *ptr, const char *var, const char *value) {
|
||||
_set_env_var(const char *var, const char *value) {
|
||||
ExecutionEnvironment *ptr = ExecutionEnvironment::get_ptr();
|
||||
ptr->_variables[std::string(var)] = std::string(value);
|
||||
}
|
||||
|
||||
extern "C" void EMSCRIPTEN_KEEPALIVE
|
||||
_set_binary_name(const char *path) {
|
||||
ExecutionEnvironment::set_binary_name(std::string(path));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Linux with GNU libc does have global argvargc variables, but we can't
|
||||
// Linux with GNU libc does have global argv/argc variables, but we can't
|
||||
// safely access them at stat init time--at least, not in libc5. (It does seem
|
||||
// to work with glibc2, however.)
|
||||
|
||||
|
|
@ -584,17 +590,10 @@ read_environment_variables() {
|
|||
}
|
||||
}
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
// We only have environment variables if we're running in node.js.
|
||||
#ifndef CPPPARSER
|
||||
EM_ASM({
|
||||
if (typeof process === 'object' && typeof process.env === 'object') {
|
||||
for (var variable in process.env) {
|
||||
__set_env_var($0, stringToUTF8OnStack(variable),
|
||||
stringToUTF8OnStack(process.env[variable]));
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
#endif
|
||||
// The environment variables get loaded in by the .js file before main()
|
||||
// using the _set_env_var exported function, defined above. Trying to load
|
||||
// env vars at static init time otherwise makes some optimizations more
|
||||
// difficult, notably wasm-ctor-eval/wizer.
|
||||
|
||||
#elif defined(HAVE_PROC_SELF_ENVIRON)
|
||||
// In some cases, we may have a file called procselfenviron that may be read
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@
|
|||
#include <map>
|
||||
|
||||
#if defined(__EMSCRIPTEN__) && !defined(CPPPARSER)
|
||||
class ExecutionEnvironment;
|
||||
|
||||
extern "C" void EMSCRIPTEN_KEEPALIVE
|
||||
_set_env_var(ExecutionEnvironment *ptr, const char *var, const char *value);
|
||||
_set_env_var(const char *var, const char *value);
|
||||
extern "C" void EMSCRIPTEN_KEEPALIVE
|
||||
_set_binary_name(const char *path);
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
@ -98,7 +98,7 @@ private:
|
|||
static ExecutionEnvironment *_global_ptr;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
friend void ::_set_env_var(ExecutionEnvironment *ptr, const char *var, const char *value);
|
||||
friend void ::_set_env_var(const char *var, const char *value);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ __init__(PyObject *path) {
|
|||
return;
|
||||
}
|
||||
|
||||
PyObject *path_str = PyObject_CallFunctionObjArgs(fspath, path, nullptr);
|
||||
PyObject *path_str = PyObject_CallOneArg(fspath, path);
|
||||
Py_DECREF(fspath);
|
||||
if (path_str == nullptr) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -134,8 +134,9 @@ readinto(PyObject *b) {
|
|||
|
||||
Py_buffer view;
|
||||
if (PyObject_GetBuffer(b, &view, PyBUF_CONTIG) == -1) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"write() requires a contiguous, read-write bytes-like object");
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"readinto() requires a contiguous, read-write bytes-like object, not '%.100s'",
|
||||
Py_TYPE(b)->tp_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -260,7 +261,9 @@ write(PyObject *b) {
|
|||
|
||||
Py_buffer view;
|
||||
if (PyObject_GetBuffer(b, &view, PyBUF_CONTIG_RO) == -1) {
|
||||
PyErr_SetString(PyExc_TypeError, "write() requires a contiguous buffer");
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"write() requires a bytes-like object, not '%.100s'",
|
||||
Py_TYPE(b)->tp_name);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@
|
|||
#include <iostream>
|
||||
#include "py_panda.h"
|
||||
|
||||
using std::ostream;
|
||||
using std::istream;
|
||||
|
||||
/**
|
||||
* These classes define the extension methods for istream and ostream, which
|
||||
* are called instead of any C++ methods with the same prototype.
|
||||
|
|
|
|||
|
|
@ -19,11 +19,15 @@ using std::string;
|
|||
static Filename resolve_dso(const DSearchPath &path, const Filename &filename) {
|
||||
if (filename.is_local()) {
|
||||
if ((path.get_num_directories()==1)&&(path.get_directory(0)=="<auto>")) {
|
||||
#ifdef ANDROID
|
||||
return filename;
|
||||
#else
|
||||
// This is a special case, meaning to search in the same directory in
|
||||
// which libp3dtool.dll, or the exe, was started from.
|
||||
Filename dtoolpath = ExecutionEnvironment::get_dtool_name();
|
||||
DSearchPath spath(dtoolpath.get_dirname());
|
||||
return spath.find_file(filename);
|
||||
#endif
|
||||
} else {
|
||||
return path.find_file(filename);
|
||||
}
|
||||
|
|
@ -119,7 +123,13 @@ get_dso_symbol(void *handle, const string &name) {
|
|||
void *
|
||||
load_dso(const DSearchPath &path, const Filename &filename) {
|
||||
Filename abspath = resolve_dso(path, filename);
|
||||
#ifdef ANDROID
|
||||
// We just try to load it on Android, because we can't verify right now
|
||||
// whether it might just be an unextracted library.
|
||||
if (abspath.empty()) {
|
||||
#else
|
||||
if (!abspath.is_regular_file()) {
|
||||
#endif
|
||||
// Make sure the error flag is cleared, to prevent a subsequent call to
|
||||
// load_dso_error() from returning a previously stored error.
|
||||
dlerror();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "filename_ext.cxx"
|
||||
#include "globPattern_ext.cxx"
|
||||
#include "iostream_ext.cxx"
|
||||
#include "pyenv_init.cxx"
|
||||
#include "textEncoder_ext.cxx"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* @file pyenv_init.cxx
|
||||
* @author rdb
|
||||
* @date 2025-02-02
|
||||
*/
|
||||
|
||||
#include "pyenv_init.h"
|
||||
#include "py_panda.h"
|
||||
#include "executionEnvironment.h"
|
||||
|
||||
/**
|
||||
* Called when panda3d.core is initialized, does some initialization specific
|
||||
* to the Python environment.
|
||||
*/
|
||||
void
|
||||
pyenv_init() {
|
||||
// MAIN_DIR needs to be set very early; this seems like a convenient place
|
||||
// to do that. Perhaps we'll find a better place for this in the future.
|
||||
static bool initialized_main_dir = false;
|
||||
if (!initialized_main_dir) {
|
||||
/*if (interrogatedb_cat.is_debug()) {
|
||||
// Good opportunity to print this out once, at startup.
|
||||
interrogatedb_cat.debug()
|
||||
<< "Python " << version << "\n";
|
||||
}*/
|
||||
|
||||
if (!ExecutionEnvironment::has_environment_variable("MAIN_DIR")) {
|
||||
// Grab the __main__ module and extract its __file__ attribute.
|
||||
Filename main_dir;
|
||||
PyObject *main_module = PyImport_ImportModule("__main__");
|
||||
PyObject *file_attr = nullptr;
|
||||
if (main_module != nullptr) {
|
||||
file_attr = PyObject_GetAttrString(main_module, "__file__");
|
||||
} else {
|
||||
std::cerr << "Warning: unable to import __main__\n";
|
||||
}
|
||||
if (file_attr == nullptr) {
|
||||
// Must be running in the interactive interpreter. Use the CWD.
|
||||
main_dir = ExecutionEnvironment::get_cwd();
|
||||
} else {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
Py_ssize_t length;
|
||||
wchar_t *buffer = PyUnicode_AsWideCharString(file_attr, &length);
|
||||
if (buffer != nullptr) {
|
||||
main_dir = Filename::from_os_specific_w(std::wstring(buffer, length));
|
||||
main_dir.make_absolute();
|
||||
main_dir = main_dir.get_dirname();
|
||||
PyMem_Free(buffer);
|
||||
}
|
||||
#else
|
||||
char *buffer;
|
||||
Py_ssize_t length;
|
||||
if (PyString_AsStringAndSize(file_attr, &buffer, &length) != -1) {
|
||||
main_dir = Filename::from_os_specific(std::string(buffer, length));
|
||||
main_dir.make_absolute();
|
||||
main_dir = main_dir.get_dirname();
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
std::cerr << "Invalid string for __main__.__file__\n";
|
||||
}
|
||||
}
|
||||
ExecutionEnvironment::shadow_environment_variable("MAIN_DIR", main_dir.to_os_specific());
|
||||
PyErr_Clear();
|
||||
}
|
||||
initialized_main_dir = true;
|
||||
}
|
||||
|
||||
// Also, while we are at it, initialize the thread swap hook.
|
||||
#if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
|
||||
global_thread_state_swap = PyThreadState_Swap;
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* @file pyenv_init.h
|
||||
* @author rdb
|
||||
* @date 2025-02-02
|
||||
*/
|
||||
|
||||
extern "C" void pyenv_init();
|
||||
|
|
@ -94,7 +94,7 @@ encode_wchar(char32_t ch, TextEncoder::Encoding encoding) {
|
|||
* given encoding.
|
||||
*/
|
||||
PyObject *Extension<TextEncoder>::
|
||||
encode_wtext(const wstring &wtext, TextEncoder::Encoding encoding) {
|
||||
encode_wtext(const std::wstring &wtext, TextEncoder::Encoding encoding) {
|
||||
std::string value = TextEncoder::encode_wtext(wtext, encoding);
|
||||
return PyBytes_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,3 +19,25 @@
|
|||
#define NAME vector_uchar
|
||||
|
||||
#include "vector_src.cxx"
|
||||
|
||||
/**
|
||||
* Writes a hex representation of the bytes to the output stream.
|
||||
*/
|
||||
std::ostream &
|
||||
operator << (std::ostream &out, const vector_uchar &data) {
|
||||
static const char nibble_to_hex[] = "0123456789abcdef";
|
||||
|
||||
if (data.empty()) {
|
||||
return out;
|
||||
}
|
||||
|
||||
out << nibble_to_hex[(data[0] & 0xf0) >> 4];
|
||||
out << nibble_to_hex[data[0] & 0xf];
|
||||
|
||||
for (size_t i = 1; i < data.size(); ++i) {
|
||||
out << ' ';
|
||||
out << nibble_to_hex[(data[i] & 0xf0) >> 4];
|
||||
out << nibble_to_hex[data[i] & 0xf];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,4 +30,7 @@
|
|||
|
||||
#include "vector_src.h"
|
||||
|
||||
EXPCL_DTOOL_DTOOLUTIL std::ostream &
|
||||
operator << (std::ostream &out, const vector_uchar &data);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ set(P3IGATERUNTIME_HEADERS
|
|||
interrogate_request.h
|
||||
py_compat.h
|
||||
py_panda.h py_panda.I
|
||||
py_wrappers.h
|
||||
)
|
||||
|
||||
install(FILES ${P3IGATERUNTIME_HEADERS} COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)
|
||||
|
|
|
|||
|
|
@ -44,12 +44,12 @@ EXPCL_INTERROGATEDB void interrogate_request_database(const char *database_filen
|
|||
|
||||
/* The more sophisticated interface uses these structures. */
|
||||
|
||||
typedef struct {
|
||||
typedef struct InterrogateUniqueNameDef {
|
||||
const char *name;
|
||||
int index_offset;
|
||||
} InterrogateUniqueNameDef;
|
||||
|
||||
typedef struct {
|
||||
typedef struct InterrogateModuleDef {
|
||||
int file_identifier;
|
||||
|
||||
const char *library_name;
|
||||
|
|
|
|||
|
|
@ -219,6 +219,14 @@ INLINE PyObject *_PyLong_Lshift(PyObject *a, size_t shiftby) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifndef PY_VECTORCALL_ARGUMENTS_OFFSET
|
||||
# define PY_VECTORCALL_ARGUMENTS_OFFSET (((size_t)1) << (8 * sizeof(size_t) - 1))
|
||||
#endif
|
||||
|
||||
#if PY_VERSION_HEX < 0x030800B1
|
||||
# define PyVectorcall_NARGS(n) ((n) & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
|
||||
#endif
|
||||
|
||||
/* Python 3.9 */
|
||||
|
||||
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_IS_TYPE)
|
||||
|
|
@ -229,6 +237,10 @@ INLINE PyObject *_PyLong_Lshift(PyObject *a, size_t shiftby) {
|
|||
# define PyCFunction_CheckExact(op) (Py_IS_TYPE(op, &PyCFunction_Type))
|
||||
#endif
|
||||
|
||||
#if PY_VERSION_HEX < 0x030900A4
|
||||
# define PyObject_Vectorcall(callable, args, nargsf, kwnames) (_PyObject_Vectorcall((callable), (args), (nargsf), (kwnames)))
|
||||
#endif
|
||||
|
||||
#if PY_VERSION_HEX < 0x03090000
|
||||
INLINE PyObject *PyObject_CallNoArgs(PyObject *func) {
|
||||
#if PY_VERSION_HEX >= 0x03080000
|
||||
|
|
@ -368,6 +380,12 @@ PyDict_GetItemStringRef(PyObject *mp, const char *key, PyObject **result) {
|
|||
# define Py_END_CRITICAL_SECTION2() }
|
||||
#endif
|
||||
|
||||
/* Python 3.14 */
|
||||
|
||||
#if PY_VERSION_HEX < 0x030E00A8
|
||||
# define PyUnstable_Object_IsUniquelyReferenced(op) (Py_REFCNT((op)) == 1)
|
||||
#endif
|
||||
|
||||
/* Other Python implementations */
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
|
|
|||
|
|
@ -59,63 +59,6 @@ DtoolInstance_GetPointer(PyObject *self, T *&into, Dtool_PyTypedObject &target_c
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to create a hash from a wrapped Python object.
|
||||
*/
|
||||
INLINE Py_hash_t DtoolInstance_HashPointer(PyObject *self) {
|
||||
if (self != nullptr && DtoolInstance_Check(self)) {
|
||||
return (Py_hash_t)(intptr_t)DtoolInstance_VOID_PTR(self);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Python 2-style comparison function that compares objects by pointer.
|
||||
*/
|
||||
INLINE int DtoolInstance_ComparePointers(PyObject *v1, PyObject *v2) {
|
||||
void *v1_this = DtoolInstance_Check(v1) ? DtoolInstance_VOID_PTR(v1) : nullptr;
|
||||
void *v2_this = DtoolInstance_Check(v2) ? DtoolInstance_VOID_PTR(v2) : nullptr;
|
||||
if (v1_this != nullptr && v2_this != nullptr) {
|
||||
return (v1_this > v2_this) - (v1_this < v2_this);
|
||||
} else {
|
||||
return (v1 > v2) - (v1 < v2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rich comparison function that compares objects by pointer.
|
||||
*/
|
||||
INLINE PyObject *DtoolInstance_RichComparePointers(PyObject *v1, PyObject *v2, int op) {
|
||||
int cmpval = DtoolInstance_ComparePointers(v1, v2);
|
||||
Py_RETURN_RICHCOMPARE(cmpval, 0, op);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for assigning a PyObject pointer while managing refcounts.
|
||||
*/
|
||||
ALWAYS_INLINE void
|
||||
Dtool_Assign_PyObject(PyObject *&ptr, PyObject *value) {
|
||||
PyObject *prev_value = ptr;
|
||||
if (prev_value != value) {
|
||||
ptr = Py_XNewRef(value);
|
||||
Py_XDECREF(prev_value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the enum value to a C long.
|
||||
*/
|
||||
INLINE long Dtool_EnumValue_AsLong(PyObject *value) {
|
||||
PyObject *val = PyObject_GetAttrString(value, "value");
|
||||
if (val != nullptr) {
|
||||
long as_long = PyLongOrInt_AS_LONG(val);
|
||||
Py_DECREF(val);
|
||||
return as_long;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* These functions wrap a pointer for a class that defines get_type_handle().
|
||||
*/
|
||||
|
|
@ -167,23 +110,6 @@ DTool_PyInit_Finalize(PyObject *self, void *local_this, Dtool_PyTypedObject *typ
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the tuple is empty.
|
||||
*/
|
||||
ALWAYS_INLINE bool
|
||||
Dtool_CheckNoArgs(PyObject *args) {
|
||||
return PyTuple_GET_SIZE(args) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the tuple is empty, and that the dict is empty or NULL.
|
||||
*/
|
||||
ALWAYS_INLINE bool
|
||||
Dtool_CheckNoArgs(PyObject *args, PyObject *kwds) {
|
||||
return PyTuple_GET_SIZE(args) == 0 &&
|
||||
(kwds == nullptr || PyDict_GET_SIZE(kwds) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* The following functions wrap an arbitrary C++ value into a PyObject.
|
||||
*/
|
||||
|
|
@ -324,7 +250,8 @@ ALWAYS_INLINE PyObject *Dtool_WrapValue(PyObject *value) {
|
|||
return value;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(const vector_uchar &value) {
|
||||
template<class Allocator>
|
||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::vector<unsigned char, Allocator> &value) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return PyBytes_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size());
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -8,15 +8,14 @@
|
|||
#include <set>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef USE_DEBUG_PYTHON
|
||||
#define Py_DEBUG
|
||||
#endif
|
||||
|
||||
#include "pnotify.h"
|
||||
#include "vector_uchar.h"
|
||||
#include "register_type.h"
|
||||
#include "interrogate_request.h"
|
||||
|
||||
#if defined(HAVE_PYTHON) && !defined(CPPPARSER)
|
||||
|
||||
|
|
@ -24,8 +23,6 @@
|
|||
#include "py_compat.h"
|
||||
#include <structmember.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// this is tempory .. untill this is glued better into the panda build system
|
||||
|
||||
#if defined(_WIN32) && !defined(LINK_ALL_STATIC)
|
||||
|
|
@ -86,83 +83,6 @@ struct Dtool_PyTypedObject {
|
|||
CoerceFunction _Dtool_Coerce;
|
||||
};
|
||||
|
||||
// This is now simply a forward declaration. The actual definition is created
|
||||
// by the code generator.
|
||||
#define Define_Dtool_Class(MODULE_NAME, CLASS_NAME, PUBLIC_NAME) \
|
||||
extern Dtool_PyTypedObject Dtool_##CLASS_NAME;
|
||||
|
||||
// More Macro(s) to Implement class functions.. Usually used if C++ needs type
|
||||
// information
|
||||
#define Define_Dtool_new(CLASS_NAME,CNAME)\
|
||||
static PyObject *Dtool_new_##CLASS_NAME(PyTypeObject *type, PyObject *args, PyObject *kwds) {\
|
||||
(void) args; (void) kwds;\
|
||||
PyObject *self = type->tp_alloc(type, 0);\
|
||||
((Dtool_PyInstDef *)self)->_signature = PY_PANDA_SIGNATURE;\
|
||||
((Dtool_PyInstDef *)self)->_My_Type = &Dtool_##CLASS_NAME;\
|
||||
return self;\
|
||||
}
|
||||
|
||||
// The following used to be in the above macro, but it doesn't seem to be
|
||||
// necessary as tp_alloc memsets the object to 0.
|
||||
// ((Dtool_PyInstDef *)self)->_ptr_to_object = NULL;
|
||||
// ((Dtool_PyInstDef *)self)->_memory_rules = false;
|
||||
// ((Dtool_PyInstDef *)self)->_is_const = false;
|
||||
|
||||
// Delete functions..
|
||||
#ifdef NDEBUG
|
||||
#define Define_Dtool_FreeInstance_Private(CLASS_NAME,CNAME)\
|
||||
static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
|
||||
Py_TYPE(self)->tp_free(self);\
|
||||
}
|
||||
#else // NDEBUG
|
||||
#define Define_Dtool_FreeInstance_Private(CLASS_NAME,CNAME)\
|
||||
static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
|
||||
if (DtoolInstance_VOID_PTR(self) != nullptr) {\
|
||||
if (((Dtool_PyInstDef *)self)->_memory_rules) {\
|
||||
std::cerr << "Detected leak for " << #CLASS_NAME \
|
||||
<< " which interrogate cannot delete.\n"; \
|
||||
}\
|
||||
}\
|
||||
Py_TYPE(self)->tp_free(self);\
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
#define Define_Dtool_FreeInstance(CLASS_NAME,CNAME)\
|
||||
static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
|
||||
if (DtoolInstance_VOID_PTR(self) != nullptr) {\
|
||||
if (((Dtool_PyInstDef *)self)->_memory_rules) {\
|
||||
delete (CNAME *)DtoolInstance_VOID_PTR(self);\
|
||||
}\
|
||||
}\
|
||||
Py_TYPE(self)->tp_free(self);\
|
||||
}
|
||||
|
||||
#define Define_Dtool_FreeInstanceRef(CLASS_NAME,CNAME)\
|
||||
static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
|
||||
if (DtoolInstance_VOID_PTR(self) != nullptr) {\
|
||||
if (((Dtool_PyInstDef *)self)->_memory_rules) {\
|
||||
unref_delete((CNAME *)DtoolInstance_VOID_PTR(self));\
|
||||
}\
|
||||
}\
|
||||
Py_TYPE(self)->tp_free(self);\
|
||||
}
|
||||
|
||||
#define Define_Dtool_FreeInstanceRef_Private(CLASS_NAME,CNAME)\
|
||||
static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
|
||||
if (DtoolInstance_VOID_PTR(self) != nullptr) {\
|
||||
if (((Dtool_PyInstDef *)self)->_memory_rules) {\
|
||||
unref_delete((ReferenceCount *)(CNAME *)DtoolInstance_VOID_PTR(self));\
|
||||
}\
|
||||
}\
|
||||
Py_TYPE(self)->tp_free(self);\
|
||||
}
|
||||
|
||||
#define Define_Dtool_Simple_FreeInstance(CLASS_NAME, CNAME)\
|
||||
static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
|
||||
((Dtool_InstDef_##CLASS_NAME *)self)->_value.~##CLASS_NAME();\
|
||||
Py_TYPE(self)->tp_free(self);\
|
||||
}
|
||||
|
||||
// Extract the PyTypeObject pointer corresponding to a Dtool_PyTypedObject.
|
||||
#define Dtool_GetPyTypeObject(type) (&(type)->_PyType)
|
||||
|
||||
|
|
@ -178,31 +98,12 @@ static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
|
|||
#define DtoolInstance_INIT_PTR(obj, ptr) { ((Dtool_PyInstDef *)obj)->_ptr_to_object = (void*)(ptr); }
|
||||
#define DtoolInstance_UPCAST(obj, type) (((Dtool_PyInstDef *)(obj))->_My_Type->_Dtool_UpcastInterface((obj), &(type)))
|
||||
|
||||
// ** HACK ** allert.. Need to keep a runtime type dictionary ... that is
|
||||
// forward declared of typed object. We rely on the fact that typed objects
|
||||
// are uniquly defined by an integer.
|
||||
|
||||
#if PY_VERSION_HEX >= 0x030d0000
|
||||
class Dtool_TypeMap : public std::map<std::string, Dtool_PyTypedObject *> {
|
||||
public:
|
||||
PyMutex _lock { 0 };
|
||||
};
|
||||
#else
|
||||
typedef std::map<std::string, Dtool_PyTypedObject *> Dtool_TypeMap;
|
||||
#endif
|
||||
|
||||
EXPCL_PYPANDA Dtool_TypeMap *Dtool_GetGlobalTypeMap();
|
||||
|
||||
class DtoolProxy {
|
||||
public:
|
||||
mutable PyObject *_self;
|
||||
TypeHandle _type;
|
||||
};
|
||||
|
||||
EXPCL_PYPANDA void DtoolProxy_Init(DtoolProxy *proxy, PyObject *self,
|
||||
Dtool_PyTypedObject &classdef,
|
||||
TypeRegistry::PythonWrapFunc *wrap_func);
|
||||
|
||||
/**
|
||||
|
||||
*/
|
||||
|
|
@ -218,23 +119,11 @@ EXPCL_PYPANDA bool Dtool_Call_ExtractThisPointer_NonConst(PyObject *self, Dtool_
|
|||
template<class T> INLINE bool DtoolInstance_GetPointer(PyObject *self, T *&into);
|
||||
template<class T> INLINE bool DtoolInstance_GetPointer(PyObject *self, T *&into, Dtool_PyTypedObject &classdef);
|
||||
|
||||
INLINE Py_hash_t DtoolInstance_HashPointer(PyObject *self);
|
||||
INLINE int DtoolInstance_ComparePointers(PyObject *v1, PyObject *v2);
|
||||
INLINE PyObject *DtoolInstance_RichComparePointers(PyObject *v1, PyObject *v2, int op);
|
||||
|
||||
// Functions related to error reporting.
|
||||
EXPCL_PYPANDA bool _Dtool_CheckErrorOccurred();
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define Dtool_CheckErrorOccurred() (UNLIKELY(PyErr_Occurred() != nullptr))
|
||||
#else
|
||||
#define Dtool_CheckErrorOccurred() (UNLIKELY(_Dtool_CheckErrorOccurred()))
|
||||
#endif
|
||||
|
||||
EXPCL_PYPANDA PyObject *Dtool_Raise_AssertionError();
|
||||
EXPCL_PYPANDA PyObject *Dtool_Raise_TypeError(const char *message);
|
||||
EXPCL_PYPANDA PyObject *Dtool_Raise_ArgTypeError(PyObject *obj, int param, const char *function_name, const char *type_name);
|
||||
EXPCL_PYPANDA PyObject *Dtool_Raise_AttributeError(PyObject *obj, const char *attribute);
|
||||
EXPCL_PYPANDA int Dtool_Raise_CantDeleteAttributeError(const char *attribute);
|
||||
|
||||
EXPCL_PYPANDA PyObject *_Dtool_Raise_BadArgumentsError();
|
||||
EXPCL_PYPANDA PyObject *_Dtool_Raise_BadArgumentsError(const char *message);
|
||||
|
|
@ -250,31 +139,6 @@ EXPCL_PYPANDA int _Dtool_Raise_BadArgumentsError_Int(const char *message);
|
|||
#define Dtool_Raise_BadArgumentsError_Int(x) _Dtool_Raise_BadArgumentsError_Int(x)
|
||||
#endif
|
||||
|
||||
// These functions are similar to Dtool_WrapValue, except that they also
|
||||
// contain code for checking assertions and exceptions when compiling with
|
||||
// NDEBUG mode on.
|
||||
EXPCL_PYPANDA PyObject *_Dtool_Return_None();
|
||||
EXPCL_PYPANDA PyObject *Dtool_Return_Bool(bool value);
|
||||
EXPCL_PYPANDA PyObject *_Dtool_Return(PyObject *value);
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define Dtool_Return_None() (LIKELY(PyErr_Occurred() == nullptr) ? (Py_NewRef(Py_None)) : nullptr)
|
||||
#define Dtool_Return(value) (LIKELY(PyErr_Occurred() == nullptr) ? value : nullptr)
|
||||
#else
|
||||
#define Dtool_Return_None() _Dtool_Return_None()
|
||||
#define Dtool_Return(value) _Dtool_Return(value)
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE void Dtool_Assign_PyObject(PyObject *&ptr, PyObject *value);
|
||||
|
||||
/**
|
||||
* Wrapper around Python 3.4's enum library, which does not have a C API.
|
||||
*/
|
||||
EXPCL_PYPANDA PyTypeObject *Dtool_EnumType_Create(const char *name, PyObject *names,
|
||||
const char *module = nullptr);
|
||||
INLINE long Dtool_EnumValue_AsLong(PyObject *value);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
*/
|
||||
|
|
@ -291,102 +155,9 @@ template<class T> INLINE PyObject *DTool_CreatePyInstance(T *obj, bool memory_ru
|
|||
template<class T> INLINE PyObject *DTool_CreatePyInstanceTyped(const T *obj, bool memory_rules);
|
||||
template<class T> INLINE PyObject *DTool_CreatePyInstanceTyped(T *obj, bool memory_rules);
|
||||
|
||||
// Macro(s) class definition .. Used to allocate storage and init some values
|
||||
// for a Dtool Py Type object.
|
||||
|
||||
// struct Dtool_PyTypedObject Dtool_##CLASS_NAME;
|
||||
|
||||
#define Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
|
||||
extern struct Dtool_PyTypedObject Dtool_##CLASS_NAME;\
|
||||
static int Dtool_Init_##CLASS_NAME(PyObject *self, PyObject *args, PyObject *kwds);\
|
||||
static PyObject *Dtool_new_##CLASS_NAME(PyTypeObject *type, PyObject *args, PyObject *kwds);
|
||||
|
||||
#define Define_Module_Class(MODULE_NAME,CLASS_NAME,CNAME,PUBLIC_NAME)\
|
||||
Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
|
||||
Define_Dtool_new(CLASS_NAME,CNAME)\
|
||||
Define_Dtool_FreeInstance(CLASS_NAME,CNAME)\
|
||||
Define_Dtool_Class(MODULE_NAME,CLASS_NAME,PUBLIC_NAME)
|
||||
|
||||
#define Define_Module_Class_Private(MODULE_NAME,CLASS_NAME,CNAME,PUBLIC_NAME)\
|
||||
Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
|
||||
Define_Dtool_new(CLASS_NAME,CNAME)\
|
||||
Define_Dtool_FreeInstance_Private(CLASS_NAME,CNAME)\
|
||||
Define_Dtool_Class(MODULE_NAME,CLASS_NAME,PUBLIC_NAME)
|
||||
|
||||
#define Define_Module_ClassRef_Private(MODULE_NAME,CLASS_NAME,CNAME,PUBLIC_NAME)\
|
||||
Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
|
||||
Define_Dtool_new(CLASS_NAME,CNAME)\
|
||||
Define_Dtool_FreeInstanceRef_Private(CLASS_NAME,CNAME)\
|
||||
Define_Dtool_Class(MODULE_NAME,CLASS_NAME,PUBLIC_NAME)
|
||||
|
||||
#define Define_Module_ClassRef(MODULE_NAME,CLASS_NAME,CNAME,PUBLIC_NAME)\
|
||||
Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
|
||||
Define_Dtool_new(CLASS_NAME,CNAME)\
|
||||
Define_Dtool_FreeInstanceRef(CLASS_NAME,CNAME)\
|
||||
Define_Dtool_Class(MODULE_NAME,CLASS_NAME,PUBLIC_NAME)
|
||||
|
||||
// The finalizer for simple instances.
|
||||
INLINE int DTool_PyInit_Finalize(PyObject *self, void *This, Dtool_PyTypedObject *type, bool memory_rules, bool is_const);
|
||||
|
||||
// A heler function to glu methed definition together .. that can not be done
|
||||
// at code generation time becouse of multiple generation passes in
|
||||
// interigate..
|
||||
typedef std::map<std::string, PyMethodDef *> MethodDefmap;
|
||||
|
||||
// We need a way to runtime merge compile units into a python "Module" .. this
|
||||
// is done with the fallowing structors and code.. along with the support of
|
||||
// interigate_module
|
||||
|
||||
struct Dtool_TypeDef {
|
||||
const char *const name;
|
||||
Dtool_PyTypedObject *type;
|
||||
};
|
||||
|
||||
struct LibraryDef {
|
||||
PyMethodDef *const _methods;
|
||||
const Dtool_TypeDef *const _types;
|
||||
Dtool_TypeDef *const _external_types;
|
||||
const InterrogateModuleDef *const _module_def;
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
EXPCL_PYPANDA PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], PyModuleDef *module_def);
|
||||
#else
|
||||
EXPCL_PYPANDA PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], const char *modulename);
|
||||
#endif
|
||||
|
||||
// HACK.... Be carefull Dtool_BorrowThisReference This function can be used to
|
||||
// grab the "THIS" pointer from an object and use it Required to support fom
|
||||
// historical inharatence in the for of "is this instance of"..
|
||||
EXPCL_PYPANDA PyObject *Dtool_BorrowThisReference(PyObject *self, PyObject *args);
|
||||
|
||||
#define DTOOL_PyObject_HashPointer DtoolInstance_HashPointer
|
||||
#define DTOOL_PyObject_ComparePointers DtoolInstance_ComparePointers
|
||||
|
||||
EXPCL_PYPANDA PyObject *
|
||||
copy_from_make_copy(PyObject *self, PyObject *noargs);
|
||||
|
||||
EXPCL_PYPANDA PyObject *
|
||||
copy_from_copy_constructor(PyObject *self, PyObject *noargs);
|
||||
|
||||
EXPCL_PYPANDA PyObject *
|
||||
map_deepcopy_to_copy(PyObject *self, PyObject *args);
|
||||
|
||||
/**
|
||||
* These functions check whether the arguments passed to a function conform to
|
||||
* certain expectations.
|
||||
*/
|
||||
ALWAYS_INLINE bool Dtool_CheckNoArgs(PyObject *args);
|
||||
ALWAYS_INLINE bool Dtool_CheckNoArgs(PyObject *args, PyObject *kwds);
|
||||
EXPCL_PYPANDA bool Dtool_ExtractArg(PyObject **result, PyObject *args,
|
||||
PyObject *kwds, const char *keyword);
|
||||
EXPCL_PYPANDA bool Dtool_ExtractArg(PyObject **result, PyObject *args,
|
||||
PyObject *kwds);
|
||||
EXPCL_PYPANDA bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args,
|
||||
PyObject *kwds, const char *keyword);
|
||||
EXPCL_PYPANDA bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args,
|
||||
PyObject *kwds);
|
||||
|
||||
/**
|
||||
* These functions convert a C++ value into the corresponding Python object.
|
||||
* This used to be generated by the code generator, but it seems more reliable
|
||||
|
|
@ -411,7 +182,8 @@ ALWAYS_INLINE PyObject *Dtool_WrapValue(char value);
|
|||
ALWAYS_INLINE PyObject *Dtool_WrapValue(wchar_t value);
|
||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(std::nullptr_t);
|
||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(PyObject *value);
|
||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(const vector_uchar &value);
|
||||
template<class Allocator>
|
||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::vector<unsigned char, Allocator> &value);
|
||||
|
||||
#if PY_MAJOR_VERSION >= 0x02060000
|
||||
ALWAYS_INLINE PyObject *Dtool_WrapValue(Py_buffer *value);
|
||||
|
|
@ -422,9 +194,12 @@ ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::pair<T1, T2> &value);
|
|||
|
||||
EXPCL_PYPANDA Dtool_PyTypedObject *Dtool_GetSuperBase();
|
||||
|
||||
#include "py_panda.I"
|
||||
/**
|
||||
* Creates a Python generator object from a next() function.
|
||||
*/
|
||||
EXPCL_PYPANDA PyObject *Dtool_NewGenerator(PyObject *self, iternextfunc func);
|
||||
|
||||
#include "py_wrappers.h"
|
||||
#include "py_panda.I"
|
||||
|
||||
#endif // HAVE_PYTHON && !CPPPARSER
|
||||
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
/**
|
||||
* @file py_wrappers.h
|
||||
* @author rdb
|
||||
* @date 2017-11-26
|
||||
*/
|
||||
|
||||
#ifndef PY_WRAPPERS_H
|
||||
#define PY_WRAPPERS_H
|
||||
|
||||
#include "py_panda.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
/**
|
||||
* These classes are returned from properties that require a subscript
|
||||
* interface, ie. something.children[i] = 3.
|
||||
*/
|
||||
struct Dtool_WrapperBase {
|
||||
PyObject_HEAD;
|
||||
PyObject *_self;
|
||||
const char *_name;
|
||||
};
|
||||
|
||||
struct Dtool_SequenceWrapper {
|
||||
Dtool_WrapperBase _base;
|
||||
lenfunc _len_func;
|
||||
ssizeargfunc _getitem_func;
|
||||
};
|
||||
|
||||
struct Dtool_MutableSequenceWrapper {
|
||||
Dtool_WrapperBase _base;
|
||||
lenfunc _len_func;
|
||||
ssizeargfunc _getitem_func;
|
||||
ssizeobjargproc _setitem_func;
|
||||
PyObject *(*_insert_func)(PyObject *, size_t, PyObject *);
|
||||
};
|
||||
|
||||
struct Dtool_MappingWrapper {
|
||||
union {
|
||||
Dtool_WrapperBase _base;
|
||||
Dtool_SequenceWrapper _keys;
|
||||
};
|
||||
binaryfunc _getitem_func;
|
||||
objobjargproc _setitem_func;
|
||||
};
|
||||
|
||||
struct Dtool_GeneratorWrapper {
|
||||
Dtool_WrapperBase _base;
|
||||
iternextfunc _iternext_func;
|
||||
};
|
||||
|
||||
EXPCL_PYPANDA Dtool_SequenceWrapper *Dtool_NewSequenceWrapper(PyObject *self, const char *name);
|
||||
EXPCL_PYPANDA Dtool_MutableSequenceWrapper *Dtool_NewMutableSequenceWrapper(PyObject *self, const char *name);
|
||||
EXPCL_PYPANDA Dtool_MappingWrapper *Dtool_NewMappingWrapper(PyObject *self, const char *name);
|
||||
EXPCL_PYPANDA Dtool_MappingWrapper *Dtool_NewMutableMappingWrapper(PyObject *self, const char *name);
|
||||
EXPCL_PYPANDA PyObject *Dtool_NewGenerator(PyObject *self, iternextfunc func);
|
||||
EXPCL_PYPANDA PyObject *Dtool_NewStaticProperty(PyTypeObject *obj, const PyGetSetDef *getset);
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
#endif // PY_WRAPPERS_H
|
||||
|
|
@ -52,4 +52,9 @@ PyObject _Py_FalseStruct;
|
|||
|
||||
typedef void *visitproc;
|
||||
|
||||
typedef enum {
|
||||
PyRefTracer_CREATE = 0,
|
||||
PyRefTracer_DESTROY = 1,
|
||||
} PyRefTracerEvent;
|
||||
|
||||
#endif // PYTHON_H
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
#include <xmmintrin.h>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
namespace std {
|
||||
class random_device;
|
||||
class seed_seq;
|
||||
|
||||
template<class IntType = int> class uniform_int_distribution;
|
||||
template<class RealType = double> class uniform_real_distribution;
|
||||
class bernoulli_distribution;
|
||||
template<class IntType = int> class binomial_distribution;
|
||||
template<class IntType = int> class geometric_distribution;
|
||||
template<class IntType = int> class negative_binomial_distribution;
|
||||
template<class IntType = int> class poisson_distribution;
|
||||
template<class RealType = double> class exponential_distribution;
|
||||
template<class RealType = double> class gamma_distribution;
|
||||
template<class RealType = double> class weibull_distribution;
|
||||
template<class RealType = double> class extreme_value_distribution;
|
||||
template<class RealType = double> class normal_distribution;
|
||||
template<class RealType = double> class lognormal_distribution;
|
||||
template<class RealType = double> class chi_squared_distribution;
|
||||
template<class RealType = double> class cauchy_distribution;
|
||||
template<class RealType = double> class fisher_f_distribution;
|
||||
template<class RealType = double> class student_t_distribution;
|
||||
template<class IntType = int> class discrete_distribution;
|
||||
template<class RealType = double> class piecewise_constant_distribution;
|
||||
template<class RealType = double> class piecewise_linear_distribution;
|
||||
}
|
||||
|
|
@ -97,7 +97,6 @@ reload_implicit_pages() {
|
|||
}
|
||||
_implicit_pages.clear();
|
||||
|
||||
#ifndef ANDROID
|
||||
// If we are running inside a deployed application, see if it exposes
|
||||
// information about how the PRC data should be initialized.
|
||||
struct BlobInfo {
|
||||
|
|
@ -129,11 +128,13 @@ reload_implicit_pages() {
|
|||
// const BlobInfo *blobinfo = (const BlobInfo *)dlsym(RTLD_SELF, "blobinfo");
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
const BlobInfo *blobinfo = nullptr;
|
||||
#elif defined(ANDROID)
|
||||
const BlobInfo *blobinfo = nullptr;
|
||||
#else
|
||||
const BlobInfo *blobinfo = (const BlobInfo *)dlsym(dlopen(nullptr, RTLD_NOW), "blobinfo");
|
||||
#endif
|
||||
if (blobinfo == nullptr) {
|
||||
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)
|
||||
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(ANDROID)
|
||||
// Clear the error flag.
|
||||
dlerror();
|
||||
#endif
|
||||
|
|
@ -482,7 +483,6 @@ reload_implicit_pages() {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif // ANDROID
|
||||
|
||||
if (!_loaded_implicit) {
|
||||
config_initialized();
|
||||
|
|
@ -492,6 +492,21 @@ reload_implicit_pages() {
|
|||
_currently_loading = false;
|
||||
invalidate_cache();
|
||||
|
||||
// These important variables are updated here to avoid recursion, since
|
||||
// they may be accessed by the PRC system.
|
||||
ConfigVariableBool notify_timestamp
|
||||
("notify-timestamp", false,
|
||||
PRC_DESC("Set true to output the date & time with each notify message."));
|
||||
NotifyCategory::_notify_timestamp = notify_timestamp;
|
||||
|
||||
#ifndef NDEBUG
|
||||
ConfigVariableBool check_debug_notify_protect
|
||||
("check-debug-notify-protect", false,
|
||||
PRC_DESC("Set true to issue a warning message if a debug or spam "
|
||||
"notify output is not protected within an if statement."));
|
||||
NotifyCategory::_check_debug_notify_protect = check_debug_notify_protect;
|
||||
#endif
|
||||
|
||||
#ifdef USE_PANDAFILESTREAM
|
||||
// Update this very low-level config variable here, for lack of any better
|
||||
// place.
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <sys/stat.h>
|
||||
#include <android/log.h>
|
||||
#include "androidLogStream.h"
|
||||
#endif
|
||||
|
|
@ -35,6 +36,18 @@
|
|||
#include "emscriptenLogStream.h"
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
#ifdef PHAVE_EXECINFO_H
|
||||
#include <execinfo.h> // for backtrace()
|
||||
#include <dlfcn.h>
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <dbghelp.h>
|
||||
#endif
|
||||
#endif // NDEBUG
|
||||
|
||||
using std::cerr;
|
||||
using std::cout;
|
||||
using std::ostream;
|
||||
|
|
@ -348,15 +361,16 @@ assert_failure(const char *expression, int line,
|
|||
<< expression << " at line " << line << " of " << source_file;
|
||||
string message = message_str.str();
|
||||
|
||||
if (!_assert_failed) {
|
||||
Notify *self = ptr();
|
||||
if (!self->_assert_failed) {
|
||||
// We only save the first assertion failure message, as this is usually
|
||||
// the most meaningful when several occur in a row.
|
||||
_assert_failed = true;
|
||||
_assert_error_message = message;
|
||||
self->_assert_failed = true;
|
||||
self->_assert_error_message = message;
|
||||
}
|
||||
|
||||
if (has_assert_handler()) {
|
||||
return (*_assert_handler)(expression, line, source_file);
|
||||
if (self->has_assert_handler()) {
|
||||
return (*self->_assert_handler)(expression, line, source_file);
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
|
|
@ -380,6 +394,33 @@ assert_failure(const char *expression, int line,
|
|||
// Make sure the error message has been flushed to the output.
|
||||
nout.flush();
|
||||
|
||||
// Capture and list a stack trace.
|
||||
#ifdef NDEBUG
|
||||
#elif defined(PHAVE_EXECINFO_H)
|
||||
void *trace[64];
|
||||
int size = backtrace(trace, 64);
|
||||
if (size > 0) {
|
||||
// Remove the frame(s) corresponding to the current function.
|
||||
void **tracep = trace;
|
||||
void *return_addr = __builtin_return_address(0);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (trace[i] == return_addr) {
|
||||
tracep = trace + (i + 1);
|
||||
size -= i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
write_backtrace(tracep, size);
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
const ULONG max_size = 62;
|
||||
void *trace[max_size];
|
||||
int size = CaptureStackBackTrace(1, max_size, trace, nullptr);
|
||||
if (size > 0) {
|
||||
write_backtrace(trace, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// How to trigger an exception in VC++ that offers to take us into the
|
||||
// debugger? abort() doesn't do it. We used to be able to assert(false),
|
||||
|
|
@ -411,6 +452,141 @@ assert_failure(const char *expression, int line,
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void Notify::
|
||||
write_backtrace(void **trace, int size) {
|
||||
std::ostream &out = nout;
|
||||
|
||||
#ifdef NDEBUG
|
||||
#elif defined(PHAVE_EXECINFO_H)
|
||||
char namebuf[128];
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
void *addr = trace[i];
|
||||
Dl_info info;
|
||||
if (dladdr((char *)addr - 1, &info) != 0) {
|
||||
const char *name = nullptr;
|
||||
|
||||
if (info.dli_sname != nullptr) {
|
||||
int status = 0;
|
||||
size_t size = 0;
|
||||
char *demangled = nullptr;
|
||||
if (info.dli_sname[0] == '_') {
|
||||
size = sizeof(namebuf) - 1;
|
||||
demangled = abi::__cxa_demangle(info.dli_sname, namebuf, &size, &status);
|
||||
}
|
||||
if (status == 0 && demangled != nullptr) {
|
||||
namebuf[size] = 0;
|
||||
name = demangled;
|
||||
//if (strncmp(name, "Notify::assert_failure", 22) == 0) {
|
||||
//continue;
|
||||
//}
|
||||
} else {
|
||||
name = info.dli_sname;
|
||||
}
|
||||
}
|
||||
|
||||
out << "[" << addr << "] ";
|
||||
|
||||
if (info.dli_fname != nullptr) {
|
||||
const char *slash = strrchr(info.dli_fname, '/');
|
||||
out << std::left << std::setw(30) << (slash ? slash + 1 : info.dli_fname) << " ";
|
||||
}
|
||||
|
||||
if (name != nullptr) {
|
||||
out << name;
|
||||
} else {
|
||||
out << info.dli_saddr;
|
||||
}
|
||||
|
||||
int offset = reinterpret_cast<uintptr_t>(addr) - reinterpret_cast<uintptr_t>(info.dli_saddr);
|
||||
if (offset > 0) {
|
||||
out << " + " << offset;
|
||||
}
|
||||
out << "\n";
|
||||
} else {
|
||||
out << "[" << addr << "]\n";
|
||||
}
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
HMODULE handle = LoadLibraryA("dbghelp.dll");
|
||||
if (!handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto pSymInitialize = (BOOL (WINAPI *)(HANDLE, PCSTR, BOOL))GetProcAddress(handle, "SymInitialize");
|
||||
auto pSymCleanup = (BOOL (WINAPI *)(HANDLE))GetProcAddress(handle, "SymCleanup");
|
||||
auto pSymFromAddr = (BOOL (WINAPI *)(HANDLE, DWORD64, DWORD64 *, PSYMBOL_INFO))GetProcAddress(handle, "SymFromAddr");
|
||||
auto pSymGetModuleInfo64 = (BOOL (WINAPI *)(HANDLE, DWORD64, PIMAGEHLP_MODULE64))GetProcAddress(handle, "SymGetModuleInfo64");
|
||||
auto pSymGetLineFromAddr64 = (BOOL (WINAPI *)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64))GetProcAddress(handle, "SymGetLineFromAddr64");
|
||||
if (!pSymInitialize || !pSymCleanup || !pSymFromAddr) {
|
||||
FreeLibrary(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
HANDLE process = GetCurrentProcess();
|
||||
pSymInitialize(process, nullptr, TRUE);
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
DWORD64 addr = (DWORD64)trace[i];
|
||||
|
||||
alignas(SYMBOL_INFO) char buffer[sizeof(SYMBOL_INFO) + 256] = {0};
|
||||
SYMBOL_INFO *symbol = (SYMBOL_INFO *)buffer;
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
symbol->MaxNameLen = 255;
|
||||
|
||||
out << "[" << (void *)addr << "]";
|
||||
|
||||
// Show the name of the library.
|
||||
IMAGEHLP_MODULE64 module;
|
||||
module.SizeOfStruct = sizeof(module);
|
||||
const char *basename = "???";
|
||||
if (pSymGetModuleInfo64 && pSymGetModuleInfo64(process, addr, &module)) {
|
||||
const char *slash = strrchr(module.ImageName, '\\');
|
||||
basename = (slash ? slash + 1 : module.ImageName);
|
||||
}
|
||||
|
||||
// Look up the symbol name. If the reported name comes from the export
|
||||
// table and the address is way off, ignore it, it's probably not right.
|
||||
if (pSymFromAddr(process, addr, nullptr, symbol) &&
|
||||
((symbol->Flags & SYMFLAG_EXPORT) == 0 || addr - (DWORD64)symbol->Address < 0x4000)) {
|
||||
|
||||
out << " " << std::left << std::setw(30) << basename << " " << symbol->Name;
|
||||
|
||||
DWORD64 offset = addr - (DWORD64)(symbol->Address);
|
||||
if (offset > 0) {
|
||||
out << " + " << offset;
|
||||
}
|
||||
|
||||
// Look up filename + line number if available.
|
||||
IMAGEHLP_LINE64 line;
|
||||
DWORD displacement = 0;
|
||||
line.SizeOfStruct = sizeof(line);
|
||||
if (pSymGetLineFromAddr64(process, addr, &displacement, &line)) {
|
||||
const char *slash = strrchr(line.FileName, '\\');
|
||||
const char *basename = (slash ? slash + 1 : line.FileName);
|
||||
|
||||
out << " (" << basename << ":" << line.LineNumber;
|
||||
//if (displacement > 0) {
|
||||
// out << " + " << displacement;
|
||||
//}
|
||||
out << ")";
|
||||
}
|
||||
} else {
|
||||
out << " " << basename;
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
pSymCleanup(process);
|
||||
FreeLibrary(handle);
|
||||
#endif
|
||||
|
||||
out.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a string, one of "debug", "info", "warning", etc., return the
|
||||
* corresponding Severity level, or NS_unspecified if none of the strings
|
||||
|
|
@ -460,22 +636,7 @@ config_initialized() {
|
|||
// notify-output even after the initial import of Panda3D modules. However,
|
||||
// it cannot be changed after the first time it is set.
|
||||
|
||||
#if defined(ANDROID)
|
||||
// Android redirects stdio and stderr to /dev/null,
|
||||
// but does provide its own logging system. We use a special
|
||||
// type of stream that redirects it to Android's log system.
|
||||
|
||||
Notify *ptr = Notify::ptr();
|
||||
|
||||
for (int severity = 0; severity <= NS_fatal; ++severity) {
|
||||
int priority = ANDROID_LOG_UNKNOWN;
|
||||
if (severity != NS_unspecified) {
|
||||
priority = severity + 1;
|
||||
}
|
||||
ptr->_log_streams[severity] = new AndroidLogStream(priority);
|
||||
}
|
||||
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
// We have no writable filesystem in JavaScript. Instead, we set up a
|
||||
// special stream that logs straight into the Javascript console.
|
||||
|
||||
|
|
@ -540,11 +701,38 @@ config_initialized() {
|
|||
}
|
||||
#endif // BUILD_IPHONE
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
for (int severity = 0; severity <= NS_fatal; ++severity) {
|
||||
ptr->_log_streams[severity] = ptr->_ostream_ptr;
|
||||
}
|
||||
|
||||
} else {
|
||||
// By default, we always redirect the notify stream to the Android log.
|
||||
// By default, we always redirect the notify stream to the Android log,
|
||||
// except if we are running from the adb shell. We decide this based
|
||||
// on whether stderr is redirected to /dev/null.
|
||||
Notify *ptr = Notify::ptr();
|
||||
ptr->set_ostream_ptr(new AndroidLogStream(ANDROID_LOG_INFO), true);
|
||||
struct stat a, b;
|
||||
if (fstat(STDERR_FILENO, &a) == 0 && stat("/dev/null", &b) == 0 &&
|
||||
a.st_dev == b.st_dev && a.st_ino == b.st_ino) {
|
||||
// Android redirects stdio and stderr to /dev/null,
|
||||
// but does provide its own logging system. We use a special
|
||||
// type of stream that redirects it to Android's log system.
|
||||
for (int severity = 0; severity <= NS_fatal; ++severity) {
|
||||
int priority = ANDROID_LOG_UNKNOWN;
|
||||
if (severity != NS_unspecified) {
|
||||
priority = severity + 1;
|
||||
}
|
||||
ptr->_log_streams[severity] = new AndroidLogStream(priority);
|
||||
}
|
||||
ptr->set_ostream_ptr(new AndroidLogStream(ANDROID_LOG_INFO), true);
|
||||
} else {
|
||||
// Running from the terminal, set all the log streams to point to the
|
||||
// same output.
|
||||
for (int severity = 0; severity <= NS_fatal; ++severity) {
|
||||
ptr->_log_streams[severity] = &cerr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@
|
|||
#include <time.h> // for strftime().
|
||||
#include <assert.h>
|
||||
|
||||
bool NotifyCategory::_notify_timestamp = false;
|
||||
bool NotifyCategory::_check_debug_notify_protect = false;
|
||||
|
||||
long NotifyCategory::_server_delta = 0;
|
||||
|
||||
/**
|
||||
|
|
@ -55,7 +58,7 @@ std::ostream &NotifyCategory::
|
|||
out(NotifySeverity severity, bool prefix) const {
|
||||
if (is_on(severity)) {
|
||||
if (prefix) {
|
||||
if (get_notify_timestamp()) {
|
||||
if (_notify_timestamp) {
|
||||
// Format a timestamp to include as a prefix as well.
|
||||
time_t now = time(nullptr) + _server_delta;
|
||||
struct tm atm;
|
||||
|
|
@ -79,7 +82,7 @@ out(NotifySeverity severity, bool prefix) const {
|
|||
return Notify::out(severity);
|
||||
}
|
||||
|
||||
} else if (severity <= NS_debug && get_check_debug_notify_protect()) {
|
||||
} else if (severity <= NS_debug && _check_debug_notify_protect) {
|
||||
// Someone issued a debug Notify output statement without protecting it
|
||||
// within an if statement. This can cause a significant runtime
|
||||
// performance hit, since it forces the iostream library to fully format
|
||||
|
|
@ -172,36 +175,3 @@ update_severity_cache() {
|
|||
|
||||
mark_cache_valid(_local_modified);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the notify-timestamp ConfigVariable. This is defined
|
||||
* using a method accessor rather than a static ConfigVariableBool, to protect
|
||||
* against the variable needing to be accessed at static init time.
|
||||
*/
|
||||
bool NotifyCategory::
|
||||
get_notify_timestamp() {
|
||||
static ConfigVariableBool *notify_timestamp = nullptr;
|
||||
if (notify_timestamp == nullptr) {
|
||||
notify_timestamp = new ConfigVariableBool
|
||||
("notify-timestamp", false,
|
||||
"Set true to output the date & time with each notify message.");
|
||||
}
|
||||
return *notify_timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the check-debug-notify-protect ConfigVariable. This
|
||||
* is defined using a method accessor rather than a static ConfigVariableBool,
|
||||
* to protect against the variable needing to be accessed at static init time.
|
||||
*/
|
||||
bool NotifyCategory::
|
||||
get_check_debug_notify_protect() {
|
||||
static ConfigVariableBool *check_debug_notify_protect = nullptr;
|
||||
if (check_debug_notify_protect == nullptr) {
|
||||
check_debug_notify_protect = new ConfigVariableBool
|
||||
("check-debug-notify-protect", false,
|
||||
"Set true to issue a warning message if a debug or spam "
|
||||
"notify output is not protected within an if statement.");
|
||||
}
|
||||
return *check_debug_notify_protect;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,8 +76,6 @@ PUBLISHED:
|
|||
private:
|
||||
std::string get_config_name() const;
|
||||
void update_severity_cache();
|
||||
static bool get_notify_timestamp();
|
||||
static bool get_check_debug_notify_protect();
|
||||
|
||||
std::string _fullname;
|
||||
std::string _basename;
|
||||
|
|
@ -86,12 +84,16 @@ private:
|
|||
typedef std::vector<NotifyCategory *> Children;
|
||||
Children _children;
|
||||
|
||||
static bool _notify_timestamp;
|
||||
static bool _check_debug_notify_protect;
|
||||
|
||||
static long _server_delta; // not a time_t because server delta may be signed.
|
||||
|
||||
AtomicAdjust::Integer _local_modified;
|
||||
NotifySeverity _severity_cache;
|
||||
|
||||
friend class Notify;
|
||||
friend class ConfigPageManager;
|
||||
};
|
||||
|
||||
INLINE std::ostream &operator << (std::ostream &out, const NotifyCategory &cat);
|
||||
|
|
|
|||
|
|
@ -76,10 +76,12 @@ PUBLISHED:
|
|||
public:
|
||||
static ios_fmtflags get_literal_flag();
|
||||
|
||||
bool assert_failure(const std::string &expression, int line,
|
||||
const char *source_file);
|
||||
bool assert_failure(const char *expression, int line,
|
||||
const char *source_file);
|
||||
static bool assert_failure(const std::string &expression, int line,
|
||||
const char *source_file);
|
||||
static bool assert_failure(const char *expression, int line,
|
||||
const char *source_file);
|
||||
|
||||
static void write_backtrace(void **trace, int size);
|
||||
|
||||
static NotifySeverity string_severity(const std::string &string);
|
||||
|
||||
|
|
@ -100,7 +102,7 @@ private:
|
|||
Categories _categories;
|
||||
|
||||
#if defined(ANDROID)
|
||||
AndroidLogStream *_log_streams[NS_fatal + 1];
|
||||
std::ostream *_log_streams[NS_fatal + 1];
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
EmscriptenLogStream *_log_streams[NS_fatal + 1];
|
||||
#endif
|
||||
|
|
@ -204,7 +206,7 @@ private:
|
|||
#define nassertr(condition, return_value) \
|
||||
{ \
|
||||
if (_nassert_check(condition)) { \
|
||||
if (Notify::ptr()->assert_failure(#condition, __LINE__, __FILE__)) { \
|
||||
if (Notify::assert_failure(#condition, __LINE__, __FILE__)) { \
|
||||
return return_value; \
|
||||
} \
|
||||
} \
|
||||
|
|
@ -213,7 +215,7 @@ private:
|
|||
#define nassertv(condition) \
|
||||
{ \
|
||||
if (_nassert_check(condition)) { \
|
||||
if (Notify::ptr()->assert_failure(#condition, __LINE__, __FILE__)) { \
|
||||
if (Notify::assert_failure(#condition, __LINE__, __FILE__)) { \
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
|
|
@ -221,12 +223,12 @@ private:
|
|||
|
||||
#define nassertd(condition) \
|
||||
if (_nassert_check(condition) && \
|
||||
Notify::ptr()->assert_failure(#condition, __LINE__, __FILE__))
|
||||
Notify::assert_failure(#condition, __LINE__, __FILE__))
|
||||
|
||||
#define nassertr_always(condition, return_value) nassertr(condition, return_value)
|
||||
#define nassertv_always(condition) nassertv(condition)
|
||||
|
||||
#define nassert_raise(message) Notify::ptr()->assert_failure(message, __LINE__, __FILE__)
|
||||
#define nassert_raise(message) Notify::assert_failure(message, __LINE__, __FILE__)
|
||||
|
||||
#endif // NDEBUG
|
||||
|
||||
|
|
|
|||
|
|
@ -114,6 +114,56 @@ output_c_string(std::ostream &out, const string &string_name,
|
|||
*/
|
||||
EVP_PKEY *
|
||||
generate_key() {
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr);
|
||||
if (ctx == nullptr) {
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
output_ssl_errors();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (EVP_PKEY_keygen_init(ctx) <= 0 ||
|
||||
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 1024) <= 0) {
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
output_ssl_errors();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
BIGNUM *e = BN_new();
|
||||
if (e == nullptr || !BN_set_word(e, 7)) {
|
||||
BN_free(e);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
output_ssl_errors();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
unsigned char *e_buf = nullptr;
|
||||
int e_len = BN_num_bytes(e);
|
||||
e_buf = (unsigned char *)OPENSSL_malloc(e_len);
|
||||
BN_bn2bin(e, e_buf);
|
||||
|
||||
size_t bits = 1024;
|
||||
OSSL_PARAM params[] = {
|
||||
OSSL_PARAM_construct_size_t("bits", &bits),
|
||||
OSSL_PARAM_construct_BN("e", e_buf, e_len),
|
||||
OSSL_PARAM_END
|
||||
};
|
||||
|
||||
EVP_PKEY *pkey = nullptr;
|
||||
if (EVP_PKEY_CTX_set_params(ctx, params) <= 0 ||
|
||||
EVP_PKEY_generate(ctx, &pkey) <= 0) {
|
||||
OPENSSL_free(e_buf);
|
||||
BN_free(e);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
output_ssl_errors();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
OPENSSL_free(e_buf);
|
||||
BN_free(e);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return pkey;
|
||||
#else
|
||||
RSA *rsa = RSA_new();
|
||||
BIGNUM *e = BN_new();
|
||||
if (rsa == nullptr || e == nullptr) {
|
||||
|
|
@ -134,6 +184,7 @@ generate_key() {
|
|||
EVP_PKEY *pkey = EVP_PKEY_new();
|
||||
EVP_PKEY_assign_RSA(pkey, rsa);
|
||||
return pkey;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -383,6 +383,7 @@ SectionGroup "Python modules" SecGroupPython
|
|||
!insertmacro PyBindingSection 3.12-32 .cp312-win32.pyd
|
||||
!insertmacro PyBindingSection 3.13-32 .cp313-win32.pyd
|
||||
!insertmacro PyBindingSection 3.14-32 .cp314-win32.pyd
|
||||
!insertmacro PyBindingSection 3.15-32 .cp315-win32.pyd
|
||||
!else
|
||||
!insertmacro PyBindingSection 3.5 .cp35-win_amd64.pyd
|
||||
!insertmacro PyBindingSection 3.6 .cp36-win_amd64.pyd
|
||||
|
|
@ -394,6 +395,7 @@ SectionGroup "Python modules" SecGroupPython
|
|||
!insertmacro PyBindingSection 3.12 .cp312-win_amd64.pyd
|
||||
!insertmacro PyBindingSection 3.13 .cp313-win_amd64.pyd
|
||||
!insertmacro PyBindingSection 3.14 .cp314-win_amd64.pyd
|
||||
!insertmacro PyBindingSection 3.15 .cp315-win_amd64.pyd
|
||||
!endif
|
||||
SectionGroupEnd
|
||||
|
||||
|
|
@ -506,6 +508,7 @@ Function .onInit
|
|||
!insertmacro MaybeEnablePyBindingSection 3.12-32
|
||||
!insertmacro MaybeEnablePyBindingSection 3.13-32
|
||||
!insertmacro MaybeEnablePyBindingSection 3.14-32
|
||||
!insertmacro MaybeEnablePyBindingSection 3.15-32
|
||||
${EndIf}
|
||||
!else
|
||||
!insertmacro MaybeEnablePyBindingSection 3.5
|
||||
|
|
@ -519,6 +522,7 @@ Function .onInit
|
|||
!insertmacro MaybeEnablePyBindingSection 3.12
|
||||
!insertmacro MaybeEnablePyBindingSection 3.13
|
||||
!insertmacro MaybeEnablePyBindingSection 3.14
|
||||
!insertmacro MaybeEnablePyBindingSection 3.15
|
||||
${EndIf}
|
||||
!endif
|
||||
|
||||
|
|
@ -548,6 +552,10 @@ Function .onInit
|
|||
SectionSetFlags ${SecPyBindings3.14} ${SF_RO}
|
||||
SectionSetInstTypes ${SecPyBindings3.14} 0
|
||||
!endif
|
||||
!ifdef SecPyBindings3.15
|
||||
SectionSetFlags ${SecPyBindings3.15} ${SF_RO}
|
||||
SectionSetInstTypes ${SecPyBindings3.15} 0
|
||||
!endif
|
||||
${EndUnless}
|
||||
FunctionEnd
|
||||
|
||||
|
|
@ -853,6 +861,7 @@ Section Uninstall
|
|||
!insertmacro RemovePythonPath 3.12-32
|
||||
!insertmacro RemovePythonPath 3.13-32
|
||||
!insertmacro RemovePythonPath 3.14-32
|
||||
!insertmacro RemovePythonPath 3.15-32
|
||||
!else
|
||||
!insertmacro RemovePythonPath 3.5
|
||||
!insertmacro RemovePythonPath 3.6
|
||||
|
|
@ -864,6 +873,7 @@ Section Uninstall
|
|||
!insertmacro RemovePythonPath 3.12
|
||||
!insertmacro RemovePythonPath 3.13
|
||||
!insertmacro RemovePythonPath 3.14
|
||||
!insertmacro RemovePythonPath 3.15
|
||||
!endif
|
||||
|
||||
SetDetailsPrint both
|
||||
|
|
@ -936,6 +946,7 @@ SectionEnd
|
|||
!insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.12-32} $(DESC_SecPyBindings3.12-32)
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.13-32} $(DESC_SecPyBindings3.13-32)
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.14-32} $(DESC_SecPyBindings3.14-32)
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.15-32} $(DESC_SecPyBindings3.15-32)
|
||||
!else
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.5} $(DESC_SecPyBindings3.5)
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.6} $(DESC_SecPyBindings3.6)
|
||||
|
|
@ -947,6 +958,7 @@ SectionEnd
|
|||
!insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.12} $(DESC_SecPyBindings3.12)
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.13} $(DESC_SecPyBindings3.13)
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.14} $(DESC_SecPyBindings3.14)
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.15} $(DESC_SecPyBindings3.15)
|
||||
!endif
|
||||
!ifdef INCLUDE_PYVER
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecPython} $(DESC_SecPython)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue