Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Open Toontown 2023-03-26 16:05:30 -04:00
commit 70d467c150
576 changed files with 200098 additions and 8729 deletions

6
.clang-tidy Normal file
View File

@ -0,0 +1,6 @@
---
Checks: 'clang-diagnostic-*,clang-analyzer-*,performance-*,portability-*,modernize-use-nullptr'
WarningsAsErrors: ''
HeaderFilterRegex: ''
FormatStyle: none
...

View File

@ -20,7 +20,7 @@ jobs:
include:
- profile: ubuntu-bionic-standard-unity-makefile
os: ubuntu-18.04
os: ubuntu-20.04
config: Standard
unity: YES
generator: Unix Makefiles
@ -30,7 +30,7 @@ jobs:
eigen: NO
- profile: ubuntu-bionic-coverage-ninja
os: ubuntu-18.04
os: ubuntu-20.04
config: Coverage
unity: NO
generator: Ninja
@ -92,10 +92,10 @@ jobs:
- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: |
curl -O https://www.panda3d.org/download/panda3d-1.10.13/panda3d-1.10.13-tools-mac.tar.gz
tar -xf panda3d-1.10.13-tools-mac.tar.gz
mv panda3d-1.10.13/thirdparty thirdparty
rmdir panda3d-1.10.13
curl -O https://www.panda3d.org/download/panda3d-1.10.14/panda3d-1.10.14-tools-mac.tar.gz
tar -xf panda3d-1.10.14-tools-mac.tar.gz
mv panda3d-1.10.14/thirdparty thirdparty
rmdir panda3d-1.10.14
# Temporary hack so that pzip can run, since we are about to remove Cg anyway.
install_name_tool -id "$(pwd)/thirdparty/darwin-libs-a/nvidiacg/lib/libCg.dylib" thirdparty/darwin-libs-a/nvidiacg/lib/libCg.dylib
@ -115,10 +115,6 @@ jobs:
libxcursor-dev libxrandr-dev nvidia-cg-toolkit zlib1g-dev
python3-setuptools
# Workaround for CMake 3.12 finding this first:
sudo rm /usr/bin/x86_64-linux-gnu-python2.7-config
- name: Cache dependencies (Windows)
if: runner.os == 'Windows'
uses: actions/cache@v1
@ -365,12 +361,12 @@ jobs:
if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')"
strategy:
matrix:
os: [ubuntu-18.04, windows-2019, macOS-11]
os: [ubuntu-20.04, windows-2019, macOS-11]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v1
- name: Install dependencies (Ubuntu)
if: matrix.os == 'ubuntu-18.04'
if: matrix.os == 'ubuntu-20.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
@ -385,10 +381,10 @@ jobs:
- name: Get thirdparty packages (macOS)
if: runner.os == 'macOS'
run: |
curl -O https://www.panda3d.org/download/panda3d-1.10.13/panda3d-1.10.13-tools-mac.tar.gz
tar -xf panda3d-1.10.13-tools-mac.tar.gz
mv panda3d-1.10.13/thirdparty thirdparty
rmdir panda3d-1.10.13
curl -O https://www.panda3d.org/download/panda3d-1.10.14/panda3d-1.10.14-tools-mac.tar.gz
tar -xf panda3d-1.10.14-tools-mac.tar.gz
mv panda3d-1.10.14/thirdparty thirdparty
rmdir panda3d-1.10.14
(cd thirdparty/darwin-libs-a && rm -rf rocket)
- name: Set up Python 3.11

39
.github/workflows/lint.yml vendored Normal file
View File

@ -0,0 +1,39 @@
name: Lint
on: [pull_request]
jobs:
clang-tidy:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Install clang-tidy
run: |
sudo apt-get update
sudo apt-get install -y clang-tidy build-essential pkg-config libpng-dev libjpeg-dev libtiff-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev libfreetype6-dev libvorbis-dev libeigen3-dev libopenal-dev libode-dev libbullet-dev libgtk-3-dev libassimp-dev libopenexr-dev
- name: Prepare compile_commands.json
run: |
cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_UNITY_BUILD=OFF -DHAVE_PYTHON=OFF -DINTERROGATE_PYTHON_INTERFACE=OFF
- name: Copy prebuilt files
run: |
for fn in **/*.prebuilt; do
echo mkdir -p $(dirname "cmake/$fn");
echo cp "$fn" "cmake/${fn%.*}";
done
- name: Create results directory
run: |
mkdir clang-tidy-result
- name: Analyze
run: |
git diff -U0 HEAD^ | clang-tidy-diff -p1 -path build -export-fixes clang-tidy-result/fixes.yml
- name: Save PR metadata
run: |
echo ${{ github.event.number }} > clang-tidy-result/pr-id.txt
echo ${{ github.event.pull_request.head.repo.full_name }} > clang-tidy-result/pr-head-repo.txt
echo ${{ github.event.pull_request.head.ref }} > clang-tidy-result/pr-head-ref.txt
- name: Upload results
uses: actions/upload-artifact@v2
with:
name: clang-tidy-result
path: clang-tidy-result/

77
.github/workflows/review.yml vendored Normal file
View File

@ -0,0 +1,77 @@
name: Post PR Review
on:
workflow_run:
workflows: ["Lint"]
types: [completed]
jobs:
clang-tidy-results:
# Trigger the job only if the previous (insecure) workflow completed successfully
if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-20.04
steps:
- name: Download analysis results
uses: actions/github-script@v3.1.0
with:
script: |
let artifacts = await github.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
let matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "clang-tidy-result"
})[0];
let download = await github.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: "zip",
});
let fs = require("fs");
fs.writeFileSync("${{github.workspace}}/clang-tidy-result.zip", Buffer.from(download.data));
- name: Set environment variables
run: |
mkdir clang-tidy-result
unzip clang-tidy-result.zip -d clang-tidy-result
echo "pr_id=$(cat clang-tidy-result/pr-id.txt)" >> $GITHUB_ENV
echo "pr_head_repo=$(cat clang-tidy-result/pr-head-repo.txt)" >> $GITHUB_ENV
echo "pr_head_ref=$(cat clang-tidy-result/pr-head-ref.txt)" >> $GITHUB_ENV
- uses: actions/checkout@v2
with:
repository: ${{ env.pr_head_repo }}
ref: ${{ env.pr_head_ref }}
persist-credentials: false
- name: Redownload analysis results
uses: actions/github-script@v3.1.0
with:
script: |
let artifacts = await github.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id}},
});
let matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "clang-tidy-result"
})[0];
let download = await github.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: "zip",
});
let fs = require("fs");
fs.writeFileSync("${{github.workspace}}/clang-tidy-result.zip", Buffer.from(download.data));
- name: Extract analysis results
run: |
mkdir clang-tidy-result
unzip clang-tidy-result.zip -d clang-tidy-result
- name: Run clang-tidy-pr-comments action
uses: platisd/clang-tidy-pr-comments@master
with:
github_token: ${{ github.token }}
clang_tidy_fixes: clang-tidy-result/fixes.yml
pull_request_id: ${{ env.pr_id }}
request_changes: true
suggestions_per_comment: 10

826
.pylintrc
View File

@ -1,27 +1,73 @@
[MASTER]
[MAIN]
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
# Load and enable all available extensions. Use --list-extensions to see a list
# all available extensions.
#enable-all-extensions=
# In error mode, messages with a category besides ERROR or FATAL are
# suppressed, and no reports are done by default. Error mode is compatible with
# disabling specific errors.
#errors-only=
# Always return a 0 (non-error) status code, even if lint errors are found.
# This is primarily useful in continuous integration scripts.
#exit-zero=
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code.
extension-pkg-whitelist=panda3d
extension-pkg-allow-list=panda3d,wx
# Specify a score threshold to be exceeded before program exits with error.
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
# for backward compatibility.)
extension-pkg-whitelist=panda3d,wx
# Return non-zero exit code if any of these messages/categories are detected,
# even if score is above --fail-under value. Syntax same as enable. Messages
# specified are enabled, while categories only check already-enabled messages.
fail-on=
# Specify a score threshold under which the program will exit with error.
fail-under=10.0
# Add files or directories to the blacklist. They should be base names, not
# paths.
# Interpret the stdin as a python script, whose filename needs to be passed as
# the module_or_package argument.
#from-stdin=
# Files or directories to be skipped. They should be base names, not paths.
ignore=thirdparty
# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
# Add files or directories matching the regular expressions patterns to the
# ignore-list. The regex matches against paths and can be in Posix or Windows
# format. Because '\\' represents the directory delimiter on Windows systems,
# it can't be used as an escape character.
ignore-paths=
# Files or directories matching the regular expression patterns are skipped.
# The regex matches against base names, not paths. The default value ignores
# Emacs file locks
ignore-patterns=
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis). It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
# number of processors available to use.
# number of processors available to use, and will cap the count on Windows to
# avoid hangs.
jobs=1
# Control the amount of potential inferred values when inferring a single
@ -36,259 +82,23 @@ load-plugins=
# Pickle collected data for later comparisons.
persistent=yes
# Minimum Python version to use for version dependent checks. Will default to
# the version used to run pylint.
py-version=3.6
# Discover python modules and packages in the file system subtree.
recursive=no
# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages.
suggestion-mode=yes
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
#unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
confidence=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once). You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use "--disable=all --enable=classes
# --disable=W".
disable=attribute-defined-outside-init,
broad-except,
comparison-with-callable,
dangerous-default-value,
global-statement,
import-outside-toplevel,
invalid-name,
line-too-long,
misplaced-comparison-constant,
missing-class-docstring,
missing-function-docstring,
missing-module-docstring,
protected-access,
r,
raise-missing-from,
redefined-builtin,
redefined-outer-name,
too-many-lines,
unused-argument,
unused-variable,
unused-wildcard-import,
using-constant-test,
wildcard-import,
wrong-import-order,
wrong-import-position
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=c-extension-no-member
[REPORTS]
# Python expression which should return a score less than or equal to 10. You
# have access to the variables 'error', 'warning', 'refactor', and 'convention'
# which contain the number of messages in each category, as well as 'statement'
# which is the total number of statements analyzed. This score is used by the
# global evaluation report (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details.
#msg-template=
# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio). You can also give a reporter class, e.g.
# mypackage.mymodule.MyReporterClass.
output-format=text
# Tells whether to display a full report or only the messages.
reports=no
# Activate the evaluation score.
score=yes
[REFACTORING]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
# Complete name of functions that never returns. When checking for
# inconsistent-return-statements if a never returning function is called then
# it will be considered as an explicit return statement and no message will be
# printed.
never-returning-functions=sys.exit
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=LF
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Maximum number of characters on a single line.
max-line-length=100
# Maximum number of lines in a module.
max-module-lines=1000
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
[SPELLING]
# Limits count of emitted suggestions for spelling mistakes.
max-spelling-suggestions=4
# Spelling dictionary name. Available dictionaries: none. To make it work,
# install the python-enchant package.
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains the private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to the private dictionary (see the
# --spelling-private-dict-file option) instead of raising a message.
spelling-store-unknown-words=no
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# Tells whether to warn about missing members when the owner of the attribute
# is inferred to be None.
ignore-none=yes
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local,direct.showbase.PythonUtil.ScratchPad
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis). It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes
# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1
# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1
# List of decorators that change the signature of a decorated function.
signature-mutators=
[SIMILARITIES]
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
# Minimum lines number of a similarity.
min-similarity-lines=4
[VARIABLES]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid defining new builtins when possible.
additional-builtins=base,simbase,__dev__,onScreenDebug,globalClock,render,hidden,cluster
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,
_cb
# A regular expression matching the name of dummy variables (i.e. expected to
# not be used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
# Argument names that match this expression will be ignored. Default to name
# with leading underscore.
ignored-argument-names=_.*|^ignored_|^unused_
# Tells whether we should check for unused import in __init__ files.
init-import=no
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,
XXX,
TODO
# Regular expression of note tags to take in consideration.
#notes-rgx=
# In verbose mode, extra non-checker-related info will be displayed.
#verbose=
[BASIC]
@ -297,13 +107,15 @@ notes=FIXME,
argument-naming-style=snake_case
# Regular expression matching correct argument names. Overrides argument-
# naming-style.
# naming-style. If left empty, argument names will be checked with the set
# naming style.
#argument-rgx=
# Naming style matching correct attribute names.
attr-naming-style=snake_case
# Regular expression matching correct attribute names. Overrides attr-naming-
# style. If left empty, attribute names will be checked with the set naming
# style.
#attr-rgx=
@ -323,20 +135,30 @@ bad-names-rgxs=
class-attribute-naming-style=any
# Regular expression matching correct class attribute names. Overrides class-
# attribute-naming-style.
# attribute-naming-style. If left empty, class attribute names will be checked
# with the set naming style.
#class-attribute-rgx=
# Naming style matching correct class constant names.
class-const-naming-style=UPPER_CASE
# Regular expression matching correct class constant names. Overrides class-
# const-naming-style. If left empty, class constant names will be checked with
# the set naming style.
#class-const-rgx=
# Naming style matching correct class names.
class-naming-style=PascalCase
# Regular expression matching correct class names. Overrides class-naming-
# style.
# style. If left empty, class names will be checked with the set naming style.
#class-rgx=
# Naming style matching correct constant names.
const-naming-style=UPPER_CASE
# Regular expression matching correct constant names. Overrides const-naming-
# style. If left empty, constant names will be checked with the set naming
# style.
#const-rgx=
@ -348,7 +170,8 @@ docstring-min-length=-1
function-naming-style=snake_case
# Regular expression matching correct function names. Overrides function-
# naming-style.
# naming-style. If left empty, function names will be checked with the set
# naming style.
#function-rgx=
# Good variable names which should always be accepted, separated by a comma.
@ -370,21 +193,22 @@ include-naming-hint=no
inlinevar-naming-style=any
# Regular expression matching correct inline iteration names. Overrides
# inlinevar-naming-style.
# inlinevar-naming-style. If left empty, inline iteration names will be checked
# with the set naming style.
#inlinevar-rgx=
# Naming style matching correct method names.
method-naming-style=snake_case
# Regular expression matching correct method names. Overrides method-naming-
# style.
# style. If left empty, method names will be checked with the set naming style.
#method-rgx=
# Naming style matching correct module names.
module-naming-style=snake_case
# Regular expression matching correct module names. Overrides module-naming-
# style.
# style. If left empty, module names will be checked with the set naming style.
#module-rgx=
# Colon-delimited sets of names that determine each other's naming style when
@ -400,38 +224,55 @@ no-docstring-rgx=^_
# These decorators are taken in consideration only for invalid-name.
property-classes=abc.abstractproperty
# Regular expression matching correct type variable names. If left empty, type
# variable names will be checked with the set naming style.
#typevar-rgx=
# Naming style matching correct variable names.
variable-naming-style=snake_case
# Regular expression matching correct variable names. Overrides variable-
# naming-style.
# naming-style. If left empty, variable names will be checked with the set
# naming style.
#variable-rgx=
[LOGGING]
[CLASSES]
# The type of string formatting that logging methods do. `old` means using %
# formatting, `new` is for `{}` formatting.
logging-format-style=old
# Warn about protected attribute access inside special methods
check-protected-access-in-special-methods=no
# Logging modules to check that the string format arguments are in logging
# function parameter format.
logging-modules=logging
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,
__new__,
setUp,
__post_init__
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,
_fields,
_replace,
_source,
_make
[STRING]
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# This flag controls whether inconsistent-quotes generates a warning when the
# character used as a quote delimiter is used inconsistently within a module.
check-quote-consistency=no
# This flag controls whether the implicit-str-concat should generate a warning
# on implicit string concatenation in sequences defined over several lines.
check-str-concat-over-line-jumps=no
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=cls
[DESIGN]
# List of regular expressions of class ancestor names to ignore when counting
# public methods (see R0903)
exclude-too-few-public-methods=
# List of qualified class names to ignore when counting class parents (see
# R0901)
ignored-parents=
# Maximum number of arguments for function / method.
max-args=5
@ -463,6 +304,42 @@ max-statements=50
min-public-methods=2
[EXCEPTIONS]
# Exceptions that will emit a warning when caught.
overgeneral-exceptions=builtins.BaseException,builtins.Exception
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=LF
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Maximum number of characters on a single line.
max-line-length=100
# Maximum number of lines in a module.
max-module-lines=1000
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
[IMPORTS]
# List of modules that can be imported at any level, not just the top level
@ -472,24 +349,20 @@ allow-any-import-level=
# Allow wildcard imports from modules that define __all__.
allow-wildcard-with-all=no
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
# Deprecated modules which should not be used, separated by a comma.
deprecated-modules=optparse,tkinter.tix
deprecated-modules=optparse,tkinter.tix,pandac.PandaModules,direct.directbase.DirectStart
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled).
# Output a graph (.gv or any supported image format) of external dependencies
# to the given file (report RP0402 must not be disabled).
ext-import-graph=
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled).
# Output a graph (.gv or any supported image format) of all (i.e. internal and
# external) dependencies to the given file (report RP0402 must not be
# disabled).
import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled).
# Output a graph (.gv or any supported image format) of internal dependencies
# to the given file (report RP0402 must not be disabled).
int-import-graph=
# Force import order to recognize a module as part of the standard
@ -503,32 +376,359 @@ known-third-party=enchant
preferred-modules=
[CLASSES]
[LOGGING]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,
__new__,
setUp,
__post_init__
# The type of string formatting that logging methods do. `old` means using %
# formatting, `new` is for `{}` formatting.
logging-format-style=old
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,
_fields,
_replace,
_source,
_make
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=cls
# Logging modules to check that the string format arguments are in logging
# function parameter format.
logging-modules=logging
[EXCEPTIONS]
[MESSAGES CONTROL]
# Exceptions that will emit a warning when being caught. Defaults to
# "BaseException, Exception".
overgeneral-exceptions=BaseException,
Exception
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE,
# UNDEFINED.
confidence=HIGH,
CONTROL_FLOW,
INFERENCE,
INFERENCE_FAILURE,
UNDEFINED
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once). You can also use "--disable=all" to
# disable everything first and then re-enable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use "--disable=all --enable=classes
# --disable=W".
disable=raw-checker-failed,
bad-inline-option,
locally-disabled,
file-ignored,
suppressed-message,
useless-suppression,
deprecated-pragma,
use-symbolic-message-instead,
consider-using-f-string,
attribute-defined-outside-init,
comparison-with-callable,
dangerous-default-value,
global-statement,
import-outside-toplevel,
invalid-name,
line-too-long,
missing-class-docstring,
missing-function-docstring,
missing-module-docstring,
protected-access,
no-classmethod-decorator,
no-staticmethod-decorator,
useless-object-inheritance,
property-with-parameters,
too-many-ancestors,
too-many-instance-attributes,
too-few-public-methods,
too-many-public-methods,
too-many-return-statements,
too-many-branches,
too-many-arguments,
too-many-locals,
too-many-statements,
too-many-boolean-expressions,
consider-merging-isinstance,
too-many-nested-blocks,
simplifiable-if-statement,
redefined-argument-from-local,
no-else-return,
consider-using-ternary,
trailing-comma-tuple,
stop-iteration-return,
simplify-boolean-expression,
inconsistent-return-statements,
useless-return,
consider-swap-variables,
consider-using-join,
consider-using-in,
consider-using-get,
chained-comparison,
consider-using-dict-comprehension,
consider-using-set-comprehension,
simplifiable-if-expression,
no-else-raise,
unnecessary-comprehension,
consider-using-sys-exit,
no-else-break,
no-else-continue,
super-with-arguments,
simplifiable-condition,
condition-evals-to-constant,
consider-using-generator,
use-a-generator,
consider-using-min-builtin,
consider-using-max-builtin,
consider-using-with,
unnecessary-dict-index-lookup,
use-list-literal,
use-dict-literal,
unnecessary-list-index-lookup,
literal-comparison,
comparison-with-itself,
comparison-of-constants,
cyclic-import,
consider-using-from-import,
duplicate-code,
raise-missing-from,
redefined-builtin,
redefined-outer-name,
too-many-lines,
unused-argument,
unused-variable,
unused-wildcard-import,
using-constant-test,
wrong-import-order,
wrong-import-position,
not-callable,
wildcard-import
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
#enable=c-extension-no-member
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,
XXX,
TODO
# Regular expression of note tags to take in consideration.
notes-rgx=
[REFACTORING]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
# Complete name of functions that never returns. When checking for
# inconsistent-return-statements if a never returning function is called then
# it will be considered as an explicit return statement and no message will be
# printed.
never-returning-functions=sys.exit
[REPORTS]
# Python expression which should return a score less than or equal to 10. You
# have access to the variables 'fatal', 'error', 'warning', 'refactor',
# 'convention', and 'info' which contain the number of messages in each
# category, as well as 'statement' which is the total number of statements
# analyzed. This score is used by the global evaluation report (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details.
msg-template=
# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio). You can also give a reporter class, e.g.
# mypackage.mymodule.MyReporterClass.
#output-format=
# Tells whether to display a full report or only the messages.
reports=no
# Activate the evaluation score.
score=yes
[SIMILARITIES]
# Comments are removed from the similarity computation
ignore-comments=yes
# Docstrings are removed from the similarity computation
ignore-docstrings=yes
# Imports are removed from the similarity computation
ignore-imports=no
# Signatures are removed from the similarity computation
ignore-signatures=yes
# Minimum lines number of a similarity.
min-similarity-lines=4
[SPELLING]
# Limits count of emitted suggestions for spelling mistakes.
max-spelling-suggestions=4
# Spelling dictionary name. Available dictionaries: none. To make it work,
# install the 'python-enchant' package.
spelling-dict=
# List of comma separated words that should be considered directives if they
# appear at the beginning of a comment and should not be checked.
spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains the private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to the private dictionary (see the
# --spelling-private-dict-file option) instead of raising a message.
spelling-store-unknown-words=no
[STRING]
# This flag controls whether inconsistent-quotes generates a warning when the
# character used as a quote delimiter is used inconsistently within a module.
check-quote-consistency=no
# This flag controls whether the implicit-str-concat should generate a warning
# on implicit string concatenation in sequences defined over several lines.
check-str-concat-over-line-jumps=no
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=base.cr,
base.le,
base.localAvatar,
Pmw.AboutDialog,
Pmw.Balloon,
Pmw.ButtonBox,
Pmw.Color,
Pmw.ComboBox,
Pmw.EntryField,
Pmw.Group,
Pmw.INITOPT,
Pmw.MegaArchetype,
Pmw.MegaToplevel,
Pmw.MegaWidget,
Pmw.MenuBar,
Pmw.MessageBar,
Pmw.NoteBook,
Pmw.OK,
Pmw.OptionMenu,
Pmw.OptionMenu,
Pmw.PARTIAL,
Pmw.PanedWidget,
Pmw.ScrolledCanvas,
Pmw.ScrolledFrame,
Pmw.ScrolledListBox,
Pmw.ScrolledText,
Pmw.aboutcontact,
Pmw.aboutcopyright,
Pmw.aboutversion,
Pmw.forwardmethods,
Pmw.integervalidator,
Pmw.popgrab,
Pmw.pushgrab,
Pmw.realvalidator,
Pmw.setgeometryanddeiconify
# Tells whether to warn about missing members when the owner of the attribute
# is inferred to be None.
ignore-none=yes
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes
# List of symbolic message names to ignore for Mixin members.
ignored-checks-for-mixins=no-member,
not-async-context-manager,
not-context-manager,
attribute-defined-outside-init
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local,direct.showbase.PythonUtil.ScratchPad
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes
# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1
# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1
# Regex pattern to define which classes are considered mixins.
mixin-class-rgx=.*[Mm]ixin
# List of decorators that change the signature of a decorated function.
signature-mutators=
[VARIABLES]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid defining new builtins when possible.
additional-builtins=base,
simbase,
__dev__,
onScreenDebug,
render,
hidden,
cluster,
launcher,
taskMgr,
localAvatar,
game
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes
# List of names allowed to shadow builtins
allowed-redefined-builtins=
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,
_cb
# A regular expression matching the name of dummy variables (i.e. expected to
# not be used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
# Argument names that match this expression will be ignored.
ignored-argument-names=_.*|^ignored_|^unused_
# Tells whether we should check for unused import in __init__ files.
init-import=no
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io,direct.showbase.ShowBase,direct.showbase.PythonUtil

View File

@ -27,6 +27,7 @@ This is a list of all the people who are contributing financially to Panda3D. I
* Maxwell Dreytser
* SureBet
* Gyedo Jeon
* GameDev JONI
## Backers

View File

@ -106,14 +106,14 @@ python3 makepanda/makepanda.py --everything --installer --no-egl --no-gles --no-
You will probably see some warnings saying that it's unable to find several
dependency packages. You should determine which ones you want to include in
your build and install the respective development packages. You may visit
[this manual page](https://www.panda3d.org/manual/?title=Third-party_dependencies_and_license_info)
[this manual page](https://docs.panda3d.org/1.11/python/distribution/thirdparty-licenses)
for an overview of the various dependencies.
If you are on Ubuntu, this command should cover the most frequently
used third-party packages:
```bash
sudo apt-get install build-essential pkg-config fakeroot python3-dev libpng-dev libjpeg-dev libtiff-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev bison flex libfreetype6-dev libvorbis-dev libeigen3-dev libopenal-dev libode-dev libbullet-dev nvidia-cg-toolkit libgtk2.0-dev libassimp-dev libopenexr-dev
sudo apt-get install build-essential pkg-config fakeroot python3-dev libpng-dev libjpeg-dev libtiff-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev bison flex libfreetype6-dev libvorbis-dev libeigen3-dev libopenal-dev libode-dev libbullet-dev nvidia-cg-toolkit libgtk-3-dev libassimp-dev libopenexr-dev
```
Once Panda3D has built, you can either install the .deb or .rpm package that
@ -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.13/panda3d-1.10.13-tools-mac.tar.gz).
compile Panda3D, which can be acquired from [here](https://www.panda3d.org/download/panda3d-1.10.14/panda3d-1.10.14-tools-mac.tar.gz).
After placing the thirdparty directory inside the panda3d source directory,
you may build Panda3D using a command like the following:

View File

@ -99,8 +99,9 @@ Flock AIWorld::get_flock(unsigned int flock_id) {
return *_flock_pool[i];
}
}
Flock *null_flock = nullptr;
return *null_flock;
static Flock null_flock(0, 0.0, 0.0, 0, 0, 0);
nassertr(false, null_flock);
return null_flock;
}
/**

View File

@ -6,7 +6,29 @@ to learn more about loading animated models.
__all__ = ['Actor']
from panda3d.core import *
from panda3d.core import (
AnimBundleNode,
AnimControlCollection,
Character,
ConfigVariableBool,
DecalEffect,
Filename,
GlobPattern,
LineStream,
LoaderOptions,
LODNode,
ModelNode,
MovingPartBase,
MovingPartMatrix,
NodePath,
PandaNode,
PartBundle,
PartSubset,
Point3,
TransformState,
Vec3,
autoBind,
)
from panda3d.core import Loader as PandaLoader
from direct.showbase.DirectObject import DirectObject
from direct.showbase.Loader import Loader

View File

@ -1,8 +1,26 @@
"""ClusterClient: Master for multi-piping or PC clusters."""
from panda3d.core import *
from .ClusterMsgs import *
from .ClusterConfig import *
from panda3d.core import (
ClockObject,
ConnectionWriter,
Point3,
QueuedConnectionManager,
QueuedConnectionReader,
VBase3,
Vec3,
decomposeMatrix,
)
from .ClusterMsgs import (
CLUSTER_DAEMON_PORT,
CLUSTER_NAMED_MOVEMENT_DONE,
CLUSTER_NAMED_OBJECT_MOVEMENT,
CLUSTER_NONE,
CLUSTER_SERVER_PORT,
CLUSTER_SWAP_READY,
SERVER_STARTUP_STRING,
ClusterMsgHandler,
)
from .ClusterConfig import ClientConfigs
from direct.directnotify import DirectNotifyGlobal
from direct.showbase import DirectObject
from direct.task import Task
@ -95,7 +113,6 @@ class ClusterClient(DirectObject.DirectObject):
self.notify.debug('post startMoveCam')
self.startMoveSelectedTask()
def startReaderPollTask(self):
""" Task to handle datagrams from server """
# Run this task just after the listener poll task
@ -112,7 +129,6 @@ class ClusterClient(DirectObject.DirectObject):
return Task.cont
def startControlObjectTask(self):
self.notify.debug("moving control objects")
taskMgr.add(self.controlObjectTask,"controlObjectTask",50)
@ -134,7 +150,6 @@ class ClusterClient(DirectObject.DirectObject):
self.notify.debug('adding move cam')
taskMgr.add(self.moveCameraTask, "moveCamTask", 49)
def controlObjectTask(self, task):
for pair in self.sortedControlMappings:
object = pair[1]
@ -153,8 +168,6 @@ class ClusterClient(DirectObject.DirectObject):
for server in serverList:
self.serverList[server].sendNamedMovementDone()
def redoSortedPriorities(self):
self.sortedControlMappings = []
for key in self.controlMappings:
@ -176,7 +189,6 @@ class ClusterClient(DirectObject.DirectObject):
for server in serverList:
self.serverList[server].sendMoveNamedObject(xyz,hpr,scale,color,hidden,object)
def moveCameraTask(self, task):
self.moveCamera(
base.camera.getPos(render),
@ -203,7 +215,6 @@ class ClusterClient(DirectObject.DirectObject):
server.sendMoveSelected(xyz, hpr, scale)
return Task.cont
def addNamedObjectMapping(self, object, name, hasColor = True):
if name not in self.objectMappings:
self.objectMappings[name] = object
@ -215,7 +226,6 @@ class ClusterClient(DirectObject.DirectObject):
if name in self.objectMappings:
self.objectMappings.pop(name)
def addControlMapping(self, objectName, controlledName, serverList = None,
offset = None, priority = 0):
if objectName not in self.controlMappings:
@ -260,7 +270,6 @@ class ClusterClient(DirectObject.DirectObject):
self.controlPriorities.pop(name)
self.redoSortedPriorities()
def getNodePathFindCmd(self, nodePath):
pathString = repr(nodePath)
index = pathString.find('/')
@ -280,7 +289,6 @@ class ClusterClient(DirectObject.DirectObject):
else:
return pathString
def addObjectTag(self,object,selectFunction,deselectFunction,selectArgs,deselectArgs):
newTag = {}
newTag["selectFunction"] = selectFunction
@ -289,12 +297,10 @@ class ClusterClient(DirectObject.DirectObject):
newTag["deselectArgs"] = deselectArgs
self.taggedObjects[object] = newTag
def removeObjectTag(self,object):
self.taggedObjects.pop(object)
def selectNodePath(self, nodePath):
name = self.getNodePathName(nodePath)
if name in self.taggedObjects:
@ -307,7 +313,6 @@ class ClusterClient(DirectObject.DirectObject):
else:
self(self.getNodePathFindCmd(nodePath) + '.select()', 0)
def deselectNodePath(self, nodePath):
name = self.getNodePathName(nodePath)
if name in self.taggedObjects:
@ -345,7 +350,6 @@ class ClusterClient(DirectObject.DirectObject):
# Execute locally
exec(commandString, __builtins__)
def handleDatagram(self,dgi,type,server):
if type == CLUSTER_NONE:
pass
@ -370,7 +374,6 @@ class ClusterClient(DirectObject.DirectObject):
# clear the queue
self.serverQueues[server] = []
def handleNamedMovement(self, data):
""" Update cameraJig position to reflect latest position """
@ -390,7 +393,6 @@ class ClusterClient(DirectObject.DirectObject):
else:
self.notify.debug("recieved unknown named object command: "+name)
def exit(self):
# Execute remotely
for server in self.serverList:
@ -457,8 +459,6 @@ class DisplayConnection:
self.qcr.addConnection(self.tcpConn)
self.cw=ConnectionWriter(qcm, 0)
def poll(self):
""" Non blocking task to read all available datagrams """
dataGrams = []
@ -473,9 +473,6 @@ class DisplayConnection:
return dataGrams
def sendCamOffset(self, xyz, hpr):
ClusterClient.notify.debug("send cam offset...")
ClusterClient.notify.debug(("packet %d xyz, hpr=%f %f %f %f %f %f" %
@ -491,12 +488,11 @@ class DisplayConnection:
(" fl, fs, fo=%0.3f, (%0.3f, %0.3f), (%0.3f, %0.3f)" %
(focalLength, filmSize[0], filmSize[1],
filmOffset[0], filmOffset[1])))
)
)
datagram = self.msgHandler.makeCamFrustumDatagram(
focalLength, filmSize, filmOffset)
self.cw.send(datagram, self.tcpConn)
def sendNamedMovementDone(self):
datagram = self.msgHandler.makeNamedMovementDone()
@ -566,6 +562,7 @@ class DisplayConnection:
frameCount, frameTime, dt)
self.cw.send(datagram, self.tcpConn)
class ClusterConfigItem:
def __init__(self, serverConfigName, serverName,
serverDaemonPort, serverMsgPort):
@ -581,9 +578,11 @@ class ClusterConfigItem:
self.focalLength = None
self.filmSize = None
self.filmOffset = None
def setCamOffset(self, xyz, hpr):
self.xyz = xyz
self.hpr = hpr
def setCamFrustum(self, focalLength, filmSize, filmOffset):
self.fFrustum = 1
self.focalLength = focalLength
@ -671,6 +670,7 @@ def createClusterClient():
class DummyClusterClient(DirectObject.DirectObject):
""" Dummy class to handle command strings when not in cluster mode """
notify = DirectNotifyGlobal.directNotify.newCategory("DummyClusterClient")
def __init__(self):
pass

View File

@ -1,5 +1,5 @@
from .ClusterClient import *
from panda3d.core import Vec3
#: A dictionary of information for various cluster configurations.
#: Dictionary is keyed on cluster-config string
@ -26,7 +26,7 @@ ClientConfigs = {
'display mode': 'client',
'pos': Vec3(0),
'hpr': Vec3(0)}
],
],
'two-server': [{'display name': 'master',
'display mode': 'client',
'pos': Vec3(0),
@ -35,7 +35,7 @@ ClientConfigs = {
'pos': Vec3(0),
'hpr': Vec3(0)
}
],
],
'three-server': [{'display name': 'master',
'display mode': 'client',
'pos': Vec3(0),
@ -48,14 +48,14 @@ ClientConfigs = {
'pos': Vec3(0),
'hpr': Vec3(0)
}
],
],
'mono-cave': [{'display name': 'la',
'pos': Vec3(-0.105, -0.020, 5.000),
'hpr': Vec3(51.213, 0.000, 0.000),
'focal length': 0.809,
'film size': (1.000, 0.831),
'film offset': (0.000, 0.173),
},
},
{'display name': 'lb',
'display mode': 'client',
'pos': Vec3(-0.105, -0.020, 5.000),
@ -71,7 +71,7 @@ ClientConfigs = {
'film size': (1.000, 0.830),
'film offset': (-0.000, 0.173),
},
],
],
'seamless-cave': [{'display name': 'master',
'display mode': 'client',
'pos': Vec3(-0.105, -0.020, 5.000),
@ -79,7 +79,7 @@ ClientConfigs = {
'focal length': 0.815,
'film size': (1.000, 0.831),
'film offset': (0.000, 0.173),
},
},
{'display name': 'la',
'pos': Vec3(-0.105, -0.020, 5.000),
'hpr': Vec3(51.213, 0.000, 0.000),
@ -122,12 +122,12 @@ ClientConfigs = {
'film size': (1.000, 0.831),
'film offset': (-0.000, 0.173),
},
],
],
'ursula': [{'display name': 'master',
'display mode': 'client',
'pos': Vec3(0),
'hpr': Vec3(0),
},
},
{'display name': 'l',
'pos': Vec3(-.105, 0, 0),
'hpr': Vec3(0, 0, 0),
@ -144,11 +144,11 @@ ClientConfigs = {
#'film offset': (-0.105, -2),
'film offset': (-0.105, -1),
}
],
],
'composite': [{'display name': 'master',
'display mode': 'client',
'pos': Vec3(0),
},
},
{'display name': 'left',
'pos': Vec3(-0.105, -0.020, 5.000),
'hpr': Vec3(-0.370, 0.000, 0.000),
@ -163,5 +163,5 @@ ClientConfigs = {
'film size': (1.000, 0.831),
'film offset': (0.000, 0.173),
}
],
}
],
}

View File

@ -3,7 +3,7 @@
# This module is intended to supply routines and dataformats common to
# both ClusterClient and ClusterServer.
from panda3d.core import *
from panda3d.core import NetDatagram
from direct.distributed.PyDatagram import PyDatagram
from direct.distributed.PyDatagramIterator import PyDatagramIterator
import time

View File

@ -1,10 +1,35 @@
from panda3d.core import *
from .ClusterMsgs import *
from direct.distributed.MsgTypes import *
from panda3d.core import (
ClockObject,
ConnectionWriter,
NetAddress,
PointerToConnection,
QueuedConnectionListener,
QueuedConnectionManager,
QueuedConnectionReader,
Vec3,
)
from .ClusterMsgs import (
CLUSTER_CAM_FRUSTUM,
CLUSTER_CAM_MOVEMENT,
CLUSTER_CAM_OFFSET,
CLUSTER_COMMAND_STRING,
CLUSTER_DAEMON_PORT,
CLUSTER_EXIT,
CLUSTER_NAMED_MOVEMENT_DONE,
CLUSTER_NAMED_OBJECT_MOVEMENT,
CLUSTER_NONE,
CLUSTER_SELECTED_MOVEMENT,
CLUSTER_SERVER_PORT,
CLUSTER_SWAP_NOW,
CLUSTER_SWAP_READY,
CLUSTER_TIME_DATA,
ClusterMsgHandler,
)
from direct.directnotify import DirectNotifyGlobal
from direct.showbase import DirectObject
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr
import builtins
# NOTE: This assumes the following variables are set via bootstrap command line
# arguments on server startup:
@ -15,6 +40,7 @@ from direct.task.TaskManagerGlobal import taskMgr
# Also, I'm not sure multiple camera-group configurations are working for the
# cluster system.
class ClusterServer(DirectObject.DirectObject):
notify = DirectNotifyGlobal.directNotify.newCategory("ClusterServer")
MSG_NUM = 2000000
@ -76,8 +102,6 @@ class ClusterServer(DirectObject.DirectObject):
clusterDaemonPort = CLUSTER_DAEMON_PORT
self.daemon.serverReady(clusterDaemonClient, clusterDaemonPort)
def startListenerPollTask(self):
# Run this task near the start of frame, sometime after the dataLoop
taskMgr.add(self.listenerPollTask, "serverListenerPollTask", -40)
@ -100,7 +124,6 @@ class ClusterServer(DirectObject.DirectObject):
self.notify.warning("getNewConnection returned false")
return Task.cont
def addNamedObjectMapping(self, object, name, hasColor = True,
priority = 0):
if name not in self.objectMappings:
@ -113,7 +136,6 @@ class ClusterServer(DirectObject.DirectObject):
if name in self.objectMappings:
self.objectMappings.pop(name)
def redoSortedPriorities(self):
self.sortedControlMappings = []
@ -123,7 +145,6 @@ class ClusterServer(DirectObject.DirectObject):
self.sortedControlMappings.sort()
def addControlMapping(self, objectName, controlledName, offset = None,
priority = 0):
if objectName not in self.controlMappings:
@ -134,20 +155,18 @@ class ClusterServer(DirectObject.DirectObject):
self.controlPriorities[objectName] = priority
self.redoSortedPriorities()
else:
self.notify.debug('attempt to add duplicate controlled object: '+name)
self.notify.debug('attempt to add duplicate controlled object: ' + objectName)
def setControlMappingOffset(self, objectName, offset):
if objectName in self.controlMappings:
self.controlOffsets[objectName] = offset
def removeControlMapping(self, name):
if name in self.controlMappings:
self.controlMappings.pop(name)
self.controlPriorities.pop(name)
self.redoSortedPriorities()
def startControlObjectTask(self):
self.notify.debug("moving control objects")
taskMgr.add(self.controlObjectTask,"controlObjectTask",50)
@ -164,7 +183,6 @@ class ClusterServer(DirectObject.DirectObject):
self.sendNamedMovementDone()
return Task.cont
def sendNamedMovementDone(self):
self.notify.debug("named movement done")
datagram = self.msgHandler.makeNamedMovementDone()
@ -308,12 +326,10 @@ class ClusterServer(DirectObject.DirectObject):
else:
self.notify.debug("recieved unknown named object command: "+name)
def handleMessageQueue(self):
#print self.messageQueue
#print(self.messageQueue)
for data in self.messageQueue:
#print "in queue",dgi
#print("in queue", dgi)
self.handleNamedMovement(data)
self.messageQueue = []
@ -328,8 +344,8 @@ class ClusterServer(DirectObject.DirectObject):
""" Update cameraJig position to reflect latest position """
(x, y, z, h, p, r, sx, sy, sz) = self.msgHandler.parseSelectedMovementDatagram(
dgi)
if last:
last.setPosHprScale(x, y, z, h, p, r, sx, sy, sz)
if getattr(builtins, 'last', None):
builtins.last.setPosHprScale(x, y, z, h, p, r, sx, sy, sz)
def handleTimeData(self, dgi):
""" Update cameraJig position to reflect latest position """
@ -345,5 +361,5 @@ class ClusterServer(DirectObject.DirectObject):
command = self.msgHandler.parseCommandStringDatagram(dgi)
try:
exec(command, __builtins__)
except:
except Exception:
pass

View File

@ -2,7 +2,7 @@
from direct.showbase.InputStateGlobal import inputState
from direct.showbase.MessengerGlobal import messenger
from direct.task.Task import Task
from panda3d.core import *
from panda3d.core import ClockObject, Mat3, Point3, Vec3
from . import GravityWalker
BattleStrafe = 0

View File

@ -41,8 +41,6 @@ class ControlManager:
#self.monitorTask = taskMgr.add(self.monitor, "ControlManager-%s"%(id(self)), priority=-1)
self.forceAvJumpToken = None
if self.passMessagesThrough: # for not breaking toontown
ist=self.inputStateTokens
ist.append(inputState.watchWithModifiers("forward", "arrow_up", inputSource=inputState.ArrowKeys))
@ -50,7 +48,6 @@ class ControlManager:
ist.append(inputState.watchWithModifiers("turnLeft", "arrow_left", inputSource=inputState.ArrowKeys))
ist.append(inputState.watchWithModifiers("turnRight", "arrow_right", inputSource=inputState.ArrowKeys))
def __str__(self):
return 'ControlManager: using \'%s\'' % self.currentControlsName
@ -325,7 +322,7 @@ class ControlManager:
self.WASDTurnTokens = (
inputState.watchWithModifiers("turnLeft", "a", inputSource=inputState.WASD),
inputState.watchWithModifiers("turnRight", "d", inputSource=inputState.WASD),
)
)
inputState.set("turnLeft", slideLeftWASDSet, inputSource=inputState.WASD)
inputState.set("turnRight", slideRightWASDSet, inputSource=inputState.WASD)
@ -337,7 +334,7 @@ class ControlManager:
self.WASDTurnTokens = (
inputState.watchWithModifiers("slideLeft", "a", inputSource=inputState.WASD),
inputState.watchWithModifiers("slideRight", "d", inputSource=inputState.WASD),
)
)
inputState.set("slideLeft", turnLeftWASDSet, inputSource=inputState.WASD)
inputState.set("slideRight", turnRightWASDSet, inputSource=inputState.WASD)

View File

@ -22,7 +22,7 @@ from direct.showbase import DirectObject
from direct.showbase.MessengerGlobal import messenger
from direct.task.Task import Task
from direct.task.TaskManagerGlobal import taskMgr
from panda3d.core import *
from panda3d.core import ClockObject, ConfigVariableBool, ConfigVariableDouble, Mat3, Point3, Vec3
class DevWalker(DirectObject.DirectObject):

View File

@ -22,9 +22,24 @@ from direct.showbase.InputStateGlobal import inputState
from direct.showbase.MessengerGlobal import messenger
from direct.task.Task import Task
from direct.task.TaskManagerGlobal import taskMgr
from direct.extensions_native import VBase3_extensions
from direct.extensions_native import VBase4_extensions
from panda3d.core import *
from direct.extensions_native import VBase3_extensions # pylint: disable=unused-import
from direct.extensions_native import VBase4_extensions # pylint: disable=unused-import
from panda3d.core import (
BitMask32,
ClockObject,
CollisionHandlerEvent,
CollisionHandlerFluidPusher,
CollisionHandlerGravity,
CollisionHandlerPusher,
CollisionNode,
CollisionRay,
CollisionSphere,
CollisionTraverser,
ConfigVariableBool,
Mat3,
Point3,
Vec3,
)
import math

View File

@ -8,36 +8,47 @@ from direct.showbase.MessengerGlobal import messenger
class InputStateToken:
_SerialGen = SerialNumGen()
Inval = 'invalidatedToken'
def __init__(self, inputState):
self._id = InputStateToken._SerialGen.next()
self._hash = self._id
self._inputState = inputState
def release(self):
# subclasses will override
assert False
def isValid(self):
return self._id != InputStateToken.Inval
def invalidate(self):
self._id = InputStateToken.Inval
def __hash__(self):
return self._hash
#snake_case alias:
is_valid = isValid
class InputStateWatchToken(InputStateToken, DirectObject.DirectObject):
def release(self):
self._inputState._ignore(self)
self.ignoreAll()
class InputStateForceToken(InputStateToken):
def release(self):
self._inputState._unforce(self)
class InputStateTokenGroup:
def __init__(self):
self._tokens = []
def addToken(self, token):
self._tokens.append(token)
def release(self):
for token in self._tokens:
token.release()
@ -46,6 +57,7 @@ class InputStateTokenGroup:
#snake_case alias:
add_token = addToken
class InputState(DirectObject.DirectObject):
"""
InputState is for tracking the on/off state of some events.
@ -190,7 +202,6 @@ class InputState(DirectObject.DirectObject):
# input state simply because we're not looking at it anymore.
# self.set(name, False, inputSource)
def force(self, name, value, inputSource):
"""
Force isSet(name) to return 'value'.
@ -213,7 +224,7 @@ class InputState(DirectObject.DirectObject):
self.notify.error(
"%s is trying to force '%s' to ON, but '%s' is already being forced OFF by %s" %
(inputSource, name, name, self._forcingOff[name])
)
)
self._forcingOn.setdefault(name, set())
self._forcingOn[name].add(inputSource)
else:
@ -221,7 +232,7 @@ class InputState(DirectObject.DirectObject):
self.notify.error(
"%s is trying to force '%s' to OFF, but '%s' is already being forced ON by %s" %
(inputSource, name, name, self._forcingOn[name])
)
)
self._forcingOff.setdefault(name, set())
self._forcingOff[name].add(inputSource)
return token

View File

@ -23,7 +23,20 @@ from direct.showbase.InputStateGlobal import inputState
from direct.showbase.MessengerGlobal import messenger
from direct.task.Task import Task
from direct.task.TaskManagerGlobal import taskMgr
from panda3d.core import *
from panda3d.core import (
BitMask32,
ClockObject,
CollisionHandlerFloor,
CollisionHandlerPusher,
CollisionNode,
CollisionRay,
CollisionSphere,
CollisionTraverser,
ConfigVariableBool,
Mat3,
Point3,
Vec3,
)
class NonPhysicsWalker(DirectObject.DirectObject):
notify = DirectNotifyGlobal.directNotify.newCategory("NonPhysicsWalker")

View File

@ -16,7 +16,13 @@ although it does send messages that allow a listener to play sounds or
animations based on walker events.
"""
from panda3d.core import *
from panda3d.core import (
BitMask32,
CollisionHandlerPusher,
CollisionNode,
CollisionSphere,
CollisionTraverser,
)
from direct.directnotify import DirectNotifyGlobal
from . import NonPhysicsWalker

View File

@ -23,15 +23,39 @@ from direct.showbase.InputStateGlobal import inputState
from direct.showbase.MessengerGlobal import messenger
from direct.task.Task import Task
from direct.task.TaskManagerGlobal import taskMgr
from direct.extensions_native import Mat3_extensions
from direct.extensions_native import VBase3_extensions
from direct.extensions_native import VBase4_extensions
from panda3d.core import *
from panda3d.physics import *
from direct.extensions_native import Mat3_extensions # pylint: disable=unused-import
from direct.extensions_native import VBase3_extensions # pylint: disable=unused-import
from direct.extensions_native import VBase4_extensions # pylint: disable=unused-import
from panda3d.core import (
BitMask32,
ClockObject,
CollisionHandlerFloor,
CollisionHandlerQueue,
CollisionNode,
CollisionRay,
CollisionSphere,
CollisionTraverser,
ConfigVariableBool,
LRotationf,
Mat3,
NodePath,
Point3,
Vec3,
)
from panda3d.physics import (
ActorNode,
ForceNode,
LinearEulerIntegrator,
LinearFrictionForce,
LinearVectorForce,
PhysicsCollisionHandler,
PhysicsManager,
)
import math
#import LineStream
class PhysicsWalker(DirectObject.DirectObject):
notify = DirectNotifyGlobal.directNotify.newCategory("PhysicsWalker")
@ -523,7 +547,7 @@ class PhysicsWalker(DirectObject.DirectObject):
onScreenDebug.add("highMark", "% 10.4f"%(self.highMark,))
#if airborneHeight < 0.1: #contact!=Vec3.zero():
if (airborneHeight > self.avatarRadius*0.5
or physObject.getVelocity().getZ() > 0.0
or physObject.getVelocity().getZ() > 0.0
): # Check stair angles before changing this.
# ...the avatar is airborne (maybe a lot or a tiny amount).
self.isAirborne = 1

View File

@ -2,9 +2,12 @@
TwoDWalker.py is for controlling the avatars in a 2D scroller game environment.
"""
from .GravityWalker import *
from .GravityWalker import GravityWalker
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.showbase.InputStateGlobal import inputState
from direct.showbase.MessengerGlobal import messenger
from panda3d.core import ConfigVariableBool
from direct.task.Task import Task
from panda3d.core import ConfigVariableBool, Vec3
class TwoDWalker(GravityWalker):

View File

@ -37,7 +37,7 @@ PUBLISHED:
const DCClass *get_class() const;
public:
virtual DCPackerInterface *get_nested_field(int n) const;
virtual DCPackerInterface *get_nested_field(int n) const final;
virtual void output_instance(std::ostream &out, bool brief, const std::string &prename,
const std::string &name, const std::string &postname) const;

View File

@ -1,8 +1,7 @@
print('TestStart: Starting up test environment.')
from panda3d.core import *
import direct.showbase.PythonUtil # pylint: disable=unused-import
from direct.showbase.PythonUtil import *
from direct.showbase import ShowBase
base = ShowBase.ShowBase()

View File

@ -1,9 +1,8 @@
print('ThreeUpStart: Starting up environment.')
from panda3d.core import *
import direct.showbase.PythonUtil # pylint: disable=unused-import
from direct.showbase.PythonUtil import *
from direct.showbase import ThreeUpShow
base = ThreeUpShow.ThreeUpShow()

View File

@ -1,8 +1,15 @@
"""Class used to create and control VRPN devices."""
from direct.showbase.DirectObject import DirectObject
from panda3d.core import *
from panda3d.vrpn import *
from panda3d.core import (
AnalogNode,
ButtonNode,
ConfigVariableDouble,
ConfigVariableString,
DialNode,
TrackerNode,
)
from panda3d.vrpn import VrpnClient
ANALOG_MIN = -0.95
ANALOG_MAX = 0.95
@ -52,7 +59,7 @@ class DirectButtons(ButtonNode, DirectObject):
# Attach node to data graph
try:
self._base = base
except:
except NameError:
self._base = simbase
self.nodePath = self._base.dataRoot.attachNewNode(self)
@ -101,7 +108,7 @@ class DirectAnalogs(AnalogNode, DirectObject):
# Attach node to data graph
try:
self._base = base
except:
except NameError:
self._base = simbase
self.nodePath = self._base.dataRoot.attachNewNode(self)
@ -169,7 +176,7 @@ class DirectAnalogs(AnalogNode, DirectObject):
def normalizeChannel(self, chan, minVal = -1, maxVal = 1, sf = 1.0):
try:
return self.normalize(self[chan], minVal, maxVal, sfx)
return self.normalize(self[chan], minVal, maxVal, sf)
except IndexError:
return 0.0
@ -199,7 +206,7 @@ class DirectTracker(TrackerNode, DirectObject):
# Attach node to data graph
try:
self._base = base
except:
except NameError:
self._base = simbase
self.nodePath = self._base.dataRoot.attachNewNode(self)
@ -231,7 +238,7 @@ class DirectDials(DialNode, DirectObject):
# Attach node to data graph
try:
self._base = base
except:
except NameError:
self._base = simbase
self.nodePath = self._base.dataRoot.attachNewNode(self)
@ -282,7 +289,7 @@ class DirectTimecodeReader(AnalogNode, DirectObject):
# Attach node to data graph
try:
self._base = base
except:
except NameError:
self._base = simbase
self.nodePath = self._base.dataRoot.attachNewNode(self)

View File

@ -1,8 +1,9 @@
""" Class used to create and control radamec device """
from panda3d.core import Vec3
from direct.showbase.DirectObject import DirectObject
from direct.task.Task import Task
from direct.task.TaskManagerGlobal import taskMgr
from .DirectDeviceManager import *
from .DirectDeviceManager import DirectDeviceManager
from direct.directnotify import DirectNotifyGlobal

View File

@ -1,11 +1,11 @@
""" Class used to create and control joybox device """
from direct.showbase.DirectObject import DirectObject
from .DirectDeviceManager import *
from direct.directtools.DirectUtil import *
from .DirectDeviceManager import ANALOG_DEADBAND, ANALOG_MAX, ANALOG_MIN, DirectDeviceManager
from direct.directtools.DirectUtil import CLAMP
from direct.gui import OnscreenText
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr
from panda3d.core import ClockObject
from panda3d.core import ButtonRegistry, ButtonThrower, ClockObject, NodePath, VBase3, Vec3
import math
@ -35,6 +35,7 @@ JOYBOX_RANGE = JOYBOX_MAX - JOYBOX_MIN
JOYBOX_TREAD_SEPERATION = 1.0
class DirectJoybox(DirectObject):
joyboxCount = 0
xyzMultiplier = 1.0
@ -87,12 +88,10 @@ class DirectJoybox(DirectObject):
# Spawn update task
self.enable()
def setHeadingNodePath(self,np):
self.headingNP = np
def enable(self):
# Kill existing task
self.disable()
@ -126,18 +125,25 @@ class DirectJoybox(DirectObject):
def getNodePath(self):
return self.nodePath
def setRefCS(self, refCS):
self.refCS = refCS
def getRefCS(self):
return self.refCS
def getEventName(self, index):
return self.name + '-button-' + repr(index)
def setXyzMultiplier(self, multiplier):
DirectJoybox.xyzMultiplier = multiplier
def getXyzMultiplier(self):
return DirectJoybox.xyzMultiplier
def setHprMultiplier(self, multiplier):
DirectJoybox.hprMultiplier = multiplier
def getHprMultiplier(self):
return DirectJoybox.hprMultiplier
@ -193,6 +199,7 @@ class DirectJoybox(DirectObject):
def acceptSwitchModeEvent(self, button = R_UPPER):
self.accept(self.getEventName(button), self.switchMode)
def ignoreSwitchModeEvent(self, button = R_UPPER):
self.ignore(self.getEventName(button))
@ -208,7 +215,7 @@ class DirectJoybox(DirectObject):
pass
def showMode(self, modeText):
def hideText(state, s = self):
def hideText(state, s=self):
s.readout.setText('')
return Task.done
taskMgr.remove(self.name + '-showMode')
@ -220,6 +227,7 @@ class DirectJoybox(DirectObject):
def acceptUprightCameraEvent(self, button = L_UPPER):
self.accept(self.getEventName(button),
base.direct.cameraControl.orbitUprightCam)
def ignoreUprightCameraEvent(self, button = L_UPPER):
self.ignore(self.getEventName(button))
@ -230,29 +238,29 @@ class DirectJoybox(DirectObject):
self.showMode(self.modeName)
self.enable()
def setUseHeadingNP(self,enabled):
def setUseHeadingNP(self, enabled):
self.useHeadingNP = enabled
def setRotateInPlace(self,enabled):
def setRotateInPlace(self, enabled):
self.rotateInPlace = enabled
def joyboxFly(self):
# Do nothing if no nodePath selected
if self.nodePath is None:
return
hprScale = ((self.aList[L_SLIDE] + 1.0) *
50.0 * DirectJoybox.hprMultiplier)
posScale = ((self.aList[R_SLIDE] + 1.0) *
50.0 * DirectJoybox.xyzMultiplier)
def getAxisVal(index, s = self):
def getAxisVal(index, s=self):
try:
return s.aList[s.mapping[index]]
except IndexError:
# If it is a null axis return 0
return 0.0
x = getAxisVal(0) * self.modifier[0]
y = getAxisVal(1) * self.modifier[1]
z = getAxisVal(2) * self.modifier[2]
@ -262,13 +270,13 @@ class DirectJoybox(DirectObject):
p = getAxisVal(4) * self.modifier[4]
r = getAxisVal(5) * self.modifier[5]
hpr = Vec3(h, p, r) * (hprScale * self.deltaTime)
# if we are using a heading nodepath, we want
# to drive in the direction we are facing,
# however, we don't want the z component to change
if self.useHeadingNP and self.headingNP is not None:
oldZ = pos.getZ()
pos = self.nodePath.getRelativeVector(self.headingNP,
pos)
pos = self.nodePath.getRelativeVector(self.headingNP, pos)
pos.setZ(oldZ)
# if we are using a heading NP we might want to rotate
# in place around that NP
@ -282,7 +290,6 @@ class DirectJoybox(DirectObject):
self.nodePath.wrtReparentTo(parent)
hpr = Vec3(0,0,0)
self.nodePath.setPosHpr(self.nodePath, pos, hpr)
def joeMode(self):
@ -291,25 +298,23 @@ class DirectJoybox(DirectObject):
self.modifier = [1, 1, 1, -1, -1, 0]
self.setMode(self.joyboxFly, 'Joe Mode')
def basicMode(self):
self.mapping = [NULL_AXIS, R_FWD_BACK, NULL_AXIS,
R_LEFT_RIGHT, NULL_AXIS, NULL_AXIS]
self.modifier = [0,1,0,-1,0,0]
self.setMode(self.joyboxFly,'Basic Mode')
self.modifier = [0, 1, 0, -1, 0, 0]
self.setMode(self.joyboxFly, 'Basic Mode')
def fpsMode(self):
self.mapping = [L_LEFT_RIGHT,R_FWD_BACK,L_FWD_BACK,
R_LEFT_RIGHT, NULL_AXIS, NULL_AXIS]
self.modifier = [1,1,1,-1,0,0]
self.setMode(self.joyboxFly,'FPS Mode')
self.modifier = [1, 1, 1, -1, 0, 0]
self.setMode(self.joyboxFly, 'FPS Mode')
def tankMode(self):
self.setMode(self.tankFly,'Tank Mode')
self.setMode(self.tankFly, 'Tank Mode')
def nullMode(self):
self.setMode(self.nullFly,'Null Mode')
self.setMode(self.nullFly, 'Null Mode')
def lucMode(self):
self.mapping = [R_LEFT_RIGHT, R_FWD_BACK, L_FWD_BACK,
@ -362,7 +367,6 @@ class DirectJoybox(DirectObject):
def spaceMode(self):
self.setMode(self.spaceFly, 'Space Mode')
def nullFly(self):
return
@ -384,10 +388,6 @@ class DirectJoybox(DirectObject):
self.nodePath.setH(self.nodePath,dh)
self.nodePath.setY(self.nodePath,dy)
def spaceFly(self):
# Do nothing if no nodePath selected
if self.nodePath is None:
@ -498,9 +498,9 @@ class DirectJoybox(DirectObject):
# Restore the original hpr of the orbiter
self.nodePath.setHpr(self.tempCS, 0, 0, 0)
# We need to override the DirectAnalog normalizeChannel to
# correct the ranges of the two twist axes of the joybox.
def normalizeChannel(self, chan, minVal = -1, maxVal = 1):
try:
if chan == L_TWIST or chan == R_TWIST:

View File

@ -1,9 +1,8 @@
""" Class used to create and control radamec device """
from math import *
from direct.showbase.DirectObject import DirectObject
from direct.task.Task import Task
from direct.task.TaskManagerGlobal import taskMgr
from .DirectDeviceManager import *
from .DirectDeviceManager import DirectDeviceManager
from direct.directnotify import DirectNotifyGlobal

View File

@ -5,6 +5,7 @@ DirectNotify module: this module contains the DirectNotify class
from . import Notifier
from . import Logger
class DirectNotify:
"""
DirectNotify class: this class contains methods for creating
@ -15,7 +16,7 @@ class DirectNotify:
"""
DirectNotify class keeps a dictionary of Notfiers
"""
self.__categories = { }
self.__categories = {}
# create a default log file
self.logger = Logger.Logger()
@ -100,7 +101,6 @@ class DirectNotify:
print("DirectNotify: unknown notify level: " + str(level)
+ " for category: " + str(categoryName))
def setDconfigLevels(self):
for categoryName in self.getCategories():
self.setDconfigLevel(categoryName)

View File

@ -126,10 +126,10 @@ class Notifier:
Exception: error
"""
message = str(errorString)
if Notifier.showTime.getValue():
string = (self.getTime() + str(exception) + ": " + self.__name + "(error): " + message)
if Notifier.showTime:
string = f'{self.getTime()}{exception!s}: {self.__name}(error): {message}'
else:
string = (str(exception) + ": " + self.__name + "(error): " + message)
string = f'{exception!s}: {self.__name}(error): {message}'
self.__log(string)
raise exception(errorString)
@ -140,10 +140,10 @@ class Notifier:
"""
if self.__warning:
message = str(warningString)
if Notifier.showTime.getValue():
string = (self.getTime() + self.__name + '(warning): ' + message)
if Notifier.showTime:
string = f'{self.getTime()}{self.__name}(warning): {message}'
else:
string = (":" + self.__name + '(warning): ' + message)
string = f':{self.__name}(warning): {message}'
self.__log(string)
self.__print(string)
return 1 # to allow assert myNotify.warning("blah")
@ -167,10 +167,10 @@ class Notifier:
"""
if self.__debug:
message = str(debugString)
if Notifier.showTime.getValue():
string = (self.getTime() + self.__name + '(debug): ' + message)
if Notifier.showTime:
string = f'{self.getTime()}{self.__name}(debug): {message}'
else:
string = (':' + self.__name + '(debug): ' + message)
string = f':{self.__name}(debug): {message}'
self.__log(string)
self.__print(string)
return 1 # to allow assert myNotify.debug("blah")
@ -194,10 +194,10 @@ class Notifier:
"""
if self.__info:
message = str(infoString)
if Notifier.showTime.getValue():
string = (self.getTime() + self.__name + ': ' + message)
if Notifier.showTime:
string = f'{self.getTime()}{self.__name}: {message}'
else:
string = (':' + self.__name + ': ' + message)
string = f':{self.__name}: {message}'
self.__log(string)
self.__print(string)
return 1 # to allow assert myNotify.info("blah")
@ -271,7 +271,7 @@ class Notifier:
state = "%s, %s"%(state, stateObj.getName())
if hasattr(obj, 'doId'):
doId = " doId:%s"%(obj.doId,)
doId = f" doId:{obj.doId}"
#if type(obj) == types.ClassType:
# name = "%s."%(obj.__class__.__name__,)
string = ":%s:%s [%-7s] id(%s)%s %s"%(

View File

@ -11,7 +11,15 @@
import os
import sys
import gc
from panda3d.core import *
from panda3d.core import (
BamCache,
ExecutionEnvironment,
Filename,
Loader,
LoaderOptions,
ModelPool,
TexturePool,
)
class EggCacher:
def __init__(self, args):

View File

@ -16,11 +16,11 @@ from panda3d.interrogatedb import *
if 'interrogate_element_is_sequence' not in globals():
def interrogate_element_is_sequence(element):
def interrogate_element_is_sequence(element): # pylint: disable=function-redefined
return False
if 'interrogate_element_is_mapping' not in globals():
def interrogate_element_is_mapping(element):
def interrogate_element_is_mapping(element): # pylint: disable=function-redefined
return False
@ -65,6 +65,7 @@ def comment(code):
else:
return ''
def block_comment(code):
code = code.strip()
@ -77,6 +78,7 @@ def block_comment(code):
return code
def translateFunctionName(name):
if name.startswith("__"):
return name
@ -93,6 +95,7 @@ def translateFunctionName(name):
new += i[0].upper() + i[1:]
return new
def translateTypeName(name, mangle=True):
# Equivalent to C++ classNameFromCppName
class_name = ""
@ -115,6 +118,7 @@ def translateTypeName(name, mangle=True):
return class_name
def translated_type_name(type, scoped=True):
while interrogate_type_is_wrapped(type):
if interrogate_type_is_const(type):
@ -205,7 +209,7 @@ def processFunction(handle, function, isConstructor = False):
def processType(handle, type):
typename = translated_type_name(type, scoped=False)
derivations = [ translated_type_name(interrogate_type_get_derivation(type, n)) for n in range(interrogate_type_number_of_derivations(type)) ]
derivations = [translated_type_name(interrogate_type_get_derivation(type, n)) for n in range(interrogate_type_number_of_derivations(type))]
if interrogate_type_has_comment(type):
print(block_comment(interrogate_type_comment(type)), file=handle)
@ -258,6 +262,7 @@ def processType(handle, type):
print("};", file=handle)
def processModule(handle, package):
print("Processing module %s" % (package))
print("namespace %s {" % package, file=handle)

View File

@ -1,7 +1,9 @@
import math
from panda3d.core import BitMask32, Mat4, NodePath, Point3, VBase3, Vec3, Vec4, rad2Deg
from direct.showbase.DirectObject import DirectObject
from .DirectUtil import *
from .DirectGeometry import *
from .DirectGlobals import *
from .DirectUtil import CLAMP, useDirectRenderStyle
from .DirectGeometry import getCrankAngle, getScreenXY
from . import DirectGlobals as DG
from .DirectSelection import SelectionRay
from direct.interval.IntervalGlobal import Sequence, Func
from direct.directnotify import DirectNotifyGlobal
@ -12,6 +14,7 @@ CAM_MOVE_DURATION = 1.2
COA_MARKER_SF = 0.0075
Y_AXIS = Vec3(0, 1, 0)
class DirectCameraControl(DirectObject):
notify = DirectNotifyGlobal.directNotify.newCategory('DirectCameraControl')
@ -48,7 +51,7 @@ class DirectCameraControl(DirectObject):
['DIRECT-mouse2Up', self.mouseFlyStop],
['DIRECT-mouse3', self.mouseDollyStart],
['DIRECT-mouse3Up', self.mouseDollyStop],
]
]
# [gjeon] moved all of the hotkeys to single place for easy remapping
## self.keyEvents = [
@ -99,7 +102,7 @@ class DirectCameraControl(DirectObject):
['DIRECT-removeManipulateCameraTask', self.removeManipulateCameraTask],
['DIRECT-zoomInCam', self.zoomCam, 0.5, t],
['DIRECT-zoomOutCam', self.zoomCam, -2.0, t],
]
]
# set this to true to prevent the camera from rolling
self.lockRoll = False
# NIK - flag to determine whether to use maya camera controls
@ -218,9 +221,9 @@ class DirectCameraControl(DirectObject):
# Allow intersection with unpickable objects
# And then spawn task to determine mouse mode
# Don't intersect with hidden or backfacing objects
skipFlags = SKIP_HIDDEN | SKIP_BACKFACE
skipFlags = DG.SKIP_HIDDEN | DG.SKIP_BACKFACE
# Skip camera (and its children), unless control key is pressed
skipFlags |= SKIP_CAMERA * (1 - base.getControl())
skipFlags |= DG.SKIP_CAMERA * (1 - base.getControl())
self.computeCOA(base.direct.iRay.pickGeom(skipFlags = skipFlags))
# Record reference point
self.coaMarkerRef.setPosHprScale(base.cam, 0, 0, 0, 0, 0, 0, 1, 1, 1)
@ -306,7 +309,7 @@ class DirectCameraControl(DirectObject):
def XZTranslateTask(self, state):
coaDist = Vec3(self.coaMarker.getPos(base.direct.camera)).length()
xlateSF = (coaDist / base.direct.dr.near)
xlateSF = coaDist / base.direct.dr.near
base.direct.camera.setPos(base.direct.camera,
(-0.5 * base.direct.dr.mouseDeltaX *
base.direct.dr.nearWidth *
@ -349,7 +352,7 @@ class DirectCameraControl(DirectObject):
else:
moveDir = Vec3(Y_AXIS)
if self.useMayaCamControls : # use maya controls
if self.useMayaCamControls: # use maya controls
moveDir.assign(moveDir * ((base.direct.dr.mouseDeltaX -1.0 * base.direct.dr.mouseDeltaY)
* state.zoomSF))
hVal = 0.0
@ -422,7 +425,7 @@ class DirectCameraControl(DirectObject):
# Set at markers position in render coordinates
self.camManipRef.setPos(self.coaMarkerPos)
self.camManipRef.setHpr(base.direct.camera, ZERO_POINT)
self.camManipRef.setHpr(base.direct.camera, DG.ZERO_POINT)
t = Task.Task(self.mouseRotateTask)
if abs(base.direct.dr.mouseX) > 0.9:
t.constrainedDir = 'y'
@ -454,7 +457,7 @@ class DirectCameraControl(DirectObject):
# flatten roll
base.direct.camera.setR(0)
self.camManipRef.setPos(self.coaMarkerPos)
self.camManipRef.setHpr(base.direct.camera, ZERO_POINT)
self.camManipRef.setHpr(base.direct.camera, DG.ZERO_POINT)
else:
if base.direct.camera.getPos().getZ() >=0 or not self.switchDirBelowZero:
dirX = -1
@ -478,7 +481,7 @@ class DirectCameraControl(DirectObject):
self.__stopManipulateCamera()
# Set at markers position in render coordinates
self.camManipRef.setPos(self.coaMarkerPos)
self.camManipRef.setHpr(base.direct.camera, ZERO_POINT)
self.camManipRef.setHpr(base.direct.camera, DG.ZERO_POINT)
t = Task.Task(self.mouseRollTask)
t.coaCenter = getScreenXY(self.coaMarker)
t.lastAngle = getCrankAngle(t.coaCenter)
@ -565,7 +568,7 @@ class DirectCameraControl(DirectObject):
base.direct.message('COA Distance: ' + repr(dist))
coa.set(0, dist, 0)
# Compute COA Dist
coaDist = Vec3(coa - ZERO_POINT).length()
coaDist = Vec3(coa - DG.ZERO_POINT).length()
if coaDist < (1.1 * dr.near):
coa.set(0, 100, 0)
coaDist = 100
@ -575,7 +578,7 @@ class DirectCameraControl(DirectObject):
def updateCoa(self, ref2point, coaDist = None, ref = None):
self.coa.set(ref2point[0], ref2point[1], ref2point[2])
if not coaDist:
coaDist = Vec3(self.coa - ZERO_POINT).length()
coaDist = Vec3(self.coa - DG.ZERO_POINT).length()
# Place the marker in render space
if ref is None:
# KEH: use the current display region
@ -611,7 +614,7 @@ class DirectCameraControl(DirectObject):
startColor = Vec4(1, 0, 0, 1),
blendType = 'easeInOut'),
Func(self.coaMarker.stash)
)
)
self.coaMarkerColorIval.start()
def homeCam(self):
@ -642,19 +645,19 @@ class DirectCameraControl(DirectObject):
# Transform camera z axis to render space
mCam2Render = Mat4(Mat4.identMat()) # [gjeon] fixed to give required argument
mCam2Render.assign(base.direct.camera.getMat(render))
zAxis = Vec3(mCam2Render.xformVec(Z_AXIS))
zAxis = Vec3(mCam2Render.xformVec(DG.Z_AXIS))
zAxis.normalize()
# Compute rotation angle needed to upright cam
orbitAngle = rad2Deg(math.acos(CLAMP(zAxis.dot(Z_AXIS), -1, 1)))
orbitAngle = rad2Deg(math.acos(CLAMP(zAxis.dot(DG.Z_AXIS), -1, 1)))
# Check angle
if orbitAngle < 0.1:
# Already upright
return
# Compute orthogonal axis of rotation
rotAxis = Vec3(zAxis.cross(Z_AXIS))
rotAxis = Vec3(zAxis.cross(DG.Z_AXIS))
rotAxis.normalize()
# Find angle between rot Axis and render X_AXIS
rotAngle = rad2Deg(math.acos(CLAMP(rotAxis.dot(X_AXIS), -1, 1)))
rotAngle = rad2Deg(math.acos(CLAMP(rotAxis.dot(DG.X_AXIS), -1, 1)))
# Determine sign or rotation angle
if rotAxis[1] < 0:
rotAngle *= -1
@ -685,7 +688,7 @@ class DirectCameraControl(DirectObject):
base.direct.pushUndo([base.direct.camera])
# Determine marker location
markerToCam = self.coaMarker.getPos(base.direct.camera)
dist = Vec3(markerToCam - ZERO_POINT).length()
dist = Vec3(markerToCam - DG.ZERO_POINT).length()
scaledCenterVec = Y_AXIS * dist
delta = markerToCam - scaledCenterVec
self.camManipRef.setPosHpr(base.direct.camera, Point3(0), Point3(0))
@ -697,7 +700,6 @@ class DirectCameraControl(DirectObject):
name = 'manipulateCamera')
self.__startManipulateCamera(ival = ival)
def zoomCam(self, zoomFactor, t):
self.__stopManipulateCamera()
# Record undo point
@ -709,7 +711,7 @@ class DirectCameraControl(DirectObject):
self.camManipRef.setPos(base.direct.camera, zoomPtToCam)
# Move to that point
ival = base.direct.camera.posInterval(CAM_MOVE_DURATION,
ZERO_POINT,
DG.ZERO_POINT,
other = self.camManipRef,
blendType = 'easeInOut')
ival = Sequence(ival, Func(self.updateCoaMarkerSizeOnDeath),
@ -746,20 +748,20 @@ class DirectCameraControl(DirectObject):
elif view == 7:
hprOffset.set(135., -35.264, 0.)
# Position target
self.camManipRef.setPosHpr(self.coaMarker, ZERO_VEC,
self.camManipRef.setPosHpr(self.coaMarker, DG.ZERO_VEC,
hprOffset)
# Scale center vec by current distance to target
offsetDistance = Vec3(base.direct.camera.getPos(self.camManipRef) -
ZERO_POINT).length()
DG.ZERO_POINT).length()
scaledCenterVec = Y_AXIS * (-1.0 * offsetDistance)
# Now put the camManipRef at that point
self.camManipRef.setPosHpr(self.camManipRef,
scaledCenterVec,
ZERO_VEC)
DG.ZERO_VEC)
# Record view for next time around
self.lastView = view
ival = base.direct.camera.posHprInterval(CAM_MOVE_DURATION,
pos = ZERO_POINT,
pos = DG.ZERO_POINT,
hpr = VBase3(0, 0, self.orthoViewRoll),
other = self.camManipRef,
blendType = 'easeInOut')
@ -767,7 +769,6 @@ class DirectCameraControl(DirectObject):
name = 'manipulateCamera')
self.__startManipulateCamera(ival = ival)
def swingCamAboutWidget(self, degrees, t):
# Remove existing camera manipulation task
self.__stopManipulateCamera()
@ -776,9 +777,9 @@ class DirectCameraControl(DirectObject):
base.direct.pushUndo([base.direct.camera])
# Coincident with widget
self.camManipRef.setPos(self.coaMarker, ZERO_POINT)
self.camManipRef.setPos(self.coaMarker, DG.ZERO_POINT)
# But aligned with render space
self.camManipRef.setHpr(ZERO_POINT)
self.camManipRef.setHpr(DG.ZERO_POINT)
parent = base.direct.camera.getParent()
base.direct.camera.wrtReparentTo(self.camManipRef)
@ -820,7 +821,8 @@ class DirectCameraControl(DirectObject):
try:
self.camManipRef.setPos(base.direct.camera, deltaMove)
except Exception:
self.notify.debug
#self.notify.debug
pass
parent = base.direct.camera.getParent()
base.direct.camera.wrtReparentTo(self.camManipRef)
@ -831,7 +833,6 @@ class DirectCameraControl(DirectObject):
name = 'manipulateCamera')
self.__startManipulateCamera(ival = ival)
def moveToFit(self):
# How big is the active widget?
widgetScale = base.direct.widget.scalingNode.getScale(render)

View File

@ -1,9 +1,24 @@
from panda3d.core import *
from .DirectGlobals import *
from .DirectUtil import *
from panda3d.core import (
CSDefault,
GeomNode,
LineSegs,
Mat4,
NodePath,
Point3,
Quat,
VBase3,
VBase4,
Vec3,
composeMatrix,
decomposeMatrix,
deg2Rad,
rad2Deg,
)
from .DirectGlobals import Q_EPSILON, UNIT_VEC, ZERO_VEC
from .DirectUtil import CLAMP
import math
class LineNodePath(NodePath):
def __init__(self, parent = None, name = None,
thickness = 1.0, colorVec = VBase4(1)):
@ -126,13 +141,16 @@ class LineNodePath(NodePath):
##
## Given a point in space, and a direction, find the point of intersection
## of that ray with a plane at the specified origin, with the specified normal
def planeIntersect (lineOrigin, lineDir, planeOrigin, normal):
def planeIntersect(lineOrigin, lineDir, planeOrigin, normal):
t = 0
offset = planeOrigin - lineOrigin
t = offset.dot(normal) / lineDir.dot(normal)
hitPt = lineDir * t
return hitPt + lineOrigin
def getNearProjectionPoint(nodePath):
# Find the position of the projection of the specified node path
# on the near plane
@ -144,6 +162,7 @@ def getNearProjectionPoint(nodePath):
# Object is coplaner with camera, just return something reasonable
return Point3(0, base.direct.dr.near, 0)
def getScreenXY(nodePath):
# Where does the node path's projection fall on the near plane
nearVec = getNearProjectionPoint(nodePath)
@ -158,6 +177,7 @@ def getScreenXY(nodePath):
# Return the resulting value
return screenXY
def getCrankAngle(center):
# Used to compute current angle of mouse (relative to the coa's
# origin) in screen space
@ -165,6 +185,7 @@ def getCrankAngle(center):
y = base.direct.dr.mouseY - center[2]
return 180 + rad2Deg(math.atan2(y, x))
def relHpr(nodePath, base, h, p, r):
# Compute nodePath2newNodePath relative to base coordinate system
# nodePath2base
@ -188,6 +209,8 @@ def relHpr(nodePath, base, h, p, r):
nodePath.setHpr(hpr)
# Quaternion interpolation
def qSlerp(startQuat, endQuat, t):
startQ = Quat(startQuat)
destQuat = Quat(Quat.identQuat())

View File

@ -51,11 +51,11 @@ LE_CAM_MASKS = {'persp':LE_PERSP_CAM_MASK,
'top':LE_TOP_CAM_MASK}
def LE_showInAllCam(nodePath):
for camName in LE_CAM_MASKS:
nodePath.show(LE_CAM_MASKS[camName])
for camName, mask in LE_CAM_MASKS.items():
nodePath.show(mask)
def LE_showInOneCam(nodePath, thisCamName):
LE_showInAllCam(nodePath)
for camName in LE_CAM_MASKS:
for camName, mask in LE_CAM_MASKS.items():
if camName != thisCamName:
nodePath.hide(LE_CAM_MASKS[camName])
nodePath.hide(mask)

View File

@ -1,8 +1,8 @@
from panda3d.core import *
import math
from panda3d.core import NodePath, Point3, VBase4
from direct.showbase.DirectObject import DirectObject
from .DirectUtil import *
from .DirectGeometry import *
from .DirectUtil import ROUND_TO, useDirectRenderStyle
from .DirectGeometry import LineNodePath
class DirectGrid(NodePath, DirectObject):

View File

@ -1,5 +1,15 @@
from panda3d.core import *
from panda3d.core import (
AmbientLight,
DirectionalLight,
LightAttrib,
Material,
NodePath,
PerspectiveLens,
PointLight,
Spotlight,
VBase4,
)
from direct.showbase.MessengerGlobal import messenger

View File

@ -1,10 +1,32 @@
import math
from panda3d.core import (
BitMask32,
BoundingHexahedron,
CSDefault,
Mat4,
NodePath,
Point3,
VBase3,
VBase4,
Vec3,
decomposeMatrix,
deg2Rad,
)
from direct.showbase.DirectObject import DirectObject
from direct.showbase.MessengerGlobal import messenger
from .DirectGlobals import *
from .DirectUtil import *
from .DirectGeometry import *
from . import DirectGlobals as DG
from .DirectUtil import useDirectRenderStyle
from .DirectGeometry import (
LineNodePath,
getCrankAngle,
getNearProjectionPoint,
getScreenXY,
planeIntersect,
relHpr,
)
from .DirectSelection import SelectionRay
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr
from copy import deepcopy
@ -50,8 +72,8 @@ class DirectManipulationControl(DirectObject):
['DIRECT-widgetScaleDown', self.scaleWidget, 0.5],
['shift-f', self.objectHandles.growToFit],
['i', self.plantSelectedNodePath],
]
self.defaultSkipFlags = SKIP_HIDDEN | SKIP_BACKFACE
]
self.defaultSkipFlags = DG.SKIP_HIDDEN | DG.SKIP_BACKFACE
self.optionalSkipFlags = 0
self.unmovableTagList = []
@ -115,7 +137,7 @@ class DirectManipulationControl(DirectObject):
self.fScaling3D == 0:
# Check for a widget hit point
entry = base.direct.iRay.pickWidget(skipFlags = SKIP_WIDGET)
entry = base.direct.iRay.pickWidget(skipFlags = DG.SKIP_WIDGET)
# Did we hit a widget?
if entry:
# Yes!
@ -137,7 +159,7 @@ class DirectManipulationControl(DirectObject):
if entry:
# Check to see if we are moving the object
# We are moving the object if we either wait long enough
taskMgr.doMethodLater(MANIPULATION_MOVE_DELAY,
taskMgr.doMethodLater(DG.MANIPULATION_MOVE_DELAY,
self.switchToMoveMode,
'manip-move-wait')
# Or we move far enough
@ -170,8 +192,8 @@ class DirectManipulationControl(DirectObject):
return Task.done
def watchMouseTask(self, state):
if (((abs (state.initX - base.direct.dr.mouseX)) > 0.01) or
((abs (state.initY - base.direct.dr.mouseY)) > 0.01)):
if (abs(state.initX - base.direct.dr.mouseX) > 0.01 or
abs(state.initY - base.direct.dr.mouseY) > 0.01):
taskMgr.remove('manip-move-wait')
self.mode = 'move'
self.manipulateObject()
@ -199,8 +221,8 @@ class DirectManipulationControl(DirectObject):
endX = base.direct.dr.mouseX
endY = base.direct.dr.mouseY
if (((abs (endX - startX)) < 0.01) and
((abs (endY - startY)) < 0.01)):
if (abs(endX - startX) < 0.01 and
abs(endY - startY) < 0.01):
return
self.marquee = LineNodePath(base.render2d, 'marquee', 0.5, VBase4(.8, .6, .6, 1))
@ -213,7 +235,7 @@ class DirectManipulationControl(DirectObject):
self.marquee.create()
if self.fMultiView:
LE_showInOneCam(self.marquee, base.direct.camera.getName())
DG.LE_showInOneCam(self.marquee, base.direct.camera.getName())
def manipulationStop(self):
taskMgr.remove('manipulateObject')
@ -227,7 +249,7 @@ class DirectManipulationControl(DirectObject):
# optionally specified things
skipFlags = self.defaultSkipFlags | self.optionalSkipFlags
# Skip camera (and its children), unless control key is pressed
skipFlags |= SKIP_CAMERA * (1 - base.getControl())
skipFlags |= DG.SKIP_CAMERA * (1 - base.getControl())
if self.marquee:
self.marquee.removeNode()
@ -269,18 +291,18 @@ class DirectManipulationControl(DirectObject):
selectionList = []
for geom in render.findAllMatches("**/+GeomNode"):
if (skipFlags & SKIP_HIDDEN) and geom.isHidden():
if (skipFlags & DG.SKIP_HIDDEN) and geom.isHidden():
# Skip if hidden node
continue
## elif (skipFlags & SKIP_BACKFACE) and base.direct.iRay.isEntryBackfacing():
## elif (skipFlags & DG.SKIP_BACKFACE) and base.direct.iRay.isEntryBackfacing():
## # Skip, if backfacing poly
## pass
elif (skipFlags & SKIP_CAMERA) and \
elif (skipFlags & DG.SKIP_CAMERA) and \
(base.camera in geom.getAncestors()):
# Skip if parented to a camera.
continue
# Can pick unpickable, use the first visible node
elif (skipFlags & SKIP_UNPICKABLE) and \
elif (skipFlags & DG.SKIP_UNPICKABLE) and \
(geom.getName() in base.direct.iRay.unpickable):
# Skip if in unpickable list
continue
@ -500,7 +522,7 @@ class DirectManipulationControl(DirectObject):
selectedList = base.direct.selected.getSelectedAsList()
# See if any of the selected are completely uneditable
editTypes = self.getEditTypes(selectedList)
if (editTypes & EDIT_TYPE_UNEDITABLE) == EDIT_TYPE_UNEDITABLE:
if (editTypes & DG.EDIT_TYPE_UNEDITABLE) == DG.EDIT_TYPE_UNEDITABLE:
return
self.currEditTypes = editTypes
if selectedList:
@ -568,13 +590,13 @@ class DirectManipulationControl(DirectObject):
if self.constraint:
type = self.constraint[2:]
if self.useSeparateScaleHandles:
if type == 'post' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
if type == 'post' and not self.currEditTypes & DG.EDIT_TYPE_UNMOVABLE:
self.xlate1D(state)
elif type == 'disc' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
elif type == 'disc' and not self.currEditTypes & DG.EDIT_TYPE_UNMOVABLE:
self.xlate2D(state)
elif type == 'ring' and not self.currEditTypes & EDIT_TYPE_UNROTATABLE:
elif type == 'ring' and not self.currEditTypes & DG.EDIT_TYPE_UNROTATABLE:
self.rotate1D(state)
elif type == 'scale' and not self.currEditTypes & EDIT_TYPE_UNSCALABLE:
elif type == 'scale' and not self.currEditTypes & DG.EDIT_TYPE_UNSCALABLE:
if base.direct.fShift:
self.fScaling3D = 1
self.scale3D(state)
@ -582,7 +604,7 @@ class DirectManipulationControl(DirectObject):
self.fScaling1D = 1
self.scale1D(state)
else:
if base.direct.fControl and not self.currEditTypes & EDIT_TYPE_UNSCALABLE:
if base.direct.fControl and not self.currEditTypes & DG.EDIT_TYPE_UNSCALABLE:
if type == 'post':
# [gjeon] non-uniform scaling
self.fScaling1D = 1
@ -592,11 +614,11 @@ class DirectManipulationControl(DirectObject):
self.fScaling3D = 1
self.scale3D(state)
else:
if type == 'post' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
if type == 'post' and not self.currEditTypes & DG.EDIT_TYPE_UNMOVABLE:
self.xlate1D(state)
elif type == 'disc' and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
elif type == 'disc' and not self.currEditTypes & DG.EDIT_TYPE_UNMOVABLE:
self.xlate2D(state)
elif type == 'ring' and not self.currEditTypes & EDIT_TYPE_UNROTATABLE:
elif type == 'ring' and not self.currEditTypes & DG.EDIT_TYPE_UNROTATABLE:
self.rotate1D(state)
# No widget interaction, determine free manip mode
elif self.fFreeManip and not self.useSeparateScaleHandles:
@ -610,17 +632,17 @@ class DirectManipulationControl(DirectObject):
self.fScaling1D = 0
self.fScaling3D = 0
# Alt key switches to a scaling mode
if base.direct.fControl and not self.currEditTypes & EDIT_TYPE_UNSCALABLE:
if base.direct.fControl and not self.currEditTypes & DG.EDIT_TYPE_UNSCALABLE:
self.fScaling3D = 1
self.scale3D(state)
# Otherwise, manip mode depends on where you started
elif state.fMouseX and state.fMouseY and not self.currEditTypes & EDIT_TYPE_UNROTATABLE:
elif state.fMouseX and state.fMouseY and not self.currEditTypes & DG.EDIT_TYPE_UNROTATABLE:
# In the corner, spin around camera's axis
self.rotateAboutViewVector(state)
elif state.fMouseX or state.fMouseY and not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
elif state.fMouseX or state.fMouseY and not self.currEditTypes & DG.EDIT_TYPE_UNMOVABLE:
# Mouse started elsewhere in the outer frame, rotate
self.rotate2D(state)
elif not self.currEditTypes & EDIT_TYPE_UNMOVABLE:
elif not self.currEditTypes & DG.EDIT_TYPE_UNMOVABLE:
# Mouse started in central region, xlate
# Mode depends on shift key
if base.direct.fShift or base.direct.fControl:
@ -805,11 +827,11 @@ class DirectManipulationControl(DirectObject):
widgetDir.normalize()
# Convert specified widget axis to view space
if axis == 'x':
widgetAxis = Vec3(mWidget2Cam.xformVec(X_AXIS))
widgetAxis = Vec3(mWidget2Cam.xformVec(DG.X_AXIS))
elif axis == 'y':
widgetAxis = Vec3(mWidget2Cam.xformVec(Y_AXIS))
widgetAxis = Vec3(mWidget2Cam.xformVec(DG.Y_AXIS))
elif axis == 'z':
widgetAxis = Vec3(mWidget2Cam.xformVec(Z_AXIS))
widgetAxis = Vec3(mWidget2Cam.xformVec(DG.Z_AXIS))
widgetAxis.normalize()
if type == 'top?':
# Check sign of angle between two vectors
@ -868,7 +890,7 @@ class DirectManipulationControl(DirectObject):
moveDir.assign(moveDir * -1)
moveDir.normalize()
else:
moveDir = Vec3(Y_AXIS)
moveDir = Vec3(DG.Y_AXIS)
# Move selected objects
dr = base.direct.dr
# Scale move dir
@ -1034,8 +1056,8 @@ class DirectManipulationControl(DirectObject):
self.initScale *
(self.objectHandles.getWidgetIntersectPt(
self.manipRef, 'y').length() /
self.initScaleMag)
)
self.initScaleMag)
)
base.direct.widget.setScale(currScale)
## Utility functions ##
@ -1043,7 +1065,7 @@ class DirectManipulationControl(DirectObject):
""" Move selected object to intersection point of cursor on scene """
# Check for intersection
entry = base.direct.iRay.pickGeom(
skipFlags = SKIP_HIDDEN | SKIP_BACKFACE | SKIP_CAMERA)
skipFlags = DG.SKIP_HIDDEN | DG.SKIP_BACKFACE | DG.SKIP_CAMERA)
# MRM: Need to handle moving COA
if entry is not None and base.direct.selected.last is not None:
# Record undo point
@ -1060,6 +1082,7 @@ class DirectManipulationControl(DirectObject):
messenger.send('DIRECT_manipulateObjectCleanup',
[base.direct.selected.getSelectedAsList()])
class ObjectHandles(NodePath, DirectObject):
def __init__(self, name='objectHandles'):
# Initialize the superclass
@ -1642,32 +1665,32 @@ class ObjectHandles(NodePath, DirectObject):
# by comparing lineDir with plane normals. The plane with the
# largest dotProduct is most "normal"
if axis == 'x':
if abs(lineDir.dot(Y_AXIS)) > abs(lineDir.dot(Z_AXIS)):
if abs(lineDir.dot(DG.Y_AXIS)) > abs(lineDir.dot(DG.Z_AXIS)):
self.hitPt.assign(
planeIntersect(lineOrigin, lineDir, ORIGIN, Y_AXIS))
planeIntersect(lineOrigin, lineDir, DG.ORIGIN, DG.Y_AXIS))
else:
self.hitPt.assign(
planeIntersect(lineOrigin, lineDir, ORIGIN, Z_AXIS))
planeIntersect(lineOrigin, lineDir, DG.ORIGIN, DG.Z_AXIS))
# We really only care about the nearest point on the axis
self.hitPt.setY(0)
self.hitPt.setZ(0)
elif axis == 'y':
if abs(lineDir.dot(X_AXIS)) > abs(lineDir.dot(Z_AXIS)):
if abs(lineDir.dot(DG.X_AXIS)) > abs(lineDir.dot(DG.Z_AXIS)):
self.hitPt.assign(
planeIntersect(lineOrigin, lineDir, ORIGIN, X_AXIS))
planeIntersect(lineOrigin, lineDir, DG.ORIGIN, DG.X_AXIS))
else:
self.hitPt.assign(
planeIntersect(lineOrigin, lineDir, ORIGIN, Z_AXIS))
planeIntersect(lineOrigin, lineDir, DG.ORIGIN, DG.Z_AXIS))
# We really only care about the nearest point on the axis
self.hitPt.setX(0)
self.hitPt.setZ(0)
elif axis == 'z':
if abs(lineDir.dot(X_AXIS)) > abs(lineDir.dot(Y_AXIS)):
if abs(lineDir.dot(DG.X_AXIS)) > abs(lineDir.dot(DG.Y_AXIS)):
self.hitPt.assign(
planeIntersect(lineOrigin, lineDir, ORIGIN, X_AXIS))
planeIntersect(lineOrigin, lineDir, DG.ORIGIN, DG.X_AXIS))
else:
self.hitPt.assign(
planeIntersect(lineOrigin, lineDir, ORIGIN, Y_AXIS))
planeIntersect(lineOrigin, lineDir, DG.ORIGIN, DG.Y_AXIS))
# We really only care about the nearest point on the axis
self.hitPt.setX(0)
self.hitPt.setY(0)
@ -1722,16 +1745,17 @@ class ObjectHandles(NodePath, DirectObject):
# Find the hit point
if plane == 'x':
self.hitPt.assign(planeIntersect(
lineOrigin, lineDir, ORIGIN, X_AXIS))
lineOrigin, lineDir, DG.ORIGIN, DG.X_AXIS))
elif plane == 'y':
self.hitPt.assign(planeIntersect(
lineOrigin, lineDir, ORIGIN, Y_AXIS))
lineOrigin, lineDir, DG.ORIGIN, DG.Y_AXIS))
elif plane == 'z':
self.hitPt.assign(planeIntersect(
lineOrigin, lineDir, ORIGIN, Z_AXIS))
lineOrigin, lineDir, DG.ORIGIN, DG.Z_AXIS))
return self.hitPt
def drawBox(lines, center, sideLength):
l = sideLength * 0.5
lines.moveTo(center[0] + l, center[1] + l, center[2] + l)

View File

@ -1,13 +1,33 @@
from panda3d.core import (
BitMask32,
BoundingSphere,
CollisionHandlerQueue,
CollisionNode,
CollisionRay,
CollisionSegment,
CollisionSphere,
CollisionTraverser,
GeomNode,
Mat4,
NodePath,
Point3,
TransformState,
VBase4,
Vec3,
Vec4,
)
from direct.showbase.DirectObject import DirectObject
from direct.showbase.MessengerGlobal import messenger
from .DirectGlobals import *
from .DirectUtil import *
from .DirectGeometry import *
from . import DirectGlobals as DG
from .DirectUtil import useDirectRenderStyle
from .DirectGeometry import LineNodePath
COA_ORIGIN = 0
COA_CENTER = 1
# MRM: To do: handle broken node paths in selected and deselected dicts
class DirectNodePath(NodePath):
# A node path augmented with info, bounding box, and utility methods
def __init__(self, nodePath, bboxColor=None):
@ -47,6 +67,7 @@ class DirectNodePath(NodePath):
def getMax(self):
return self.bbox.getMax()
class SelectedNodePaths(DirectObject):
def __init__(self):
self.reset()
@ -427,7 +448,7 @@ class DirectBoundingBox:
'Max:\t\t%s\n' % self.vecAsString(self.max) +
'Center:\t\t%s\n' % self.vecAsString(self.center) +
'Radius:\t\t%.2f' % self.radius
)
)
class SelectionQueue(CollisionHandlerQueue):
@ -439,7 +460,7 @@ class SelectionQueue(CollisionHandlerQueue):
# Current index and entry in collision queue
self.index = -1
self.entry = None
self.skipFlags = SKIP_NONE
self.skipFlags = DG.SKIP_NONE
# Create a collision node path attached to the given NP
self.collisionNodePath = NodePath(CollisionNode("collisionNP"))
self.setParentNP(parentNP)
@ -454,7 +475,7 @@ class SelectionQueue(CollisionHandlerQueue):
# Let the traverser know about the collision node and the queue
self.ct.addCollider(self.collisionNodePath, self)
# List of objects that can't be selected
self.unpickable = UNPICKABLE
self.unpickable = DG.UNPICKABLE
# Derived class must add Collider to complete initialization
def setParentNP(self, parentNP):
@ -548,10 +569,10 @@ class SelectionQueue(CollisionHandlerQueue):
v.normalize()
return v.dot(n) >= 0
def findNextCollisionEntry(self, skipFlags = SKIP_NONE):
def findNextCollisionEntry(self, skipFlags = DG.SKIP_NONE):
return self.findCollisionEntry(skipFlags, self.index + 1)
def findCollisionEntry(self, skipFlags = SKIP_NONE, startIndex = 0):
def findCollisionEntry(self, skipFlags = DG.SKIP_NONE, startIndex = 0):
# Init self.index and self.entry
self.setCurrentIndex(-1)
self.setCurrentEntry(None)
@ -559,29 +580,29 @@ class SelectionQueue(CollisionHandlerQueue):
for i in range(startIndex, self.getNumEntries()):
entry = self.getEntry(i)
nodePath = entry.getIntoNodePath()
if (skipFlags & SKIP_HIDDEN) and nodePath.isHidden():
if (skipFlags & DG.SKIP_HIDDEN) and nodePath.isHidden():
# Skip if hidden node
pass
elif (skipFlags & SKIP_BACKFACE) and self.isEntryBackfacing(entry):
elif (skipFlags & DG.SKIP_BACKFACE) and self.isEntryBackfacing(entry):
# Skip, if backfacing poly
pass
elif (skipFlags & SKIP_CAMERA) and \
elif (skipFlags & DG.SKIP_CAMERA) and \
(base.camera in nodePath.getAncestors()):
# Skip if parented to a camera.
pass
# Can pick unpickable, use the first visible node
elif (skipFlags & SKIP_UNPICKABLE) and\
elif (skipFlags & DG.SKIP_UNPICKABLE) and \
(nodePath.getName() in self.unpickable):
# Skip if in unpickable list
pass
elif base.direct and\
((skipFlags & SKIP_WIDGET) and
(nodePath.getTag('WidgetName') != base.direct.widget.getName())):
elif base.direct and \
((skipFlags & DG.SKIP_WIDGET) and
(nodePath.getTag('WidgetName') != base.direct.widget.getName())):
# Skip if this widget part is not belong to current widget
pass
elif base.direct and\
((skipFlags & SKIP_WIDGET) and base.direct.fControl and
(nodePath.getName()[2:] == 'ring')):
elif base.direct and \
((skipFlags & DG.SKIP_WIDGET) and base.direct.fControl and
(nodePath.getName()[2:] == 'ring')):
# Skip when ununiformly scale in ortho view
pass
else:
@ -590,6 +611,7 @@ class SelectionQueue(CollisionHandlerQueue):
break
return self.getCurrentEntry()
class SelectionRay(SelectionQueue):
def __init__(self, parentNP = None):
if parentNP is None:
@ -623,7 +645,7 @@ class SelectionRay(SelectionQueue):
def pickBitMask(self, bitMask = BitMask32.allOff(),
targetNodePath = None,
skipFlags = SKIP_ALL):
skipFlags = DG.SKIP_ALL):
if targetNodePath is None:
targetNodePath = render
self.collideWithBitMask(bitMask)
@ -631,7 +653,7 @@ class SelectionRay(SelectionQueue):
# Determine collision entry
return self.findCollisionEntry(skipFlags)
def pickGeom(self, targetNodePath = None, skipFlags = SKIP_ALL,
def pickGeom(self, targetNodePath = None, skipFlags = DG.SKIP_ALL,
xy = None):
if targetNodePath is None:
targetNodePath = render
@ -640,7 +662,7 @@ class SelectionRay(SelectionQueue):
# Determine collision entry
return self.findCollisionEntry(skipFlags)
def pickWidget(self, targetNodePath = None, skipFlags = SKIP_NONE):
def pickWidget(self, targetNodePath = None, skipFlags = DG.SKIP_NONE):
if targetNodePath is None:
targetNodePath = render
self.collideWithWidget()
@ -657,7 +679,7 @@ class SelectionRay(SelectionQueue):
def pickGeom3D(self, targetNodePath = None,
origin = Point3(0), dir = Vec3(0, 0, -1),
skipFlags = SKIP_HIDDEN | SKIP_CAMERA):
skipFlags = DG.SKIP_HIDDEN | DG.SKIP_CAMERA):
if targetNodePath is None:
targetNodePath = render
self.collideWithGeom()
@ -668,7 +690,7 @@ class SelectionRay(SelectionQueue):
def pickBitMask3D(self, bitMask = BitMask32.allOff(),
targetNodePath = None,
origin = Point3(0), dir = Vec3(0, 0, -1),
skipFlags = SKIP_ALL):
skipFlags = DG.SKIP_ALL):
if targetNodePath is None:
targetNodePath = render
self.collideWithBitMask(bitMask)
@ -698,7 +720,7 @@ class SelectionSegment(SelectionQueue):
self.numColliders += 1
def pickGeom(self, targetNodePath = None, endPointList = [],
skipFlags = SKIP_HIDDEN | SKIP_CAMERA):
skipFlags = DG.SKIP_HIDDEN | DG.SKIP_CAMERA):
if targetNodePath is None:
targetNodePath = render
self.collideWithGeom()
@ -713,7 +735,7 @@ class SelectionSegment(SelectionQueue):
def pickBitMask(self, bitMask = BitMask32.allOff(),
targetNodePath = None, endPointList = [],
skipFlags = SKIP_HIDDEN | SKIP_CAMERA):
skipFlags = DG.SKIP_HIDDEN | DG.SKIP_CAMERA):
if targetNodePath is None:
targetNodePath = render
self.collideWithBitMask(bitMask)
@ -781,7 +803,7 @@ class SelectionSphere(SelectionQueue):
return self.findCollisionEntry(skipFlags)
def pickGeom(self, targetNodePath = None,
skipFlags = SKIP_HIDDEN | SKIP_CAMERA):
skipFlags = DG.SKIP_HIDDEN | DG.SKIP_CAMERA):
if targetNodePath is None:
targetNodePath = render
self.collideWithGeom()
@ -789,7 +811,7 @@ class SelectionSphere(SelectionQueue):
def pickBitMask(self, bitMask = BitMask32.allOff(),
targetNodePath = None,
skipFlags = SKIP_HIDDEN | SKIP_CAMERA):
skipFlags = DG.SKIP_HIDDEN | DG.SKIP_CAMERA):
if targetNodePath is None:
targetNodePath = render
self.collideWithBitMask(bitMask)

View File

@ -1,26 +1,41 @@
import math
from panda3d.core import *
from .DirectUtil import *
from panda3d.core import (
CollisionNode,
ConfigVariableBool,
ConfigVariableString,
CSDefault,
NodePath,
Point3,
TextNode,
VBase3,
VBase4,
Vec3,
Vec4,
decomposeMatrix,
deg2Rad,
)
from .DirectUtil import useDirectRenderStyle
from direct.showbase.DirectObject import DirectObject
from direct.showbase.BulletinBoardGlobal import bulletinBoard as bboard
from direct.task import Task
from .DirectGlobals import DIRECT_NO_MOD
from . import DirectGlobals as DG
from .DirectCameraControl import DirectCameraControl
from .DirectManipulation import DirectManipulationControl
from .DirectSelection import SelectionRay, COA_ORIGIN, SelectedNodePaths
from .DirectGrid import DirectGrid
#from DirectGeometry import *
from .DirectLights import DirectLights
from direct.cluster.ClusterClient import createClusterClient, DummyClusterClient
from direct.cluster.ClusterServer import ClusterServer
## from direct.tkpanels import Placer
## from direct.tkwidgets import Slider
## from direct.tkwidgets import SceneGraphExplorer
from direct.gui import OnscreenText
from direct.interval.IntervalGlobal import *
from direct.interval.IntervalGlobal import Func, Sequence
from direct.task.TaskManagerGlobal import taskMgr
from direct.showbase.MessengerGlobal import messenger
class DirectSession(DirectObject):
@ -117,7 +132,6 @@ class DirectSession(DirectObject):
for i in range(len(fastrak))[1:]:
self.fastrak.append(DirectFastrak.DirectFastrak(fastrak[0] + ':' + fastrak[i]))
self.fControl = 0
self.fAlt = 0
self.fShift = 0
@ -179,7 +193,7 @@ class DirectSession(DirectObject):
['DIRECT-doWrtReparent', self.doWrtReparent],
['DIRECT-doReparent', self.doReparent],
['DIRECT-doSelect', self.doSelect],
]
]
if base.wantTk:
from direct.tkpanels import Placer
@ -248,7 +262,7 @@ class DirectSession(DirectObject):
'shift-[': ('DIRECT-Undo', 'DIRECT-Undo'),
']': ('DIRECT-Redo', 'DIRECT-Redo'),
'shift-]': ('DIRECT-Redo', 'DIRECT-Redo'),
}
}
self.hotKeyMap = {
'c': ('Center Camera', 'DIRECT-centerCamIn'),
@ -276,14 +290,14 @@ class DirectSession(DirectObject):
'shift-a': ('Toggle Vis all', 'DIRECT-toggleVisAll'),
'w': ('Toggle Wireframe', 'DIRECT-toggleWireframe'),
'control-z': ('Undo', 'LE-Undo'),
'shift-z' : ('Redo', 'LE-Redo'),
'shift-z': ('Redo', 'LE-Redo'),
'control-d': ('Duplicate', 'LE-Duplicate'),
'control-l': ('Make Live', 'LE-MakeLive'),
'control-n': ('New Scene', 'LE-NewScene'),
'control-s': ('Save Scene', 'LE-SaveScene'),
'control-o': ('Open Scene', 'LE-OpenScene'),
'control-q': ('Quit', 'LE-Quit'),
}
}
self.speicalKeyMap = {
'enter': 'DIRECT-enter',
@ -303,14 +317,16 @@ class DirectSession(DirectObject):
self.clusterMode = ConfigVariableString("cluster-mode", '').value
if self.clusterMode == 'client':
from direct.cluster.ClusterClient import createClusterClient
self.cluster = createClusterClient()
elif self.clusterMode == 'server':
from direct.cluster.ClusterServer import ClusterServer
self.cluster = ClusterServer(base.camera, base.cam)
else:
from direct.cluster.ClusterClient import DummyClusterClient
self.cluster = DummyClusterClient()
__builtins__['cluster'] = self.cluster
def addPassThroughKey(self,key):
self.passThroughKeys.append(key)
@ -541,7 +557,7 @@ class DirectSession(DirectObject):
base.mouseWatcher = winCtrl.mouseWatcher
base.mouseWatcherNode = winCtrl.mouseWatcher.node()
base.direct.dr.mouseUpdate()
LE_showInOneCam(self.selectedNPReadout, self.camera.getName())
DG.LE_showInOneCam(self.selectedNPReadout, self.camera.getName())
base.direct.widget = base.direct.manipulationControl.widgetList[base.camList.index(NodePath(winCtrl.camNode))]
input = input[8:] # get rid of camera prefix
@ -590,8 +606,8 @@ class DirectSession(DirectObject):
self.fControl = 1
# [gjeon] to update control key information while mouse1 is pressed
if self.fMouse1:
modifiers = DIRECT_NO_MOD
modifiers |= DIRECT_CONTROL_MOD
modifiers = DG.DIRECT_NO_MOD
modifiers |= DG.DIRECT_CONTROL_MOD
messenger.send('DIRECT-mouse1', sentArgs = [modifiers])
elif input == 'control-up':
self.fControl = 0
@ -601,16 +617,16 @@ class DirectSession(DirectObject):
self.fAlt = 1
# [gjeon] to update alt key information while mouse1 is pressed
if self.fMouse1:
modifiers = DIRECT_NO_MOD
modifiers |= DIRECT_ALT_MOD
modifiers = DG.DIRECT_NO_MOD
modifiers |= DG.DIRECT_ALT_MOD
messenger.send('DIRECT-mouse1', sentArgs = [modifiers])
elif self.fMouse2:
modifiers = DIRECT_NO_MOD
modifiers |= DIRECT_ALT_MOD
modifiers = DG.DIRECT_NO_MOD
modifiers |= DG.DIRECT_ALT_MOD
messenger.send('DIRECT-mouse2', sentArgs = [modifiers])
elif self.fMouse3:
modifiers = DIRECT_NO_MOD
modifiers |= DIRECT_ALT_MOD
modifiers = DG.DIRECT_NO_MOD
modifiers |= DG.DIRECT_ALT_MOD
messenger.send('DIRECT-mouse3', sentArgs = [modifiers])
elif input == 'alt-up':
self.fAlt = 0
@ -637,24 +653,24 @@ class DirectSession(DirectObject):
self.select(self.selected.last)
def getModifiers(self, input, base):
modifiers = DIRECT_NO_MOD
modifiers = DG.DIRECT_NO_MOD
modifierString = input[: input.find(base)]
if modifierString.find('shift') != -1:
modifiers |= DIRECT_SHIFT_MOD
modifiers |= DG.DIRECT_SHIFT_MOD
if modifierString.find('control') != -1:
modifiers |= DIRECT_CONTROL_MOD
modifiers |= DG.DIRECT_CONTROL_MOD
if modifierString.find('alt') != -1:
modifiers |= DIRECT_ALT_MOD
modifiers |= DG.DIRECT_ALT_MOD
return modifiers
def gotShift(self, modifiers):
return modifiers & DIRECT_SHIFT_MOD
return modifiers & DG.DIRECT_SHIFT_MOD
def gotControl(self, modifiers):
return modifiers & DIRECT_CONTROL_MOD
return modifiers & DG.DIRECT_CONTROL_MOD
def gotAlt(self, modifiers):
return modifiers & DIRECT_ALT_MOD
return modifiers & DG.DIRECT_ALT_MOD
def setFScaleWidgetByCam(self, flag):
self.fScaleWidgetByCam = flag
@ -708,7 +724,7 @@ class DirectSession(DirectObject):
else:
self.widget.showWidget()
editTypes = self.manipulationControl.getEditTypes([dnp])
if (editTypes & EDIT_TYPE_UNEDITABLE) == EDIT_TYPE_UNEDITABLE:
if (editTypes & DG.EDIT_TYPE_UNEDITABLE) == DG.EDIT_TYPE_UNEDITABLE:
self.manipulationControl.disableWidgetMove()
else:
self.manipulationControl.enableWidgetMove()
@ -831,7 +847,7 @@ class DirectSession(DirectObject):
# Temporarily set node path color
nodePath.setColor(flashColor)
# Clean up color in a few seconds
t = taskMgr.doMethodLater(DIRECT_FLASH_DURATION,
t = taskMgr.doMethodLater(DG.DIRECT_FLASH_DURATION,
# This is just a dummy task
self.flashDummy,
'flashNodePath',)
@ -859,6 +875,7 @@ class DirectSession(DirectObject):
# If nothing specified, try selected node path
nodePath = self.selected.last
base.direct.select(nodePath)
def fitTask(state, self = self):
self.cameraControl.fitOnWidget()
return Task.done
@ -1203,12 +1220,13 @@ class DisplayRegionContext(DirectObject):
self.near,
(self.nearHeight*0.5) * self.mouseY)
class DisplayRegionList(DirectObject):
def __init__(self):
self.displayRegionList = []
i = 0
# Things are funky if we are oobe
if (hasattr(base, 'oobeMode') and base.oobeMode):
if getattr(base, 'oobeMode', False):
# assume we only have one cam at this point
drc = DisplayRegionContext(base.cam)
self.displayRegionList.append(drc)
@ -1224,10 +1242,9 @@ class DisplayRegionList(DirectObject):
# a display region for each real display region, and then
# keep track of which are currently active (e.g. use a flag)
# processing only them.
for camIndex in range(len(base.camList)):
cam = base.camList[camIndex]
if cam.getName()=='<noname>':
cam.setName('Camera%d' % camIndex)
for camIndex, cam in enumerate(base.camList):
if cam.name == '<noname>':
cam.name = f'Camera{camIndex}'
drc = DisplayRegionContext(cam)
self.displayRegionList.append(drc)
@ -1272,7 +1289,7 @@ class DisplayRegionList(DirectObject):
for dr in self.displayRegionList:
dr.setVfov(fov)
def mouseUpdate(self, modifiers = DIRECT_NO_MOD):
def mouseUpdate(self, modifiers = DG.DIRECT_NO_MOD):
for dr in self.displayRegionList:
dr.mouseUpdate()
#base.direct.dr = self.getCurrentDr()

View File

@ -1,5 +1,3 @@
from .DirectGlobals import *
from panda3d.core import VBase4
from direct.task.Task import Task
from direct.task.TaskManagerGlobal import taskMgr

View File

@ -7,6 +7,8 @@ ChunkSize = 100
FilePattern = 'largeBlob.%s'
def getLargeBlobPath():
from panda3d.core import ConfigVariableString, ConfigFlags
# this folder needs to be accessible by everyone that is going to level edit
# an area as a group
return config.GetString('large-blob-path', 'i:\\toontown_in_game_editor_temp')
return ConfigVariableString('large-blob-path', 'i:\\toontown_in_game_editor_temp', 'DConfig', ConfigFlags.F_dconfig).value

View File

@ -1,8 +1,20 @@
from direct.showbase.DirectObject import DirectObject
from direct.showbase.MessengerGlobal import messenger
from direct.directtools.DirectGeometry import *
from direct.directtools.DirectUtil import CLAMP
from direct.task.TaskManagerGlobal import taskMgr
from panda3d.core import NodePath, LineSegs, ClockObject
from panda3d.core import (
PCTHPR,
PCTNONE,
PCTT,
PCTXYZ,
ClockObject,
LineSegs,
NodePath,
ParametricCurve,
Point3,
Vec3,
)
class Mopath(DirectObject):
@ -11,7 +23,7 @@ class Mopath(DirectObject):
def __init__(self, name = None, fluid = 1, objectToLoad = None, upVectorNodePath = None, reverseUpVector = False):
if name is None:
name = 'mopath%d' % self.nameIndex
name = f'mopath{self.nameIndex}'
self.nameIndex = self.nameIndex + 1
self.name = name
self.fluid = fluid
@ -26,12 +38,12 @@ class Mopath(DirectObject):
self.upVectorNodePath = upVectorNodePath
self.reverseUpVector = reverseUpVector
self.reset()
if isinstance( objectToLoad, NodePath ):
self.loadNodePath( objectToLoad )
elif isinstance( objectToLoad, str ):
self.loadFile( objectToLoad )
if isinstance(objectToLoad, NodePath):
self.loadNodePath(objectToLoad)
elif isinstance(objectToLoad, str):
self.loadFile(objectToLoad)
elif objectToLoad is not None:
print("Mopath: Unable to load object '%s', objectToLoad must be a file name string or a NodePath" % objectToLoad)
print(f"Mopath: Unable to load object '{objectToLoad}', objectToLoad must be a file name string or a NodePath")
def getMaxT(self):
return self.maxT * self.timeScale
@ -49,7 +61,7 @@ class Mopath(DirectObject):
self.reset()
self.__extractCurves(nodePath)
if self.tNurbsCurve != []:
if self.tNurbsCurve:
self.maxT = self.tNurbsCurve[-1].getMaxT()
elif self.xyzNurbsCurve is not None:
self.maxT = self.xyzNurbsCurve.getMaxT()
@ -58,7 +70,6 @@ class Mopath(DirectObject):
else:
print('Mopath: no valid curves in nodePath: %s' % nodePath)
def reset(self):
self.maxT = 0.0
self.loop = 0

View File

@ -45,6 +45,8 @@ Please use assert (properly) and do proper error handling; and use
where it helps you resist using assert for error handling.
"""
__all__ = ["verify"]
from panda3d.core import ConfigVariableBool
# Set to true to load pdb on failure.

View File

@ -9,7 +9,7 @@ import imp
import platform
import struct
import io
import distutils.sysconfig as sysconf
import sysconfig
import zipfile
import importlib
import warnings
@ -22,7 +22,7 @@ try:
except ImportError:
p3extend_frozen = None
from panda3d.core import *
from panda3d.core import Filename, Multifile, PandaSystem, StringStream
# Check to see if we are running python_d, which implies we have a
# debug build, and we have to build the module with debug options.
@ -83,10 +83,13 @@ defaultHiddenImports = {
'plyer': ['plyer.platforms'],
'scipy.linalg': ['scipy.linalg.cython_blas', 'scipy.linalg.cython_lapack'],
'scipy.sparse.csgraph': ['scipy.sparse.csgraph._validation'],
'scipy.spatial.qhull': ['scipy._lib.messagestream'],
'scipy.spatial._qhull': ['scipy._lib.messagestream'],
'scipy.spatial.transform.rotation': ['scipy.spatial.transform._rotation_groups'],
'scipy.spatial.transform._rotation': ['scipy.spatial.transform._rotation_groups'],
'scipy.special._ufuncs': ['scipy.special._ufuncs_cxx'],
'scipy.stats._stats': ['scipy.special.cython_special'],
'setuptools.monkey': ['setuptools.msvc'],
}
@ -139,6 +142,11 @@ def updatecache(filename, module_globals=None):
def lazycache(filename, module_globals):
pass
""",
# Used by setuptools to redirect distutils to setuptools' vendored copy.
# This causes problems because it makes assumptions about __file__, so we
# simply implement the logic ourselves.
'_distutils_hack.override': '',
}
# These are missing modules that we've reported already this session.
@ -168,8 +176,8 @@ class CompilationEnvironment:
# Paths to Python stuff.
self.Python = None
self.PythonIPath = sysconf.get_python_inc()
self.PythonVersion = sysconf.get_config_var("LDVERSION") or sysconf.get_python_version()
self.PythonIPath = sysconfig.get_path('include')
self.PythonVersion = sysconfig.get_config_var("LDVERSION") or sysconfig.get_python_version()
# The VC directory of Microsoft Visual Studio (if relevant)
self.MSVC = None
@ -273,32 +281,32 @@ class CompilationEnvironment:
def compileExe(self, filename, basename, extraLink=[]):
compile = self.compileObjExe % dict({
'python' : self.Python,
'MSVC' : self.MSVC,
'PSDK' : self.PSDK,
'suffix64' : self.suffix64,
'MD' : self.MD,
'pythonIPath' : self.PythonIPath,
'pythonVersion' : self.PythonVersion,
'arch' : self.arch,
'filename' : filename,
'basename' : basename,
}, **sysconf.get_config_vars())
'python': self.Python,
'MSVC': self.MSVC,
'PSDK': self.PSDK,
'suffix64': self.suffix64,
'MD': self.MD,
'pythonIPath': self.PythonIPath,
'pythonVersion': self.PythonVersion,
'arch': self.arch,
'filename': filename,
'basename': basename,
}, **sysconf.get_config_vars())
sys.stderr.write(compile + '\n')
if os.system(compile) != 0:
raise Exception('failed to compile %s.' % basename)
link = self.linkExe % dict({
'python' : self.Python,
'MSVC' : self.MSVC,
'PSDK' : self.PSDK,
'suffix64' : self.suffix64,
'pythonIPath' : self.PythonIPath,
'pythonVersion' : self.PythonVersion,
'arch' : self.arch,
'filename' : filename,
'basename' : basename,
}, **sysconf.get_config_vars())
'python': self.Python,
'MSVC': self.MSVC,
'PSDK': self.PSDK,
'suffix64': self.suffix64,
'pythonIPath': self.PythonIPath,
'pythonVersion': self.PythonVersion,
'arch': self.arch,
'filename': filename,
'basename': basename,
}, **sysconf.get_config_vars())
link += ' ' + ' '.join(extraLink)
sys.stderr.write(link + '\n')
if os.system(link) != 0:
@ -306,38 +314,39 @@ class CompilationEnvironment:
def compileDll(self, filename, basename, extraLink=[]):
compile = self.compileObjDll % dict({
'python' : self.Python,
'MSVC' : self.MSVC,
'PSDK' : self.PSDK,
'suffix64' : self.suffix64,
'MD' : self.MD,
'pythonIPath' : self.PythonIPath,
'pythonVersion' : self.PythonVersion,
'arch' : self.arch,
'filename' : filename,
'basename' : basename,
}, **sysconf.get_config_vars())
'python': self.Python,
'MSVC': self.MSVC,
'PSDK': self.PSDK,
'suffix64': self.suffix64,
'MD': self.MD,
'pythonIPath': self.PythonIPath,
'pythonVersion': self.PythonVersion,
'arch': self.arch,
'filename': filename,
'basename': basename,
}, **sysconf.get_config_vars())
sys.stderr.write(compile + '\n')
if os.system(compile) != 0:
raise Exception('failed to compile %s.' % basename)
link = self.linkDll % dict({
'python' : self.Python,
'MSVC' : self.MSVC,
'PSDK' : self.PSDK,
'suffix64' : self.suffix64,
'pythonIPath' : self.PythonIPath,
'pythonVersion' : self.PythonVersion,
'arch' : self.arch,
'filename' : filename,
'basename' : basename,
'dllext' : self.dllext,
}, **sysconf.get_config_vars())
'python': self.Python,
'MSVC': self.MSVC,
'PSDK': self.PSDK,
'suffix64': self.suffix64,
'pythonIPath': self.PythonIPath,
'pythonVersion': self.PythonVersion,
'arch': self.arch,
'filename': filename,
'basename': basename,
'dllext': self.dllext,
}, **sysconf.get_config_vars())
link += ' ' + ' '.join(extraLink)
sys.stderr.write(link + '\n')
if os.system(link) != 0:
raise Exception('failed to link %s.' % basename)
# The code from frozenmain.c in the Python source repository.
frozenMainCode = """
/* Python interpreter main program for frozen scripts */
@ -361,6 +370,8 @@ extern PyAPI_FUNC(int) PyImport_ExtendInittab(struct _inittab *newtab);
/* Main program */
EXTRA_INIT_FUNC_DECLS
int
Py_FrozenMain(int argc, char **argv)
{
@ -440,6 +451,8 @@ Py_FrozenMain(int argc, char **argv)
PySys_SetArgv(argc, argv);
#endif
EXTRA_INIT_FUNC_CALLS
n = PyImport_ImportFrozenModule("__main__");
if (n == 0)
Py_FatalError("__main__ not frozen");
@ -673,7 +686,7 @@ okMissing = [
'direct.extensions_native.extensions_darwin', '_manylinux',
'collections.Iterable', 'collections.Mapping', 'collections.MutableMapping',
'collections.Sequence', 'numpy_distutils', '_winapi',
]
]
# Since around macOS 10.15, Apple's codesigning process has become more strict.
# Appending data to the end of a Mach-O binary is now explicitly forbidden. The
@ -720,6 +733,7 @@ lc_indices_to_slide = {
LC_DATA_IN_CODE: [2],
}
class Freezer:
class ModuleDef:
def __init__(self, moduleName, filename = None,
@ -829,6 +843,12 @@ class Freezer:
# modules.
self.extras = []
# This is a list of init functions that must be called after
# Py_Initialize(), but before importing __main__. This is a
# tuple of (return type, name). They should use C calling
# convention.
self.extraInitFuncs = []
# Set this to true if extension modules should be linked in to
# the resulting executable.
self.linkExtensionModules = False
@ -1139,7 +1159,7 @@ class Freezer:
if mdef.implicit and '.' in newName:
# For implicit modules, check if the parent is excluded.
parentName, baseName = newName.rsplit('.', 1)
if parentName in excludeDict :
if parentName in excludeDict:
mdef = excludeDict[parentName]
if mdef.exclude:
@ -1180,7 +1200,7 @@ class Freezer:
self.__loadModule(mdef)
# Since it successfully loaded, it's no longer a guess.
mdef.guess = False
except:
except Exception:
# Something went wrong, guess it's not an importable
# module.
pass
@ -1197,13 +1217,16 @@ class Freezer:
except ImportError:
pass
else:
self.__loadModule(self.ModuleDef(modname, implicit = True))
try:
self.__loadModule(self.ModuleDef(modname, implicit = True))
except ImportError:
pass
# Special case for sysconfig, which depends on a platform-specific
# sysconfigdata module on POSIX systems.
missing = []
if 'sysconfig' in self.mf.modules and \
('linux' in self.platform or 'mac' in self.platform):
('linux' in self.platform or 'mac' in self.platform or 'emscripten' in self.platform):
modname = '_sysconfigdata'
if sys.version_info >= (3, 6):
modname += '_'
@ -1215,10 +1238,16 @@ class Freezer:
modname += '_linux_' + arch + '-linux-gnu'
elif 'mac' in self.platform:
modname += '_darwin_darwin'
elif 'emscripten' in self.platform:
if '_' in self.platform:
arch = self.platform.split('_', 1)[1]
else:
arch = 'wasm32'
modname += '_emscripten_' + arch + '-emscripten'
try:
self.__loadModule(self.ModuleDef(modname, implicit=True))
except:
except Exception:
missing.append(modname)
# Now, any new modules we found get added to the export list.
@ -1594,7 +1623,7 @@ class Freezer:
text = programFile % {
'moduleDefs': '\n'.join(moduleDefs),
'moduleList': '\n'.join(moduleList),
}
}
if self.linkExtensionModules and self.extras:
# Should we link in extension modules? If so, we write out a new
@ -1692,14 +1721,26 @@ class Freezer:
if compileToExe:
code = self.frozenMainCode
decls = ''
calls = ''
for func in self.extraInitFuncs:
if isinstance(func, str):
func = ('void', func)
decls += f'extern {func[0]} {func[1]}();\n'
calls += f' {func[1]}();\n';
code = code.replace('EXTRA_INIT_FUNC_DECLS', decls)
code = code.replace('EXTRA_INIT_FUNC_CALLS', calls)
if self.platform.startswith('win'):
code += self.frozenDllMainCode
initCode = self.mainInitCode % {
'frozenMainCode' : code,
'programName' : os.path.basename(basename),
'dllexport' : dllexport,
'dllimport' : dllimport,
}
'frozenMainCode': code,
'programName': os.path.basename(basename),
'dllexport': dllexport,
'dllimport': dllimport,
}
if self.platform.startswith('win'):
target = basename + '.exe'
else:
@ -1714,10 +1755,10 @@ class Freezer:
target = basename + '.so'
initCode = dllInitCode % {
'moduleName' : os.path.basename(basename),
'dllexport' : dllexport,
'dllimport' : dllimport,
}
'moduleName': os.path.basename(basename),
'dllexport': dllexport,
'dllimport': dllimport,
}
compileFunc = self.cenv.compileDll
self.writeCode(filename, initCode=initCode)
@ -2333,17 +2374,8 @@ class Freezer:
return blob_offset
def makeModuleDef(self, mangledName, code):
result = ''
result += 'static unsigned char %s[] = {' % (mangledName)
for i in range(0, len(code), 16):
result += '\n '
for c in code[i:i+16]:
if isinstance(c, int): # Python 3
result += ('%d,' % c)
else: # Python 2
result += ('%d,' % ord(c))
result += '\n};\n'
return result
lines = ',\n '.join(','.join(map(str, code[i:i+16])) for i in range(0, len(code), 16))
return f'static unsigned char {mangledName}[] = {{\n {lines}\n}};\n'
def makeModuleListEntry(self, mangledName, code, moduleName, module):
size = len(code)
@ -2355,7 +2387,6 @@ class Freezer:
def makeForbiddenModuleListEntry(self, moduleName):
return ' {"%s", NULL, 0},' % (moduleName)
def __writingModule(self, moduleName):
""" Returns true if we are outputting the named module in this
pass, false if we have already output in a previous pass, or
@ -2384,6 +2415,8 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
:param debug: an integer indicating the level of verbosity
"""
self.builtin_module_names = kw.pop('builtin_module_names', sys.builtin_module_names)
self.suffixes = kw.pop('suffixes', imp.get_suffixes())
self.optimize = kw.pop('optimize', -1)
@ -2708,11 +2741,12 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
if fullname in overrideModules:
return (None, '', ('.py', 'r', imp.PY_SOURCE))
# It's built into the interpreter.
if fullname in self.builtin_module_names:
return (None, None, ('', '', imp.C_BUILTIN))
# If no search path is given, look for a built-in module.
if path is None:
if name in sys.builtin_module_names:
return (None, None, ('', '', imp.C_BUILTIN))
path = self.path
if fullname == 'distutils' and hasattr(sys, 'real_prefix'):
@ -2726,6 +2760,22 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
except ImportError:
pass
elif (fullname == 'distutils' and 'setuptools' in self.modules and
'_distutils_hack.override' in self.modules):
# Redirect to setuptools' vendored copy.
setuptools = self.modules['setuptools']
return self.find_module('_distutils', setuptools.__path__, parent=setuptools)
elif parent is not None and parent.__name__ in ('setuptools.extern', 'pkg_resources.extern'):
# Look for vendored versions of these libraries.
root = self.modules[parent.__name__.split('.', 1)[0]]
try:
fp, fn, stuff = self.find_module('_vendor', root.__path__, parent=root)
vendor = self.load_module(root.__name__ + '._vendor', fp, fn, stuff)
return self.find_module(name, vendor.__path__, parent=vendor)
except ImportError:
pass
# Look for the module on the search path.
ns_dirs = []

View File

@ -3,9 +3,10 @@
import xml.etree.ElementTree as ET
from ._proto.targeting_pb2 import Abi
from ._proto.config_pb2 import BundleConfig
from ._proto.files_pb2 import NativeLibraries
from ._proto.Resources_pb2 import XmlNode, ResourceTable
from ._proto.config_pb2 import BundleConfig # 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
AbiAlias = Abi.AbiAlias

View File

@ -6,7 +6,6 @@ on how to use these commands.
import os
import plistlib
import pkg_resources
import sys
import subprocess
import zipfile
@ -58,6 +57,7 @@ def _register_python_loaders():
registry = p3d.LoaderFileTypeRegistry.getGlobalPtr()
import pkg_resources
for entry_point in pkg_resources.iter_entry_points('panda3d.loaders'):
registry.register_deferred_type(entry_point)
@ -125,7 +125,7 @@ PACKAGE_LIB_DIRS = {
'PyQt5': [('PyQt5/Qt5/bin', 'PyQt5_Qt5')],
}
SITE_PY = u"""
SITE_PY = """
import sys
from _frozen_importlib import _imp, FrozenImporter
@ -592,7 +592,7 @@ class build_apps(setuptools.Command):
whlcache = os.path.join(self.build_base, '__whl_cache__')
pip_version = int(pip.__version__.split('.')[0])
pip_version = int(pip.__version__.split('.', 1)[0])
if pip_version < 9:
raise RuntimeError("pip 9.0 or greater is required, but found {}".format(pip.__version__))
@ -1121,7 +1121,7 @@ class build_apps(setuptools.Command):
# Remove python version string
parts = basename.split('.')
if len(parts) >= 3 and '-' in parts[-2]:
if len(parts) >= 3 and ('-' in parts[-2] or parts[-2] == 'abi' + str(sys.version_info[0])):
parts = parts[:-2] + parts[-1:]
basename = '.'.join(parts)
@ -1494,7 +1494,8 @@ class build_apps(setuptools.Command):
for idx in string_tables.keys():
elf.seek(shoff + idx * shentsize)
type, offset, size, link, entsize = struct.unpack_from(section_struct, elf.read(shentsize))
if type != 3: continue
if type != 3:
continue
elf.seek(offset)
string_tables[idx] = elf.read(size)

View File

@ -1,4 +1,4 @@
from direct.directnotify.DirectNotifyGlobal import *
from direct.directnotify.DirectNotifyGlobal import directNotify
from panda3d.core import PNMImage, Filename, PNMFileTypeRegistry, StringStream
import struct
@ -114,9 +114,6 @@ class Icon:
for x in range(size):
pixel = image2.get_pixel(x, size - y - 1)
index = colors.index(pixel)
if index >= 256:
# Find closest pixel instead.
index = closest_indices[index - 256]
fp.write(struct.pack('<B', index))
fp.write(rowalign)
else:

View File

@ -271,7 +271,7 @@ def create_aab(command, basename, build_dir):
bundle.add_subfile('base/manifest/AndroidManifest.xml', p3d.StringStream(axml.dumps()), 9)
# Add the classes.dex.
bundle.add_subfile(f'base/dex/classes.dex', build_dir_fn / 'classes.dex', 9)
bundle.add_subfile('base/dex/classes.dex', build_dir_fn / 'classes.dex', 9)
# Add libraries, compressed.
for abi in os.listdir(os.path.join(build_dir, 'lib')):
@ -302,7 +302,7 @@ def create_aab(command, basename, build_dir):
# It appears to be encrypted, and we don't have a passphrase, so we
# must request it on the command-line.
from getpass import getpass
password = getpass(f'Enter pass phrase for private key: ')
password = getpass('Enter pass phrase for private key: ')
if not bundle.add_jar_signature(
p3d.Filename.from_os_specific(command.signing_certificate),

View File

@ -28,6 +28,7 @@ def _unpack_zstring(mem, offs=0):
c = mem[offs]
return str
def _unpack_wstring(mem, offs=0):
"Read a UCS-2 string from memory."
name_len, = unpack('<H', mem[offs:offs+2])
@ -37,6 +38,7 @@ def _unpack_wstring(mem, offs=0):
name += chr(*unpack('<H', mem[offs:offs+2]))
return name
def _padded(n, boundary):
align = n % boundary
if align:
@ -250,11 +252,11 @@ class VersionInfoResource(object):
self.struct_version = dwords[1]
if len(dwords) > 3:
self.file_version = \
(int(dwords[2] >> 16), int(dwords[2] & 0xffff),
(int(dwords[2] >> 16), int(dwords[2] & 0xffff),
int(dwords[3] >> 16), int(dwords[3] & 0xffff))
if len(dwords) > 5:
self.product_version = \
(int(dwords[4] >> 16), int(dwords[4] & 0xffff),
(int(dwords[4] >> 16), int(dwords[4] & 0xffff),
int(dwords[5] >> 16), int(dwords[5] & 0xffff))
if len(dwords) > 7:
self.file_flags_mask = dwords[6]
@ -302,7 +304,7 @@ class VersionInfoResource(object):
# It contains a value.
if type:
# It's a wchar array value.
value = u""
value = ""
c, = unpack('<H', data[offset:offset+2])
offset += 2
while c:

View File

@ -2,7 +2,8 @@
from direct.directnotify import DirectNotifyGlobal
from direct.showbase.DirectObject import DirectObject
from direct.showbase.MessengerGlobal import messenger
from .ConnectionRepository import *
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr
from panda3d.core import ConfigVariableDouble, ConfigVariableInt, ConfigVariableBool
ASYNC_REQUEST_DEFAULT_TIMEOUT_IN_SECONDS = 8.0
@ -266,4 +267,4 @@ def cleanupAsyncRequests():
"""
for asyncRequest in AsyncRequest._asyncRequests:
asyncRequest.delete()
assert AsyncRequest._asyncRequests == {}
assert not AsyncRequest._asyncRequests

View File

@ -3,7 +3,19 @@
from .ClientRepositoryBase import ClientRepositoryBase
from direct.directnotify import DirectNotifyGlobal
from direct.showbase.MessengerGlobal import messenger
from .MsgTypesCMU import *
from .MsgTypesCMU import (
CLIENT_DISCONNECT_CMU,
CLIENT_HEARTBEAT_CMU,
CLIENT_OBJECT_UPDATE_FIELD_TARGETED_CMU,
CLIENT_SET_INTEREST_CMU,
OBJECT_DELETE_CMU,
OBJECT_DISABLE_CMU,
OBJECT_GENERATE_CMU,
OBJECT_SET_ZONE_CMU,
OBJECT_UPDATE_FIELD_CMU,
REQUEST_GENERATES_CMU,
SET_DOID_RANGE_CMU,
)
from .PyDatagram import PyDatagram
from .PyDatagramIterator import PyDatagramIterator
from panda3d.core import UniqueIdAllocator, Notify, ClockObject

View File

@ -1,5 +1,10 @@
from panda3d.core import *
from panda3d.direct import *
from panda3d.core import (
ClockObject,
ConfigVariableBool,
ConfigVariableDouble,
Datagram,
DatagramIterator,
)
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr
from direct.directnotify import DirectNotifyGlobal
@ -7,11 +12,10 @@ from direct.distributed.CRDataCache import CRDataCache
from direct.distributed.ConnectionRepository import ConnectionRepository
from direct.showbase.PythonUtil import safeRepr, itype, makeList
from direct.showbase.MessengerGlobal import messenger
from .MsgTypes import *
from .MsgTypes import CLIENT_ENTER_OBJECT_REQUIRED_OTHER, MsgId2Names
from . import CRCache
from . import ParentMgr
from . import RelatedObjectMgr
from .ClockDelta import *
import time
@ -106,7 +110,7 @@ class ClientRepositoryBase(ConnectionRepository):
## self.flush()
def specialName(self, label):
name = ("SpecialName %s %s" % (self.specialNameNumber, label))
name = f"SpecialName {self.specialNameNumber} {label}"
self.specialNameNumber += 1
return name
@ -118,7 +122,7 @@ class ClientRepositoryBase(ConnectionRepository):
def _getMsgName(self, msgId):
# we might get a list of message names, use the first one
return makeList(MsgId2Names.get(msgId, 'UNKNOWN MESSAGE: %s' % msgId))[0]
return makeList(MsgId2Names.get(msgId, f'UNKNOWN MESSAGE: {msgId}'))[0]
def allocateContext(self):
self.context+=1
@ -157,7 +161,7 @@ class ClientRepositoryBase(ConnectionRepository):
# Look up the dclass
assert parentId == self.GameGlobalsId or parentId in self.doId2do
dclass = self.dclassesByNumber[classId]
assert self.notify.debug("performing generate for %s %s" % (dclass.getName(), doId))
assert self.notify.debug(f"performing generate for {dclass.getName()} {doId}")
dclass.startGenerate()
# Create a new distributed object, and put it in the dictionary
distObj = self.generateWithRequiredOtherFields(dclass, doId, di, parentId, zoneId)
@ -358,7 +362,6 @@ class ClientRepositoryBase(ConnectionRepository):
# updateRequiredOtherFields calls announceGenerate
return distObj
def disableDoId(self, doId, ownerView=False):
table, cache = self.getTables(ownerView)
# Make sure the object exists
@ -442,7 +445,6 @@ class ClientRepositoryBase(ConnectionRepository):
# This object has been fully generated. It's OK to update.
self.__doUpdate(doId, di, ovUpdated)
def __doUpdate(self, doId, di, ovUpdated):
# Find the DO
do = self.doId2do.get(doId)
@ -463,13 +465,12 @@ class ClientRepositoryBase(ConnectionRepository):
if handle:
dclass = self.dclassesByName[handle.dclassName]
dclass.receiveUpdate(handle, di)
else:
self.notify.warning(
"Asked to update non-existent DistObj " + str(doId))
except:
f"Asked to update non-existent DistObj {doId}")
except Exception:
self.notify.warning(
"Asked to update non-existent DistObj " + str(doId) + "and failed to find it")
f"Asked to update non-existent DistObj {doId} and failed to find it")
def __doUpdateOwner(self, doId, di):
ovObj = self.doId2ownerView.get(doId)
@ -488,7 +489,7 @@ class ClientRepositoryBase(ConnectionRepository):
self.bootedText = di.getString()
self.notify.warning(
"Server is booting us out (%d): %s" % (self.bootedIndex, self.bootedText))
f"Server is booting us out ({self.bootedIndex}): {self.bootedText}")
else:
self.bootedIndex = None
self.bootedText = None
@ -536,7 +537,6 @@ class ClientRepositoryBase(ConnectionRepository):
doDict[doId] = do
return doDict
def considerHeartbeat(self):
"""Send a heartbeat message if we haven't sent one recently."""
if not self.heartbeatStarted:
@ -566,7 +566,7 @@ class ClientRepositoryBase(ConnectionRepository):
def waitForNextHeartBeat(self):
taskMgr.doMethodLater(self.heartbeatInterval, self.sendHeartbeatTask,
"heartBeat", taskChain = 'net')
"heartBeat", taskChain='net')
def replaceMethod(self, oldMethod, newFunction):
return 0

View File

@ -1,5 +1,5 @@
from panda3d.core import *
from panda3d.direct import *
from panda3d.core import DocumentSpec, Filename, HTTPClient, VirtualFileSystem, getModelPath
from panda3d.direct import CConnectionRepository, DCPacker
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr
from direct.directnotify.DirectNotifyGlobal import directNotify
@ -13,6 +13,7 @@ import gc
__all__ = ["ConnectionRepository", "GCTrigger"]
class ConnectionRepository(
DoInterestManager, DoCollectionManager, CConnectionRepository):
"""
@ -233,7 +234,7 @@ class ConnectionRepository(
distObj.parentId = 0
distObj.zoneId = 0
# updateRequiredFields calls announceGenerate
return distObj
return distObj
def readDCFile(self, dcFileNames = None):
"""
@ -382,7 +383,7 @@ class ConnectionRepository(
# in the DC file.
for i in range(dcFile.getNumClasses()):
dclass = dcFile.getClass(i)
if (dclass.getName()+ownerDcSuffix) in ownerImportSymbols:
if dclass.getName() + ownerDcSuffix in ownerImportSymbols:
number = dclass.getNumber()
className = dclass.getName() + ownerDcSuffix
@ -466,7 +467,7 @@ class ConnectionRepository(
hasProxy = 0
if self.checkHttp():
proxies = self.http.getProxiesForUrl(serverList[0])
hasProxy = (proxies != 'DIRECT')
hasProxy = proxies != 'DIRECT'
if hasProxy:
self.notify.info("Connecting to gameserver via proxy list: %s" % (proxies))
@ -589,7 +590,7 @@ class ConnectionRepository(
if self.http is None:
try:
self.http = HTTPClient()
except:
except Exception:
pass
return self.http
@ -667,6 +668,7 @@ class ConnectionRepository(
def uniqueName(self, idString):
return "%s-%s" % (idString, self.uniqueId)
class GCTrigger:
# used to trigger garbage collection
pass

View File

@ -1,9 +1,8 @@
from panda3d.core import *
from panda3d.direct import *
from panda3d.core import ConfigVariableInt, GeomNode, NodePath, PerspectiveLens, Point3, VBase2
from direct.fsm.FSM import FSM
from direct.interval.IntervalGlobal import *
from direct.interval.IntervalGlobal import LerpScaleInterval, Sequence
from direct.distributed.DistributedObject import DistributedObject
from direct.showbase.MessengerGlobal import messenger
_camera_id = ConfigVariableInt('camera-id', -1)
_aware_of_cameras = ConfigVariableInt('aware-of-cameras', 0)

View File

@ -1,19 +1,18 @@
from panda3d.core import *
from panda3d.direct import *
from direct.interval.IntervalGlobal import *
from panda3d.core import ConfigVariableBool, TextNode, VBase4, Vec3
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.distributed.DistributedNode import DistributedNode
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr
from direct.gui import DirectGuiGlobals
from direct.showbase.EventGroup import EventGroup
from direct.showbase.PythonUtil import report
from direct.showbase.MessengerGlobal import messenger
from direct.distributed.GridParent import GridParent
if __debug__:
# For grid drawing
from direct.directtools.DirectGeometry import *
from direct.directtools.DirectGeometry import LineNodePath
from direct.showbase.PythonUtil import randFloat
from .CartesianGridBase import CartesianGridBase

View File

@ -1,6 +1,3 @@
from panda3d.core import *
from panda3d.direct import *
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr

View File

@ -1,7 +1,6 @@
"""DistributedObject module: contains the DistributedObject class"""
from panda3d.core import *
from panda3d.direct import *
from panda3d.direct import DCPacker
from direct.showbase.MessengerGlobal import messenger
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.distributed.DistributedObjectBase import DistributedObjectBase
@ -25,7 +24,7 @@ ESNum2Str = {
ESDisabled: 'ESDisabled',
ESGenerating: 'ESGenerating',
ESGenerated: 'ESGenerated',
}
}
class DistributedObject(DistributedObjectBase):
@ -241,7 +240,6 @@ class DistributedObject(DistributedObjectBase):
"""
assert self.notify.debug('announceGenerate(): %s' % (self.doId))
def _deactivateDO(self):
# after this is called, the object is no longer an active DistributedObject
# and it may be placed in the cache
@ -330,9 +328,9 @@ class DistributedObject(DistributedObjectBase):
"""
return self.doId
#This message was moved out of announce generate
#to avoid ordering issues.
def postGenerateMessage(self):
if self.activeState != ESGenerated:
self.activeState = ESGenerated

View File

@ -4,8 +4,6 @@ from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.distributed.DistributedObjectBase import DistributedObjectBase
from direct.showbase.MessengerGlobal import messenger
from direct.showbase import PythonUtil
from panda3d.core import *
from panda3d.direct import *
#from PyDatagram import PyDatagram
#from PyDatagramIterator import PyDatagramIterator

View File

@ -1,8 +1,9 @@
"""DistributedSmoothNode module: contains the DistributedSmoothNode class"""
from panda3d.core import *
from panda3d.direct import *
from .ClockDelta import *
import math
from panda3d.core import ClockObject, ConfigVariableBool, ConfigVariableDouble, NodePath
from panda3d.direct import SmoothMover
from .ClockDelta import globalClockDelta
from . import DistributedNode
from . import DistributedSmoothNodeBase
from direct.task.Task import cont
@ -35,6 +36,8 @@ PredictionLag = ConfigVariableDouble("smooth-prediction-lag", 0.0)
GlobalSmoothing = 0
GlobalPrediction = 0
def globalActivateSmoothing(smoothing, prediction):
""" Globally activates or deactivates smoothing and prediction on
all DistributedSmoothNodes currently in existence, or yet to be
@ -47,6 +50,7 @@ def globalActivateSmoothing(smoothing, prediction):
for obj in base.cr.getAllOfType(DistributedSmoothNode):
obj.activateSmoothing(smoothing, prediction)
# For historical reasons, we temporarily define
# DistributedSmoothNode.activateSmoothing() to be the global function.
# We'll remove this soon, so it won't get confused with the instance
@ -153,6 +157,7 @@ class DistributedSmoothNode(DistributedNode.DistributedNode,
def setSmoothWrtReparents(self, flag):
self._smoothWrtReparents = flag
def getSmoothWrtReparents(self):
return self._smoothWrtReparents
@ -212,42 +217,50 @@ class DistributedSmoothNode(DistributedNode.DistributedNode,
def setSmStop(self, timestamp=None):
self.setComponentTLive(timestamp)
self.stopped = True
def setSmH(self, h, timestamp=None):
self._checkResume(timestamp)
self.setComponentH(h)
self.setComponentTLive(timestamp)
def setSmZ(self, z, timestamp=None):
self._checkResume(timestamp)
self.setComponentZ(z)
self.setComponentTLive(timestamp)
def setSmXY(self, x, y, timestamp=None):
self._checkResume(timestamp)
self.setComponentX(x)
self.setComponentY(y)
self.setComponentTLive(timestamp)
def setSmXZ(self, x, z, timestamp=None):
self._checkResume(timestamp)
self.setComponentX(x)
self.setComponentZ(z)
self.setComponentTLive(timestamp)
def setSmPos(self, x, y, z, timestamp=None):
self._checkResume(timestamp)
self.setComponentX(x)
self.setComponentY(y)
self.setComponentZ(z)
self.setComponentTLive(timestamp)
def setSmHpr(self, h, p, r, timestamp=None):
self._checkResume(timestamp)
self.setComponentH(h)
self.setComponentP(p)
self.setComponentR(r)
self.setComponentTLive(timestamp)
def setSmXYH(self, x, y, h, timestamp):
self._checkResume(timestamp)
self.setComponentX(x)
self.setComponentY(y)
self.setComponentH(h)
self.setComponentTLive(timestamp)
def setSmXYZH(self, x, y, z, h, timestamp=None):
self._checkResume(timestamp)
self.setComponentX(x)
@ -255,6 +268,7 @@ class DistributedSmoothNode(DistributedNode.DistributedNode,
self.setComponentZ(z)
self.setComponentH(h)
self.setComponentTLive(timestamp)
def setSmPosHpr(self, x, y, z, h, p, r, timestamp=None):
self._checkResume(timestamp)
self.setComponentX(x)
@ -284,26 +298,33 @@ class DistributedSmoothNode(DistributedNode.DistributedNode,
@report(types = ['args'], dConfigParam = 'smoothnode')
def setComponentX(self, x):
self.smoother.setX(x)
@report(types = ['args'], dConfigParam = 'smoothnode')
def setComponentY(self, y):
self.smoother.setY(y)
@report(types = ['args'], dConfigParam = 'smoothnode')
def setComponentZ(self, z):
self.smoother.setZ(z)
@report(types = ['args'], dConfigParam = 'smoothnode')
def setComponentH(self, h):
self.smoother.setH(h)
@report(types = ['args'], dConfigParam = 'smoothnode')
def setComponentP(self, p):
self.smoother.setP(p)
@report(types = ['args'], dConfigParam = 'smoothnode')
def setComponentR(self, r):
self.smoother.setR(r)
@report(types = ['args'], dConfigParam = 'smoothnode')
def setComponentL(self, l):
if l != self.zoneId:
# only perform set location if location is different
self.setLocation(self.parentId,l)
@report(types = ['args'], dConfigParam = 'smoothnode')
def setComponentT(self, timestamp):
# This is a little bit hacky. If *this* function is called,
@ -386,18 +407,25 @@ class DistributedSmoothNode(DistributedNode.DistributedNode,
# match set* in more cases than the Disney server does.
def getComponentL(self):
return self.zoneId
def getComponentX(self):
return self.getX()
def getComponentY(self):
return self.getY()
def getComponentZ(self):
return self.getZ()
def getComponentH(self):
return self.getH()
def getComponentP(self):
return self.getP()
def getComponentR(self):
return self.getR()
def getComponentT(self):
return 0
@ -408,7 +436,6 @@ class DistributedSmoothNode(DistributedNode.DistributedNode,
#printStack()
self.smoother.clearPositions(1)
@report(types = ['args'], dConfigParam = 'smoothnode')
def wrtReparentTo(self, parent):
# We override this NodePath method to force it to
@ -464,6 +491,7 @@ class DistributedSmoothNode(DistributedNode.DistributedNode,
"Warning: couldn't find the avatar %d" % (avId))
elif hasattr(other, "d_returnResync") and \
hasattr(self.cr, 'localAvatarDoId'):
globalClock = ClockObject.getGlobalClock()
realTime = globalClock.getRealTime()
serverTime = realTime - globalClockDelta.getDelta()
assert self.notify.info(
@ -474,7 +502,6 @@ class DistributedSmoothNode(DistributedNode.DistributedNode,
serverTime,
globalClockDelta.getUncertainty())
def d_returnResync(self, avId, timestampB, serverTime, uncertainty):
serverTimeSec = math.floor(serverTime)
serverTimeUSec = (serverTime - serverTimeSec) * 10000.0
@ -482,7 +509,7 @@ class DistributedSmoothNode(DistributedNode.DistributedNode,
avId, timestampB, serverTimeSec, serverTimeUSec, uncertainty])
def returnResync(self, avId, timestampB, serverTimeSec, serverTimeUSec,
uncertainty):
uncertainty):
"""
A reply sent by a client whom we recently sent suggestResync
to, this reports the client's new delta information so we can

View File

@ -1,6 +1,6 @@
"""DistributedSmoothNodeBase module: contains the DistributedSmoothNodeBase class"""
from .ClockDelta import *
from .ClockDelta import globalClockDelta
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr
from direct.showbase.PythonUtil import randFloat
@ -13,8 +13,10 @@ class DummyTaskClass:
def setDelay(self, blah):
pass
DummyTask = DummyTaskClass()
class DistributedSmoothNodeBase:
"""common base class for DistributedSmoothNode and DistributedSmoothNodeAI
"""
@ -43,6 +45,7 @@ class DistributedSmoothNodeBase:
def b_clearSmoothing(self):
self.d_clearSmoothing()
self.clearSmoothing()
def d_clearSmoothing(self):
self.sendUpdate("clearSmoothing", [0])
@ -85,7 +88,7 @@ class DistributedSmoothNodeBase:
BT.FULL: self.cnode.broadcastPosHprFull,
BT.XYH: self.cnode.broadcastPosHprXyh,
BT.XY: self.cnode.broadcastPosHprXy,
}
}
# this comment is here so it will show up in a grep for 'def d_broadcastPosHpr'
self.d_broadcastPosHpr = broadcastFuncs[self.broadcastType]

View File

@ -7,15 +7,22 @@ zone, remove interest in that zone.
p.s. A great deal of this code is just code moved from ClientRepository.py.
"""
from panda3d.core import *
from .MsgTypes import *
from direct.showbase.PythonUtil import *
from panda3d.core import ConfigVariableBool
from .MsgTypes import CLIENT_ADD_INTEREST, CLIENT_ADD_INTEREST_MULTIPLE, CLIENT_REMOVE_INTEREST
from direct.showbase import DirectObject
from direct.showbase.MessengerGlobal import messenger
from .PyDatagram import PyDatagram
from direct.directnotify.DirectNotifyGlobal import directNotify
import types
from direct.showbase.PythonUtil import report
from direct.showbase.PythonUtil import (
FrameDelayedCall,
ScratchPad,
SerialNumGen,
report,
serialNum,
uniqueElements,
uniqueName,
)
class InterestState:
StateActive = 'Active'
@ -649,6 +656,7 @@ class DoInterestManager(DirectObject.DirectObject):
if __debug__:
import unittest
import time
class AsyncTestCase(unittest.TestCase):
def setCompleted(self):
@ -663,7 +671,7 @@ if __debug__:
suiteClass = AsyncTestSuite
class AsyncTextTestRunner(unittest.TextTestRunner):
def run(self, testCase):
def run(self, test):
result = self._makeResult()
startTime = time.time()
test(result)

View File

@ -1,6 +1,6 @@
from direct.distributed.DistributedSmoothNodeBase import DistributedSmoothNodeBase
from direct.distributed.GridParent import GridParent
from direct.showbase.PythonUtil import report
from direct.showbase.PythonUtil import report, getBase
class GridChild:

View File

@ -1,3 +1,5 @@
from panda3d.core import NodePath
#
# GridParent.py
# Any object that can be parented to the ocean grid

View File

@ -140,7 +140,7 @@ if ConfigVariableBool('astron-support', True):
'CLIENTAGENT_ADD_INTEREST': 1200,
'CLIENTAGENT_ADD_INTEREST_MULTIPLE': 1201,
'CLIENTAGENT_REMOVE_INTEREST': 1203,
}
}
else:
MsgName2Id = {
# 2 new params: passwd, char bool 0/1 1 = new account
@ -241,7 +241,7 @@ else:
'STATESERVER_OBJECT_CREATE_WITH_REQUIRED_CONTEXT': 2050,
'STATESERVER_OBJECT_CREATE_WITH_REQUIR_OTHER_CONTEXT': 2051,
'STATESERVER_BOUNCE_MESSAGE': 2086,
}
}
# create id->name table for debugging
MsgId2Names = invertDictLossless(MsgName2Id)
@ -261,7 +261,7 @@ QUIET_ZONE_IGNORED_LIST = [
#CLIENT_CREATE_OBJECT_REQUIRED,
#CLIENT_CREATE_OBJECT_REQUIRED_OTHER,
]
]
# The following is a different set of numbers from above.
# These are the sub-message types for CLIENT_LOGIN_2.

View File

@ -20,7 +20,7 @@ MsgName2Id = {
'OBJECT_SET_ZONE_CMU' : 9010,
'CLIENT_HEARTBEAT_CMU' : 9011,
'CLIENT_OBJECT_UPDATE_FIELD_TARGETED_CMU' : 9011,
}
}
if ConfigVariableBool('astron-support', True):
MsgName2Id['CLIENT_OBJECT_UPDATE_FIELD'] = 120 # Matches MsgTypes.CLIENT_OBJECT_SET_FIELD

View File

@ -20,9 +20,9 @@ MESSAGE_TYPES=(
# This is the reverse look up for the recipient of the
# datagram:
MESSAGE_STRINGS={}
for i in zip(MESSAGE_TYPES, range(1, len(MESSAGE_TYPES)+1)):
MESSAGE_STRINGS[i[0]]=i[1]
MESSAGE_STRINGS = {}
for i in zip(MESSAGE_TYPES, range(1, len(MESSAGE_TYPES) + 1)):
MESSAGE_STRINGS[i[0]] = i[1]
class OTPNetMessenger(Messenger):

View File

@ -4,10 +4,30 @@
# of the file rather than every time we call the putArg function.
from panda3d.core import Datagram
from panda3d.direct import *
from panda3d.direct import (
STInt8,
STInt16,
STInt32,
STInt64,
STUint8,
STUint16,
STUint32,
STUint64,
STFloat64,
STString,
STBlob,
STBlob32,
STInt16array,
STInt32array,
STUint16array,
STUint32array,
STInt8array,
STUint8array,
STUint32uint8array,
)
# Import the type numbers
from direct.distributed.MsgTypes import *
from direct.distributed.MsgTypes import CONTROL_CHANNEL
class PyDatagram(Datagram):
@ -28,7 +48,7 @@ class PyDatagram(Datagram):
STString: (Datagram.addString, None),
STBlob: (Datagram.addBlob, None),
STBlob32: (Datagram.addBlob32, None),
}
}
addChannel = Datagram.addUint64

View File

@ -3,8 +3,28 @@
# class variable FuncDict and so we can import DCSubatomicType at the top
# of the file rather than every time we call the putArg function.
from panda3d.core import *
from panda3d.direct import *
from panda3d.core import DatagramIterator
from panda3d.direct import (
STInt8,
STInt16,
STInt32,
STInt64,
STUint8,
STUint16,
STUint32,
STUint64,
STFloat64,
STString,
STBlob,
STBlob32,
STInt16array,
STInt32array,
STUint16array,
STUint32array,
STInt8array,
STUint8array,
STUint32uint8array,
)
# Import the type numbers
@ -26,7 +46,7 @@ class PyDatagramIterator(DatagramIterator):
STString: DatagramIterator.getString,
STBlob: DatagramIterator.getBlob,
STBlob32: DatagramIterator.getBlob32,
}
}
getChannel = DatagramIterator.getUint64

View File

@ -1,7 +1,7 @@
"""SampleObject module: contains the SampleObject class"""
from direct.directnotify.DirectNotifyGlobal import *
from direct.distributed.DistributedObject import *
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.distributed.DistributedObject import DistributedObject
class SampleObject(DistributedObject):

View File

@ -1,8 +1,38 @@
"""ServerRepository module: contains the ServerRepository class"""
from panda3d.core import *
from panda3d.direct import *
from direct.distributed.MsgTypesCMU import *
from panda3d.core import (
ConfigVariableBool,
ConfigVariableDouble,
ConfigVariableInt,
ConnectionWriter,
DatagramIterator,
Filename,
NetAddress,
NetDatagram,
PointerToConnection,
QueuedConnectionListener,
QueuedConnectionManager,
QueuedConnectionReader,
TPLow,
UniqueIdAllocator,
VirtualFileSystem,
getModelPath,
)
from panda3d.direct import DCFile
from direct.distributed.MsgTypesCMU import (
CLIENT_DISCONNECT_CMU,
CLIENT_OBJECT_GENERATE_CMU,
CLIENT_OBJECT_UPDATE_FIELD,
CLIENT_OBJECT_UPDATE_FIELD_TARGETED_CMU,
CLIENT_SET_INTEREST_CMU,
OBJECT_DELETE_CMU,
OBJECT_DISABLE_CMU,
OBJECT_GENERATE_CMU,
OBJECT_SET_ZONE_CMU,
OBJECT_UPDATE_FIELD_CMU,
REQUEST_GENERATES_CMU,
SET_DOID_RANGE_CMU,
)
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr
from direct.directnotify import DirectNotifyGlobal

View File

@ -1,10 +1,10 @@
from panda3d.core import *
from direct.showbase.DirectObject import *
from panda3d.core import ClockObject, ConfigVariableDouble, ConfigVariableInt
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr
from direct.distributed import DistributedObject
from direct.directnotify import DirectNotifyGlobal
from direct.distributed.ClockDelta import globalClockDelta
from direct.showbase.MessengerGlobal import messenger
class TimeManager(DistributedObject.DistributedObject):

View File

@ -1,4 +1,5 @@
from direct.distributed.ClockDelta import *
from direct.directnotify import DirectNotifyGlobal
from direct.distributed.ClockDelta import globalClockDelta
from direct.distributed import DistributedObjectAI
class TimeManagerAI(DistributedObjectAI.DistributedObjectAI):

View File

@ -61,66 +61,66 @@ del privPostEvent
#####################################################################
def popupControls(self, tl = None):
"""
Popup control panel for interval.
"""
import math
# Don't use a regular import, to prevent ModuleFinder from picking
# it up as a dependency when building a .p3d package.
import importlib
EntryScale = importlib.import_module('direct.tkwidgets.EntryScale')
tkinter = importlib.import_module('tkinter')
"""
Popup control panel for interval.
"""
import math
# Don't use a regular import, to prevent ModuleFinder from picking
# it up as a dependency when building a .p3d package.
import importlib
EntryScale = importlib.import_module('direct.tkwidgets.EntryScale')
tkinter = importlib.import_module('tkinter')
if tl is None:
tl = tkinter.Toplevel()
tl.title('Interval Controls')
outerFrame = tkinter.Frame(tl)
def entryScaleCommand(t, s=self):
s.setT(t)
s.pause()
self.es = es = EntryScale.EntryScale(
outerFrame, text = self.getName(),
min = 0, max = math.floor(self.getDuration() * 100) / 100,
command = entryScaleCommand)
es.set(self.getT(), fCommand = 0)
es.pack(expand = 1, fill = tkinter.X)
bf = tkinter.Frame(outerFrame)
# Jump to start and end
def toStart(s=self, es=es):
s.setT(0.0)
s.pause()
def toEnd(s=self):
s.setT(s.getDuration())
s.pause()
jumpToStart = tkinter.Button(bf, text = '<<', command = toStart)
# Stop/play buttons
def doPlay(s=self, es=es):
s.resume(es.get())
if tl is None:
tl = tkinter.Toplevel()
tl.title('Interval Controls')
outerFrame = tkinter.Frame(tl)
def entryScaleCommand(t, s=self):
s.setT(t)
s.pause()
self.es = es = EntryScale.EntryScale(
outerFrame, text = self.getName(),
min = 0, max = math.floor(self.getDuration() * 100) / 100,
command = entryScaleCommand)
es.set(self.getT(), fCommand = 0)
es.pack(expand = 1, fill = tkinter.X)
bf = tkinter.Frame(outerFrame)
# Jump to start and end
def toStart(s=self, es=es):
s.setT(0.0)
s.pause()
def toEnd(s=self):
s.setT(s.getDuration())
s.pause()
jumpToStart = tkinter.Button(bf, text = '<<', command = toStart)
# Stop/play buttons
def doPlay(s=self, es=es):
s.resume(es.get())
stop = tkinter.Button(bf, text = 'Stop',
command = lambda s=self: s.pause())
play = tkinter.Button(
bf, text = 'Play',
command = doPlay)
jumpToEnd = tkinter.Button(bf, text = '>>', command = toEnd)
jumpToStart.pack(side = tkinter.LEFT, expand = 1, fill = tkinter.X)
play.pack(side = tkinter.LEFT, expand = 1, fill = tkinter.X)
stop.pack(side = tkinter.LEFT, expand = 1, fill = tkinter.X)
jumpToEnd.pack(side = tkinter.LEFT, expand = 1, fill = tkinter.X)
bf.pack(expand = 1, fill = tkinter.X)
outerFrame.pack(expand = 1, fill = tkinter.X)
# Add function to update slider during setT calls
def update(t, es=es):
es.set(t, fCommand = 0)
if not hasattr(self, "setTHooks"):
self.setTHooks = []
self.setTHooks.append(update)
self.setWantsTCallback(1)
# Clear out function on destroy
def onDestroy(e, s=self, u=update):
if u in s.setTHooks:
s.setTHooks.remove(u)
tl.bind('<Destroy>', onDestroy)
stop = tkinter.Button(bf, text = 'Stop',
command = lambda s=self: s.pause())
play = tkinter.Button(
bf, text = 'Play',
command = doPlay)
jumpToEnd = tkinter.Button(bf, text = '>>', command = toEnd)
jumpToStart.pack(side = tkinter.LEFT, expand = 1, fill = tkinter.X)
play.pack(side = tkinter.LEFT, expand = 1, fill = tkinter.X)
stop.pack(side = tkinter.LEFT, expand = 1, fill = tkinter.X)
jumpToEnd.pack(side = tkinter.LEFT, expand = 1, fill = tkinter.X)
bf.pack(expand = 1, fill = tkinter.X)
outerFrame.pack(expand = 1, fill = tkinter.X)
# Add function to update slider during setT calls
def update(t, es=es):
es.set(t, fCommand = 0)
if not hasattr(self, "setTHooks"):
self.setTHooks = []
self.setTHooks.append(update)
self.setWantsTCallback(1)
# Clear out function on destroy
def onDestroy(e, s=self, u=update):
if u in s.setTHooks:
s.setTHooks.remove(u)
tl.bind('<Destroy>', onDestroy)
Dtool_funcToMethod(popupControls, CInterval)
del popupControls

View File

@ -8,22 +8,22 @@ from .extension_native_helpers import Dtool_funcToMethod
def spawnTask(self, name = None, callback = None, extraArgs = []):
"""Spawns a task to service the download recently requested
via beginGetDocument(), etc., and/or downloadToFile() or
downloadToRam(). If a callback is specified, that function is
called when the download is complete, passing in the extraArgs
given.
"""Spawns a task to service the download recently requested
via beginGetDocument(), etc., and/or downloadToFile() or
downloadToRam(). If a callback is specified, that function is
called when the download is complete, passing in the extraArgs
given.
Returns the newly-spawned task.
"""
if not name:
name = str(self.getUrl())
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr
task = Task.Task(self.doTask)
task.callback = callback
task.callbackArgs = extraArgs
return taskMgr.add(task, name)
Returns the newly-spawned task.
"""
if not name:
name = str(self.getUrl())
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr
task = Task.Task(self.doTask)
task.callback = callback
task.callbackArgs = extraArgs
return taskMgr.add(task, name)
if hasattr(core, 'HTTPChannel'):
Dtool_funcToMethod(spawnTask, core.HTTPChannel)
@ -31,12 +31,12 @@ del spawnTask
#####################################################################
def doTask(self, task):
from direct.task import Task
if self.run():
return Task.cont
if task.callback:
task.callback(*task.callbackArgs)
return Task.done
from direct.task import Task
if self.run():
return Task.cont
if task.callback:
task.callback(*task.callbackArgs)
return Task.done
if hasattr(core, 'HTTPChannel'):
Dtool_funcToMethod(doTask, core.HTTPChannel)

View File

@ -116,6 +116,7 @@ def remove(self):
warnings.warn("NodePath.remove() is deprecated. Use remove_node() instead.", DeprecationWarning, stacklevel=2)
# Send message in case anyone needs to do something
# before node is deleted
from direct.showbase.MessengerGlobal import messenger
messenger.send('preRemoveNodePath', [self])
# Remove nodePath
self.removeNode()
@ -493,7 +494,7 @@ def showCS(self, mask = None):
npc = self.findAllMatches('**/+CollisionNode')
for p in range(0, npc.getNumPaths()):
np = npc[p]
if (mask == None or (np.node().getIntoCollideMask() & mask).getWord()):
if mask is None or (np.node().getIntoCollideMask() & mask).getWord():
np.show()
Dtool_funcToMethod(showCS, NodePath)
@ -512,7 +513,7 @@ def hideCS(self, mask = None):
npc = self.findAllMatches('**/+CollisionNode')
for p in range(0, npc.getNumPaths()):
np = npc[p]
if (mask == None or (np.node().getIntoCollideMask() & mask).getWord()):
if mask is None or (np.node().getIntoCollideMask() & mask).getWord():
np.hide()
Dtool_funcToMethod(hideCS, NodePath)
@ -667,40 +668,40 @@ del attachCollisionRay
#####################################################################
def flattenMultitex(self, stateFrom = None, target = None,
useGeom = 0, allowTexMat = 0, win = None):
from panda3d.core import MultitexReducer
mr = MultitexReducer()
if target is not None:
mr.setTarget(target)
mr.setUseGeom(useGeom)
mr.setAllowTexMat(allowTexMat)
from panda3d.core import MultitexReducer
mr = MultitexReducer()
if target is not None:
mr.setTarget(target)
mr.setUseGeom(useGeom)
mr.setAllowTexMat(allowTexMat)
if win is None:
win = base.win
if win is None:
win = base.win
if stateFrom is None:
mr.scan(self)
else:
mr.scan(self, stateFrom)
mr.flatten(win)
if stateFrom is None:
mr.scan(self)
else:
mr.scan(self, stateFrom)
mr.flatten(win)
Dtool_funcToMethod(flattenMultitex, NodePath)
del flattenMultitex
#####################################################################
def getNumDescendants(self):
return len(self.findAllMatches('**')) - 1
return len(self.findAllMatches('**')) - 1
Dtool_funcToMethod(getNumDescendants, NodePath)
del getNumDescendants
#####################################################################
def removeNonCollisions(self):
# remove anything that is not collision-related
print("NodePath.removeNonCollisions() is deprecated")
stack = [self]
while len(stack) > 0:
np = stack.pop()
# if there are no CollisionNodes under this node, remove it
if np.find('**/+CollisionNode').isEmpty():
np.detachNode()
else:
stack.extend(np.getChildren())
# remove anything that is not collision-related
print("NodePath.removeNonCollisions() is deprecated")
stack = [self]
while len(stack) > 0:
np = stack.pop()
# if there are no CollisionNodes under this node, remove it
if np.find('**/+CollisionNode').isEmpty():
np.detachNode()
else:
stack.extend(np.getChildren())
Dtool_funcToMethod(removeNonCollisions, NodePath)
del removeNonCollisions
#####################################################################
@ -729,130 +730,130 @@ def subdivideCollisions(self, numSolidsInLeaves):
colNp.stash()
def r_subdivideCollisions(self, solids, numSolidsInLeaves):
# takes a list of solids, returns a list containing some number of lists,
# with the solids evenly distributed between them (recursively nested until
# the lists at the leaves contain no more than numSolidsInLeaves)
# if solids is already small enough, returns solids unchanged
if len(solids) <= numSolidsInLeaves:
return solids
origins = []
avgX = 0
avgY = 0
avgZ = 0
minX = None
minY = None
minZ = None
maxX = None
maxY = None
maxZ = None
for solid in solids:
origin = solid.getCollisionOrigin()
origins.append(origin)
x = origin.getX()
y = origin.getY()
z = origin.getZ()
avgX += x
avgY += y
avgZ += z
if minX is None:
minX = x
minY = y
minZ = z
maxX = x
maxY = y
maxZ = z
else:
minX = min(x, minX)
minY = min(y, minY)
minZ = min(z, minZ)
maxX = max(x, maxX)
maxY = max(y, maxY)
maxZ = max(z, maxZ)
avgX /= len(solids)
avgY /= len(solids)
avgZ /= len(solids)
extentX = maxX - minX
extentY = maxY - minY
extentZ = maxZ - minZ
maxExtent = max(max(extentX, extentY), extentZ)
# sparse octree
xyzSolids = []
XyzSolids = []
xYzSolids = []
XYzSolids = []
xyZSolids = []
XyZSolids = []
xYZSolids = []
XYZSolids = []
midX = avgX
midY = avgY
midZ = avgZ
# throw out axes that are not close to the max axis extent; try and keep
# the divisions square/spherical
if extentX < (maxExtent * .75) or extentX > (maxExtent * 1.25):
midX += maxExtent
if extentY < (maxExtent * .75) or extentY > (maxExtent * 1.25):
midY += maxExtent
if extentZ < (maxExtent * .75) or extentZ > (maxExtent * 1.25):
midZ += maxExtent
for i, solid in enumerate(solids):
origin = origins[i]
x = origin.getX()
y = origin.getY()
z = origin.getZ()
if x < midX:
if y < midY:
if z < midZ:
xyzSolids.append(solids[i])
else:
xyZSolids.append(solids[i])
# takes a list of solids, returns a list containing some number of lists,
# with the solids evenly distributed between them (recursively nested until
# the lists at the leaves contain no more than numSolidsInLeaves)
# if solids is already small enough, returns solids unchanged
if len(solids) <= numSolidsInLeaves:
return solids
origins = []
avgX = 0
avgY = 0
avgZ = 0
minX = None
minY = None
minZ = None
maxX = None
maxY = None
maxZ = None
for solid in solids:
origin = solid.getCollisionOrigin()
origins.append(origin)
x = origin.getX()
y = origin.getY()
z = origin.getZ()
avgX += x
avgY += y
avgZ += z
if minX is None:
minX = x
minY = y
minZ = z
maxX = x
maxY = y
maxZ = z
else:
minX = min(x, minX)
minY = min(y, minY)
minZ = min(z, minZ)
maxX = max(x, maxX)
maxY = max(y, maxY)
maxZ = max(z, maxZ)
avgX /= len(solids)
avgY /= len(solids)
avgZ /= len(solids)
extentX = maxX - minX
extentY = maxY - minY
extentZ = maxZ - minZ
maxExtent = max(extentX, extentY, extentZ)
# sparse octree
xyzSolids = []
XyzSolids = []
xYzSolids = []
XYzSolids = []
xyZSolids = []
XyZSolids = []
xYZSolids = []
XYZSolids = []
midX = avgX
midY = avgY
midZ = avgZ
# throw out axes that are not close to the max axis extent; try and keep
# the divisions square/spherical
if extentX < (maxExtent * .75) or extentX > (maxExtent * 1.25):
midX += maxExtent
if extentY < (maxExtent * .75) or extentY > (maxExtent * 1.25):
midY += maxExtent
if extentZ < (maxExtent * .75) or extentZ > (maxExtent * 1.25):
midZ += maxExtent
for i, solid in enumerate(solids):
origin = origins[i]
x = origin.getX()
y = origin.getY()
z = origin.getZ()
if x < midX:
if y < midY:
if z < midZ:
xyzSolids.append(solids[i])
else:
if z < midZ:
xYzSolids.append(solids[i])
else:
xYZSolids.append(solids[i])
xyZSolids.append(solids[i])
else:
if y < midY:
if z < midZ:
XyzSolids.append(solids[i])
else:
XyZSolids.append(solids[i])
if z < midZ:
xYzSolids.append(solids[i])
else:
if z < midZ:
XYzSolids.append(solids[i])
else:
XYZSolids.append(solids[i])
newSolids = []
if len(xyzSolids) > 0:
newSolids.append(self.r_subdivideCollisions(xyzSolids, numSolidsInLeaves))
if len(XyzSolids) > 0:
newSolids.append(self.r_subdivideCollisions(XyzSolids, numSolidsInLeaves))
if len(xYzSolids) > 0:
newSolids.append(self.r_subdivideCollisions(xYzSolids, numSolidsInLeaves))
if len(XYzSolids) > 0:
newSolids.append(self.r_subdivideCollisions(XYzSolids, numSolidsInLeaves))
if len(xyZSolids) > 0:
newSolids.append(self.r_subdivideCollisions(xyZSolids, numSolidsInLeaves))
if len(XyZSolids) > 0:
newSolids.append(self.r_subdivideCollisions(XyZSolids, numSolidsInLeaves))
if len(xYZSolids) > 0:
newSolids.append(self.r_subdivideCollisions(xYZSolids, numSolidsInLeaves))
if len(XYZSolids) > 0:
newSolids.append(self.r_subdivideCollisions(XYZSolids, numSolidsInLeaves))
#import pdb;pdb.set_trace()
return newSolids
xYZSolids.append(solids[i])
else:
if y < midY:
if z < midZ:
XyzSolids.append(solids[i])
else:
XyZSolids.append(solids[i])
else:
if z < midZ:
XYzSolids.append(solids[i])
else:
XYZSolids.append(solids[i])
newSolids = []
if len(xyzSolids) > 0:
newSolids.append(self.r_subdivideCollisions(xyzSolids, numSolidsInLeaves))
if len(XyzSolids) > 0:
newSolids.append(self.r_subdivideCollisions(XyzSolids, numSolidsInLeaves))
if len(xYzSolids) > 0:
newSolids.append(self.r_subdivideCollisions(xYzSolids, numSolidsInLeaves))
if len(XYzSolids) > 0:
newSolids.append(self.r_subdivideCollisions(XYzSolids, numSolidsInLeaves))
if len(xyZSolids) > 0:
newSolids.append(self.r_subdivideCollisions(xyZSolids, numSolidsInLeaves))
if len(XyZSolids) > 0:
newSolids.append(self.r_subdivideCollisions(XyZSolids, numSolidsInLeaves))
if len(xYZSolids) > 0:
newSolids.append(self.r_subdivideCollisions(xYZSolids, numSolidsInLeaves))
if len(XYZSolids) > 0:
newSolids.append(self.r_subdivideCollisions(XYZSolids, numSolidsInLeaves))
#import pdb;pdb.set_trace()
return newSolids
def r_constructCollisionTree(self, solidTree, parentNode, colName):
from panda3d.core import CollisionNode
for item in solidTree:
if isinstance(item[0], list):
newNode = parentNode.attachNewNode('%s-branch' % colName)
self.r_constructCollisionTree(item, newNode, colName)
else:
cn = CollisionNode('%s-leaf' % colName)
for solid in item:
cn.addSolid(solid)
parentNode.attachNewNode(cn)
from panda3d.core import CollisionNode
for item in solidTree:
if isinstance(item[0], list):
newNode = parentNode.attachNewNode(f'{colName}-branch')
self.r_constructCollisionTree(item, newNode, colName)
else:
cn = CollisionNode(f'{colName}-leaf')
for solid in item:
cn.addSolid(solid)
parentNode.attachNewNode(cn)
Dtool_funcToMethod(subdivideCollisions, NodePath)
Dtool_funcToMethod(r_subdivideCollisions, NodePath)

View File

@ -351,7 +351,7 @@ class CommonFilters:
text += "{\n"
text += " o_color = tex2D(k_txcolor, %s);\n" % (texcoords["color"])
if "CartoonInk" in configuration:
text += CARTOON_BODY % {"texcoord" : texcoords["aux"]}
text += CARTOON_BODY % {"texcoord": texcoords["aux"]}
if "AmbientOcclusion" in configuration:
text += " o_color *= tex2D(k_txssao2, %s).r;\n" % (texcoords["ssao2"])
if "BlurSharpen" in configuration:

View File

@ -25,7 +25,7 @@ from panda3d.core import Camera
from panda3d.core import OrthographicLens
from panda3d.core import AuxBitplaneAttrib
from panda3d.core import LightRampAttrib
from direct.directnotify.DirectNotifyGlobal import *
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.showbase.DirectObject import DirectObject
__all__ = ["FilterManager"]
@ -348,10 +348,10 @@ class FilterManager(DirectObject):
def resizeBuffers(self):
""" Resize all buffers to match the size of the window. """
for i in range(len(self.buffers)):
for i, buffer in enumerate(self.buffers):
(mul, div, align) = self.sizes[i]
(xsize, ysize) = self.getScaledSize(mul, div, align)
self.buffers[i].setSize(xsize, ysize)
buffer.setSize(xsize, ysize)
def cleanup(self):
""" Restore everything to its original state, deleting any

View File

@ -16,7 +16,6 @@ if __debug__:
_debugFsms = {}
def printDebugFsmList():
global _debugFsms
for k in sorted(_debugFsms.keys()):
print("%s %s" % (k, _debugFsms[k]()))
__builtins__['debugFsmList'] = printDebugFsmList
@ -83,7 +82,6 @@ class ClassicFSM(DirectObject):
# doing this.
self.__internalStateInFlux = 0
if __debug__:
global _debugFsms
_debugFsms[name] = weakref.ref(self)
# I know this isn't how __repr__ is supposed to be used, but it
@ -95,12 +93,12 @@ class ClassicFSM(DirectObject):
"""
Print out something useful about the fsm
"""
name = self.getName()
currentState = self.getCurrentState()
if currentState:
str = ("ClassicFSM " + self.getName() + ' in state "' +
currentState.getName() + '"')
str = f'ClassicFSM {name} in state "{currentState.getName()}"'
else:
str = ("ClassicFSM " + self.getName() + ' not in any state')
str = f'ClassicFSM {name} not in any state'
return str
def enterInitialState(self, argList=[]):
@ -152,7 +150,6 @@ class ClassicFSM(DirectObject):
def getCurrentState(self):
return self.__currentState
# lookup funcs
def getStateNamed(self, stateName):
@ -317,7 +314,6 @@ class ClassicFSM(DirectObject):
ClassicFSM.notify.warning(msg)
return 0
def forceTransition(self, aStateName, enterArgList=[], exitArgList=[]):
"""
force a transition -- for debugging ONLY
@ -357,7 +353,7 @@ class ClassicFSM(DirectObject):
self.__currentState.isTransitionDefined(aStateName) or
aStateName in [self.__currentState.getName(),
self.__finalState.getName()]
)
)
if transitionDefined:
return self.request(aStateName, enterArgList, exitArgList)

View File

@ -615,9 +615,8 @@ class FSM(DirectObject):
try:
className = self.__class__.__name__
if self.state:
str = ('%s FSM:%s in state "%s"' % (className, self._name, self.state))
return f'{className} FSM:{self._name} in state "{self.state}"'
else:
str = ('%s FSM:%s in transition from \'%s\' to \'%s\'' % (className, self._name, self.oldState, self.newState))
return str
return f'{className} FSM:{self._name} in transition from \'{self.oldState}\' to \'{self.newState}\''
finally:
self.fsmLock.release()

View File

@ -115,7 +115,7 @@ class FourState:
self.enterState4,
self.exitState4,
[names[1]]),
}
}
self.fsm = ClassicFSM.ClassicFSM('FourState',
list(self.states.values()),
# Initial State

View File

@ -123,7 +123,7 @@ class FourStateAI:
self.enterState4,
self.exitState4,
[names[1]]),
}
}
self.fsm = ClassicFSM.ClassicFSM('FourState',
list(self.states.values()),
# Initial State
@ -145,6 +145,9 @@ class FourStateAI:
assert self.__debugPrint("getState() returning %s"%(self.stateIndex,))
return [self.stateIndex]
def sendUpdate(self, fieldName, args = [], sendToId = None):
raise NotImplementedError
def sendState(self):
assert self.__debugPrint("sendState()")
self.sendUpdate('setState', self.getState())

View File

@ -16,7 +16,7 @@ class ClassicStyle(FSM.FSM):
'Red': ['Green'],
'Yellow': ['Red'],
'Green': ['Yellow'],
}
}
def enterRed(self):
print("enterRed(self, '%s', '%s')" % (self.oldState, self.newState))

View File

@ -251,12 +251,12 @@ class FunctionCall(ReceivesMultipleStateChanges, PushesStateChanges):
if __debug__:
l = []
def handler(value, l=l):
def handler1(value, l=l):
l.append(value)
assert l == []
assert not l
sv = StateVar(0)
fc = FunctionCall(handler, sv)
assert l == []
fc = FunctionCall(handler1, sv)
assert not l
fc.pushCurrentState()
assert l == [0,]
sv.set(1)
@ -267,17 +267,17 @@ if __debug__:
sv.destroy()
del fc
del sv
del handler
del handler1
del l
l = []
def handler(value, kDummy=None, kValue=None, l=l):
def handler2(value, kDummy=None, kValue=None, l=l):
l.append((value, kValue))
assert l == []
assert not l
sv = StateVar(0)
ksv = StateVar('a')
fc = FunctionCall(handler, sv, kValue=ksv)
assert l == []
fc = FunctionCall(handler2, sv, kValue=ksv)
assert not l
fc.pushCurrentState()
assert l == [(0,'a',),]
sv.set(1)
@ -288,7 +288,7 @@ if __debug__:
sv.destroy()
del fc
del sv
del handler
del handler2
del l
class EnterExit(StateChangeNode):
@ -323,7 +323,7 @@ if __debug__:
sv = StateVar(0)
ee = EnterExit(sv, enter, exit)
sv.set(0)
assert l == []
assert not l
sv.set(1)
assert l == [1,]
sv.set(2)
@ -357,7 +357,7 @@ if __debug__:
l.append(value)
p = Pulse()
fc = FunctionCall(handler, p)
assert l == []
assert not l
fc.pushCurrentState()
assert l == [False, ]
p.sendPulse()

View File

@ -6,15 +6,17 @@ in-depth explanation and an example of how to use this class.
__all__ = ['DirectButton']
from panda3d.core import *
from panda3d.core import Mat4, MouseButton, PGButton
from . import DirectGuiGlobals as DGG
from .DirectFrame import *
from .DirectFrame import DirectFrame
class DirectButton(DirectFrame):
"""
DirectButton(parent) - Create a DirectGuiWidget which responds
to mouse clicks and execute a callback function if defined
"""
def __init__(self, parent = None, **kw):
# Inherits from DirectFrame
# A Direct Frame can have:
@ -45,7 +47,7 @@ class DirectButton(DirectFrame):
# 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),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)

View File

@ -1,5 +1,5 @@
from direct.gui.DirectGui import *
from panda3d.core import *
from direct.gui.DirectGui import DGG, DirectButton
from panda3d.core import PGButton
class DirectCheckBox(DirectButton):
@ -10,6 +10,7 @@ class DirectCheckBox(DirectButton):
Uses an image swap rather than a text change to indicate state.
"""
def __init__(self, parent = None, **kw):
optiondefs = (
@ -33,7 +34,7 @@ class DirectCheckBox(DirectButton):
('uncheckedImage', None, None),
('checkedImage', None, None),
('isChecked', False, None),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)
@ -42,7 +43,6 @@ class DirectCheckBox(DirectButton):
self.initialiseoptions(DirectCheckBox)
def commandFunc(self, event):
self['isChecked'] = not self['isChecked']

View File

@ -8,9 +8,10 @@ in-depth explanation and an example of how to use this class.
__all__ = ['DirectCheckButton']
from panda3d.core import *
from .DirectButton import *
from .DirectLabel import *
from panda3d.core import PGFrameStyle, VBase4
from .DirectButton import DirectButton
from .DirectLabel import DirectLabel
class DirectCheckButton(DirectButton):
"""
@ -18,6 +19,7 @@ class DirectCheckButton(DirectButton):
to mouse clicks by setting a state of on or off and execute a callback
function (passing that state through) if defined
"""
def __init__(self, parent = None, **kw):
# Inherits from DirectButton
# A Direct Frame can have:
@ -42,7 +44,7 @@ class DirectCheckButton(DirectButton):
('boxImageScale', 1, None),
('boxImageColor', None, None),
('boxRelief', 'sunken', None),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)
# Initialize superclasses
@ -167,7 +169,6 @@ class DirectCheckButton(DirectButton):
self.indicator.setPos(newpos[0], newpos[1], newpos[2])
def commandFunc(self, event):
self['indicatorValue'] = 1 - self['indicatorValue']
if self.colors is not None:

View File

@ -9,11 +9,11 @@ __all__ = [
'OkCancelDialog', 'YesNoDialog', 'YesNoCancelDialog', 'RetryCancelDialog',
]
from panda3d.core import *
from panda3d.core import NodePath, Point3, TextNode, VBase3
from direct.showbase import ShowBaseGlobal
from . import DirectGuiGlobals as DGG
from .DirectFrame import *
from .DirectButton import *
from .DirectFrame import DirectFrame
from .DirectButton import DirectButton
def findDialog(uniqueName):
@ -120,7 +120,7 @@ class DirectDialog(DirectFrame):
('command', None, None),
('extraArgs', [], None),
('sortOrder', DGG.NO_FADE_SORT_INDEX, None),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs, dynamicGroups = ("button",))
@ -178,7 +178,7 @@ class DirectDialog(DirectFrame):
suppressKeys = self['suppressKeys'],
frameSize = self['buttonSize'],
command = lambda s = self, v = value: s.buttonCommand(v)
)
)
self.buttonList.append(button)
# Update dialog when everything has been initialised
@ -356,6 +356,7 @@ class DirectDialog(DirectFrame):
button.destroy()
DirectFrame.destroy(self)
class OkDialog(DirectDialog):
def __init__(self, parent = None, **kw):
# Inherits from DirectFrame
@ -363,12 +364,13 @@ class OkDialog(DirectDialog):
# Define type of DirectGuiWidget
('buttonTextList', ['OK'], DGG.INITOPT),
('buttonValueList', [DGG.DIALOG_OK], DGG.INITOPT),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)
DirectDialog.__init__(self, parent)
self.initialiseoptions(OkDialog)
class OkCancelDialog(DirectDialog):
def __init__(self, parent = None, **kw):
# Inherits from DirectFrame
@ -376,12 +378,13 @@ class OkCancelDialog(DirectDialog):
# Define type of DirectGuiWidget
('buttonTextList', ['OK','Cancel'], DGG.INITOPT),
('buttonValueList', [DGG.DIALOG_OK, DGG.DIALOG_CANCEL], DGG.INITOPT),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)
DirectDialog.__init__(self, parent)
self.initialiseoptions(OkCancelDialog)
class YesNoDialog(DirectDialog):
def __init__(self, parent = None, **kw):
# Inherits from DirectFrame
@ -389,12 +392,13 @@ class YesNoDialog(DirectDialog):
# Define type of DirectGuiWidget
('buttonTextList', ['Yes', 'No'], DGG.INITOPT),
('buttonValueList', [DGG.DIALOG_YES, DGG.DIALOG_NO], DGG.INITOPT),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)
DirectDialog.__init__(self, parent)
self.initialiseoptions(YesNoDialog)
class YesNoCancelDialog(DirectDialog):
def __init__(self, parent = None, **kw):
# Inherits from DirectFrame
@ -403,12 +407,13 @@ class YesNoCancelDialog(DirectDialog):
('buttonTextList', ['Yes', 'No', 'Cancel'], DGG.INITOPT),
('buttonValueList', [DGG.DIALOG_YES, DGG.DIALOG_NO, DGG.DIALOG_CANCEL],
DGG.INITOPT),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)
DirectDialog.__init__(self, parent)
self.initialiseoptions(YesNoCancelDialog)
class RetryCancelDialog(DirectDialog):
def __init__(self, parent = None, **kw):
# Inherits from DirectFrame
@ -416,7 +421,7 @@ class RetryCancelDialog(DirectDialog):
# Define type of DirectGuiWidget
('buttonTextList', ['Retry','Cancel'], DGG.INITOPT),
('buttonValueList', [DGG.DIALOG_RETRY, DGG.DIALOG_CANCEL], DGG.INITOPT),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)
DirectDialog.__init__(self, parent)

View File

@ -7,13 +7,13 @@ explanation and an example of how to use this class.
__all__ = ['DirectEntry']
from panda3d.core import *
from panda3d.core import ConfigVariableBool, PGEntry, Point3, TextNode, Vec3
from direct.showbase import ShowBaseGlobal
from . import DirectGuiGlobals as DGG
from .DirectFrame import *
from .DirectFrame import DirectFrame
from .OnscreenText import OnscreenText
# import this to make sure it gets pulled into the publish
import encodings.utf_8
import encodings.utf_8 # pylint: disable=unused-import
from direct.showbase.DirectObject import DirectObject
# DirectEntry States:
@ -21,6 +21,7 @@ ENTRY_FOCUS_STATE = PGEntry.SFocus # 0
ENTRY_NO_FOCUS_STATE = PGEntry.SNoFocus # 1
ENTRY_INACTIVE_STATE = PGEntry.SInactive # 2
class DirectEntry(DirectFrame):
"""
DirectEntry(parent) - Create a DirectGuiWidget which responds
@ -82,7 +83,7 @@ class DirectEntry(DirectFrame):
('autoCapitalize', 0, self.autoCapitalizeFunc),
('autoCapitalizeAllowPrefixes', DirectEntry.AllowCapNamePrefixes, None),
('autoCapitalizeForcePrefixes', DirectEntry.ForceCapNamePrefixes, None),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)
@ -215,15 +216,16 @@ class DirectEntry(DirectFrame):
def _handleTyping(self, guiEvent):
self._autoCapitalize()
def _handleErasing(self, guiEvent):
self._autoCapitalize()
def _autoCapitalize(self):
name = self.guiItem.getWtext()
# capitalize each word, allowing for things like McMutton
capName = u''
capName = ''
# track each individual word to detect prefixes like Mc
wordSoFar = u''
wordSoFar = ''
# track whether the previous character was part of a word or not
wasNonWordChar = True
for i, character in enumerate(name):
@ -232,9 +234,9 @@ class DirectEntry(DirectFrame):
# This assumes that string.lower and string.upper will return different
# values for all unicode letters.
# - Don't count apostrophes as a break between words
if character.lower() == character.upper() and character != u"'":
if character.lower() == character.upper() and character != "'":
# we are between words
wordSoFar = u''
wordSoFar = ''
wasNonWordChar = True
else:
capitalize = False

View File

@ -1,10 +1,9 @@
__all__ = ['DirectEntryScroll']
from panda3d.core import *
from panda3d.core import NodePath, OmniBoundingVolume, PGVirtualFrame
from . import DirectGuiGlobals as DGG
from .DirectScrolledFrame import *
from .DirectFrame import *
from .DirectEntry import *
from .DirectFrame import DirectFrame
class DirectEntryScroll(DirectFrame):
def __init__(self, entry, parent = None, **kw):
@ -12,7 +11,7 @@ class DirectEntryScroll(DirectFrame):
('pgFunc', PGVirtualFrame, None),
('relief', None, None),
('clipSize', (-1, 1, -1, 1), self.setClipSize),
)
)
self.defineoptions(kw, optiondefs)
DirectFrame.__init__(self, parent, **kw)
@ -81,7 +80,6 @@ class DirectEntryScroll(DirectFrame):
if abs(distanceToCenter) > (clipExtent * 0.5):
self.moveToCenterCursor()
def moveToCenterCursor(self):
cursorX = self.entry.guiItem.getCursorX() * self.entry['text_scale'][0]
canvasX = self.canvas.getX()
@ -122,7 +120,6 @@ class DirectEntryScroll(DirectFrame):
self.entry = None
DirectFrame.destroy(self)
def getCanvas(self):
return self.canvas

View File

@ -18,9 +18,9 @@ explanation and an example of how to use this class.
__all__ = ['DirectFrame']
from panda3d.core import *
from panda3d.core import Filename, NodePath, PGItem, Texture
from . import DirectGuiGlobals as DGG
from .DirectGuiBase import *
from .DirectGuiBase import DirectGuiWidget
from .OnscreenImage import OnscreenImage
from .OnscreenGeom import OnscreenGeom
from .OnscreenText import OnscreenText

View File

@ -87,14 +87,21 @@ Code overview:
__all__ = ['DirectGuiBase', 'DirectGuiWidget']
from panda3d.core import *
from panda3d.core import (
ConfigVariableBool,
KeyboardButton,
MouseWatcherRegion,
NodePath,
PGFrameStyle,
PGItem,
Point3,
Texture,
Vec3,
)
from direct.showbase import ShowBaseGlobal
from direct.showbase.ShowBase import ShowBase
from direct.showbase.MessengerGlobal import messenger
from . import DirectGuiGlobals as DGG
from .OnscreenText import *
from .OnscreenGeom import *
from .OnscreenImage import *
from direct.directtools.DirectUtil import ROUND_TO
from direct.showbase import DirectObject
from direct.task import Task
@ -652,9 +659,11 @@ class DirectGuiBase(DirectObject.DirectObject):
gEvent = event + self.guiId
self.ignore(gEvent)
def toggleGuiGridSnap():
DirectGuiWidget.snapToGrid = 1 - DirectGuiWidget.snapToGrid
def setGuiGridSpacing(spacing):
DirectGuiWidget.gridSpacing = spacing
@ -715,7 +724,7 @@ class DirectGuiWidget(DirectGuiBase, NodePath):
('suppressMouse', 1, DGG.INITOPT),
('suppressKeys', 0, DGG.INITOPT),
('enableEdit', 1, DGG.INITOPT),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)
@ -822,7 +831,7 @@ class DirectGuiWidget(DirectGuiBase, NodePath):
vMouse2render2d = Point3(event.getMouse()[0], 0, event.getMouse()[1])
editVec = Vec3(vWidget2render2d - vMouse2render2d)
if base.mouseWatcherNode.getModifierButtons().isDown(
KeyboardButton.control()):
KeyboardButton.control()):
t = taskMgr.add(self.guiScaleTask, 'guiEditTask')
t.refPos = vWidget2render2d
t.editVecLen = editVec.length()
@ -904,7 +913,6 @@ class DirectGuiWidget(DirectGuiBase, NodePath):
self.bounds[2] - bw[1],
self.bounds[3] + bw[1])
def getBounds(self, state = 0):
self.stateNodePath[state].calcTightBounds(self.ll, self.ur)
# Scale bounds to give a pad around graphics

View File

@ -5,7 +5,15 @@ that can be used during widget construction
__all__ = []
from panda3d.core import *
from panda3d.core import (
KeyboardButton,
MouseButton,
PGButton,
PGEntry,
PGFrameStyle,
PGSliderBar,
TextNode,
)
defaultFont = None
defaultFontFunc = TextNode.getDefaultFont
@ -138,11 +146,9 @@ def setDefaultFontFunc(newFontFunc):
defaultFontFunc = newFontFunc
def getDefaultDialogGeom():
global defaultDialogGeom
return defaultDialogGeom
def getDefaultDialogRelief():
global defaultDialogRelief
return defaultDialogRelief
def setDefaultDialogGeom(newDialogGeom, relief=None):

View File

@ -4,12 +4,13 @@ __all__ = []
if __name__ == "__main__":
from panda3d.core import Point3
from direct.showbase.ShowBase import ShowBase
from direct.task.TaskManagerGlobal import taskMgr
from . import DirectGuiGlobals
from .DirectGui import *
from .DirectGui import DirectButton, DirectDialog, DirectEntry, DirectFrame, YesNoDialog
#from whrandom import *
from random import *
from random import random
base = ShowBase()

View File

@ -6,14 +6,16 @@ explanation and an example of how to use this class.
__all__ = ['DirectLabel']
from panda3d.core import *
from .DirectFrame import *
from panda3d.core import PGItem
from .DirectFrame import DirectFrame
class DirectLabel(DirectFrame):
"""
DirectLabel(parent) - Create a DirectGuiWidget which has multiple
states. User explicitly chooses a state to display
"""
def __init__(self, parent = None, **kw):
# Inherits from DirectFrame
# A Direct Frame can have:
@ -32,7 +34,7 @@ class DirectLabel(DirectFrame):
('numStates', 1, None),
('state', self.inactiveInitState, None),
('activeState', 0, self.setActiveState),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)

View File

@ -6,12 +6,11 @@ in-depth explanation and an example of how to use this class.
__all__ = ['DirectOptionMenu']
from panda3d.core import *
from panda3d.core import OmniBoundingVolume, TextNode, VBase3
from direct.showbase import ShowBaseGlobal
from . import DirectGuiGlobals as DGG
from .DirectButton import *
from .DirectLabel import *
from .DirectFrame import *
from .DirectButton import DirectButton
from .DirectFrame import DirectFrame
class DirectOptionMenu(DirectButton):
@ -22,6 +21,7 @@ class DirectOptionMenu(DirectButton):
To cancel the popup menu click anywhere on the screen outside of the
popup menu. No command is executed in this case.
"""
def __init__(self, parent = None, **kw):
# Inherits from DirectButton
optiondefs = (
@ -43,7 +43,7 @@ class DirectOptionMenu(DirectButton):
('text_align', TextNode.ALeft, None),
# Remove press effect because it looks a bit funny
('pressEffect', 0, DGG.INITOPT),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)
# Initialize superclasses

View File

@ -9,10 +9,11 @@ in-depth explanation and an example of how to use this class.
__all__ = ['DirectRadioButton']
from panda3d.core import *
from panda3d.core import PGFrameStyle, VBase4
from . import DirectGuiGlobals as DGG
from .DirectButton import *
from .DirectLabel import *
from .DirectButton import DirectButton
from .DirectLabel import DirectLabel
class DirectRadioButton(DirectButton):
"""
@ -20,6 +21,7 @@ class DirectRadioButton(DirectButton):
to mouse clicks by setting given value to given variable and
execute a callback function (passing that state through) if defined
"""
def __init__(self, parent = None, **kw):
# Inherits from DirectButton
# A Direct Frame can have:
@ -54,7 +56,7 @@ class DirectRadioButton(DirectButton):
('boxImageScale', 1.0, None),
('boxImageColor', VBase4(1, 1, 1, 1), None),
('boxRelief', None, None),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)
# Initialize superclasses
@ -194,7 +196,6 @@ class DirectRadioButton(DirectButton):
self.indicator.setPos(newpos[0], newpos[1], newpos[2])
def commandFunc(self, event):
if len(self['value']) == len(self['variable']) != 0:
for i in range(len(self['value'])):

View File

@ -6,10 +6,10 @@ in-depth explanation and an example of how to use this class.
__all__ = ['DirectScrollBar']
from panda3d.core import *
from panda3d.core import PGSliderBar, Vec3
from . import DirectGuiGlobals as DGG
from .DirectFrame import *
from .DirectButton import *
from .DirectFrame import DirectFrame
from .DirectButton import DirectButton
class DirectScrollBar(DirectFrame):
@ -17,6 +17,7 @@ class DirectScrollBar(DirectFrame):
DirectScrollBar -- a widget which represents a scroll bar the user can
use for paging through a large document or panel.
"""
def __init__(self, parent = None, **kw):
optiondefs = (
# Define type of DirectGuiWidget
@ -35,18 +36,18 @@ class DirectScrollBar(DirectFrame):
# Function to be called repeatedly as the bar is scrolled
('command', None, None),
('extraArgs', [], None),
)
)
if kw.get('orientation') in (DGG.VERTICAL, DGG.VERTICAL_INVERTED):
# These are the default options for a vertical layout.
optiondefs += (
('frameSize', (-0.04, 0.04, -0.5, 0.5), None),
)
)
else:
# These are the default options for a horizontal layout.
optiondefs += (
('frameSize', (-0.5, 0.5, -0.04, 0.04), None),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)

View File

@ -6,10 +6,10 @@ in-depth explanation and an example of how to use this class.
__all__ = ['DirectScrolledFrame']
from panda3d.core import *
from panda3d.core import NodePath, PGScrollFrame
from . import DirectGuiGlobals as DGG
from .DirectFrame import *
from .DirectScrollBar import *
from .DirectFrame import DirectFrame
from .DirectScrollBar import DirectScrollBar
class DirectScrolledFrame(DirectFrame):
@ -24,6 +24,7 @@ class DirectScrolledFrame(DirectFrame):
0 and explicitly position and hide or show the scroll bars
yourself.
"""
def __init__(self, parent = None, **kw):
optiondefs = (
# Define type of DirectGuiWidget
@ -35,7 +36,7 @@ class DirectScrolledFrame(DirectFrame):
('autoHideScrollBars', 1, self.setAutoHideScrollBars),
('scrollBarWidth', 0.08, self.setScrollBarWidth),
('borderWidth', (0.01, 0.01), self.setBorderWidth),
)
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)

Some files were not shown because too many files have changed in this diff Show More