mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2025-01-09 17:53:50 +00:00
Initial commit
This commit is contained in:
commit
02c7dc11e4
3305 changed files with 1122482 additions and 0 deletions
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Python artifacts:
|
||||
*.pyc
|
||||
|
||||
# Windows Files
|
||||
*.exe
|
||||
|
||||
# Eclipse IDE:
|
||||
.project
|
||||
.pydevproject
|
||||
|
||||
# PyCharm
|
||||
.idea
|
||||
|
||||
# Mac directory info:
|
||||
.DS_Store
|
||||
|
||||
# Game-specific files and directories:
|
||||
preferences.json
|
||||
*.json
|
||||
logs/
|
||||
screenshots/
|
||||
backups/
|
||||
contentpacks/
|
||||
toondata/
|
||||
resources/
|
||||
panel_save.mp
|
1
PPYTHON_PATH
Normal file
1
PPYTHON_PATH
Normal file
|
@ -0,0 +1 @@
|
|||
"panda/python/ppython.exe"
|
12
README.md
Normal file
12
README.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
# src #
|
||||
|
||||
The source code for Toontown Unlimited.
|
||||
|
||||
### What is this repository for? ###
|
||||
|
||||
* Game Development
|
||||
* Denying Rabbit Stew usage until he learns python.
|
||||
|
||||
It is recommended that you make all of your changes in a fork before committing.
|
||||
|
||||
Do **NOT** erase or revert another person's commit without first consulting them.
|
4
astron/.gitignore
vendored
Normal file
4
astron/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
astrond
|
||||
astrond_debug
|
||||
astrond.exe
|
||||
astrond_debug.exe
|
BIN
astron/astrondlinux
Normal file
BIN
astron/astrondlinux
Normal file
Binary file not shown.
BIN
astron/astrondmac
Normal file
BIN
astron/astrondmac
Normal file
Binary file not shown.
BIN
astron/astrondprod
Normal file
BIN
astron/astrondprod
Normal file
Binary file not shown.
67
astron/config/clientagent-0.yml
Normal file
67
astron/config/clientagent-0.yml
Normal file
|
@ -0,0 +1,67 @@
|
|||
daemon:
|
||||
name: Client Agent #0
|
||||
|
||||
general:
|
||||
eventlogger: 127.0.0.1:7198
|
||||
dc_files:
|
||||
- ../dclass/otp.dc
|
||||
- ../dclass/toon.dc
|
||||
|
||||
uberdogs:
|
||||
- class: CentralLogger
|
||||
id: 4688
|
||||
anonymous: false
|
||||
|
||||
- class: ClientServicesManager
|
||||
id: 4665
|
||||
anonymous: true
|
||||
|
||||
- class: ChatAgent
|
||||
id: 4681
|
||||
anonymous: false
|
||||
|
||||
- class: FriendManager
|
||||
id: 4501
|
||||
anonymous: false
|
||||
|
||||
- class: AvatarFriendsManager
|
||||
id: 4686
|
||||
anonymous: false
|
||||
|
||||
- class: PlayerFriendsManager
|
||||
id: 4687
|
||||
anonymous: false
|
||||
|
||||
- class: TTUFriendsManager
|
||||
id: 4666
|
||||
anonymous: false
|
||||
|
||||
- class: TTSpeedchatRelay
|
||||
id: 4712
|
||||
anonymous: false
|
||||
|
||||
- class: DistributedDeliveryManager
|
||||
id: 4683
|
||||
anonymous: false
|
||||
|
||||
- class: TTCodeRedemptionMgr
|
||||
id: 4695
|
||||
anonymous: false
|
||||
|
||||
- class: GlobalPartyManager
|
||||
id: 4477
|
||||
anonymous: false
|
||||
|
||||
messagedirector:
|
||||
connect: 127.0.0.1:7100
|
||||
|
||||
roles:
|
||||
- type: clientagent
|
||||
bind: 0.0.0.0:7199
|
||||
version: "unlimited-dev"
|
||||
client:
|
||||
relocate: true
|
||||
add_interest: enabled
|
||||
channels:
|
||||
min: 1000000000
|
||||
max: 1000001000
|
67
astron/config/clientagent-1.yml
Normal file
67
astron/config/clientagent-1.yml
Normal file
|
@ -0,0 +1,67 @@
|
|||
daemon:
|
||||
name: Client Agent #1
|
||||
|
||||
general:
|
||||
eventlogger: 127.0.0.1:7198
|
||||
dc_files:
|
||||
- ../dclass/otp.dc
|
||||
- ../dclass/toon.dc
|
||||
|
||||
uberdogs:
|
||||
- class: CentralLogger
|
||||
id: 4688
|
||||
anonymous: false
|
||||
|
||||
- class: ClientServicesManager
|
||||
id: 4665
|
||||
anonymous: true
|
||||
|
||||
- class: ChatAgent
|
||||
id: 4681
|
||||
anonymous: false
|
||||
|
||||
- class: FriendManager
|
||||
id: 4501
|
||||
anonymous: false
|
||||
|
||||
- class: AvatarFriendsManager
|
||||
id: 4686
|
||||
anonymous: false
|
||||
|
||||
- class: PlayerFriendsManager
|
||||
id: 4687
|
||||
anonymous: false
|
||||
|
||||
- class: TTUFriendsManager
|
||||
id: 4666
|
||||
anonymous: false
|
||||
|
||||
- class: TTSpeedchatRelay
|
||||
id: 4712
|
||||
anonymous: false
|
||||
|
||||
- class: DistributedDeliveryManager
|
||||
id: 4683
|
||||
anonymous: false
|
||||
|
||||
- class: TTCodeRedemptionMgr
|
||||
id: 4695
|
||||
anonymous: false
|
||||
|
||||
- class: GlobalPartyManager
|
||||
id: 4477
|
||||
anonymous: false
|
||||
|
||||
messagedirector:
|
||||
connect: 127.0.0.1:7100
|
||||
|
||||
roles:
|
||||
- type: clientagent
|
||||
bind: 0.0.0.0:7299
|
||||
version: "unlimited-dev"
|
||||
client:
|
||||
relocate: true
|
||||
add_interest: enabled
|
||||
channels:
|
||||
min: 1000001001
|
||||
max: 1000002000
|
67
astron/config/clientagent-2.yml
Normal file
67
astron/config/clientagent-2.yml
Normal file
|
@ -0,0 +1,67 @@
|
|||
daemon:
|
||||
name: Client Agent #2
|
||||
|
||||
general:
|
||||
eventlogger: 127.0.0.1:7198
|
||||
dc_files:
|
||||
- ../dclass/otp.dc
|
||||
- ../dclass/toon.dc
|
||||
|
||||
uberdogs:
|
||||
- class: CentralLogger
|
||||
id: 4688
|
||||
anonymous: false
|
||||
|
||||
- class: ClientServicesManager
|
||||
id: 4665
|
||||
anonymous: true
|
||||
|
||||
- class: ChatAgent
|
||||
id: 4681
|
||||
anonymous: false
|
||||
|
||||
- class: FriendManager
|
||||
id: 4501
|
||||
anonymous: false
|
||||
|
||||
- class: AvatarFriendsManager
|
||||
id: 4686
|
||||
anonymous: false
|
||||
|
||||
- class: PlayerFriendsManager
|
||||
id: 4687
|
||||
anonymous: false
|
||||
|
||||
- class: TTUFriendsManager
|
||||
id: 4666
|
||||
anonymous: false
|
||||
|
||||
- class: TTSpeedchatRelay
|
||||
id: 4712
|
||||
anonymous: false
|
||||
|
||||
- class: DistributedDeliveryManager
|
||||
id: 4683
|
||||
anonymous: false
|
||||
|
||||
- class: TTCodeRedemptionMgr
|
||||
id: 4695
|
||||
anonymous: false
|
||||
|
||||
- class: GlobalPartyManager
|
||||
id: 4477
|
||||
anonymous: false
|
||||
|
||||
messagedirector:
|
||||
connect: 127.0.0.1:7100
|
||||
|
||||
roles:
|
||||
- type: clientagent
|
||||
bind: 0.0.0.0:7399
|
||||
version: "unlimited-dev"
|
||||
client:
|
||||
relocate: true
|
||||
add_interest: enabled
|
||||
channels:
|
||||
min: 1000002001
|
||||
max: 1000003000
|
67
astron/config/clientagent-3.yml
Normal file
67
astron/config/clientagent-3.yml
Normal file
|
@ -0,0 +1,67 @@
|
|||
daemon:
|
||||
name: Client Agent #3
|
||||
|
||||
general:
|
||||
eventlogger: 127.0.0.1:7198
|
||||
dc_files:
|
||||
- ../dclass/otp.dc
|
||||
- ../dclass/toon.dc
|
||||
|
||||
uberdogs:
|
||||
- class: CentralLogger
|
||||
id: 4688
|
||||
anonymous: false
|
||||
|
||||
- class: ClientServicesManager
|
||||
id: 4665
|
||||
anonymous: true
|
||||
|
||||
- class: ChatAgent
|
||||
id: 4681
|
||||
anonymous: false
|
||||
|
||||
- class: FriendManager
|
||||
id: 4501
|
||||
anonymous: false
|
||||
|
||||
- class: AvatarFriendsManager
|
||||
id: 4686
|
||||
anonymous: false
|
||||
|
||||
- class: PlayerFriendsManager
|
||||
id: 4687
|
||||
anonymous: false
|
||||
|
||||
- class: TTUFriendsManager
|
||||
id: 4666
|
||||
anonymous: false
|
||||
|
||||
- class: TTSpeedchatRelay
|
||||
id: 4712
|
||||
anonymous: false
|
||||
|
||||
- class: DistributedDeliveryManager
|
||||
id: 4683
|
||||
anonymous: false
|
||||
|
||||
- class: TTCodeRedemptionMgr
|
||||
id: 4695
|
||||
anonymous: false
|
||||
|
||||
- class: GlobalPartyManager
|
||||
id: 4477
|
||||
anonymous: false
|
||||
|
||||
messagedirector:
|
||||
connect: 127.0.0.1:7100
|
||||
|
||||
roles:
|
||||
- type: clientagent
|
||||
bind: 0.0.0.0:7499
|
||||
version: "unlimited-dev"
|
||||
client:
|
||||
relocate: true
|
||||
add_interest: enabled
|
||||
channels:
|
||||
min: 1000003001
|
||||
max: 1000004000
|
67
astron/config/clientagent-4.yml
Normal file
67
astron/config/clientagent-4.yml
Normal file
|
@ -0,0 +1,67 @@
|
|||
daemon:
|
||||
name: Client Agent #4
|
||||
|
||||
general:
|
||||
eventlogger: 127.0.0.1:7198
|
||||
dc_files:
|
||||
- ../dclass/otp.dc
|
||||
- ../dclass/toon.dc
|
||||
|
||||
uberdogs:
|
||||
- class: CentralLogger
|
||||
id: 4688
|
||||
anonymous: false
|
||||
|
||||
- class: ClientServicesManager
|
||||
id: 4665
|
||||
anonymous: true
|
||||
|
||||
- class: ChatAgent
|
||||
id: 4681
|
||||
anonymous: false
|
||||
|
||||
- class: FriendManager
|
||||
id: 4501
|
||||
anonymous: false
|
||||
|
||||
- class: AvatarFriendsManager
|
||||
id: 4686
|
||||
anonymous: false
|
||||
|
||||
- class: PlayerFriendsManager
|
||||
id: 4687
|
||||
anonymous: false
|
||||
|
||||
- class: TTUFriendsManager
|
||||
id: 4666
|
||||
anonymous: false
|
||||
|
||||
- class: TTSpeedchatRelay
|
||||
id: 4712
|
||||
anonymous: false
|
||||
|
||||
- class: DistributedDeliveryManager
|
||||
id: 4683
|
||||
anonymous: false
|
||||
|
||||
- class: TTCodeRedemptionMgr
|
||||
id: 4695
|
||||
anonymous: false
|
||||
|
||||
- class: GlobalPartyManager
|
||||
id: 4477
|
||||
anonymous: false
|
||||
|
||||
messagedirector:
|
||||
connect: 127.0.0.1:7100
|
||||
|
||||
roles:
|
||||
- type: clientagent
|
||||
bind: 0.0.0.0:7599
|
||||
version: "unlimited-dev"
|
||||
client:
|
||||
relocate: true
|
||||
add_interest: enabled
|
||||
channels:
|
||||
min: 1000004001
|
||||
max: 1000005000
|
67
astron/config/clientagent-5.yml
Normal file
67
astron/config/clientagent-5.yml
Normal file
|
@ -0,0 +1,67 @@
|
|||
daemon:
|
||||
name: Client Agent #5
|
||||
|
||||
general:
|
||||
eventlogger: 127.0.0.1:7198
|
||||
dc_files:
|
||||
- ../dclass/otp.dc
|
||||
- ../dclass/toon.dc
|
||||
|
||||
uberdogs:
|
||||
- class: CentralLogger
|
||||
id: 4688
|
||||
anonymous: false
|
||||
|
||||
- class: ClientServicesManager
|
||||
id: 4665
|
||||
anonymous: true
|
||||
|
||||
- class: ChatAgent
|
||||
id: 4681
|
||||
anonymous: false
|
||||
|
||||
- class: FriendManager
|
||||
id: 4501
|
||||
anonymous: false
|
||||
|
||||
- class: AvatarFriendsManager
|
||||
id: 4686
|
||||
anonymous: false
|
||||
|
||||
- class: PlayerFriendsManager
|
||||
id: 4687
|
||||
anonymous: false
|
||||
|
||||
- class: TTUFriendsManager
|
||||
id: 4666
|
||||
anonymous: false
|
||||
|
||||
- class: TTSpeedchatRelay
|
||||
id: 4712
|
||||
anonymous: false
|
||||
|
||||
- class: DistributedDeliveryManager
|
||||
id: 4683
|
||||
anonymous: false
|
||||
|
||||
- class: TTCodeRedemptionMgr
|
||||
id: 4695
|
||||
anonymous: false
|
||||
|
||||
- class: GlobalPartyManager
|
||||
id: 4477
|
||||
anonymous: false
|
||||
|
||||
messagedirector:
|
||||
connect: 127.0.0.1:7100
|
||||
|
||||
roles:
|
||||
- type: clientagent
|
||||
bind: 0.0.0.0:7699
|
||||
version: "unlimited-dev"
|
||||
client:
|
||||
relocate: true
|
||||
add_interest: enabled
|
||||
channels:
|
||||
min: 1000005001
|
||||
max: 1000006000
|
67
astron/config/clientagent-6.yml
Normal file
67
astron/config/clientagent-6.yml
Normal file
|
@ -0,0 +1,67 @@
|
|||
daemon:
|
||||
name: Client Agent #6
|
||||
|
||||
general:
|
||||
eventlogger: 127.0.0.1:7198
|
||||
dc_files:
|
||||
- ../dclass/otp.dc
|
||||
- ../dclass/toon.dc
|
||||
|
||||
uberdogs:
|
||||
- class: CentralLogger
|
||||
id: 4688
|
||||
anonymous: false
|
||||
|
||||
- class: ClientServicesManager
|
||||
id: 4665
|
||||
anonymous: true
|
||||
|
||||
- class: ChatAgent
|
||||
id: 4681
|
||||
anonymous: false
|
||||
|
||||
- class: FriendManager
|
||||
id: 4501
|
||||
anonymous: false
|
||||
|
||||
- class: AvatarFriendsManager
|
||||
id: 4686
|
||||
anonymous: false
|
||||
|
||||
- class: PlayerFriendsManager
|
||||
id: 4687
|
||||
anonymous: false
|
||||
|
||||
- class: TTUFriendsManager
|
||||
id: 4666
|
||||
anonymous: false
|
||||
|
||||
- class: TTSpeedchatRelay
|
||||
id: 4712
|
||||
anonymous: false
|
||||
|
||||
- class: DistributedDeliveryManager
|
||||
id: 4683
|
||||
anonymous: false
|
||||
|
||||
- class: TTCodeRedemptionMgr
|
||||
id: 4695
|
||||
anonymous: false
|
||||
|
||||
- class: GlobalPartyManager
|
||||
id: 4477
|
||||
anonymous: false
|
||||
|
||||
messagedirector:
|
||||
connect: 127.0.0.1:7100
|
||||
|
||||
roles:
|
||||
- type: clientagent
|
||||
bind: 0.0.0.0:7799
|
||||
version: "unlimited-dev"
|
||||
client:
|
||||
relocate: true
|
||||
add_interest: enabled
|
||||
channels:
|
||||
min: 1000006001
|
||||
max: 1000007000
|
67
astron/config/clientagent-7.yml
Normal file
67
astron/config/clientagent-7.yml
Normal file
|
@ -0,0 +1,67 @@
|
|||
daemon:
|
||||
name: Client Agent #7
|
||||
|
||||
general:
|
||||
eventlogger: 127.0.0.1:7198
|
||||
dc_files:
|
||||
- ../dclass/otp.dc
|
||||
- ../dclass/toon.dc
|
||||
|
||||
uberdogs:
|
||||
- class: CentralLogger
|
||||
id: 4688
|
||||
anonymous: false
|
||||
|
||||
- class: ClientServicesManager
|
||||
id: 4665
|
||||
anonymous: true
|
||||
|
||||
- class: ChatAgent
|
||||
id: 4681
|
||||
anonymous: false
|
||||
|
||||
- class: FriendManager
|
||||
id: 4501
|
||||
anonymous: false
|
||||
|
||||
- class: AvatarFriendsManager
|
||||
id: 4686
|
||||
anonymous: false
|
||||
|
||||
- class: PlayerFriendsManager
|
||||
id: 4687
|
||||
anonymous: false
|
||||
|
||||
- class: TTUFriendsManager
|
||||
id: 4666
|
||||
anonymous: false
|
||||
|
||||
- class: TTSpeedchatRelay
|
||||
id: 4712
|
||||
anonymous: false
|
||||
|
||||
- class: DistributedDeliveryManager
|
||||
id: 4683
|
||||
anonymous: false
|
||||
|
||||
- class: TTCodeRedemptionMgr
|
||||
id: 4695
|
||||
anonymous: false
|
||||
|
||||
- class: GlobalPartyManager
|
||||
id: 4477
|
||||
anonymous: false
|
||||
|
||||
messagedirector:
|
||||
connect: 127.0.0.1:7100
|
||||
|
||||
roles:
|
||||
- type: clientagent
|
||||
bind: 0.0.0.0:7899
|
||||
version: "unlimited-dev"
|
||||
client:
|
||||
relocate: true
|
||||
add_interest: enabled
|
||||
channels:
|
||||
min: 1000007001
|
||||
max: 1000008000
|
89
astron/config/cluster.yml
Normal file
89
astron/config/cluster.yml
Normal file
|
@ -0,0 +1,89 @@
|
|||
daemon:
|
||||
name: Developer Cluster
|
||||
|
||||
general:
|
||||
eventlogger: 127.0.0.1:7198
|
||||
dc_files:
|
||||
- ../dclass/otp.dc
|
||||
- ../dclass/toon.dc
|
||||
|
||||
messagedirector:
|
||||
bind: 127.0.0.1:7100
|
||||
|
||||
uberdogs:
|
||||
- class: CentralLogger
|
||||
id: 4688
|
||||
anonymous: false
|
||||
|
||||
- class: ClientServicesManager
|
||||
id: 4665
|
||||
anonymous: true
|
||||
|
||||
- class: ChatAgent
|
||||
id: 4681
|
||||
anonymous: false
|
||||
|
||||
- class: FriendManager
|
||||
id: 4501
|
||||
anonymous: false
|
||||
|
||||
- class: AvatarFriendsManager
|
||||
id: 4686
|
||||
anonymous: false
|
||||
|
||||
- class: PlayerFriendsManager
|
||||
id: 4687
|
||||
anonymous: false
|
||||
|
||||
- class: TTUFriendsManager
|
||||
id: 4666
|
||||
anonymous: false
|
||||
|
||||
- class: TTSpeedchatRelay
|
||||
id: 4712
|
||||
anonymous: false
|
||||
|
||||
- class: DistributedDeliveryManager
|
||||
id: 4683
|
||||
anonymous: false
|
||||
|
||||
- class: TTCodeRedemptionMgr
|
||||
id: 4695
|
||||
anonymous: false
|
||||
|
||||
- class: GlobalPartyManager
|
||||
id: 4477
|
||||
anonymous: false
|
||||
|
||||
roles:
|
||||
- type: clientagent
|
||||
bind: 0.0.0.0:7199
|
||||
version: "ttu-dev"
|
||||
client:
|
||||
relocate: true
|
||||
add_interest: enabled
|
||||
channels:
|
||||
min: 1000000000
|
||||
max: 1000001000
|
||||
|
||||
- type: stateserver
|
||||
control: 4002
|
||||
|
||||
- type: database
|
||||
control: 4003
|
||||
generate:
|
||||
min: 100000000
|
||||
max: 399999999
|
||||
backend:
|
||||
type: yaml
|
||||
foldername: ../databases/astrondb
|
||||
|
||||
- type: dbss
|
||||
database: 4003
|
||||
ranges:
|
||||
- min: 100000000
|
||||
max: 399999999
|
||||
|
||||
- type: eventlogger
|
||||
bind: 127.0.0.1:7198
|
||||
output: ../logs/events-%y%m%d_%H%M%S.log
|
7
astron/config/eventlogger.yml
Normal file
7
astron/config/eventlogger.yml
Normal file
|
@ -0,0 +1,7 @@
|
|||
daemon:
|
||||
name: Event Logger
|
||||
|
||||
roles:
|
||||
- type: eventlogger
|
||||
bind: 127.0.0.1:7198
|
||||
output: ../logs/events-%y%m%d_%H%M%S.log
|
31
astron/config/production-cluster.yml
Normal file
31
astron/config/production-cluster.yml
Normal file
|
@ -0,0 +1,31 @@
|
|||
daemon:
|
||||
name: Production Cluster
|
||||
|
||||
general:
|
||||
eventlogger: 127.0.0.1:7198
|
||||
dc_files:
|
||||
- ../dclass/otp.dc
|
||||
- ../dclass/toon.dc
|
||||
|
||||
messagedirector:
|
||||
bind: 127.0.0.1:7100
|
||||
|
||||
roles:
|
||||
- type: stateserver
|
||||
control: 4002
|
||||
|
||||
- type: database
|
||||
control: 4003
|
||||
generate:
|
||||
min: 100000000
|
||||
max: 399999999
|
||||
backend:
|
||||
type: mongodb
|
||||
server: 127.0.0.1:21021
|
||||
database: test
|
||||
|
||||
- type: dbss
|
||||
database: 4003
|
||||
ranges:
|
||||
- min: 100000000
|
||||
max: 399999999
|
35
astron/darwin/start-ai-server.sh
Normal file
35
astron/darwin/start-ai-server.sh
Normal file
|
@ -0,0 +1,35 @@
|
|||
#!/bin/sh
|
||||
cd ../..
|
||||
|
||||
export DYLD_LIBRARY_PATH=`pwd`/Libraries.bundle
|
||||
export DYLD_FRAMEWORK_PATH="Frameworks"
|
||||
|
||||
# Define some constants for our AI server:
|
||||
MAX_CHANNELS=999999
|
||||
STATESERVER=4002
|
||||
ASTRON_IP="127.0.0.1:7100"
|
||||
EVENTLOGGER_IP="127.0.0.1:7198"
|
||||
|
||||
# Get the user input:
|
||||
read -p "District name (DEFAULT: Nuttyboro): " DISTRICT_NAME
|
||||
DISTRICT_NAME=${DISTRICT_NAME:-Nuttyboro}
|
||||
read -p "Base channel (DEFAULT: 401000000): " BASE_CHANNEL
|
||||
BASE_CHANNEL=${BASE_CHANNEL:-401000000}
|
||||
|
||||
echo "==============================="
|
||||
echo "Starting Toontown Unlimited AI server..."
|
||||
echo "District name: $DISTRICT_NAME"
|
||||
echo "Base channel: $BASE_CHANNEL"
|
||||
echo "Max channels: $MAX_CHANNELS"
|
||||
echo "State Server: $STATESERVER"
|
||||
echo "Astron IP: $ASTRON_IP"
|
||||
echo "Event Logger IP: $EVENTLOGGER_IP"
|
||||
echo "==============================="
|
||||
|
||||
while [ true ]
|
||||
do
|
||||
ppython -m toontown.ai.ServiceStart --base-channel $BASE_CHANNEL \
|
||||
--max-channels $MAX_CHANNELS --stateserver $STATESERVER \
|
||||
--astron-ip $ASTRON_IP --eventlogger-ip $EVENTLOGGER_IP \
|
||||
--district-name $DISTRICT_NAME
|
||||
done
|
3
astron/darwin/start-astron-cluster.sh
Normal file
3
astron/darwin/start-astron-cluster.sh
Normal file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
cd ..
|
||||
./astrond --loglevel info config/cluster.yml
|
31
astron/darwin/start-uberdog-server.sh
Normal file
31
astron/darwin/start-uberdog-server.sh
Normal file
|
@ -0,0 +1,31 @@
|
|||
#!/bin/sh
|
||||
cd ../..
|
||||
|
||||
export DYLD_LIBRARY_PATH=`pwd`/Libraries.bundle
|
||||
export DYLD_FRAMEWORK_PATH="Frameworks"
|
||||
|
||||
# Define some constants for our AI server:
|
||||
MAX_CHANNELS=999999
|
||||
STATESERVER=4002
|
||||
ASTRON_IP="127.0.0.1:7100"
|
||||
EVENTLOGGER_IP="127.0.0.1:7198"
|
||||
|
||||
# Get the user input:
|
||||
read -p "Base channel (DEFAULT: 1000000): " BASE_CHANNEL
|
||||
BASE_CHANNEL=${BASE_CHANNEL:-1000000}
|
||||
|
||||
echo "==============================="
|
||||
echo "Starting Toontown Unlimited UberDOG server..."
|
||||
echo "Base channel: $BASE_CHANNEL"
|
||||
echo "Max channels: $MAX_CHANNELS"
|
||||
echo "State Server: $STATESERVER"
|
||||
echo "Astron IP: $ASTRON_IP"
|
||||
echo "Event Logger IP: $EVENTLOGGER_IP"
|
||||
echo "==============================="
|
||||
|
||||
while [ true ]
|
||||
do
|
||||
ppython -m toontown.uberdog.ServiceStart --base-channel $BASE_CHANNEL \
|
||||
--max-channels $MAX_CHANNELS --stateserver $STATESERVER \
|
||||
--astron-ip $ASTRON_IP --eventlogger-ip $EVENTLOGGER_IP
|
||||
done
|
1
astron/databases/.gitignore
vendored
Normal file
1
astron/databases/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
*.db
|
2
astron/databases/astrondb/.gitignore
vendored
Normal file
2
astron/databases/astrondb/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
497
astron/dclass/otp.dc
Normal file
497
astron/dclass/otp.dc
Normal file
|
@ -0,0 +1,497 @@
|
|||
from direct.distributed import DistributedObject/AI/UD
|
||||
from direct.distributed import DistributedNode/AI/UD
|
||||
from direct.distributed import DistributedSmoothNode/AI
|
||||
from direct.distributed import DistributedCartesianGrid/AI
|
||||
from direct.distributed import DistributedCamera/AI/OV
|
||||
from otp.distributed import Account/AI/UD
|
||||
from otp.ai import TimeManager/AI
|
||||
from otp.ai import MagicWordManager/AI
|
||||
from otp.avatar import DistributedAvatar/AI/UD
|
||||
from otp.avatar import DistributedPlayer/AI
|
||||
from otp.friends import FriendManager/AI
|
||||
from otp.friends import AvatarFriendsManager/UD
|
||||
from otp.friends import PlayerFriendsManager/UD
|
||||
from otp.friends import GuildManager/AI/UD
|
||||
from otp.friends import FriendInfo
|
||||
from otp.friends import AvatarFriendInfo
|
||||
from otp.distributed import ObjectServer/AI/UD
|
||||
from otp.distributed import DistributedDistrict/AI/UD
|
||||
from otp.distributed import DistributedDirectory/AI
|
||||
from otp.distributed import DistributedTestObject/AI
|
||||
from otp.snapshot import SnapshotDispatcher/AI/UD
|
||||
from otp.snapshot import SnapshotRenderer/AI/UD
|
||||
from otp.uberdog import OtpAvatarManager/AI/UD
|
||||
from otp.chat import ChatAgent/UD
|
||||
from otp.uberdog import SpeedchatRelay/UD
|
||||
from otp.distributed import CentralLogger/AI/UD
|
||||
from otp.web import SettingsMgr/AI/UD
|
||||
from otp.status import StatusDatabase/UD
|
||||
from otp.avatar import AvatarHandle
|
||||
|
||||
typedef uint8 bool;
|
||||
|
||||
typedef uint32 DoId;
|
||||
|
||||
typedef DoId DoIdList[];
|
||||
|
||||
struct AvatarPendingDel {
|
||||
uint32 Avatar;
|
||||
uint32 date;
|
||||
};
|
||||
|
||||
dclass Account {
|
||||
string DcObjectType db;
|
||||
uint32 ACCOUNT_AV_SET[] required db;
|
||||
uint32 ESTATE_ID db;
|
||||
AvatarPendingDel ACCOUNT_AV_SET_DEL[] db;
|
||||
string CREATED db;
|
||||
string LAST_LOGIN db;
|
||||
string ACCOUNT_ID db;
|
||||
uint16 ACCESS_LEVEL db;
|
||||
uint32 MONEY db;
|
||||
};
|
||||
|
||||
struct BarrierData {
|
||||
uint16 context;
|
||||
string name;
|
||||
DoIdList avIds;
|
||||
};
|
||||
|
||||
dclass DistributedObject {
|
||||
setBarrierData(BarrierData []) broadcast ram;
|
||||
setBarrierReady(uint16 barrierContext) airecv clsend;
|
||||
execCommand(string command, DoId magicWordMgr,
|
||||
DoId avatar, uint32 zoneId);
|
||||
broadcastMessage() broadcast;
|
||||
};
|
||||
|
||||
dclass DistributedTestObject : DistributedObject {
|
||||
uint32 AutoInterest[];
|
||||
setParentingRules(string, string) broadcast ram;
|
||||
setRequiredField(uint32) required broadcast ram;
|
||||
setB(uint32) broadcast;
|
||||
setBA(uint32) broadcast airecv;
|
||||
setBO(uint32) broadcast ownsend;
|
||||
setBR(uint32) broadcast ram;
|
||||
setBRA(uint32) broadcast ram airecv;
|
||||
setBRO(uint32) broadcast ram ownsend;
|
||||
setBROA(uint32) broadcast ram ownsend airecv;
|
||||
};
|
||||
|
||||
struct OSInfo {
|
||||
string name;
|
||||
int16 platform;
|
||||
int16 major;
|
||||
int16 minor;
|
||||
};
|
||||
|
||||
struct CPUSpeed {
|
||||
int32/1000 maxSpeed;
|
||||
int32/1000 currentSpeed;
|
||||
};
|
||||
|
||||
dclass TimeManager : DistributedObject {
|
||||
requestServerTime(uint8 context) airecv clsend;
|
||||
serverTime(uint8 context, int32 timestap, uint32 timeOfDay);
|
||||
setDisconnectReason(uint8) airecv clsend;
|
||||
setExceptionInfo(string(0-1024)) airecv clsend;
|
||||
setSignature(string(0-1024) signature, char prcHash[16],
|
||||
char pycHash[16]) airecv clsend;
|
||||
setFrameRate(uint16/10 fps, uint16/1000 deviation, uint16 numAvatars,
|
||||
string(0-256) locationCode, uint32/10 timeInLocation,
|
||||
uint32/10 timeInGame, string(0-256) gameOptionsCode,
|
||||
uint16 vendorId, uint16 deviceId, uint32/10 processMemory,
|
||||
uint32/10 pageFileUsage, uint32/10 physicalMemory,
|
||||
uint32 pageFaultCount, OSInfo, CPUSpeed, uint16 cpuCores,
|
||||
uint16 logicalCPUs, string(0-256) apiName) airecv clsend;
|
||||
setCpuInfo(string(0-1024) infoStr, string cacheStatus) airecv clsend;
|
||||
checkForGarbageLeaks(bool) airecv clsend;
|
||||
setNumAIGarbageLeaks(uint32);
|
||||
setClientGarbageLeak(uint32, string(0-1024)) airecv clsend;
|
||||
checkAvOnDistrict(uint32 context, DoId avatar) clsend airecv;
|
||||
checkAvOnDistrictResult(uint32 context, DoId av, bool isOnDistrict);
|
||||
};
|
||||
|
||||
dclass ObjectServer {
|
||||
setName(string) airecv ram required;
|
||||
setDcHash(uint32) ram required;
|
||||
setDateCreated(uint32) airecv;
|
||||
};
|
||||
|
||||
dclass DistributedDirectory : DistributedObject {
|
||||
setParentingRules(string, string) broadcast ram;
|
||||
};
|
||||
|
||||
dclass DistributedDistrict : DistributedObject {
|
||||
setName(string) required broadcast ram;
|
||||
setAvailable(uint8) required broadcast ram;
|
||||
};
|
||||
|
||||
dclass DistributedNode : DistributedObject {
|
||||
setParentStr(blob) broadcast ram ownsend airecv;
|
||||
setParent(uint32) broadcast ram ownsend airecv;
|
||||
setX(int16/10) broadcast ram ownsend airecv;
|
||||
setY(int16/10) broadcast ram ownsend airecv;
|
||||
setZ(int16/10) broadcast ram ownsend airecv;
|
||||
setH(int16%360/10) broadcast ram ownsend airecv;
|
||||
setP(int16%360/10) broadcast ram ownsend airecv;
|
||||
setR(int16%360/10) broadcast ram ownsend airecv;
|
||||
setPos : setX, setY, setZ;
|
||||
setHpr : setH, setP, setR;
|
||||
setPosHpr : setX, setY, setZ, setH, setP, setR;
|
||||
setXY : setX, setY;
|
||||
setXZ : setX, setZ;
|
||||
setXYH : setX, setY, setH;
|
||||
setXYZH : setX, setY, setZ, setH;
|
||||
};
|
||||
|
||||
dclass DistributedSmoothNode : DistributedNode {
|
||||
setComponentL(uint64) broadcast ram ownsend airecv;
|
||||
setComponentX(int16/10) broadcast ram ownsend airecv;
|
||||
setComponentY(int16/10) broadcast ram ownsend airecv;
|
||||
setComponentZ(int16/10) broadcast ram ownsend airecv;
|
||||
setComponentH(int16%360/10) broadcast ram ownsend airecv;
|
||||
setComponentP(int16%360/10) broadcast ram ownsend airecv;
|
||||
setComponentR(int16%360/10) broadcast ram ownsend airecv;
|
||||
setComponentT(int16) broadcast ram ownsend airecv;
|
||||
setSmStop : setComponentT;
|
||||
setSmH : setComponentH, setComponentT;
|
||||
setSmZ : setComponentZ, setComponentT;
|
||||
setSmXY : setComponentX, setComponentY, setComponentT;
|
||||
setSmXZ : setComponentX, setComponentZ, setComponentT;
|
||||
setSmPos : setComponentX, setComponentY, setComponentZ, setComponentT;
|
||||
setSmHpr : setComponentH, setComponentP, setComponentR, setComponentT;
|
||||
setSmXYH : setComponentX, setComponentY, setComponentH, setComponentT;
|
||||
setSmXYZH : setComponentX, setComponentY, setComponentZ, setComponentH, setComponentT;
|
||||
setSmPosHpr : setComponentX, setComponentY, setComponentZ, setComponentH, setComponentP, setComponentR, setComponentT;
|
||||
setSmPosHprL : setComponentL, setComponentX, setComponentY, setComponentZ, setComponentH, setComponentP, setComponentR, setComponentT;
|
||||
clearSmoothing(int8) broadcast ownsend;
|
||||
suggestResync(uint32, int16, int16, int32, uint16, uint16/100) ownrecv clsend;
|
||||
returnResync(uint32, int16, int32, uint16, uint16/100) ownrecv clsend;
|
||||
};
|
||||
|
||||
dclass DistributedCartesianGrid : DistributedNode {
|
||||
setCellWidth(uint32) required broadcast ram;
|
||||
setParentingRules(string, string) broadcast ram;
|
||||
};
|
||||
|
||||
struct Fixture {
|
||||
int32/10 x;
|
||||
int32/10 y;
|
||||
int32/10 z;
|
||||
int16/10 h;
|
||||
int16/10 p;
|
||||
int16/10 r;
|
||||
string state;
|
||||
};
|
||||
|
||||
dclass DistributedCamera : DistributedNode {
|
||||
setCamParent(uint32) required broadcast ram ownsend airecv;
|
||||
setFixtures(Fixture []) required broadcast ram ownsend airecv;
|
||||
};
|
||||
|
||||
struct TalkModification {
|
||||
uint16 offset;
|
||||
uint16 size;
|
||||
};
|
||||
|
||||
dclass TalkPath_owner {
|
||||
setTalk(DoId fromAv, DoId fromAcc, string(0-256) avName,
|
||||
string(0-400) chat, TalkModification [], uint8 flags) broadcast ownsend;
|
||||
};
|
||||
|
||||
dclass TalkPath_whisper {
|
||||
setTalkWhisper(DoId fromAv, DoId fromAcc, string(0-256) avName,
|
||||
string(0-400) chat, TalkModification [], uint8 flags) ownrecv clsend;
|
||||
};
|
||||
|
||||
dclass TalkPath_group {
|
||||
setTalkGroup(DoId fromAv, DoId fromAcc, string(0-256) avName,
|
||||
string(0-400) chat, TalkModification [], uint8 flags) clsend airecv;
|
||||
};
|
||||
|
||||
dclass TalkPath_account {
|
||||
setTalkAccount(DoId toAcc, DoId fromAcc, string(0-256) avName,
|
||||
string(0-400) msg, TalkModification [], uint8 flags) airecv clsend;
|
||||
};
|
||||
|
||||
dclass AvatarHandle : TalkPath_whisper {
|
||||
};
|
||||
|
||||
dclass DistributedAvatar : DistributedSmoothNode, TalkPath_whisper {
|
||||
string DcObjectType db;
|
||||
setName(string = "[Name not set]") required broadcast db airecv;
|
||||
friendsNotify(DoId avId, int8 status) ownrecv airecv;
|
||||
checkAvOnShard(DoId) clsend airecv;
|
||||
confirmAvOnShard(DoId avId, int8 isOnShard);
|
||||
setTalk(DoId fromAv, DoId fromAcc, string(0-256) avName,
|
||||
string(0-400) chat, TalkModification [], uint8 flags) broadcast;
|
||||
};
|
||||
|
||||
struct FriendEntry {
|
||||
uint32 friendId;
|
||||
uint8 friendType;
|
||||
}
|
||||
|
||||
dclass DistributedPlayer : DistributedAvatar {
|
||||
arrivedOnDistrict(DoId districtId) ownrecv ram;
|
||||
setAccountName(string name = "") required ownrecv db;
|
||||
setWhisperSCFrom(DoId fromAv, uint16 msgIndex) ownrecv clsend;
|
||||
setWhisperSCCustomFrom(DoId fromAv, uint16 msgIndex) ownrecv clsend;
|
||||
setWhisperSCEmoteFrom(DoId fromAv, uint16 emoteId) ownrecv clsend;
|
||||
setSystemMessage(DoId aboutId, string(0-256) chatString) ownrecv;
|
||||
setCommonChatFlags(uint8) broadcast ownrecv ram airecv;
|
||||
setWhitelistChatFlags(uint8) broadcast ownrecv ram airecv;
|
||||
setSC(uint16 msgIndex) broadcast ownsend airecv;
|
||||
setSCCustom(uint16 msgIndex) broadcast ownsend airecv;
|
||||
setFriendsList(FriendEntry[] = []) ownrecv required db airecv;
|
||||
setDISLname(string) broadcast ownrecv ram;
|
||||
setDISLid(uint32 = 0) broadcast ownrecv ram db airecv required;
|
||||
OwningAccount(DoId);
|
||||
WishName(string = "") db ram;
|
||||
WishNameState(string = "OPEN") db ram;
|
||||
setPreviousAccess(uint8 = 0) required db airecv;
|
||||
setAccess(uint8 = 2) broadcast ownrecv required ram airecv;
|
||||
setAdminAccess(uint16 = 0) broadcast ownrecv required airecv;
|
||||
setAsGM(bool = 0) required ram broadcast ownrecv airecv;
|
||||
};
|
||||
|
||||
dclass MagicWordManager : DistributedObject {
|
||||
sendMagicWord(string, uint32) airecv clsend;
|
||||
sendMagicWordResponse(string);
|
||||
};
|
||||
|
||||
dclass OtpAvatarManager : DistributedObject {
|
||||
online();
|
||||
requestAvatarList(uint32) airecv clsend;
|
||||
rejectAvatarList(uint32);
|
||||
avatarListResponse(blob);
|
||||
requestAvatarSlot(uint32, uint32, uint8) clsend airecv;
|
||||
rejectAvatarSlot(uint32, uint32, uint8);
|
||||
avatarSlotResponse(uint32, uint8);
|
||||
requestPlayAvatar(uint32, uint32, uint32) clsend airecv;
|
||||
rejectPlayAvatar(uint32, uint32);
|
||||
playAvatarResponse(uint32, uint32, uint8, uint8);
|
||||
rejectCreateAvatar(uint32);
|
||||
createAvatarResponse(uint32, uint32, uint8, uint8);
|
||||
requestRemoveAvatar(uint32, uint32, uint32, string(0-256)) airecv clsend;
|
||||
rejectRemoveAvatar(uint32);
|
||||
removeAvatarResponse(uint32, uint32);
|
||||
requestShareAvatar(uint32, uint32, uint32, uint8) airecv clsend;
|
||||
rejectShareAvatar(uint32);
|
||||
shareAvatarResponse(uint32, uint32, uint8);
|
||||
};
|
||||
|
||||
dclass ChatAgent : DistributedObject {
|
||||
adminChat(uint32, string);
|
||||
chatMessage(string(0-256)) clsend;
|
||||
};
|
||||
|
||||
dclass FriendManager : DistributedObject {
|
||||
friendQuery(int32) airecv clsend;
|
||||
cancelFriendQuery(int32) airecv clsend;
|
||||
inviteeFriendConsidering(int8, int32) airecv clsend;
|
||||
inviteeFriendResponse(int8, int32) airecv clsend;
|
||||
inviteeAcknowledgeCancel(int32) airecv clsend;
|
||||
friendConsidering(int8, int32);
|
||||
friendResponse(int8, int32);
|
||||
inviteeFriendQuery(int32, string, blob, int32);
|
||||
inviteeCancelFriendQuery(int32);
|
||||
requestSecret() airecv clsend;
|
||||
requestSecretResponse(int8, string);
|
||||
submitSecret(string(0-256)) airecv clsend;
|
||||
submitSecretResponse(int8, int32);
|
||||
};
|
||||
|
||||
struct FriendInfo {
|
||||
string avatarName;
|
||||
uint32 avatarId;
|
||||
string playerName;
|
||||
uint8 onlineYesNo;
|
||||
uint8 openChatEnabledYesNo;
|
||||
uint8 openChatFriendshipYesNo;
|
||||
uint8 wlChatEnabledYesNo;
|
||||
string location;
|
||||
string sublocation;
|
||||
uint32 timestamp;
|
||||
};
|
||||
|
||||
struct AvatarFriendInfo {
|
||||
string avatarName;
|
||||
string playerName;
|
||||
uint32 playerId;
|
||||
uint8 onlineYesNo;
|
||||
uint8 openChatEnabledYesNo;
|
||||
uint8 openChatFriendshipYesNo;
|
||||
uint8 wlChatEnabledYesNo;
|
||||
};
|
||||
|
||||
struct MemberInfo {
|
||||
uint32 avatarId;
|
||||
string avatarName;
|
||||
uint8 avatarRank;
|
||||
uint8 avatarOnline;
|
||||
uint32 bandManagerId;
|
||||
uint32 bandId;
|
||||
};
|
||||
|
||||
struct leaderBoardRecordResponces {
|
||||
char found;
|
||||
uint32 id;
|
||||
string text;
|
||||
int32 value;
|
||||
};
|
||||
|
||||
struct leaderBoardRecord {
|
||||
uint32 id;
|
||||
string text;
|
||||
int32 value;
|
||||
};
|
||||
|
||||
dclass LeaderBoardReceiver {
|
||||
getTopTenResponce(string, leaderBoardRecord []);
|
||||
getValuesResponce(string, leaderBoardRecordResponces []);
|
||||
};
|
||||
|
||||
dclass LeaderBoard : LeaderBoardReceiver {
|
||||
setValue(string [], uint32, string, int32);
|
||||
alterValue(string [], uint32, string, int32);
|
||||
setHighScore(string [], uint32, string, int32);
|
||||
getValues(string, uint32 []);
|
||||
getTopTen(string);
|
||||
getValuesRespondTo(string, uint32 [], uint32);
|
||||
getTopTenRespondTo(string, uint32);
|
||||
};
|
||||
|
||||
dclass GuildManager : DistributedObject, LeaderBoardReceiver, TalkPath_group {
|
||||
online();
|
||||
guildRejectInvite(uint32, uint32);
|
||||
invitationFrom(uint32, string, uint32, string);
|
||||
requestInvite(uint32) airecv clsend;
|
||||
memberList() airecv clsend;
|
||||
createGuild() airecv clsend;
|
||||
acceptInvite() airecv clsend;
|
||||
declineInvite() airecv clsend;
|
||||
setWantName(string(0-256)) airecv clsend;
|
||||
removeMember(uint32) airecv clsend;
|
||||
changeRank(uint32, uint8) airecv clsend;
|
||||
changeRankAvocate(uint32) airecv clsend;
|
||||
statusRequest() airecv clsend;
|
||||
requestLeaderboardTopTen() airecv clsend;
|
||||
guildStatusUpdate(uint32, string(0-256), uint8);
|
||||
guildNameReject(uint32);
|
||||
guildNameChange(string, uint8);
|
||||
receiveMember(MemberInfo);
|
||||
receiveMembersDone();
|
||||
guildAcceptInvite(uint32);
|
||||
guildDeclineInvite(uint32);
|
||||
updateRep(uint32, uint32);
|
||||
leaderboardTopTen(leaderBoardRecord []);
|
||||
recvAvatarOnline(uint32, string, uint32, uint32);
|
||||
recvAvatarOffline(uint32, string);
|
||||
sendChat(string(0-256), uint8, uint32) airecv clsend;
|
||||
sendWLChat(string(0-256), uint8, uint32) airecv clsend;
|
||||
sendSC(uint16) airecv clsend;
|
||||
sendSCQuest(uint16, uint16, uint16) airecv clsend;
|
||||
recvChat(uint32, string, uint8, uint32);
|
||||
recvWLChat(uint32, string, uint8, uint32);
|
||||
recvSC(uint32, uint16);
|
||||
recvSCQuest(uint32, uint16, uint16, uint16);
|
||||
sendTokenRequest() airecv clsend;
|
||||
recvTokenGenerated(string);
|
||||
recvTokenInviteValue(string, int8);
|
||||
sendTokenForJoinRequest(string(0-256), string(0-256)) airecv clsend;
|
||||
recvTokenRedeemMessage(string);
|
||||
recvTokenRedeemedByPlayerMessage(string);
|
||||
sendTokenRValue(string(0-256), int8) airecv clsend;
|
||||
sendPermToken() airecv clsend;
|
||||
sendNonPermTokenCount() airecv clsend;
|
||||
recvPermToken(string);
|
||||
recvNonPermTokenCount(uint8);
|
||||
sendClearTokens(uint8) airecv clsend;
|
||||
sendAvatarBandId(uint32, uint32, uint32);
|
||||
recvMemberAdded(MemberInfo, uint32, string);
|
||||
notifyGuildKicksMaxed();
|
||||
recvMemberRemoved(uint32, uint32, string, string);
|
||||
recvMemberUpdateName(uint32, string);
|
||||
recvMemberUpdateRank(uint32, uint32, string, string, uint8, bool);
|
||||
recvMemberUpdateBandId(uint32, uint32, uint32);
|
||||
avatarOnline(uint32, uint16);
|
||||
avatarOffline(uint32);
|
||||
reflectTeleportQuery(uint32, uint32, uint32, uint32, uint32) clsend airecv;
|
||||
teleportQuery(uint32, uint32, uint32, uint32, uint32);
|
||||
reflectTeleportResponse(uint32, int8, uint32, uint32, uint32) clsend airecv;
|
||||
teleportResponse(uint32, int8, uint32, uint32, uint32);
|
||||
requestGuildMatesList(uint32, uint32, uint32);
|
||||
updateAvatarName(uint32, string);
|
||||
avatarDeleted(uint32);
|
||||
};
|
||||
|
||||
dclass AvatarFriendsManager : DistributedObject {
|
||||
online();
|
||||
requestInvite(uint32) airecv clsend;
|
||||
friendConsidering(uint32) airecv clsend;
|
||||
invitationFrom(uint32, string);
|
||||
retractInvite(uint32);
|
||||
rejectInvite(uint32, uint32);
|
||||
requestRemove(uint32) airecv clsend;
|
||||
rejectRemove(uint32, uint32);
|
||||
updateAvatarFriend(uint32, AvatarFriendInfo);
|
||||
removeAvatarFriend(uint32);
|
||||
updateAvatarName(uint32, string);
|
||||
avatarOnline(uint32, uint32, string, bool, bool, string, string);
|
||||
avatarOffline(uint32);
|
||||
};
|
||||
|
||||
dclass PlayerFriendsManager : DistributedObject, TalkPath_account {
|
||||
requestInvite(uint32, uint32, uint8) airecv clsend;
|
||||
invitationFrom(uint32, string);
|
||||
retractInvite(uint32);
|
||||
invitationResponse(uint32, uint16, uint32);
|
||||
requestDecline(uint32, uint32) airecv clsend;
|
||||
requestDeclineWithReason(uint32, uint32, uint32) airecv clsend;
|
||||
requestRemove(uint32, uint32) airecv clsend;
|
||||
secretResponse(string);
|
||||
rejectSecret(string);
|
||||
rejectUseSecret(string);
|
||||
updatePlayerFriend(uint32, FriendInfo, uint8);
|
||||
removePlayerFriend(uint32);
|
||||
};
|
||||
|
||||
dclass SnapshotDispatcher : DistributedObject {
|
||||
online();
|
||||
requestRender(uint32);
|
||||
avatarDeleted(uint32);
|
||||
requestNewWork(uint32);
|
||||
errorFetchingAvatar(uint32, uint32);
|
||||
errorRenderingAvatar(uint32, uint32);
|
||||
renderSuccessful(uint32, uint32);
|
||||
};
|
||||
|
||||
dclass SnapshotRenderer : DistributedObject {
|
||||
online();
|
||||
requestRender(uint32, uint32, string);
|
||||
};
|
||||
|
||||
dclass SpeedchatRelay : DistributedObject, TalkPath_account {
|
||||
forwardSpeedchat(uint32, uint8, uint32 [], uint32, string(0-256), uint8) clsend;
|
||||
};
|
||||
|
||||
dclass CentralLogger : DistributedObject {
|
||||
sendMessage(string(0-256), string(0-1024), uint32, uint32) clsend;
|
||||
logAIGarbage() airecv;
|
||||
};
|
||||
|
||||
dclass SettingsMgr : DistributedObject {
|
||||
requestAllChangedSettings() airecv clsend;
|
||||
settingChange(string, string) airecv;
|
||||
};
|
||||
|
||||
dclass StatusDatabase : DistributedObject {
|
||||
requestOfflineAvatarStatus(uint32 []) airecv clsend;
|
||||
recvOfflineAvatarStatus(uint32, uint32);
|
||||
};
|
||||
|
||||
dclass CallbackObject {
|
||||
callback(uint32, bool, uint8);
|
||||
};
|
3429
astron/dclass/toon.dc
Normal file
3429
astron/dclass/toon.dc
Normal file
File diff suppressed because it is too large
Load diff
BIN
astron/libeay32.dll
Normal file
BIN
astron/libeay32.dll
Normal file
Binary file not shown.
32
astron/linux/start-ai-server.sh
Normal file
32
astron/linux/start-ai-server.sh
Normal file
|
@ -0,0 +1,32 @@
|
|||
#!/bin/sh
|
||||
cd ../..
|
||||
|
||||
# Define some constants for our AI server:
|
||||
MAX_CHANNELS=999999
|
||||
STATESERVER=4002
|
||||
ASTRON_IP="127.0.0.1:7100"
|
||||
EVENTLOGGER_IP="127.0.0.1:7198"
|
||||
|
||||
# Get the user input:
|
||||
read -p "District name (DEFAULT: Nuttyboro): " DISTRICT_NAME
|
||||
DISTRICT_NAME=${DISTRICT_NAME:-Nuttyboro}
|
||||
read -p "Base channel (DEFAULT: 401000000): " BASE_CHANNEL
|
||||
BASE_CHANNEL=${BASE_CHANNEL:-401000000}
|
||||
|
||||
echo "==============================="
|
||||
echo "Starting Toontown Unlimited AI server..."
|
||||
echo "District name: $DISTRICT_NAME"
|
||||
echo "Base channel: $BASE_CHANNEL"
|
||||
echo "Max channels: $MAX_CHANNELS"
|
||||
echo "State Server: $STATESERVER"
|
||||
echo "Astron IP: $ASTRON_IP"
|
||||
echo "Event Logger IP: $EVENTLOGGER_IP"
|
||||
echo "==============================="
|
||||
|
||||
while [ true ]
|
||||
do
|
||||
/usr/bin/python2 -m toontown.ai.ServiceStart --base-channel $BASE_CHANNEL \
|
||||
--max-channels $MAX_CHANNELS --stateserver $STATESERVER \
|
||||
--astron-ip $ASTRON_IP --eventlogger-ip $EVENTLOGGER_IP \
|
||||
--district-name $DISTRICT_NAME
|
||||
done
|
3
astron/linux/start-astron-cluster.sh
Normal file
3
astron/linux/start-astron-cluster.sh
Normal file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
cd ..
|
||||
./astrond --loglevel info config/cluster.yml
|
28
astron/linux/start-uberdog-server.sh
Normal file
28
astron/linux/start-uberdog-server.sh
Normal file
|
@ -0,0 +1,28 @@
|
|||
#!/bin/sh
|
||||
cd ../..
|
||||
|
||||
# Define some constants for our AI server:
|
||||
MAX_CHANNELS=999999
|
||||
STATESERVER=4002
|
||||
ASTRON_IP="127.0.0.1:7100"
|
||||
EVENTLOGGER_IP="127.0.0.1:7198"
|
||||
|
||||
# Get the user input:
|
||||
read -p "Base channel (DEFAULT: 1000000): " BASE_CHANNEL
|
||||
BASE_CHANNEL=${BASE_CHANNEL:-1000000}
|
||||
|
||||
echo "==============================="
|
||||
echo "Starting Toontown Unlimited UberDOG server..."
|
||||
echo "Base channel: $BASE_CHANNEL"
|
||||
echo "Max channels: $MAX_CHANNELS"
|
||||
echo "State Server: $STATESERVER"
|
||||
echo "Astron IP: $ASTRON_IP"
|
||||
echo "Event Logger IP: $EVENTLOGGER_IP"
|
||||
echo "==============================="
|
||||
|
||||
while [ true ]
|
||||
do
|
||||
/usr/bin/python2 -m toontown.uberdog.ServiceStart --base-channel $BASE_CHANNEL \
|
||||
--max-channels $MAX_CHANNELS --stateserver $STATESERVER \
|
||||
--astron-ip $ASTRON_IP --eventlogger-ip $EVENTLOGGER_IP
|
||||
done
|
BIN
astron/msvcp120.dll
Normal file
BIN
astron/msvcp120.dll
Normal file
Binary file not shown.
BIN
astron/msvcr120.dll
Normal file
BIN
astron/msvcr120.dll
Normal file
Binary file not shown.
BIN
astron/ssleay32.dll
Normal file
BIN
astron/ssleay32.dll
Normal file
Binary file not shown.
39
config/events/grand-opening.prc
Normal file
39
config/events/grand-opening.prc
Normal file
|
@ -0,0 +1,39 @@
|
|||
# Safe zones:
|
||||
want-donalds-dock #f
|
||||
want-daisys-garden #f
|
||||
want-minnies-melodyland #f
|
||||
want-the-burrrgh #f
|
||||
want-donalds-dreamland #f
|
||||
want-goofy-speedway #f
|
||||
want-outdoor-zone #f
|
||||
want-golf-zone #f
|
||||
|
||||
# Safe zone settings:
|
||||
want-treasure-planners #f
|
||||
|
||||
# Cog headquarters:
|
||||
want-cog-headquarters #f
|
||||
|
||||
# Trolley minigames:
|
||||
want-minigames #f
|
||||
|
||||
# Cog buildings:
|
||||
silly-street-building-min 14
|
||||
silly-street-building-max 14
|
||||
silly-street-building-chance 100.0
|
||||
loopy-lane-building-min 14
|
||||
loopy-lane-building-max 14
|
||||
loopy-lane-building-chance 100.0
|
||||
punchline-place-building-min 14
|
||||
punchline-place-building-max 14
|
||||
punchline-place-building-chance 100.0
|
||||
|
||||
# Core features:
|
||||
want-fishing #f
|
||||
want-housing #f
|
||||
want-pets #f
|
||||
want-parties #f
|
||||
|
||||
# Optional:
|
||||
want-talkative-tyler #f
|
||||
want-yin-yang #f
|
131
config/general.prc
Normal file
131
config/general.prc
Normal file
|
@ -0,0 +1,131 @@
|
|||
# Window settings:
|
||||
window-title Toontown Unlimited
|
||||
win-origin -1 -1
|
||||
icon-filename phase_3/etc/icon.ico
|
||||
cursor-filename phase_3/etc/toonmono.cur
|
||||
|
||||
# Audio:
|
||||
audio-library-name p3fmod_audio
|
||||
|
||||
# Graphics:
|
||||
aux-display pandagl
|
||||
aux-display pandadx9
|
||||
aux-display p3tinydisplay
|
||||
|
||||
# Models:
|
||||
model-path resources/
|
||||
model-cache-models #f
|
||||
model-cache-textures #f
|
||||
default-model-extension .bam
|
||||
|
||||
# Textures:
|
||||
texture-anisotropic-degree 16
|
||||
|
||||
# Preferences:
|
||||
preferences-filename preferences.json
|
||||
|
||||
# Content packs:
|
||||
content-packs-filepath contentpacks/
|
||||
content-packs-sort-filename sort.yaml
|
||||
|
||||
# Backups:
|
||||
backups-filepath backups/
|
||||
backups-extension .json
|
||||
|
||||
# Server:
|
||||
server-timezone EST/EDT/-5
|
||||
server-port 7199
|
||||
account-server-endpoint https://toontownunlimited.com/api/
|
||||
account-bridge-filename astron/databases/account-bridge.db
|
||||
|
||||
# Performance:
|
||||
sync-video #f
|
||||
texture-power-2 none
|
||||
gl-check-errors #f
|
||||
garbage-collect-states #f
|
||||
|
||||
# Egg object types:
|
||||
egg-object-type-barrier <Scalar> collide-mask { 0x01 } <Collide> { Polyset descend }
|
||||
egg-object-type-trigger <Scalar> collide-mask { 0x01 } <Collide> { Polyset descend intangible }
|
||||
egg-object-type-sphere <Scalar> collide-mask { 0x01 } <Collide> { Sphere descend }
|
||||
egg-object-type-trigger-sphere <Scalar> collide-mask { 0x01 } <Collide> { Sphere descend intangible }
|
||||
egg-object-type-floor <Scalar> collide-mask { 0x02 } <Collide> { Polyset descend }
|
||||
egg-object-type-dupefloor <Scalar> collide-mask { 0x02 } <Collide> { Polyset keep descend }
|
||||
egg-object-type-camera-collide <Scalar> collide-mask { 0x04 } <Collide> { Polyset descend }
|
||||
egg-object-type-camera-collide-sphere <Scalar> collide-mask { 0x04 } <Collide> { Sphere descend }
|
||||
egg-object-type-camera-barrier <Scalar> collide-mask { 0x05 } <Collide> { Polyset descend }
|
||||
egg-object-type-camera-barrier-sphere <Scalar> collide-mask { 0x05 } <Collide> { Sphere descend }
|
||||
egg-object-type-model <Model> { 1 }
|
||||
egg-object-type-dcs <DCS> { 1 }
|
||||
|
||||
# Safe zones:
|
||||
want-safe-zones #t
|
||||
want-toontown-central #t
|
||||
want-donalds-dock #t
|
||||
want-daisys-garden #t
|
||||
want-minnies-melodyland #t
|
||||
want-the-burrrgh #t
|
||||
want-donalds-dreamland #t
|
||||
want-goofy-speedway #t
|
||||
want-outdoor-zone #t
|
||||
want-golf-zone #t
|
||||
|
||||
# Safe zone settings:
|
||||
want-treasure-planners #t
|
||||
want-suit-planners #t
|
||||
want-butterflies #f
|
||||
|
||||
# Classic characters:
|
||||
want-classic-chars #f
|
||||
want-mickey #f
|
||||
want-donald-dock #f
|
||||
want-daisy #f
|
||||
want-minnie #f
|
||||
want-pluto #f
|
||||
want-donald-dreamland #f
|
||||
want-chip-and-dale #f
|
||||
want-goofy #f
|
||||
|
||||
# Trolley minigames:
|
||||
want-minigames #t
|
||||
want-photo-game #f
|
||||
want-travel-game #f
|
||||
|
||||
# Picnic table board games:
|
||||
want-game-tables #f
|
||||
|
||||
# Cog headquarters:
|
||||
want-cog-headquarters #t
|
||||
want-sellbot-headquarters #t
|
||||
want-cashbot-headquarters #t
|
||||
want-lawbot-headquarters #t
|
||||
want-bossbot-headquarters #t
|
||||
|
||||
# Cashbot boss:
|
||||
want-resistance-toonup #f
|
||||
want-resistance-restock #f
|
||||
want-resistance-dance #f
|
||||
|
||||
# Cog battles:
|
||||
base-xp-multiplier 1.0
|
||||
|
||||
# Cog buildings:
|
||||
want-cogbuildings #t
|
||||
|
||||
# Optional:
|
||||
show-total-population #t
|
||||
want-mat-all-tailors #t
|
||||
want-long-pattern-game #f
|
||||
want-talkative-tyler #f
|
||||
want-yin-yang #f
|
||||
|
||||
# Developer options:
|
||||
want-dev #f
|
||||
want-pstats 0
|
||||
|
||||
# Temporary:
|
||||
smooth-lag 0.4
|
||||
want-old-fireworks #t
|
||||
|
||||
# Live updates:
|
||||
want-live-updates #t
|
2
config/holidays/christmas.prc
Normal file
2
config/holidays/christmas.prc
Normal file
|
@ -0,0 +1,2 @@
|
|||
want-christmas #t
|
||||
active-holidays 4, 57
|
2
config/holidays/halloween.prc
Normal file
2
config/holidays/halloween.prc
Normal file
|
@ -0,0 +1,2 @@
|
|||
want-halloween #t
|
||||
active-holidays 26, 27, 13
|
42
config/release/dev.prc
Normal file
42
config/release/dev.prc
Normal file
|
@ -0,0 +1,42 @@
|
|||
# Distribution:
|
||||
distribution dev
|
||||
|
||||
# Art assets:
|
||||
model-path resources/
|
||||
|
||||
# Server:
|
||||
server-version ttu-dev
|
||||
min-access-level 600
|
||||
accountdb-type developer
|
||||
shard-low-pop 50
|
||||
shard-mid-pop 100
|
||||
|
||||
# RPC:
|
||||
want-rpc-server #f
|
||||
rpc-server-endpoint http://localhost:8080/
|
||||
|
||||
# DClass files (in reverse order):
|
||||
dc-file astron/dclass/toon.dc
|
||||
dc-file astron/dclass/otp.dc
|
||||
|
||||
# Core features:
|
||||
want-pets #f
|
||||
want-parties #f
|
||||
want-cogdominiums #f
|
||||
want-achievements #f
|
||||
|
||||
# Chat:
|
||||
want-whitelist #f
|
||||
|
||||
# Cashbot boss:
|
||||
want-resistance-toonup #t
|
||||
want-resistance-restock #t
|
||||
want-resistance-dance #t
|
||||
|
||||
# Optional:
|
||||
want-yin-yang #t
|
||||
|
||||
# Developer options:
|
||||
show-population #t
|
||||
force-skip-tutorial #t
|
||||
want-instant-parties #t
|
2
config/release/en.prc
Normal file
2
config/release/en.prc
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Distribution:
|
||||
distribution en
|
29
config/release/test.prc
Normal file
29
config/release/test.prc
Normal file
|
@ -0,0 +1,29 @@
|
|||
# Distribution:
|
||||
distribution test
|
||||
|
||||
# Server:
|
||||
server-version SERVER_VERSION
|
||||
client-agents 8
|
||||
shard-low-pop 100
|
||||
shard-mid-pop 150
|
||||
|
||||
# Core features:
|
||||
want-housing #t
|
||||
want-pets #f
|
||||
want-parties #f
|
||||
want-cogdominiums #f
|
||||
want-achievements #f
|
||||
boarding-group-merges #t
|
||||
|
||||
# Sellbot boss:
|
||||
disable-sos-card 91917
|
||||
disable-sos-card 91918
|
||||
|
||||
# Optional:
|
||||
want-chestnut-park-construction #t
|
||||
|
||||
# Temporary:
|
||||
want-phone-quest #f
|
||||
|
||||
# Staff events:
|
||||
cfo-staff-event #t
|
22
darwin/start-game-localhost.sh
Normal file
22
darwin/start-game-localhost.sh
Normal file
|
@ -0,0 +1,22 @@
|
|||
#!/bin/sh
|
||||
cd ..
|
||||
|
||||
export DYLD_LIBRARY_PATH=`pwd`/Libraries.bundle
|
||||
export DYLD_FRAMEWORK_PATH="Frameworks"
|
||||
|
||||
# Get the user input:
|
||||
read -p "Username: " ttuUsername
|
||||
|
||||
# Export the environment variables:
|
||||
export ttuUsername=$ttuUsername
|
||||
export ttuPassword="password"
|
||||
export TTU_PLAYCOOKIE=$ttuUsername
|
||||
export TTU_GAMESERVER="127.0.0.1"
|
||||
|
||||
echo "==============================="
|
||||
echo "Starting Toontown Unlimited..."
|
||||
echo "Username: $ttuUsername"
|
||||
echo "Gameserver: $TTU_GAMESERVER"
|
||||
echo "==============================="
|
||||
|
||||
ppython -m toontown.toonbase.ClientStart
|
26
darwin/start-game-remotedb.sh
Normal file
26
darwin/start-game-remotedb.sh
Normal file
|
@ -0,0 +1,26 @@
|
|||
#!/bin/sh
|
||||
cd ..
|
||||
|
||||
export DYLD_LIBRARY_PATH=`pwd`/Libraries.bundle
|
||||
export DYLD_FRAMEWORK_PATH="Frameworks"
|
||||
|
||||
# Get the user input:
|
||||
read -p "Username: " ttuUsername
|
||||
read -s -p "Password: " ttuPassword
|
||||
echo
|
||||
read -p "Gameserver (DEFAULT: 167.114.28.238): " TTU_GAMESERVER
|
||||
TTU_GAMESERVER=${TTU_GAMESERVER:-"167.114.28.238"}
|
||||
|
||||
# Export the environment variables:
|
||||
export ttuUsername=$ttuUsername
|
||||
export ttuPassword=$ttuPassword
|
||||
export TTU_PLAYCOOKIE=$ttuUsername
|
||||
export TTU_GAMESERVER=$TTU_GAMESERVER
|
||||
|
||||
echo "==============================="
|
||||
echo "Starting Toontown Unlimited..."
|
||||
echo "Username: $ttuUsername"
|
||||
echo "Gameserver: $TTU_GAMESERVER"
|
||||
echo "==============================="
|
||||
|
||||
ppython -m toontown.toonbase.ClientStartRemoteDB
|
24
darwin/start-game.sh
Normal file
24
darwin/start-game.sh
Normal file
|
@ -0,0 +1,24 @@
|
|||
#!/bin/sh
|
||||
cd ..
|
||||
|
||||
export DYLD_LIBRARY_PATH=`pwd`/Libraries.bundle
|
||||
export DYLD_FRAMEWORK_PATH="Frameworks"
|
||||
|
||||
# Get the user input:
|
||||
read -p "Username: " ttuUsername
|
||||
read -p "Gameserver (DEFAULT: 167.114.28.238): " TTU_GAMESERVER
|
||||
TTU_GAMESERVER=${TTU_GAMESERVER:-"167.114.28.238"}
|
||||
|
||||
# Export the environment variables:
|
||||
export ttuUsername=$ttuUsername
|
||||
export ttuPassword="password"
|
||||
export TTU_PLAYCOOKIE=$ttuUsername
|
||||
export TTU_GAMESERVER=$TTU_GAMESERVER
|
||||
|
||||
echo "==============================="
|
||||
echo "Starting Toontown Unlimited..."
|
||||
echo "Username: $ttuUsername"
|
||||
echo "Gameserver: $TTU_GAMESERVER"
|
||||
echo "==============================="
|
||||
|
||||
ppython -m toontown.toonbase.ClientStart
|
8
deployment/.gitignore
vendored
Normal file
8
deployment/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
unlimitedcipher
|
||||
unlimitedcipher.exe
|
||||
unlimited
|
||||
unlimited.exe
|
||||
upx.exe
|
||||
src
|
||||
build
|
||||
dist
|
19
deployment/FreezeTool.patch
Normal file
19
deployment/FreezeTool.patch
Normal file
|
@ -0,0 +1,19 @@
|
|||
--- FreezeTool.py.bk Tue May 6 21:26:46 2014
|
||||
+++ FreezeTool.py Sun Jun 29 23:37:25 2014
|
||||
@@ -1379,16 +1379,6 @@
|
||||
modulefinder.ModuleFinder.__init__(self, *args, **kw)
|
||||
|
||||
def import_module(self, partname, fqname, parent):
|
||||
- if parent and parent.__name__ == 'panda3d':
|
||||
- # A special case: map a reference to the "panda3d.blah"
|
||||
- # module into the appropriate Panda3D dll.
|
||||
- m = getattr(panda3d, partname, None)
|
||||
- if m:
|
||||
- libname = m.__libraries__[-1]
|
||||
- partname = libname
|
||||
- fqname = libname
|
||||
- parent = None
|
||||
-
|
||||
return modulefinder.ModuleFinder.import_module(self, partname, fqname, parent)
|
||||
|
||||
def find_module(self, name, path, parent=None):
|
368
deployment/deploy.py
Normal file
368
deployment/deploy.py
Normal file
|
@ -0,0 +1,368 @@
|
|||
#!/usr/bin/env python2
|
||||
import StringIO
|
||||
import copy
|
||||
import ftplib
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
from xml.etree import ElementTree
|
||||
|
||||
import bz2
|
||||
|
||||
|
||||
# We have some dependencies that aren't in the standard Python library. Notify
|
||||
# the user if they are missing one:
|
||||
try:
|
||||
import requests
|
||||
except ImportError, e:
|
||||
print 'Missing dependency:', e.message[16:]
|
||||
print 'It is recommended that you install this using Pip.'
|
||||
sys.exit(1)
|
||||
|
||||
print 'Starting the deployment process...'
|
||||
|
||||
# Stop the user if they are missing vital files:
|
||||
missingFiles = []
|
||||
for filename in ('deploy.json', 'unlimitedcipher'):
|
||||
if sys.platform == 'win32':
|
||||
# On the Windows platform, if there is no extension, we must infer that
|
||||
# this is an executable file. Therefore, let's append '.exe':
|
||||
if not os.path.splitext(filename)[1]:
|
||||
filename += '.exe'
|
||||
if filename not in os.listdir('.'):
|
||||
missingFiles.append(filename)
|
||||
if missingFiles:
|
||||
for filename in missingFiles:
|
||||
print 'Missing file:', filename
|
||||
sys.exit(1)
|
||||
|
||||
print 'Reading deploy configuration...'
|
||||
with open('deploy.json', 'r') as f:
|
||||
deployData = json.load(f)
|
||||
|
||||
# Next, we must choose the correct path to Python for our Panda3D installation:
|
||||
if sys.platform == 'win32':
|
||||
with open('../PPYTHON_PATH', 'r') as f:
|
||||
pythonPath = f.read().strip()
|
||||
else:
|
||||
pythonPath = '/usr/bin/python2'
|
||||
|
||||
# Collect our FTP credentials:
|
||||
ftpAddress = deployData['ftp-address']
|
||||
ftpUsername = deployData['ftp-username']
|
||||
if not ftpUsername:
|
||||
print 'Missing FTP username.'
|
||||
ftpPassword = deployData['ftp-password']
|
||||
if not ftpPassword:
|
||||
print 'Missing FTP password.'
|
||||
sys.exit(1)
|
||||
|
||||
# Ensure that the platform we're building for is supported:
|
||||
platform = deployData['platform']
|
||||
if platform not in ('win32', 'linux2', 'darwin'): # Supported platforms
|
||||
print 'Unsupported platform:', platform
|
||||
sys.exit(2)
|
||||
|
||||
# Ensure that the distribution we're building for is supported:
|
||||
distribution = deployData['distribution']
|
||||
if distribution not in ('dev', 'test', 'en'): # Supported distributions
|
||||
print 'Unsupported distribution:', distribution
|
||||
sys.exit(2)
|
||||
|
||||
deployToken = distribution + '/' + platform
|
||||
|
||||
# Ensure the desired source code branch exists:
|
||||
branch = deployData['branch']
|
||||
os.chdir('..')
|
||||
branches = subprocess.Popen(
|
||||
['git', 'rev-parse', '--abbrev-ref', '--branches', 'HEAD'],
|
||||
stdout=subprocess.PIPE).stdout.read().split()
|
||||
if branch not in branches:
|
||||
print "No local source code branch named:", branch
|
||||
sys.exit(3)
|
||||
|
||||
# Check if the desired resources branch exists:
|
||||
resourcesBranch = deployData['resources-branch']
|
||||
os.chdir('../resources')
|
||||
branches = subprocess.Popen(
|
||||
['git', 'rev-parse', '--abbrev-ref', '--branches', 'HEAD'],
|
||||
stdout=subprocess.PIPE).stdout.read().split()
|
||||
if resourcesBranch not in branches:
|
||||
print "No local resources branch named:", resourcesBranch
|
||||
sys.exit(3)
|
||||
|
||||
# We're all set. Let's gather the rest of the deployment configurations:
|
||||
serverVersion = deployData['version-prefix'] + deployData['version']
|
||||
launcherVersion = deployData['launcher-version']
|
||||
accountServer = deployData['account-server']
|
||||
clientAgent = deployData['client-agent']
|
||||
patcherIncludes = deployData['patcher-includes']
|
||||
configDir = deployData['config-dir']
|
||||
vfsMounts = deployData['vfs-mounts']
|
||||
modules = deployData['modules']
|
||||
mainModule = deployData['main-module']
|
||||
|
||||
# ...and output them for verbosity:
|
||||
print 'Deploy token:', deployToken
|
||||
print 'Branch:', branch
|
||||
print 'Resources branch:', resourcesBranch
|
||||
print 'Server version:', serverVersion
|
||||
print 'Configuration directory:', configDir
|
||||
print 'Virtual file system (%d):' % len(vfsMounts)
|
||||
for vfsMount in vfsMounts:
|
||||
print ' %s' % vfsMount
|
||||
print 'Modules (%d):' % len(modules)
|
||||
for module in modules:
|
||||
print ' %s' % module
|
||||
print 'Main module:', mainModule
|
||||
|
||||
# Create a 'src' directory containing the source code from the desired branch:
|
||||
sys.stdout.write('Collecting source code from branch: ' + branch + '... 0%')
|
||||
sys.stdout.flush()
|
||||
os.chdir('../src')
|
||||
if os.path.exists('deployment/src'):
|
||||
shutil.rmtree('deployment/src')
|
||||
os.mkdir('deployment/src')
|
||||
td = subprocess.Popen(['git', 'archive', branch],
|
||||
stdout=subprocess.PIPE).stdout.read()
|
||||
tss = StringIO.StringIO(td)
|
||||
tf = tarfile.TarFile(fileobj=tss)
|
||||
directories = []
|
||||
members = tf.getmembers()
|
||||
for (i, ti) in enumerate(members):
|
||||
if ti.isdir():
|
||||
directories.append(ti)
|
||||
ti = copy.copy(ti)
|
||||
ti.mode = 0o700
|
||||
tf.extract(ti, 'deployment/src')
|
||||
percentage = int((float(i+1)/len(members)) * 100)
|
||||
sys.stdout.write('\rCollecting source code from branch: ' + branch +
|
||||
'... ' + str(percentage) + '%')
|
||||
sys.stdout.flush()
|
||||
directories.sort(key=lambda a: a.name)
|
||||
directories.reverse()
|
||||
for ti in directories:
|
||||
dirpath = os.path.join('deployment/src', ti.name)
|
||||
try:
|
||||
tf.chown(ti, dirpath)
|
||||
tf.utime(ti, dirpath)
|
||||
tf.chmod(ti, dirpath)
|
||||
except tarfile.ExtractError as e:
|
||||
if tf.errorlevel > 1:
|
||||
raise
|
||||
else:
|
||||
tf._dbg(1, 'tarfile: %s' % e)
|
||||
sys.stdout.write('\n')
|
||||
sys.stdout.flush()
|
||||
|
||||
# Create a 'resources' directory inside the 'src' directory containing all of
|
||||
# the resource files from the desired resources branch:
|
||||
sys.stdout.write('Collecting resources from branch: ' + resourcesBranch + '... 0%')
|
||||
sys.stdout.flush()
|
||||
os.chdir('../resources')
|
||||
td = subprocess.Popen(['git', 'archive', resourcesBranch],
|
||||
stdout=subprocess.PIPE).stdout.read()
|
||||
tss = StringIO.StringIO(td)
|
||||
tf = tarfile.TarFile(fileobj=tss)
|
||||
os.chdir('../src/deployment')
|
||||
directories = []
|
||||
members = tf.getmembers()
|
||||
for (i, ti) in enumerate(members):
|
||||
if ti.isdir():
|
||||
directories.append(ti)
|
||||
ti = copy.copy(ti)
|
||||
ti.mode = 0o700
|
||||
tf.extract(ti, 'src/resources')
|
||||
percentage = int((float(i+1)/len(members)) * 100)
|
||||
sys.stdout.write('\rCollecting resources from branch: ' + resourcesBranch +
|
||||
'... ' + str(percentage) + '%')
|
||||
sys.stdout.flush()
|
||||
directories.sort(key=lambda a: a.name)
|
||||
directories.reverse()
|
||||
for ti in directories:
|
||||
dirpath = os.path.join('src/resources', ti.name)
|
||||
try:
|
||||
tf.chown(ti, dirpath)
|
||||
tf.utime(ti, dirpath)
|
||||
tf.chmod(ti, dirpath)
|
||||
except tarfile.ExtractError as e:
|
||||
if tf.errorlevel > 1:
|
||||
raise
|
||||
else:
|
||||
tf._dbg(1, 'tarfile: %s' % e)
|
||||
sys.stdout.write('\n')
|
||||
sys.stdout.flush()
|
||||
|
||||
# All of our source code and resources are collected. Now, let's run the
|
||||
# prepare_client utility:
|
||||
cmd = (pythonPath + ' ../tools/prepare_client.py' +
|
||||
' --distribution ' + distribution +
|
||||
' --build-dir build' +
|
||||
' --src-dir src' +
|
||||
' --server-ver ' + serverVersion +
|
||||
' --build-mfs' +
|
||||
' --resources-dir src/resources' +
|
||||
' --config-dir ' + configDir +
|
||||
' --include NonRepeatableRandomSourceUD.py' +
|
||||
' --include NonRepeatableRandomSourceAI.py' +
|
||||
' --exclude ServiceStart.py')
|
||||
for vfsMount in vfsMounts:
|
||||
cmd += ' --vfs ' + vfsMount
|
||||
for module in modules:
|
||||
cmd += ' ' + module
|
||||
os.system(cmd)
|
||||
|
||||
# Next, run the build_client utility:
|
||||
if sys.platform == 'win32':
|
||||
output = 'GameData.pyd'
|
||||
else:
|
||||
output = 'GameData.so'
|
||||
cmd = (pythonPath + ' ../tools/build_client.py' +
|
||||
' --output ' + output +
|
||||
' --main-module ' + mainModule +
|
||||
' --build-dir build')
|
||||
for module in modules:
|
||||
cmd += ' ' + module
|
||||
os.system(cmd)
|
||||
|
||||
# ...and encrypt the product:
|
||||
os.chdir('build')
|
||||
if sys.platform == 'win32':
|
||||
os.system('..\\unlimitedcipher.exe %s GameData.bin' % output)
|
||||
else:
|
||||
os.system('../unlimitedcipher %s GameData.bin' % output)
|
||||
|
||||
# Copy the necessary patcher includes:
|
||||
for include in patcherIncludes:
|
||||
dirname = os.path.dirname(include)
|
||||
if dirname and (not os.path.exists(dirname)):
|
||||
os.makedirs(dirname)
|
||||
if os.path.exists(os.path.join('..', include)):
|
||||
shutil.copyfile(os.path.join('..', include), include)
|
||||
|
||||
# Create a 'dist' directory that will contain everything that will be uploaded
|
||||
# to the CDN:
|
||||
os.chdir('..')
|
||||
if os.path.exists('dist'):
|
||||
shutil.rmtree('dist')
|
||||
os.mkdir('dist')
|
||||
|
||||
# Now, if we have deployed a previous version of this distribution before,
|
||||
# let's get the last resources revision so that we can choose what phase files
|
||||
# need to be updated using 'git diff'. We need to do this because two
|
||||
# compilations of the same multifile will never have the same hash:
|
||||
updatedFiles = []
|
||||
request = requests.get('http://' + ftpAddress + '/' + deployToken + '/patcher.xml')
|
||||
try:
|
||||
root = ElementTree.fromstring(request.text)
|
||||
except:
|
||||
root = None
|
||||
os.chdir('../../resources')
|
||||
if root and (root.tag == 'patcher'): # We have a patcher file
|
||||
resourcesRevision = root.find('resources-revision')
|
||||
if resourcesRevision is not None:
|
||||
resourcesRevision = resourcesRevision.text
|
||||
diff = subprocess.Popen(
|
||||
['git', 'diff', '--name-only', resourcesRevision, resourcesBranch],
|
||||
stdout=subprocess.PIPE).stdout.read()
|
||||
filenames = diff.split('\n')
|
||||
for filename in filenames:
|
||||
directory = filename.split('/', 1)[0].split('\\', 1)[0]
|
||||
if directory.startswith('phase_'):
|
||||
phase = 'resources/' + directory + '.mf'
|
||||
if phase not in updatedFiles:
|
||||
updatedFiles.append(phase)
|
||||
resourcesRevision = subprocess.Popen(
|
||||
['git', 'rev-parse', resourcesBranch],
|
||||
stdout=subprocess.PIPE).stdout.read()[:7]
|
||||
os.chdir('../src/deployment')
|
||||
updatedFiles.extend(patcherIncludes)
|
||||
|
||||
cmd = (pythonPath + ' ../tools/write_patcher.py' +
|
||||
' --build-dir build' +
|
||||
' --dest-dir dist' +
|
||||
' --output patcher.xml' +
|
||||
' --launcher-version ' + launcherVersion +
|
||||
' --account-server ' + accountServer +
|
||||
' --client-agent ' + clientAgent +
|
||||
' --server-version ' + serverVersion +
|
||||
' --resources-revision ' + resourcesRevision)
|
||||
for include in patcherIncludes:
|
||||
cmd += ' ' + include
|
||||
os.system(cmd)
|
||||
|
||||
et = ElementTree.parse('dist/patcher.xml')
|
||||
localRoot = et.getroot()
|
||||
for directory in localRoot.findall('directory'):
|
||||
directoryName = directory.get('name')
|
||||
# If we haven't pushed a patcher previously, we can assume this is the
|
||||
# first time deploying this distribution. Therefore, let's upload
|
||||
# everything:
|
||||
if (not root) or (root.tag != 'patcher'):
|
||||
for child in directory.getchildren():
|
||||
filepath = child.get('name')
|
||||
if directoryName:
|
||||
filepath = directoryName + '/' + filepath
|
||||
if filepath not in updatedFiles:
|
||||
updatedFiles.append(filepath)
|
||||
else:
|
||||
# Otherwise, we'll want to ensure that we don't overwrite certain
|
||||
# files' size/hash, in case they weren't updated:
|
||||
for child in directory.getchildren():
|
||||
filepath = child.get('name')
|
||||
if directoryName:
|
||||
filepath = directoryName + '/' + filepath
|
||||
if filepath not in updatedFiles:
|
||||
for _directory in root.findall('directory'):
|
||||
if _directory.get('name') != directoryName:
|
||||
continue
|
||||
for _child in _directory.getchildren():
|
||||
if _child.get('name') != child.get('name'):
|
||||
continue
|
||||
child.find('size').text = _child.find('size').text
|
||||
child.find('hash').text = _child.find('hash').text
|
||||
break
|
||||
break
|
||||
ElementTree.ElementTree(localRoot).write('dist/patcher.xml')
|
||||
|
||||
|
||||
def compressFile(filepath):
|
||||
with open(filepath, 'rb') as f:
|
||||
data = f.read()
|
||||
filename = os.path.basename(filepath)
|
||||
directory = filepath[6:].split(filename, 1)[0]
|
||||
if not os.path.exists(os.path.join('dist', directory)):
|
||||
os.mkdir(os.path.join('dist', directory))
|
||||
bz2Filename = os.path.splitext(filename)[0] + '.bz2'
|
||||
bz2Filepath = os.path.join('dist', directory, bz2Filename)
|
||||
f = bz2.BZ2File(bz2Filepath, 'w')
|
||||
f.write(data)
|
||||
f.close()
|
||||
|
||||
|
||||
# Compress the updated files:
|
||||
for filepath in updatedFiles:
|
||||
print 'Compressing %s...' % filepath
|
||||
compressFile(os.path.join('build', filepath))
|
||||
|
||||
print 'Uploading files to download.toontownunlimited.com...'
|
||||
ftp = ftplib.FTP(ftpAddress, ftpUsername, ftpPassword)
|
||||
ftp.cwd(deployToken)
|
||||
|
||||
print 'Uploading... patcher.xml'
|
||||
with open('dist/patcher.xml', 'rb') as f:
|
||||
ftp.storbinary('STOR patcher.xml', f)
|
||||
|
||||
|
||||
for filepath in updatedFiles:
|
||||
filepath = os.path.splitext(filepath)[0] + '.bz2'
|
||||
print 'Uploading... ' + filepath
|
||||
with open('dist/' + filepath, 'rb') as f:
|
||||
ftp.storbinary('STOR ' + filepath, f)
|
||||
|
||||
print 'Done uploading files.'
|
||||
|
||||
print 'Successfully finished the deployment process!'
|
11
doc/building/README.md
Normal file
11
doc/building/README.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
Building
|
||||
========
|
||||
These documents outline everything you need to know for building a Toontown Infinite client.
|
||||
|
||||
- - -
|
||||
|
||||
## Steps ##
|
||||
|
||||
1. [Prepare for building](prepare-client.md)
|
||||
2. [Build the frozen Python module](build-client.md)
|
||||
3. [Encrypt the frozen Python module](encrypt-client.md)
|
39
doc/building/build-client.md
Normal file
39
doc/building/build-client.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
Building the Client
|
||||
===================
|
||||
The first step in building a distributable Toontown Infinite client is building ```GameData.bin```. ```GameData.bin``` is an encrypted blob of frozen Python code. It contains all of the code necessary to run the game. There are three steps to building this file:
|
||||
|
||||
* [Prepare for building](prepare-client.md)
|
||||
* **Build the frozen Python module**
|
||||
* [Encrypt the frozen Python module](encrypt-client.md)
|
||||
|
||||
This document outlines how to accomplish the second task.
|
||||
|
||||
- - -
|
||||
|
||||
After preparing the client using the ```prepare_client.py``` utility, you're all set to build! Simply use the ```build_client.py``` utility through the _Visual Studio 2008 Command Prompt_. This will create a frozen Python module named ```GameData.pyd```.
|
||||
|
||||
## Usage ##
|
||||
|
||||
usage: build_client.py [-h] [--panda3d-dir PANDA3D_DIR]
|
||||
[--build-dir BUILD_DIR] [--main-module MAIN_MODULE]
|
||||
[modules [modules ...]]
|
||||
|
||||
positional arguments:
|
||||
modules The Toontown Infinite modules to be included in the
|
||||
build.
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--panda3d-dir PANDA3D_DIR
|
||||
The path to the Panda3D build to use for this
|
||||
distribution.
|
||||
--build-dir BUILD_DIR
|
||||
The directory of which the build was prepared.
|
||||
--main-module MAIN_MODULE
|
||||
The path to the instantiation module.
|
||||
|
||||
## Example ##
|
||||
|
||||
ppython -m build_client --panda3d-dir C:/Panda3D-1.9.0 --build-dir build
|
||||
--main-module toontown.toonbase.ToontownStartDist
|
||||
otp toontown
|
28
doc/building/encrypt-client.md
Normal file
28
doc/building/encrypt-client.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
Encrypting the Client
|
||||
=====================
|
||||
The first step in building a distributable Toontown Infinite client is building ```GameData.bin```. ```GameData.bin``` is an encrypted blob of frozen Python code. It contains all of the code necessary to run the game. There are three steps to building this file:
|
||||
|
||||
* [Prepare for building](prepare-client.md)
|
||||
* [Build the frozen Python module](build-client.md)
|
||||
* **Encrypt the frozen Python module**
|
||||
|
||||
This document outlines how to accomplish the third and final task.
|
||||
|
||||
- - -
|
||||
|
||||
By now, you should have a file named ```GameData.pyd``` in your build directory. The last step is to encrypt this file, and rename it to ```GameData.bin```! To do this, we use a utility called ```infinitecipher```. To get this utility, ask one of the lead developers.
|
||||
|
||||
## Usage ##
|
||||
|
||||
Usage: infinitecipher [-h] [-o OUTPUT] [INPUT]
|
||||
|
||||
Positional arguments:
|
||||
INPUT The file that needs to be encrypted.
|
||||
|
||||
Optional arguments:
|
||||
-h, --help Print this dialog and exit.
|
||||
-o, --output The encrypted outputile.
|
||||
|
||||
## Example ##
|
||||
|
||||
infinitecipher -o GameData.bin GameData.pyd
|
54
doc/building/prepare-client.md
Normal file
54
doc/building/prepare-client.md
Normal file
|
@ -0,0 +1,54 @@
|
|||
Client Build Preparation
|
||||
========================
|
||||
The first step in building a distributable Toontown Infinite client is building ```GameData.bin```. ```GameData.bin``` is an encrypted blob of frozen Python code. It contains all of the code necessary to run the game. There are three steps to building this file:
|
||||
|
||||
* **Prepare for building**
|
||||
* [Build the frozen Python module](build-client.md)
|
||||
* [Encrypt the frozen Python module](encrypt-client.md)
|
||||
|
||||
This document outlines how to accomplish the first task.
|
||||
|
||||
- - -
|
||||
|
||||
Preparing the client for building is quite simple when using the ```prepare_client.py``` utility. What it does is it creates a build directory with all of the necessary files for running a client. All server-specific files get removed. Next, it removes all ```__debug__``` blocks from the code, as they may pose a security risk, or be highly developer specific. After that, a file called ```game_data.py``` is generated. This file contains the PRC file data, (stripped) DC file, and time zone info. If a ```REVISION``` token was provided in the ```--server-ver``` option, it gets replaced in the PRC file data with the first 7 characters of the GitHub revision. Finally, if ```--build-mfs``` is provided, any phase files that were modified get compiled.
|
||||
|
||||
## Usage ##
|
||||
|
||||
usage: prepare_client.py [-h] [--distribution DISTRIBUTION]
|
||||
[--build-dir BUILD_DIR] [--src-dir SRC_DIR]
|
||||
[--server-ver SERVER_VER] [--build-mfs]
|
||||
[--resources-dir RESOURCES_DIR] [--include INCLUDE]
|
||||
[--exclude EXCLUDE]
|
||||
[modules [modules ...]]
|
||||
|
||||
positional arguments:
|
||||
modules The Toontown Infinite modules to be included in the
|
||||
build.
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--distribution DISTRIBUTION
|
||||
The distribution token.
|
||||
--build-dir BUILD_DIR
|
||||
The directory in which to store the build files.
|
||||
--src-dir SRC_DIR The directory of the Toontown Infinite source code.
|
||||
--server-ver SERVER_VER
|
||||
The server version of this build. REVISION tokens will
|
||||
be replaced with the current Git revision string.
|
||||
--build-mfs When present, multifiles will be built.
|
||||
--resources-dir RESOURCES_DIR
|
||||
The directory of the Toontown Infinite resources.
|
||||
--include INCLUDE, -i INCLUDE
|
||||
Explicitly include this file in the build.
|
||||
--exclude EXCLUDE, -x EXCLUDE
|
||||
Explicitly exclude this file from the build.
|
||||
|
||||
## Example ##
|
||||
|
||||
ppython -m prepare_client --distribution devdist --build-dir build --src-dir ..
|
||||
--server-ver infinite-REVISION --build-mfs
|
||||
--resources-dir ../resources
|
||||
--include NonRepeatableRandomSourceUD.py
|
||||
--include NonRepeatableRandomSourceAI.py
|
||||
--exclude ServiceStart.py
|
||||
otp toontown
|
9
doc/style-guide/README.md
Normal file
9
doc/style-guide/README.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
Toontown Infinite Style Guidelines
|
||||
==================================
|
||||
Code and documentation in the master and release branches of the Toontown Infinite repositories must conform to these guidelines. Any code submitted that is not properly formated will be rejected, as it is best to keep a readable, and consistent style for future contributors to read, and understand the code. Don't, however, blindly follow these guidelines into writing unreadable code. Sometimes it is best to use your own judgement.
|
||||
|
||||
- - -
|
||||
|
||||
* [Git style guidelines](git-style.md)
|
||||
* [Python style guidelines](python-style.md)
|
||||
* [C++ style guidelines](cxx-style.md)
|
145
doc/style-guide/cxx-style.md
Normal file
145
doc/style-guide/cxx-style.md
Normal file
|
@ -0,0 +1,145 @@
|
|||
C++ Style Guidelines
|
||||
====================
|
||||
For C++ programming, we use the [Oct 8, 2013 - Astron C++ Style Guide](https://github.com/Astron/Astron/blob/6a974ce247a364fdcd11d440db1cad0f1c2f6ba2/doc/style-guide/cxx-style.md "Oct 8, 2013 - Astron C++ Style Guide").
|
||||
- - -
|
||||
## Whitespace ##
|
||||
Tabs shall be used to indent, spaces shall be used to align.
|
||||
Source files should end with a newline.
|
||||
|
||||
## Variable Names ##
|
||||
Variables shall have a descriptive lowercase name, where words are seperated by underscores.
|
||||
Global variables shall start with g_
|
||||
Member variables shall start with m_
|
||||
|
||||
Example: `field_count` or
|
||||
|
||||
class Foo
|
||||
{
|
||||
private:
|
||||
int m_my_number;
|
||||
};
|
||||
|
||||
## Function Names ##
|
||||
Functions shall be named the same way as variables
|
||||
|
||||
## Class Names ##
|
||||
Class names shall be in CamelCase
|
||||
|
||||
Example: `DistributedObject`
|
||||
|
||||
## Braces ##
|
||||
Each brace shall be on it's own line, even if it's for an empty member:
|
||||
|
||||
Example:
|
||||
|
||||
void foo()
|
||||
{
|
||||
}
|
||||
|
||||
## Header Files ##
|
||||
A class shall not have a header file if nothing else interacts with it or if nothing else will ever inherit from it.
|
||||
|
||||
## Typedefs ##
|
||||
Typedefs shall have a descriptive name and end with _t
|
||||
|
||||
Example: `typedef unsigned int uint32_t`
|
||||
|
||||
## Usage of std::string (and when possible for stl types) ##
|
||||
Whenever possible, have function parameters be of type `const std::string&` and not `std::string`
|
||||
|
||||
Example:
|
||||
|
||||
void foo(const std::string &name)
|
||||
{
|
||||
std::cout << "Hello " << name << "!" << std::endl;
|
||||
}
|
||||
|
||||
## Preprocessor Macros ##
|
||||
Preproc macros shall be UPPER CASE and words shall be seperated by underlines.
|
||||
|
||||
Example: `#define CLIENT_HELLO 1`
|
||||
|
||||
## auto Keyword ##
|
||||
The `auto` keyword shall be used to avoid typing out long iterator types, and only for that.
|
||||
|
||||
Example:
|
||||
|
||||
std::list<DistributedObjects> my_objects;
|
||||
auto it = my_objects.begin();
|
||||
|
||||
## Template specifiers ##
|
||||
There shall be no space between the identifier and the <>
|
||||
|
||||
Good example: `std::list<channel_t> my_channels;`
|
||||
|
||||
Bad example: `std::list <channel_t> my_channels;`
|
||||
|
||||
## Access specifiers ##
|
||||
Class/struct access specifiers shall be indented.
|
||||
|
||||
Good example:
|
||||
|
||||
class Foo
|
||||
{
|
||||
public:
|
||||
Foo();
|
||||
};
|
||||
|
||||
Bad examples:
|
||||
|
||||
class Foo
|
||||
{
|
||||
public:
|
||||
Foo();
|
||||
};
|
||||
|
||||
class Foo
|
||||
{
|
||||
public:
|
||||
Foo();
|
||||
};
|
||||
|
||||
## Switches ##
|
||||
Case statements inside switches shall be indented. If the case does not fall through, it shall have it's own scope.
|
||||
The braces for the scope shall be on the same indentation level as the case statement itself.
|
||||
At the end of the scope, a `break;` shall be placed on the same indentation level as the case statement.
|
||||
|
||||
Example:
|
||||
|
||||
int temp = some_int;
|
||||
switch(temp)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
//code
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//code
|
||||
}
|
||||
|
||||
## Character Limit ##
|
||||
Each line shall be no longer than 100 characters, each tab counting as 4 characters.
|
||||
This is not a hard-limit, exceptions may be made.
|
||||
|
||||
## Initializer lists ##
|
||||
The first variable inside of the initializer list shall be on the same line as the function header
|
||||
if the character limit allows.
|
||||
The following variables will be on the next line, with another level of indentation.
|
||||
That line will continue until it hits the character limit, once that occurs a new line will be created,
|
||||
with the same level of indenation.
|
||||
|
||||
Example:
|
||||
|
||||
class Foo
|
||||
{
|
||||
private:
|
||||
int m_number;
|
||||
int m_number2;
|
||||
|
||||
public:
|
||||
Foo() : m_number(0),
|
||||
m_number2(0)
|
||||
{
|
||||
}
|
||||
};
|
30
doc/style-guide/git-style.md
Normal file
30
doc/style-guide/git-style.md
Normal file
|
@ -0,0 +1,30 @@
|
|||
Git Style Guidelines
|
||||
====================
|
||||
For Git, we try to follow a general pattern for commit messages and branch naming to make things organized and neat.
|
||||
- - -
|
||||
## Commit Messages ##
|
||||
All commit messages should:
|
||||
* Start with a capital letter.
|
||||
* Never end in puncuation.
|
||||
* Be in the present tense.
|
||||
* Have a title less than 100 characters.
|
||||
* End in a new line.
|
||||
|
||||
If a description is provided in the commit message, it should be separated from the title by a blank line. If the commit addresses an issue, its issue number should be referenced at the end of the commit message's description.
|
||||
|
||||
Whenever possible, commit messages should be prefixed with the directory name of which the commit modified the most, followed by a colon and a space.
|
||||
|
||||
For example: ```toon: ``` or ```tools: ``` or ```ai: ```
|
||||
|
||||
## Branch Naming ##
|
||||
All branch names should:
|
||||
* Be entirely lower case.
|
||||
* Use **-** as a separator.
|
||||
* Be categorized into one of the following groups:
|
||||
* wip
|
||||
* bugfix
|
||||
* test
|
||||
* enhancement
|
||||
* feature
|
||||
|
||||
For example: ```feature/parties``` or ```bugfix/toontorial``` or ```enhancement/fix-memory-leak```
|
37
doc/style-guide/python-style.md
Normal file
37
doc/style-guide/python-style.md
Normal file
|
@ -0,0 +1,37 @@
|
|||
Python Style Guidelines
|
||||
=======================
|
||||
For Python programming, we use a slightly modified version of the standard [PEP-8 Style Guide for Python Code](http://legacy.python.org/dev/peps/pep-0008 "PEP-8 Style Guide for Python Code"). Read below for our modifications.
|
||||
- - -
|
||||
## Code lay-out ##
|
||||
### Indentation ###
|
||||
The closing brace/bracket/parenthesis on multi-line constructs may either be directly at the end, as in:
|
||||
|
||||
my_list = [
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20]
|
||||
result = some_function_that_takes_arguments(
|
||||
'a', 'b', 'c', 'd', 'e', 'f')
|
||||
|
||||
or it may be by itself on the next line:
|
||||
|
||||
my_list = [
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20
|
||||
]
|
||||
result = some_function_that_takes_arguments(
|
||||
'a', 'b', 'c', 'd', 'e', 'f'
|
||||
)
|
||||
|
||||
### Tabs or Spaces? ###
|
||||
**_Always_** use spaces.
|
||||
|
||||
### Maximum Line Length ###
|
||||
**Docstrings and comments** should be restricted to _80 characters_. Anything else should be limited to _100 characters_.
|
||||
|
||||
## Naming Conventions ##
|
||||
### Variables ###
|
||||
Intentionally **unused** variables should be named "**_**". This will make common IDEs and editors ignore it.
|
||||
|
||||
## Strings ##
|
||||
### Quotations ###
|
||||
Use single quotations _(')_ unless there is one inside the string, in which case use double quotations _(")_.
|
19
linux/start-game-localhost.sh
Normal file
19
linux/start-game-localhost.sh
Normal file
|
@ -0,0 +1,19 @@
|
|||
#!/bin/sh
|
||||
cd ..
|
||||
|
||||
# Get the user input:
|
||||
read -p "Username: " ttuUsername
|
||||
|
||||
# Export the environment variables:
|
||||
export ttuUsername=$ttuUsername
|
||||
export ttuPassword="password"
|
||||
export TTU_PLAYCOOKIE=$ttuUsername
|
||||
export TTU_GAMESERVER="127.0.0.1"
|
||||
|
||||
echo "==============================="
|
||||
echo "Starting Toontown Unlimited..."
|
||||
echo "Username: $ttuUsername"
|
||||
echo "Gameserver: $TTU_GAMESERVER"
|
||||
echo "==============================="
|
||||
|
||||
/usr/bin/python2 -m toontown.toonbase.ClientStart
|
23
linux/start-game-remotedb.sh
Normal file
23
linux/start-game-remotedb.sh
Normal file
|
@ -0,0 +1,23 @@
|
|||
#!/bin/bash
|
||||
cd ..
|
||||
|
||||
# Get the user input:
|
||||
read -p "Username: " ttuUsername
|
||||
read -s -p "Password: " ttuPassword
|
||||
echo
|
||||
read -p "Gameserver (DEFAULT: 167.114.28.238): " TTU_GAMESERVER
|
||||
TTU_GAMESERVER=${TTU_GAMESERVER:-"167.114.28.238"}
|
||||
|
||||
# Export the environment variables:
|
||||
export ttuUsername=$ttuUsername
|
||||
export ttuPassword=$ttuPassword
|
||||
export TTU_PLAYCOOKIE=$ttuUsername
|
||||
export TTU_GAMESERVER=$TTU_GAMESERVER
|
||||
|
||||
echo "==============================="
|
||||
echo "Starting Toontown Unlimited..."
|
||||
echo "Username: $ttuUsername"
|
||||
echo "Gameserver: $TTU_GAMESERVER"
|
||||
echo "==============================="
|
||||
|
||||
/usr/bin/python2 -m toontown.toonbase.ClientStartRemoteDB
|
21
linux/start-game.sh
Normal file
21
linux/start-game.sh
Normal file
|
@ -0,0 +1,21 @@
|
|||
#!/bin/sh
|
||||
cd ..
|
||||
|
||||
# Get the user input:
|
||||
read -p "Username: " ttuUsername
|
||||
read -p "Gameserver (DEFAULT: 167.114.28.238): " TTU_GAMESERVER
|
||||
TTU_GAMESERVER=${TTU_GAMESERVER:-"167.114.28.238"}
|
||||
|
||||
# Export the environment variables:
|
||||
export ttuUsername=$ttuUsername
|
||||
export ttuPassword="password"
|
||||
export TTU_PLAYCOOKIE=$ttuUsername
|
||||
export TTU_GAMESERVER=$TTU_GAMESERVER
|
||||
|
||||
echo "==============================="
|
||||
echo "Starting Toontown Unlimited..."
|
||||
echo "Username: $ttuUsername"
|
||||
echo "Gameserver: $TTU_GAMESERVER"
|
||||
echo "==============================="
|
||||
|
||||
/usr/bin/python2 -m toontown.toonbase.ClientStart
|
0
otp/__init__.py
Normal file
0
otp/__init__.py
Normal file
179
otp/ai/AIBase.py
Normal file
179
otp/ai/AIBase.py
Normal file
|
@ -0,0 +1,179 @@
|
|||
import gc
|
||||
import math
|
||||
import sys
|
||||
import time
|
||||
|
||||
from direct.directnotify.DirectNotifyGlobal import *
|
||||
from direct.interval.IntervalManager import ivalMgr
|
||||
from direct.showbase import EventManager
|
||||
from direct.showbase import ExceptionVarDump
|
||||
from direct.showbase import PythonUtil
|
||||
from direct.showbase.BulletinBoardGlobal import *
|
||||
from direct.showbase.EventManagerGlobal import *
|
||||
from direct.showbase.JobManagerGlobal import *
|
||||
from direct.showbase.MessengerGlobal import *
|
||||
from direct.showbase.PythonUtil import *
|
||||
from direct.task import Task
|
||||
from direct.task.TaskManagerGlobal import *
|
||||
from otp.otpbase import BackupManager
|
||||
from pandac.PandaModules import *
|
||||
|
||||
|
||||
class AIBase:
|
||||
notify = directNotify.newCategory('AIBase')
|
||||
|
||||
def __init__(self):
|
||||
self.config = getConfigShowbase()
|
||||
__builtins__['__dev__'] = self.config.GetBool('want-dev', 0)
|
||||
logStackDump = (self.config.GetBool('log-stack-dump', (not __dev__)) or self.config.GetBool('ai-log-stack-dump', (not __dev__)))
|
||||
uploadStackDump = self.config.GetBool('upload-stack-dump', 0)
|
||||
if logStackDump or uploadStackDump:
|
||||
ExceptionVarDump.install(logStackDump, uploadStackDump)
|
||||
if self.config.GetBool('use-vfs', 1):
|
||||
vfs = VirtualFileSystem.getGlobalPtr()
|
||||
else:
|
||||
vfs = None
|
||||
self.wantTk = self.config.GetBool('want-tk', 0)
|
||||
self.AISleep = self.config.GetFloat('ai-sleep', 0.04)
|
||||
self.AIRunningNetYield = self.config.GetBool('ai-running-net-yield', 0)
|
||||
self.AIForceSleep = self.config.GetBool('ai-force-sleep', 0)
|
||||
self.eventMgr = eventMgr
|
||||
self.messenger = messenger
|
||||
self.bboard = bulletinBoard
|
||||
self.taskMgr = taskMgr
|
||||
Task.TaskManager.taskTimerVerbose = self.config.GetBool('task-timer-verbose', 0)
|
||||
Task.TaskManager.extendedExceptions = self.config.GetBool('extended-exceptions', 0)
|
||||
self.sfxManagerList = None
|
||||
self.musicManager = None
|
||||
self.jobMgr = jobMgr
|
||||
self.hidden = NodePath('hidden')
|
||||
self.graphicsEngine = GraphicsEngine()
|
||||
globalClock = ClockObject.getGlobalClock()
|
||||
self.trueClock = TrueClock.getGlobalPtr()
|
||||
globalClock.setRealTime(self.trueClock.getShortTime())
|
||||
globalClock.setAverageFrameRateInterval(30.0)
|
||||
globalClock.tick()
|
||||
taskMgr.globalClock = globalClock
|
||||
__builtins__['ostream'] = Notify.out()
|
||||
__builtins__['globalClock'] = globalClock
|
||||
__builtins__['vfs'] = vfs
|
||||
__builtins__['hidden'] = self.hidden
|
||||
AIBase.notify.info('__dev__ == %s' % __dev__)
|
||||
PythonUtil.recordFunctorCreationStacks()
|
||||
__builtins__['wantTestObject'] = self.config.GetBool('want-test-object', 0)
|
||||
self.wantStats = self.config.GetBool('want-pstats', 0)
|
||||
Task.TaskManager.pStatsTasks = self.config.GetBool('pstats-tasks', 0)
|
||||
taskMgr.resumeFunc = PStatClient.resumeAfterPause
|
||||
defaultValue = 1
|
||||
if __dev__:
|
||||
defaultValue = 0
|
||||
wantFakeTextures = self.config.GetBool('want-fake-textures-ai', defaultValue)
|
||||
if wantFakeTextures:
|
||||
loadPrcFileData('aibase', 'textures-header-only 1')
|
||||
self.wantPets = self.config.GetBool('want-pets', 1)
|
||||
if self.wantPets:
|
||||
from toontown.pets import PetConstants
|
||||
self.petMoodTimescale = self.config.GetFloat('pet-mood-timescale', 1.0)
|
||||
self.petMoodDriftPeriod = self.config.GetFloat('pet-mood-drift-period', PetConstants.MoodDriftPeriod)
|
||||
self.petThinkPeriod = self.config.GetFloat('pet-think-period', PetConstants.ThinkPeriod)
|
||||
self.petMovePeriod = self.config.GetFloat('pet-move-period', PetConstants.MovePeriod)
|
||||
self.petPosBroadcastPeriod = self.config.GetFloat('pet-pos-broadcast-period', PetConstants.PosBroadcastPeriod)
|
||||
self.wantBingo = self.config.GetBool('want-fish-bingo', 1)
|
||||
self.wantKarts = self.config.GetBool('wantKarts', 1)
|
||||
self.newDBRequestGen = self.config.GetBool('new-database-request-generate', 1)
|
||||
self.waitShardDelete = self.config.GetBool('wait-shard-delete', 1)
|
||||
self.blinkTrolley = self.config.GetBool('blink-trolley', 0)
|
||||
self.fakeDistrictPopulations = self.config.GetBool('fake-district-populations', 0)
|
||||
self.wantSwitchboard = self.config.GetBool('want-switchboard', 0)
|
||||
self.wantSwitchboardHacks = self.config.GetBool('want-switchboard-hacks', 0)
|
||||
self.GEMdemoWhisperRecipientDoid = self.config.GetBool('gem-demo-whisper-recipient-doid', 0)
|
||||
self.sqlAvailable = self.config.GetBool('sql-available', 1)
|
||||
self.backups = BackupManager.BackupManager(
|
||||
filepath=self.config.GetString('backups-filepath', 'backups/'),
|
||||
extension=self.config.GetString('backups-extension', '.json'))
|
||||
self.createStats()
|
||||
self.restart()
|
||||
|
||||
def setupCpuAffinities(self, minChannel):
|
||||
if process == 'uberdog':
|
||||
affinityMask = self.config.GetInt('uberdog-cpu-affinity-mask', -1)
|
||||
else:
|
||||
affinityMask = self.config.GetInt('ai-cpu-affinity-mask', -1)
|
||||
if affinityMask != -1:
|
||||
TrueClock.getGlobalPtr().setCpuAffinity(affinityMask)
|
||||
else:
|
||||
autoAffinity = self.config.GetBool('auto-single-cpu-affinity', 0)
|
||||
if process == 'uberdog':
|
||||
affinity = self.config.GetInt('uberdog-cpu-affinity', -1)
|
||||
if autoAffinity and affinity == -1:
|
||||
affinity = 2
|
||||
else:
|
||||
affinity = self.config.GetInt('ai-cpu-affinity', -1)
|
||||
if autoAffinity and affinity == -1:
|
||||
affinity = 1
|
||||
if affinity != -1:
|
||||
TrueClock.getGlobalPtr().setCpuAffinity(1 << affinity)
|
||||
elif autoAffinity:
|
||||
if process == 'uberdog':
|
||||
channelSet = int(minChannel / 1000000)
|
||||
channelSet -= 240
|
||||
affinity = channelSet + 3
|
||||
TrueClock.getGlobalPtr().setCpuAffinity(1 << affinity % 4)
|
||||
|
||||
def taskManagerDoYield(self, frameStartTime, nextScheuledTaksTime):
|
||||
minFinTime = frameStartTime + self.MaxEpockSpeed
|
||||
if nextScheuledTaksTime > 0 and nextScheuledTaksTime < minFinTime:
|
||||
minFinTime = nextScheuledTaksTime
|
||||
delta = minFinTime - globalClock.getRealTime()
|
||||
while delta > 0.002:
|
||||
time.sleep(delta)
|
||||
delta = minFinTime - globalClock.getRealTime()
|
||||
|
||||
def createStats(self, hostname = None, port = None):
|
||||
if not self.wantStats:
|
||||
return False
|
||||
if PStatClient.isConnected():
|
||||
PStatClient.disconnect()
|
||||
if hostname is None:
|
||||
hostname = ''
|
||||
if port is None:
|
||||
port = -1
|
||||
PStatClient.connect(hostname, port)
|
||||
return PStatClient.isConnected()
|
||||
|
||||
def __sleepCycleTask(self, task):
|
||||
time.sleep(self.AISleep)
|
||||
return Task.cont
|
||||
|
||||
def __resetPrevTransform(self, state):
|
||||
PandaNode.resetAllPrevTransform()
|
||||
return Task.cont
|
||||
|
||||
def __ivalLoop(self, state):
|
||||
ivalMgr.step()
|
||||
return Task.cont
|
||||
|
||||
def __igLoop(self, state):
|
||||
self.graphicsEngine.renderFrame()
|
||||
return Task.cont
|
||||
|
||||
def shutdown(self):
|
||||
self.taskMgr.remove('ivalLoop')
|
||||
self.taskMgr.remove('igLoop')
|
||||
self.taskMgr.remove('aiSleep')
|
||||
self.eventMgr.shutdown()
|
||||
|
||||
def restart(self):
|
||||
self.shutdown()
|
||||
self.taskMgr.add(self.__resetPrevTransform, 'resetPrevTransform', priority=-51)
|
||||
self.taskMgr.add(self.__ivalLoop, 'ivalLoop', priority=20)
|
||||
self.taskMgr.add(self.__igLoop, 'igLoop', priority=50)
|
||||
if self.AISleep >= 0 and (not self.AIRunningNetYield or self.AIForceSleep):
|
||||
self.taskMgr.add(self.__sleepCycleTask, 'aiSleep', priority=55)
|
||||
self.eventMgr.restart()
|
||||
|
||||
def getRepository(self):
|
||||
return self.air
|
||||
|
||||
def run(self):
|
||||
self.taskMgr.run()
|
26
otp/ai/AIBaseGlobal.py
Normal file
26
otp/ai/AIBaseGlobal.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
from AIBase import *
|
||||
__builtins__['simbase'] = AIBase()
|
||||
__builtins__['ostream'] = Notify.out()
|
||||
__builtins__['run'] = simbase.run
|
||||
__builtins__['taskMgr'] = simbase.taskMgr
|
||||
__builtins__['jobMgr'] = simbase.jobMgr
|
||||
__builtins__['eventMgr'] = simbase.eventMgr
|
||||
__builtins__['messenger'] = simbase.messenger
|
||||
__builtins__['bboard'] = simbase.bboard
|
||||
__builtins__['config'] = simbase.config
|
||||
__builtins__['directNotify'] = directNotify
|
||||
from direct.showbase import Loader
|
||||
simbase.loader = Loader.Loader(simbase)
|
||||
__builtins__['loader'] = simbase.loader
|
||||
directNotify.setDconfigLevels()
|
||||
|
||||
def inspect(anObject):
|
||||
from direct.tkpanels import Inspector
|
||||
Inspector.inspect(anObject)
|
||||
|
||||
|
||||
__builtins__['inspect'] = inspect
|
||||
if not __debug__ and __dev__:
|
||||
notify = directNotify.newCategory('ShowBaseGlobal')
|
||||
notify.error("You must set 'want-dev' to false in non-debug mode.")
|
||||
taskMgr.finalInit()
|
8
otp/ai/AIInterestHandles.py
Normal file
8
otp/ai/AIInterestHandles.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
PIRATES_CARDGAME = 1
|
||||
PIRATES_CREW = 2
|
||||
PIRATES_GUILD = 3
|
||||
PIRATES_FRIENDS = 4
|
||||
PIRATES_BAND = 5
|
||||
PIRATES_PVP_RESPAWN = 6
|
||||
PIRATES_TREASUREMAP = 7
|
||||
PIRATES_SHIPPVP = 8
|
77
otp/ai/AIMsgTypes.py
Normal file
77
otp/ai/AIMsgTypes.py
Normal file
|
@ -0,0 +1,77 @@
|
|||
from otp.distributed.OtpDoGlobals import *
|
||||
from direct.showbase.PythonUtil import invertDictLossless
|
||||
OTP_SERVER_ROOT_DO_ID = 4007
|
||||
CHANNEL_CLIENT_BROADCAST = 4014
|
||||
BAD_CHANNEL_ID = 0
|
||||
BAD_ZONE_ID = 0
|
||||
BAD_DO_ID = 0
|
||||
CONTROL_MESSAGE = 4001
|
||||
CONTROL_SET_CHANNEL = 2001
|
||||
CONTROL_REMOVE_CHANNEL = 2002
|
||||
CONTROL_SET_CON_NAME = 2004
|
||||
CONTROL_SET_CON_URL = 2005
|
||||
CONTROL_ADD_RANGE = 2008
|
||||
CONTROL_REMOVE_RANGE = 2009
|
||||
CONTROL_ADD_POST_REMOVE = 2010
|
||||
CONTROL_CLEAR_POST_REMOVE = 2011
|
||||
AIMsgName2Id = {'STATESERVER_OBJECT_GENERATE_WITH_REQUIRED': 2001,
|
||||
'STATESERVER_OBJECT_GENERATE_WITH_REQUIRED_OTHER': 2003,
|
||||
'STATESERVER_OBJECT_UPDATE_FIELD': 2004,
|
||||
'STATESERVER_OBJECT_UPDATE_FIELD_MULTIPLE': 2005,
|
||||
'STATESERVER_OBJECT_DELETE_RAM': 2007,
|
||||
'STATESERVER_OBJECT_SET_ZONE': 2008,
|
||||
'STATESERVER_OBJECT_CHANGE_ZONE': 2009,
|
||||
'STATESERVER_OBJECT_NOTFOUND': 2015,
|
||||
'STATESERVER_QUERY_OBJECT_ALL': 2020,
|
||||
'STATESERVER_QUERY_ZONE_OBJECT_ALL': 2021,
|
||||
'STATESERVER_OBJECT_LOCATE': 2022,
|
||||
'STATESERVER_OBJECT_LOCATE_RESP': 2023,
|
||||
'STATESERVER_OBJECT_QUERY_FIELD': 2024,
|
||||
'STATESERVER_QUERY_OBJECT_ALL_RESP': 2030,
|
||||
'STATESERVER_SHARD_REST': 2061,
|
||||
'STATESERVER_ADD_AI_RECV': 2045,
|
||||
'STATESERVER_QUERY_ZONE_OBJECT_ALL_DONE': 2046,
|
||||
'STATESERVER_OBJECT_CREATE_WITH_REQUIRED_CONTEXT': 2050,
|
||||
'STATESERVER_OBJECT_CREATE_WITH_REQUIR_OTHER_CONTEXT': 2051,
|
||||
'STATESERVER_OBJECT_CREATE_WITH_REQUIRED_CONTEXT_RESP': 2052,
|
||||
'STATESERVER_OBJECT_CREATE_WITH_REQUIR_OTHER_CONTEXT_RESP': 2053,
|
||||
'STATESERVER_OBJECT_DELETE_DISK': 2060,
|
||||
'STATESERVER_OBJECT_QUERY_FIELD_RESP': 2062,
|
||||
'STATESERVER_OBJECT_ENTERZONE_WITH_REQUIRED_OTHER': 2066,
|
||||
'STATESERVER_OBJECT_ENTER_AI_RECV': 2067,
|
||||
'STATESERVER_OBJECT_LEAVING_AI_INTEREST': 2033,
|
||||
'STATESERVER_OBJECT_ENTER_OWNER_RECV': 2068,
|
||||
'STATESERVER_OBJECT_CHANGE_OWNER_RECV': 2069,
|
||||
'STATESERVER_OBJECT_SET_OWNER_RECV': 2070,
|
||||
'STATESERVER_OBJECT_QUERY_FIELDS': 2080,
|
||||
'STATESERVER_OBJECT_QUERY_FIELDS_RESP': 2081,
|
||||
'STATESERVER_OBJECT_QUERY_FIELDS_STRING': 2082,
|
||||
'STATESERVER_OBJECT_QUERY_MANAGING_AI': 2083,
|
||||
'STATESERVER_BOUNCE_MESSAGE': 2086,
|
||||
'STATESERVER_QUERY_OBJECT_CHILDREN_LOCAL': 2087,
|
||||
'STATESERVER_QUERY_OBJECT_CHILDREN_LOCAL_DONE': 2089,
|
||||
'STATESERVER_QUERY_OBJECT_CHILDREN_RESP': 2087,
|
||||
'ACCOUNT_AVATAR_USAGE': 3005,
|
||||
'ACCOUNT_ACCOUNT_USAGE': 3006,
|
||||
'CLIENT_AGENT_OPEN_CHANNEL': 3104,
|
||||
'CLIENT_AGENT_CLOSE_CHANNEL': 3105,
|
||||
'CLIENT_AGENT_SET_INTEREST': 3106,
|
||||
'CLIENT_AGENT_REMOVE_INTEREST': 3107,
|
||||
'CHANNEL_PUPPET_ACTION': 4004,
|
||||
'DBSERVER_MAKE_FRIENDS': 1017,
|
||||
'DBSERVER_MAKE_FRIENDS_RESP': 1031,
|
||||
'DBSERVER_REQUEST_SECRET': 1025,
|
||||
'DBSERVER_REQUEST_SECRET_RESP': 1026,
|
||||
'DBSERVER_SUBMIT_SECRET': 1027,
|
||||
'DBSERVER_SUBMIT_SECRET_RESP': 1028,
|
||||
'DBSERVER_CREATE_STORED_OBJECT': 1003,
|
||||
'DBSERVER_CREATE_STORED_OBJECT_RESP': 1004,
|
||||
'DBSERVER_DELETE_STORED_OBJECT': 1008,
|
||||
'DBSERVER_GET_STORED_VALUES': 1012,
|
||||
'DBSERVER_GET_STORED_VALUES_RESP': 1013,
|
||||
'DBSERVER_SET_STORED_VALUES': 1014,
|
||||
'SERVER_PING': 5002}
|
||||
AIMsgId2Names = invertDictLossless(AIMsgName2Id)
|
||||
globals().update(AIMsgName2Id)
|
||||
|
||||
DBSERVER_ID = 4003
|
217
otp/ai/AIZoneData.py
Normal file
217
otp/ai/AIZoneData.py
Normal file
|
@ -0,0 +1,217 @@
|
|||
from pandac.PandaModules import *
|
||||
from direct.distributed import ParentMgr
|
||||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||
from direct.task import Task
|
||||
from direct.showbase import LeakDetectors
|
||||
from otp.otpbase import OTPGlobals
|
||||
import random
|
||||
|
||||
class AIZoneData:
|
||||
notify = directNotify.newCategory('AIZoneData')
|
||||
|
||||
def __init__(self, air, parentId, zoneId):
|
||||
self._air = air
|
||||
self._parentId = parentId
|
||||
self._zoneId = zoneId
|
||||
self._data = self._air.getZoneDataStore().getDataForZone(self._parentId, self._zoneId)
|
||||
|
||||
def destroy(self):
|
||||
del self._data
|
||||
self._air.getZoneDataStore().releaseDataForZone(self._parentId, self._zoneId)
|
||||
del self._zoneId
|
||||
del self._parentId
|
||||
del self._air
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self._data, attr)
|
||||
|
||||
|
||||
class AIZoneDataObj:
|
||||
notify = directNotify.newCategory('AIZoneDataObj')
|
||||
DefaultCTravName = 'default'
|
||||
|
||||
def __init__(self, parentId, zoneId):
|
||||
self._parentId = parentId
|
||||
self._zoneId = zoneId
|
||||
self._refCount = 0
|
||||
self._collTravs = {}
|
||||
self._collTravsStarted = set()
|
||||
|
||||
def __str__(self):
|
||||
output = str(self._collTravs)
|
||||
output += '\n'
|
||||
totalColliders = 0
|
||||
totalTraversers = 0
|
||||
for currCollTrav in self._collTravs.values():
|
||||
totalTraversers += 1
|
||||
totalColliders += currCollTrav.getNumColliders()
|
||||
|
||||
output += 'Num traversers: %s Num total colliders: %s' % (totalTraversers, totalColliders)
|
||||
return output
|
||||
|
||||
def _incRefCount(self):
|
||||
self._refCount += 1
|
||||
|
||||
def _decRefCount(self):
|
||||
self._refCount -= 1
|
||||
|
||||
def _getRefCount(self):
|
||||
return self._refCount
|
||||
|
||||
def destroy(self):
|
||||
for name in list(self._collTravsStarted):
|
||||
self.stopCollTrav(cTravName=name)
|
||||
|
||||
del self._collTravsStarted
|
||||
del self._collTravs
|
||||
if hasattr(self, '_nonCollidableParent'):
|
||||
self._nonCollidableParent.removeNode()
|
||||
del self._nonCollidableParent
|
||||
if hasattr(self, '_render'):
|
||||
if hasattr(self, '_renderLeakDetector'):
|
||||
self._renderLeakDetector.destroy()
|
||||
del self._renderLeakDetector
|
||||
self._render.removeNode()
|
||||
del self._render
|
||||
if hasattr(self, '_parentMgr'):
|
||||
self._parentMgr.destroy()
|
||||
del self._parentMgr
|
||||
del self._zoneId
|
||||
del self._parentId
|
||||
|
||||
def getLocation(self):
|
||||
return (self._parentId, self._zoneId)
|
||||
|
||||
def getRender(self):
|
||||
if not hasattr(self, '_render'):
|
||||
self._render = NodePath('render-%s-%s' % (self._parentId, self._zoneId))
|
||||
if config.GetBool('leak-scene-graph', 0):
|
||||
self._renderLeakDetector = LeakDetectors.SceneGraphLeakDetector(self._render)
|
||||
return self._render
|
||||
|
||||
def getNonCollidableParent(self):
|
||||
if not hasattr(self, '_nonCollidableParent'):
|
||||
render = self.getRender()
|
||||
self._nonCollidableParent = render.attachNewNode('nonCollidables')
|
||||
if __dev__:
|
||||
pass
|
||||
return self._nonCollidableParent
|
||||
|
||||
def getParentMgr(self):
|
||||
if not hasattr(self, '_parentMgr'):
|
||||
self._parentMgr = ParentMgr.ParentMgr()
|
||||
self._parentMgr.registerParent(OTPGlobals.SPHidden, hidden)
|
||||
self._parentMgr.registerParent(OTPGlobals.SPRender, self.getRender())
|
||||
return self._parentMgr
|
||||
|
||||
def hasCollTrav(self, name = None):
|
||||
if name is None:
|
||||
name = AIZoneDataObj.DefaultCTravName
|
||||
return name in self._collTravs
|
||||
|
||||
def getCollTrav(self, name = None):
|
||||
if name is None:
|
||||
name = AIZoneDataObj.DefaultCTravName
|
||||
if name not in self._collTravs:
|
||||
self._collTravs[name] = CollisionTraverser('cTrav-%s-%s-%s' % (name, self._parentId, self._zoneId))
|
||||
return self._collTravs[name]
|
||||
|
||||
def removeCollTrav(self, name):
|
||||
if name in self._collTravs:
|
||||
del self._collTravs[name]
|
||||
|
||||
def _getCTravTaskName(self, name = None):
|
||||
if name is None:
|
||||
name = AIZoneDataObj.DefaultCTravName
|
||||
return 'collTrav-%s-%s-%s' % (name, self._parentId, self._zoneId)
|
||||
|
||||
def _doCollisions(self, task = None, topNode = None, cTravName = None):
|
||||
render = self.getRender()
|
||||
curTime = globalClock.getFrameTime()
|
||||
render.setTag('lastTraverseTime', str(curTime))
|
||||
if topNode is not None:
|
||||
if not render.isAncestorOf(topNode):
|
||||
self.notify.warning('invalid topNode for collision traversal in %s: %s' % (self.getLocation(), topNode))
|
||||
else:
|
||||
topNode = render
|
||||
if cTravName is None:
|
||||
cTravName = AIZoneDataObj.DefaultCTravName
|
||||
collTrav = self._collTravs[cTravName]
|
||||
messenger.send('preColl-' + collTrav.getName())
|
||||
collTrav.traverse(topNode)
|
||||
messenger.send('postColl-' + collTrav.getName())
|
||||
return Task.cont
|
||||
|
||||
def doCollTrav(self, topNode = None, cTravName = None):
|
||||
self.getCollTrav(cTravName)
|
||||
self._doCollisions(topNode=topNode, cTravName=cTravName)
|
||||
|
||||
def startCollTrav(self, respectPrevTransform = 1, cTravName = None):
|
||||
if cTravName is None:
|
||||
cTravName = AIZoneDataObj.DefaultCTravName
|
||||
if cTravName not in self._collTravsStarted:
|
||||
self.getCollTrav(name=cTravName)
|
||||
taskMgr.add(self._doCollisions, self._getCTravTaskName(name=cTravName), priority=OTPGlobals.AICollisionPriority, extraArgs=[self._zoneId])
|
||||
self._collTravsStarted.add(cTravName)
|
||||
self.setRespectPrevTransform(respectPrevTransform, cTravName=cTravName)
|
||||
return
|
||||
|
||||
def stopCollTrav(self, cTravName = None):
|
||||
if cTravName is None:
|
||||
cTravName = AIZoneDataObj.DefaultCTravName
|
||||
self.notify.debug('stopCollTrav(%s, %s, %s)' % (cTravName, self._parentId, self._zoneId))
|
||||
if cTravName in self._collTravsStarted:
|
||||
self.notify.info('removing %s collision traversal for (%s, %s)' % (cTravName, self._parentId, self._zoneId))
|
||||
taskMgr.remove(self._getCTravTaskName(name=cTravName))
|
||||
self._collTravsStarted.remove(cTravName)
|
||||
return
|
||||
|
||||
def setRespectPrevTransform(self, flag, cTravName = None):
|
||||
if cTravName is None:
|
||||
cTravName = AIZoneDataObj.DefaultCTravName
|
||||
self._collTravs[cTravName].setRespectPrevTransform(flag)
|
||||
return
|
||||
|
||||
def getRespectPrevTransform(self, cTravName = None):
|
||||
if cTravName is None:
|
||||
cTravName = AIZoneDataObj.DefaultCTravName
|
||||
return self._collTravs[cTravName].getRespectPrevTransform()
|
||||
|
||||
|
||||
class AIZoneDataStore:
|
||||
notify = directNotify.newCategory('AIZoneDataStore')
|
||||
|
||||
def __init__(self):
|
||||
self._zone2data = {}
|
||||
|
||||
def destroy(self):
|
||||
for zone, data in self._zone2data.items():
|
||||
data.destroy()
|
||||
|
||||
del self._zone2data
|
||||
|
||||
def hasDataForZone(self, parentId, zoneId):
|
||||
key = (parentId, zoneId)
|
||||
return key in self._zone2data
|
||||
|
||||
def getDataForZone(self, parentId, zoneId):
|
||||
key = (parentId, zoneId)
|
||||
if key not in self._zone2data:
|
||||
self._zone2data[key] = AIZoneDataObj(parentId, zoneId)
|
||||
self.printStats()
|
||||
data = self._zone2data[key]
|
||||
data._incRefCount()
|
||||
return data
|
||||
|
||||
def releaseDataForZone(self, parentId, zoneId):
|
||||
key = (parentId, zoneId)
|
||||
data = self._zone2data[key]
|
||||
data._decRefCount()
|
||||
refCount = data._getRefCount()
|
||||
if refCount == 0:
|
||||
del self._zone2data[key]
|
||||
data.destroy()
|
||||
self.printStats()
|
||||
|
||||
def printStats(self):
|
||||
self.notify.debug('%s zones have zone data allocated' % len(self._zone2data))
|
149
otp/ai/BanManagerAI.py
Normal file
149
otp/ai/BanManagerAI.py
Normal file
|
@ -0,0 +1,149 @@
|
|||
from direct.directnotify import DirectNotifyGlobal
|
||||
from toontown.uberdog.ClientServicesManagerUD import executeHttpRequest
|
||||
import datetime
|
||||
from direct.fsm.FSM import FSM
|
||||
from direct.distributed.PyDatagram import PyDatagram
|
||||
from direct.distributed.MsgTypes import *
|
||||
from otp.ai.MagicWordGlobal import *
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
|
||||
|
||||
class BanFSM(FSM):
|
||||
|
||||
def __init__(self, air, avId, comment, duration):
|
||||
FSM.__init__(self, 'banFSM-%s' % avId)
|
||||
self.air = air
|
||||
self.avId = avId
|
||||
|
||||
# Needed variables for the actual banning.
|
||||
self.comment = comment
|
||||
self.duration = duration
|
||||
self.DISLid = None
|
||||
self.accountId = None
|
||||
self.avName = None
|
||||
|
||||
def performBan(self, bannedUntil):
|
||||
executeHttpRequest('accounts/ban/', Id=self.accountId, Release=bannedUntil,
|
||||
Reason=self.comment)
|
||||
|
||||
def ejectPlayer(self):
|
||||
av = self.air.doId2do.get(self.avId)
|
||||
if not av:
|
||||
return
|
||||
|
||||
# Send the client a 'CLIENTAGENT_EJECT' with the players name.
|
||||
datagram = PyDatagram()
|
||||
datagram.addServerHeader(
|
||||
av.GetPuppetConnectionChannel(self.avId),
|
||||
self.air.ourChannel, CLIENTAGENT_EJECT)
|
||||
datagram.addUint16(152)
|
||||
datagram.addString(self.avName)
|
||||
simbase.air.send(datagram)
|
||||
|
||||
def dbCallback(self, dclass, fields):
|
||||
if dclass != self.air.dclassesByName['AccountAI']:
|
||||
return
|
||||
|
||||
self.accountId = fields.get('ACCOUNT_ID')
|
||||
|
||||
if not self.accountId:
|
||||
return
|
||||
|
||||
date = datetime.date.today()
|
||||
if simbase.config.GetBool('want-bans', True):
|
||||
if self.duration == 0:
|
||||
bannedUntil = "0000-00-00" # Terminated.
|
||||
else:
|
||||
bannedUntil = date + datetime.timedelta(days=self.duration)
|
||||
|
||||
self.duration = None
|
||||
self.performBan(bannedUntil)
|
||||
|
||||
def getAvatarDetails(self):
|
||||
av = self.air.doId2do.get(self.avId)
|
||||
if not av:
|
||||
return
|
||||
|
||||
self.DISLid = av.getDISLid()
|
||||
self.avName = av.getName()
|
||||
|
||||
def log(self):
|
||||
simbase.air.writeServerEvent('ban', self.accountId, self.comment)
|
||||
|
||||
def cleanup(self):
|
||||
self.air = None
|
||||
self.avId = None
|
||||
|
||||
self.DISLid = None
|
||||
self.avName = None
|
||||
self.accountId = None
|
||||
self.comment = None
|
||||
self.duration = None
|
||||
self = None
|
||||
|
||||
def enterStart(self):
|
||||
self.getAvatarDetails()
|
||||
self.air.dbInterface.queryObject(self.air.dbId, self.DISLid,
|
||||
self.dbCallback)
|
||||
self.ejectPlayer()
|
||||
|
||||
def exitStart(self):
|
||||
self.log()
|
||||
self.cleanup()
|
||||
|
||||
def enterOff(self):
|
||||
pass
|
||||
|
||||
def exitOff(self):
|
||||
pass
|
||||
|
||||
|
||||
class BanManagerAI(DirectObject):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('BanManagerAI')
|
||||
|
||||
def __init__(self, air):
|
||||
self.air = air
|
||||
self.banFSMs = {}
|
||||
|
||||
def ban(self, avId, duration, comment):
|
||||
self.banFSMs[avId] = BanFSM(self.air, avId, comment, duration)
|
||||
self.banFSMs[avId].request('Start')
|
||||
|
||||
self.acceptOnce(self.air.getAvatarExitEvent(avId), self.banDone, [avId])
|
||||
|
||||
def banDone(self, avId):
|
||||
self.banFSMs[avId].request('Off')
|
||||
self.banFSMs[avId] = None
|
||||
|
||||
|
||||
@magicWord(category=CATEGORY_MODERATOR, types=[str])
|
||||
def kick(reason):
|
||||
"""
|
||||
Kick the target from the game server.
|
||||
"""
|
||||
target = spellbook.getTarget()
|
||||
if target == spellbook.getInvoker():
|
||||
return "You can't kick yourself!"
|
||||
datagram = PyDatagram()
|
||||
datagram.addServerHeader(
|
||||
target.GetPuppetConnectionChannel(target.doId),
|
||||
simbase.air.ourChannel, CLIENTAGENT_EJECT)
|
||||
datagram.addUint16(155)
|
||||
datagram.addString('You were kicked by a moderator for the following reason: "%s"\n\nBehave next time!' % reason)
|
||||
simbase.air.send(datagram)
|
||||
return "Kicked %s from the game server!" % target.getName()
|
||||
|
||||
|
||||
@magicWord(category=CATEGORY_MODERATOR, types=[str, int])
|
||||
def ban(reason, duration):
|
||||
"""
|
||||
Ban the target from the game server.
|
||||
"""
|
||||
target = spellbook.getTarget()
|
||||
if target == spellbook.getInvoker():
|
||||
return "You can't ban yourself!"
|
||||
if reason not in ('hacking', 'language', 'other'):
|
||||
return "'%s' is not a valid reason." % reason
|
||||
simbase.air.banManager.ban(target.doId, duration, reason)
|
||||
return "Banned %s from the game server!" % target.getName()
|
||||
|
83
otp/ai/Barrier.py
Normal file
83
otp/ai/Barrier.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
from otp.ai.AIBase import *
|
||||
from direct.task import Task
|
||||
from direct.showbase import DirectObject
|
||||
import random
|
||||
|
||||
class Barrier(DirectObject.DirectObject):
|
||||
notify = directNotify.newCategory('Barrier')
|
||||
|
||||
def __init__(self, name, uniqueName, avIdList, timeout, clearedFunc = None, timeoutFunc = None, doneFunc = None):
|
||||
self.name = name
|
||||
self.uniqueName = uniqueName + '-Barrier'
|
||||
self.avIdList = avIdList[:]
|
||||
self.pendingAvatars = self.avIdList[:]
|
||||
self.timeout = timeout
|
||||
self.clearedFunc = clearedFunc
|
||||
self.timeoutFunc = timeoutFunc
|
||||
self.doneFunc = doneFunc
|
||||
if len(self.pendingAvatars) == 0:
|
||||
self.notify.debug('%s: barrier with empty list' % self.uniqueName)
|
||||
self.active = 0
|
||||
if self.clearedFunc:
|
||||
self.clearedFunc()
|
||||
if self.doneFunc:
|
||||
self.doneFunc(self.avIdList)
|
||||
return
|
||||
self.taskName = self.uniqueName + '-Timeout'
|
||||
origTaskName = self.taskName
|
||||
while taskMgr.hasTaskNamed(self.taskName):
|
||||
self.taskName = origTaskName + '-' + str(random.randint(0, 10000))
|
||||
|
||||
taskMgr.doMethodLater(self.timeout, self.__timerExpired, self.taskName)
|
||||
for avId in self.avIdList:
|
||||
event = simbase.air.getAvatarExitEvent(avId)
|
||||
self.acceptOnce(event, self.__handleUnexpectedExit, extraArgs=[avId])
|
||||
|
||||
self.notify.debug('%s: expecting responses from %s within %s seconds' % (self.uniqueName, self.avIdList, self.timeout))
|
||||
self.active = 1
|
||||
|
||||
def cleanup(self):
|
||||
if self.active:
|
||||
taskMgr.remove(self.taskName)
|
||||
self.active = 0
|
||||
self.ignoreAll()
|
||||
|
||||
def clear(self, avId):
|
||||
if avId not in self.pendingAvatars:
|
||||
self.notify.warning('%s: tried to clear %s, who was not listed.' % (self.uniqueName, avId))
|
||||
return
|
||||
self.notify.debug('%s: clearing avatar %s' % (self.uniqueName, avId))
|
||||
self.pendingAvatars.remove(avId)
|
||||
if len(self.pendingAvatars) == 0:
|
||||
self.notify.debug('%s: barrier cleared by %s' % (self.uniqueName, self.avIdList))
|
||||
self.cleanup()
|
||||
if self.clearedFunc:
|
||||
self.clearedFunc()
|
||||
if self.doneFunc:
|
||||
self.doneFunc(self.avIdList)
|
||||
|
||||
def isActive(self):
|
||||
return self.active
|
||||
|
||||
def getPendingAvatars(self):
|
||||
return self.pendingAvatars[:]
|
||||
|
||||
def __timerExpired(self, task):
|
||||
self.notify.warning('%s: timeout expired; responses not received from %s' % (self.uniqueName, self.pendingAvatars))
|
||||
self.cleanup()
|
||||
if self.timeoutFunc:
|
||||
self.timeoutFunc(self.pendingAvatars[:])
|
||||
if self.doneFunc:
|
||||
clearedAvIds = self.avIdList[:]
|
||||
for avId in self.pendingAvatars:
|
||||
clearedAvIds.remove(avId)
|
||||
|
||||
self.doneFunc(clearedAvIds)
|
||||
return Task.done
|
||||
|
||||
def __handleUnexpectedExit(self, avId):
|
||||
if avId not in self.avIdList:
|
||||
return
|
||||
self.avIdList.remove(avId)
|
||||
if avId in self.pendingAvatars:
|
||||
self.clear(avId)
|
44
otp/ai/GarbageLeakServerEventAggregator.py
Normal file
44
otp/ai/GarbageLeakServerEventAggregator.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
from direct.showbase.DirectObject import DirectObject
|
||||
from direct.showbase import GarbageReport
|
||||
|
||||
class GarbageLeakServerEventAggregator(DirectObject):
|
||||
|
||||
def __init__(self, cr):
|
||||
self.cr = cr
|
||||
self._doLaterName = None
|
||||
self._sentLeakDesc2num = {}
|
||||
self._curLeakDesc2num = {}
|
||||
self.accept(GarbageReport.GarbageCycleCountAnnounceEvent, self._handleCycleCounts)
|
||||
return
|
||||
|
||||
def destroy(self):
|
||||
self._stopSending()
|
||||
self.ignoreAll()
|
||||
del self.cr
|
||||
|
||||
def _handleCycleCounts(self, desc2num):
|
||||
self._curLeakDesc2num = desc2num
|
||||
self._startSending()
|
||||
|
||||
def _startSending(self):
|
||||
if not self._doLaterName:
|
||||
self._sendLeaks()
|
||||
self._doLaterName = uniqueName('%s-sendGarbageLeakInfo' % self.__class__.__name__)
|
||||
self.doMethodLater(60 * 60.0, self._sendLeaks, self._doLaterName)
|
||||
|
||||
def _stopSending(self):
|
||||
if self._doLaterName:
|
||||
self.removeTask(self._doLaterName)
|
||||
self._doLaterName = None
|
||||
return
|
||||
|
||||
def _sendLeaks(self, task = None):
|
||||
for desc, curNum in self._curLeakDesc2num.iteritems():
|
||||
self._sentLeakDesc2num.setdefault(desc, 0)
|
||||
num = curNum - self._sentLeakDesc2num[desc]
|
||||
if num > 0:
|
||||
base.cr.timeManager.d_setClientGarbageLeak(num, desc)
|
||||
self._sentLeakDesc2num[desc] = curNum
|
||||
|
||||
if task:
|
||||
return task.again
|
158
otp/ai/MagicWordGlobal.py
Normal file
158
otp/ai/MagicWordGlobal.py
Normal file
|
@ -0,0 +1,158 @@
|
|||
from direct.showbase import PythonUtil
|
||||
|
||||
class MagicError(Exception): pass
|
||||
|
||||
def ensureAccess(access, msg='Insufficient access'):
|
||||
if spellbook.getInvokerAccess() < access:
|
||||
raise MagicError(msg)
|
||||
|
||||
class Spellbook:
|
||||
"""
|
||||
The Spellbook manages the list of all Magic Words that have been registered
|
||||
anywhere in the system. When the MagicWordManager(AI) wants to process a
|
||||
Magic Word, it is passed off to the Spellbook, which performs the operation.
|
||||
|
||||
To add Magic Words to the Spellbook, use the @magicWord() decorator.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.words = {}
|
||||
|
||||
self.currentInvoker = None
|
||||
self.currentTarget = None
|
||||
|
||||
def addWord(self, word):
|
||||
self.words[word.name.lower()] = word # lets make this stuff case insensitive
|
||||
|
||||
def process(self, invoker, target, incantation):
|
||||
self.currentInvoker = invoker
|
||||
self.currentTarget = target
|
||||
word, args = (incantation.split(' ', 1) + [''])[:2]
|
||||
|
||||
try:
|
||||
return self.doWord(word, args)
|
||||
except MagicError as e:
|
||||
return e.message
|
||||
except Exception:
|
||||
return PythonUtil.describeException(backTrace=1)
|
||||
finally:
|
||||
self.currentInvoker = None
|
||||
self.currentTarget = None
|
||||
|
||||
def doWord(self, wordName, args):
|
||||
word = self.words.get(wordName.lower()) # look it up by its lower case value
|
||||
|
||||
if not word:
|
||||
if process == 'ai':
|
||||
wname = wordName.lower()
|
||||
for key in self.words:
|
||||
if self.words.get(key).access <= self.getInvokerAccess():
|
||||
if wname in key:
|
||||
return 'Did you mean %s' % (self.words.get(key).name)
|
||||
if not word:
|
||||
return
|
||||
|
||||
ensureAccess(word.access)
|
||||
if self.getTarget() and self.getTarget() != self.getInvoker():
|
||||
if self.getInvokerAccess() <= self.getTarget().getAdminAccess():
|
||||
raise MagicError('Target must have lower access')
|
||||
|
||||
result = word.run(args)
|
||||
if result is not None:
|
||||
return str(result)
|
||||
|
||||
def getInvoker(self):
|
||||
return self.currentInvoker
|
||||
|
||||
def getTarget(self):
|
||||
return self.currentTarget
|
||||
|
||||
def getInvokerAccess(self):
|
||||
if not self.currentInvoker:
|
||||
return 0
|
||||
return self.currentInvoker.getAdminAccess()
|
||||
|
||||
spellbook = Spellbook()
|
||||
|
||||
|
||||
# CATEGORIES
|
||||
class MagicWordCategory:
|
||||
def __init__(self, name, defaultAccess=600):
|
||||
self.name = name
|
||||
self.defaultAccess = defaultAccess
|
||||
|
||||
CATEGORY_UNKNOWN = MagicWordCategory('Unknown')
|
||||
CATEGORY_USER = MagicWordCategory('Community manager', defaultAccess=100)
|
||||
CATEGORY_COMMUNITY_MANAGER = MagicWordCategory('Community manager', defaultAccess=200)
|
||||
CATEGORY_MODERATOR = MagicWordCategory('Moderator', defaultAccess=300)
|
||||
CATEGORY_CREATIVE = MagicWordCategory('Creative', defaultAccess=400)
|
||||
CATEGORY_PROGRAMMER = MagicWordCategory('Programmer', defaultAccess=500)
|
||||
CATEGORY_ADMINISTRATOR = MagicWordCategory('Administrator', defaultAccess=600)
|
||||
CATEGORY_SYSTEM_ADMINISTRATOR = MagicWordCategory('System administrator', defaultAccess=700)
|
||||
|
||||
MINIMUM_MAGICWORD_ACCESS = CATEGORY_COMMUNITY_MANAGER.defaultAccess
|
||||
|
||||
|
||||
class MagicWord:
|
||||
def __init__(self, name, func, types, access, doc):
|
||||
self.name = name
|
||||
self.func = func
|
||||
self.types = types
|
||||
self.access = access
|
||||
self.doc = doc
|
||||
|
||||
def parseArgs(self, string):
|
||||
maxArgs = self.func.func_code.co_argcount
|
||||
minArgs = maxArgs - (len(self.func.func_defaults) if self.func.func_defaults else 0)
|
||||
|
||||
args = string.split(None, maxArgs-1)[:maxArgs]
|
||||
if len(args) < minArgs:
|
||||
raise MagicError('Magic word %s requires at least %d arguments' % (self.name, minArgs))
|
||||
|
||||
output = []
|
||||
for i, (type, arg) in enumerate(zip(self.types, args)):
|
||||
try:
|
||||
targ = type(arg)
|
||||
except (TypeError, ValueError):
|
||||
raise MagicError('Argument %d of magic word %s must be %s' % (i, self.name, type.__name__))
|
||||
|
||||
output.append(targ)
|
||||
|
||||
return output
|
||||
|
||||
def run(self, rawArgs):
|
||||
args = self.parseArgs(rawArgs)
|
||||
return self.func(*args)
|
||||
|
||||
|
||||
class MagicWordDecorator:
|
||||
"""
|
||||
This class manages Magic Word decoration. It is aliased as magicWord, so that
|
||||
the @magicWord(...) construct instantiates this class and has the resulting
|
||||
object process the Magic Word's construction.
|
||||
"""
|
||||
|
||||
def __init__(self, name=None, types=[str], access=None, category=CATEGORY_UNKNOWN):
|
||||
self.name = name
|
||||
self.types = types
|
||||
self.category = category
|
||||
if access is not None:
|
||||
self.access = access
|
||||
else:
|
||||
self.access = self.category.defaultAccess
|
||||
|
||||
def __call__(self, mw):
|
||||
# This is the actual decoration routine. We add the function 'mw' as a
|
||||
# Magic Word to the Spellbook, using the attributes specified at construction
|
||||
# time.
|
||||
|
||||
name = self.name
|
||||
if name is None:
|
||||
name = mw.func_name
|
||||
|
||||
word = MagicWord(name, mw, self.types, self.access, mw.__doc__)
|
||||
spellbook.addWord(word)
|
||||
|
||||
return mw
|
||||
|
||||
magicWord = MagicWordDecorator
|
45
otp/ai/MagicWordManager.py
Normal file
45
otp/ai/MagicWordManager.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.distributed import DistributedObject
|
||||
|
||||
from otp.ai.MagicWordGlobal import *
|
||||
|
||||
|
||||
lastClickedNametag = None
|
||||
|
||||
|
||||
class MagicWordManager(DistributedObject.DistributedObject):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('MagicWordManager')
|
||||
neverDisable = 1
|
||||
|
||||
def generate(self):
|
||||
DistributedObject.DistributedObject.generate(self)
|
||||
self.accept('magicWord', self.handleMagicWord)
|
||||
|
||||
def disable(self):
|
||||
self.ignore('magicWord')
|
||||
DistributedObject.DistributedObject.disable(self)
|
||||
|
||||
def handleMagicWord(self, magicWord):
|
||||
if not self.cr.wantMagicWords:
|
||||
return
|
||||
|
||||
if magicWord.startswith('~~'):
|
||||
if lastClickedNametag == None:
|
||||
target = base.localAvatar
|
||||
else:
|
||||
target = lastClickedNametag
|
||||
magicWord = magicWord[2:]
|
||||
if magicWord.startswith('~'):
|
||||
target = base.localAvatar
|
||||
magicWord = magicWord[1:]
|
||||
|
||||
targetId = target.doId
|
||||
self.sendUpdate('sendMagicWord', [magicWord, targetId])
|
||||
if target == base.localAvatar:
|
||||
response = spellbook.process(base.localAvatar, target, magicWord)
|
||||
if response:
|
||||
self.sendMagicWordResponse(response)
|
||||
|
||||
def sendMagicWordResponse(self, response):
|
||||
self.notify.info(response)
|
||||
base.localAvatar.setSystemMessage(0, 'Spellbook: ' + str(response))
|
77
otp/ai/MagicWordManagerAI.py
Normal file
77
otp/ai/MagicWordManagerAI.py
Normal file
|
@ -0,0 +1,77 @@
|
|||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.distributed.DistributedObjectAI import DistributedObjectAI
|
||||
from otp.ai.MagicWordGlobal import *
|
||||
from direct.distributed.PyDatagram import PyDatagram
|
||||
from direct.distributed.MsgTypes import *
|
||||
|
||||
class MagicWordManagerAI(DistributedObjectAI):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("MagicWordManagerAI")
|
||||
|
||||
def sendMagicWord(self, word, targetId):
|
||||
invokerId = self.air.getAvatarIdFromSender()
|
||||
invoker = self.air.doId2do.get(invokerId)
|
||||
|
||||
if not 'DistributedToonAI' in str(self.air.doId2do.get(targetId)):
|
||||
self.sendUpdateToAvatarId(invokerId, 'sendMagicWordResponse', ['Target is not a toon object!'])
|
||||
return
|
||||
|
||||
if not invoker:
|
||||
self.sendUpdateToAvatarId(invokerId, 'sendMagicWordResponse', ['missing invoker'])
|
||||
return
|
||||
|
||||
if invoker.getAdminAccess() < MINIMUM_MAGICWORD_ACCESS:
|
||||
self.air.writeServerEvent('suspicious', invokerId, 'Attempted to issue magic word: %s' % word)
|
||||
dg = PyDatagram()
|
||||
dg.addServerHeader(self.GetPuppetConnectionChannel(invokerId), self.air.ourChannel, CLIENTAGENT_EJECT)
|
||||
dg.addUint16(126)
|
||||
dg.addString('Magic Words are reserved for administrators only!')
|
||||
self.air.send(dg)
|
||||
return
|
||||
|
||||
target = self.air.doId2do.get(targetId)
|
||||
if not target:
|
||||
self.sendUpdateToAvatarId(invokerId, 'sendMagicWordResponse', ['missing target'])
|
||||
return
|
||||
|
||||
response = spellbook.process(invoker, target, word)
|
||||
if response:
|
||||
self.sendUpdateToAvatarId(invokerId, 'sendMagicWordResponse', [response])
|
||||
|
||||
self.air.writeServerEvent('magic-word',
|
||||
invokerId, invoker.getAdminAccess(),
|
||||
targetId, target.getAdminAccess(),
|
||||
word, response)
|
||||
|
||||
@magicWord(category=CATEGORY_COMMUNITY_MANAGER, types=[str])
|
||||
def help(wordName=None):
|
||||
print 'help called with %s' % (wordName)
|
||||
if not wordName:
|
||||
return "What were you interested getting help for?"
|
||||
word = spellbook.words.get(wordName.lower()) # look it up by its lower case value
|
||||
if not word:
|
||||
accessLevel = spellbook.getInvoker().getAdminAccess()
|
||||
wname = wordName.lower()
|
||||
for key in spellbook.words:
|
||||
if spellbook.words.get(key).access <= accessLevel:
|
||||
if wname in key:
|
||||
return 'Did you mean %s' % (spellbook.words.get(key).name)
|
||||
return 'I have no clue what %s is refering to' % (wordName)
|
||||
return word.doc
|
||||
|
||||
@magicWord(category=CATEGORY_COMMUNITY_MANAGER, types=[])
|
||||
def words():
|
||||
accessLevel = spellbook.getInvoker().getAdminAccess()
|
||||
wordString = None
|
||||
for key in spellbook.words:
|
||||
word = spellbook.words.get(key)
|
||||
if word.access <= accessLevel:
|
||||
if wordString is None:
|
||||
wordString = key
|
||||
else:
|
||||
wordString += ", ";
|
||||
wordString += key;
|
||||
if wordString is None:
|
||||
return "You are chopped liver"
|
||||
else:
|
||||
return wordString
|
||||
|
352
otp/ai/TimeManager.py
Normal file
352
otp/ai/TimeManager.py
Normal file
|
@ -0,0 +1,352 @@
|
|||
import base64
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.distributed import DistributedObject
|
||||
from direct.distributed.ClockDelta import *
|
||||
from direct.showbase import GarbageReport
|
||||
from direct.showbase import PythonUtil
|
||||
from direct.showbase.DirectObject import *
|
||||
from direct.task import Task
|
||||
import os
|
||||
from pandac.PandaModules import *
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
|
||||
from otp.otpbase import OTPGlobals
|
||||
from toontown.chat.ChatGlobals import *
|
||||
|
||||
|
||||
class TimeManager(DistributedObject.DistributedObject):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('TimeManager')
|
||||
neverDisable = 1
|
||||
|
||||
def __init__(self, cr):
|
||||
DistributedObject.DistributedObject.__init__(self, cr)
|
||||
self.updateFreq = base.config.GetFloat('time-manager-freq', 1800)
|
||||
self.minWait = base.config.GetFloat('time-manager-min-wait', 10)
|
||||
self.maxUncertainty = base.config.GetFloat('time-manager-max-uncertainty', 1)
|
||||
self.maxAttempts = base.config.GetInt('time-manager-max-attempts', 5)
|
||||
self.extraSkew = base.config.GetInt('time-manager-extra-skew', 0)
|
||||
if self.extraSkew != 0:
|
||||
self.notify.info('Simulating clock skew of %0.3f s' % self.extraSkew)
|
||||
self.reportFrameRateInterval = base.config.GetDouble('report-frame-rate-interval', 300.0)
|
||||
self.talkResult = 0
|
||||
self.thisContext = -1
|
||||
self.nextContext = 0
|
||||
self.attemptCount = 0
|
||||
self.start = 0
|
||||
self.lastAttempt = -self.minWait * 2
|
||||
self.setFrameRateInterval(self.reportFrameRateInterval)
|
||||
self._numClientGarbage = 0
|
||||
|
||||
def generate(self):
|
||||
self._gotFirstTimeSync = False
|
||||
if self.cr.timeManager != None:
|
||||
self.cr.timeManager.delete()
|
||||
self.cr.timeManager = self
|
||||
DistributedObject.DistributedObject.generate(self)
|
||||
self.accept(OTPGlobals.SynchronizeHotkey, self.handleHotkey)
|
||||
self.accept('clock_error', self.handleClockError)
|
||||
if __dev__ and base.config.GetBool('enable-garbage-hotkey', 0):
|
||||
self.accept(OTPGlobals.DetectGarbageHotkey, self.handleDetectGarbageHotkey)
|
||||
if self.updateFreq > 0:
|
||||
self.startTask()
|
||||
return
|
||||
|
||||
def announceGenerate(self):
|
||||
DistributedObject.DistributedObject.announceGenerate(self)
|
||||
self.synchronize('TimeManager.announceGenerate')
|
||||
|
||||
def gotInitialTimeSync(self):
|
||||
return self._gotFirstTimeSync
|
||||
|
||||
def disable(self):
|
||||
self.ignore(OTPGlobals.SynchronizeHotkey)
|
||||
if __dev__:
|
||||
self.ignore(OTPGlobals.DetectGarbageHotkey)
|
||||
self.ignore('clock_error')
|
||||
self.stopTask()
|
||||
taskMgr.remove('frameRateMonitor')
|
||||
if self.cr.timeManager == self:
|
||||
self.cr.timeManager = None
|
||||
del self._gotFirstTimeSync
|
||||
DistributedObject.DistributedObject.disable(self)
|
||||
return
|
||||
|
||||
def delete(self):
|
||||
self.ignore(OTPGlobals.SynchronizeHotkey)
|
||||
self.ignore(OTPGlobals.DetectGarbageHotkey)
|
||||
self.ignore('clock_error')
|
||||
self.stopTask()
|
||||
taskMgr.remove('frameRateMonitor')
|
||||
if self.cr.timeManager == self:
|
||||
self.cr.timeManager = None
|
||||
DistributedObject.DistributedObject.delete(self)
|
||||
return
|
||||
|
||||
def startTask(self):
|
||||
self.stopTask()
|
||||
taskMgr.doMethodLater(self.updateFreq, self.doUpdate, 'timeMgrTask')
|
||||
|
||||
def stopTask(self):
|
||||
taskMgr.remove('timeMgrTask')
|
||||
|
||||
def doUpdate(self, task):
|
||||
self.synchronize('timer')
|
||||
taskMgr.doMethodLater(self.updateFreq, self.doUpdate, 'timeMgrTask')
|
||||
return Task.done
|
||||
|
||||
def handleHotkey(self):
|
||||
self.lastAttempt = -self.minWait * 2
|
||||
if self.synchronize('user hotkey'):
|
||||
self.talkResult = 1
|
||||
else:
|
||||
base.localAvatar.setChatAbsolute('Too soon.', CFSpeech | CFTimeout)
|
||||
|
||||
def handleClockError(self):
|
||||
self.synchronize('clock error')
|
||||
|
||||
def synchronize(self, description):
|
||||
now = globalClock.getRealTime()
|
||||
if now - self.lastAttempt < self.minWait:
|
||||
self.notify.debug('Not resyncing (too soon): %s' % description)
|
||||
return 0
|
||||
self.talkResult = 0
|
||||
self.thisContext = self.nextContext
|
||||
self.attemptCount = 0
|
||||
self.nextContext = self.nextContext + 1 & 255
|
||||
self.notify.info('Clock sync: %s' % description)
|
||||
self.start = now
|
||||
self.lastAttempt = now
|
||||
self.sendUpdate('requestServerTime', [self.thisContext])
|
||||
return 1
|
||||
|
||||
def serverTime(self, context, timestamp, timeOfDay):
|
||||
end = globalClock.getRealTime()
|
||||
aiTimeSkew = timeOfDay - self.cr.getServerTimeOfDay()
|
||||
if context != self.thisContext:
|
||||
self.notify.info('Ignoring TimeManager response for old context %d' % context)
|
||||
return
|
||||
elapsed = end - self.start
|
||||
self.attemptCount += 1
|
||||
self.notify.info('Clock sync roundtrip took %0.3f ms' % (elapsed * 1000.0))
|
||||
self.notify.info('AI time delta is %s from server delta' % PythonUtil.formatElapsedSeconds(aiTimeSkew))
|
||||
average = (self.start + end) / 2.0 - self.extraSkew
|
||||
uncertainty = (end - self.start) / 2.0 + abs(self.extraSkew)
|
||||
globalClockDelta.resynchronize(average, timestamp, uncertainty)
|
||||
self.notify.info('Local clock uncertainty +/- %.3f s' % globalClockDelta.getUncertainty())
|
||||
if globalClockDelta.getUncertainty() > self.maxUncertainty:
|
||||
if self.attemptCount < self.maxAttempts:
|
||||
self.notify.info('Uncertainty is too high, trying again.')
|
||||
self.start = globalClock.getRealTime()
|
||||
self.sendUpdate('requestServerTime', [self.thisContext])
|
||||
return
|
||||
self.notify.info('Giving up on uncertainty requirement.')
|
||||
if self.talkResult:
|
||||
base.localAvatar.setChatAbsolute('latency %0.0f ms, sync \xc2\xb1%0.0f ms' % (elapsed * 1000.0, globalClockDelta.getUncertainty() * 1000.0), CFSpeech | CFTimeout)
|
||||
self._gotFirstTimeSync = True
|
||||
messenger.send('gotTimeSync')
|
||||
|
||||
toontownTimeManager = getattr(base.cr, 'toontownTimeManager', None)
|
||||
if toontownTimeManager:
|
||||
toontownTimeManager.updateLoginTimes(timeOfDay, int(time.time()), globalClock.getRealTime())
|
||||
|
||||
def setDisconnectReason(self, disconnectCode):
|
||||
self.notify.info('Client disconnect reason %s.' % disconnectCode)
|
||||
self.sendUpdate('setDisconnectReason', [disconnectCode])
|
||||
|
||||
def setExceptionInfo(self):
|
||||
info = PythonUtil.describeException()
|
||||
self.notify.info('Client exception: %s' % info)
|
||||
self.sendUpdate('setExceptionInfo', [info])
|
||||
self.cr.flush()
|
||||
|
||||
def setStackDump(self, dump):
|
||||
self.notify.debug('Stack dump: %s' % fastRepr(dump))
|
||||
maxLen = 900
|
||||
dataLeft = base64.b64encode(dump)
|
||||
index = 0
|
||||
while dataLeft:
|
||||
if len(dataLeft) >= maxLen:
|
||||
data = dataLeft[:maxLen]
|
||||
dataLeft = dataLeft[maxLen:]
|
||||
else:
|
||||
data = dataLeft
|
||||
dataLeft = None
|
||||
self.sendUpdate('setStackDump', [index, data])
|
||||
index += 1
|
||||
self.cr.flush()
|
||||
|
||||
return
|
||||
|
||||
def d_setSignature(self, signature, hash, pyc):
|
||||
self.sendUpdate('setSignature', [signature, hash, pyc])
|
||||
|
||||
def sendCpuInfo(self):
|
||||
if not base.pipe:
|
||||
return
|
||||
di = base.pipe.getDisplayInformation()
|
||||
if di.getNumCpuCores() == 0 and hasattr(base.pipe, 'lookupCpuData'):
|
||||
base.pipe.lookupCpuData()
|
||||
di = base.pipe.getDisplayInformation()
|
||||
di.updateCpuFrequency(0)
|
||||
try:
|
||||
cacheStatus = preloadCache()
|
||||
except NameError:
|
||||
cacheStatus = ''
|
||||
|
||||
ooghz = 1e-09
|
||||
cpuSpeed = (di.getMaximumCpuFrequency() * ooghz, di.getCurrentCpuFrequency() * ooghz)
|
||||
numCpuCores = di.getNumCpuCores()
|
||||
numLogicalCpus = di.getNumLogicalCpus()
|
||||
info = '%s|%s|%d|%d|%s|%s cpus' % (di.getCpuVendorString(),
|
||||
di.getCpuBrandString(),
|
||||
di.getCpuVersionInformation(),
|
||||
di.getCpuBrandIndex(),
|
||||
'%0.03f,%0.03f' % cpuSpeed,
|
||||
'%d,%d' % (numCpuCores, numLogicalCpus))
|
||||
self.notify.debug('setCpuInfo: "%s"' % info)
|
||||
self.sendUpdate('setCpuInfo', [info, cacheStatus])
|
||||
|
||||
def setFrameRateInterval(self, frameRateInterval):
|
||||
if frameRateInterval == 0:
|
||||
return
|
||||
if not base.frameRateMeter:
|
||||
maxFrameRateInterval = base.config.GetDouble('max-frame-rate-interval', 30.0)
|
||||
globalClock.setAverageFrameRateInterval(min(frameRateInterval, maxFrameRateInterval))
|
||||
taskMgr.remove('frameRateMonitor')
|
||||
taskMgr.doMethodLater(frameRateInterval, self.frameRateMonitor, 'frameRateMonitor')
|
||||
|
||||
def frameRateMonitor(self, task):
|
||||
from otp.avatar.Avatar import Avatar
|
||||
vendorId = 0
|
||||
deviceId = 0
|
||||
processMemory = 0
|
||||
pageFileUsage = 0
|
||||
physicalMemory = 0
|
||||
pageFaultCount = 0
|
||||
osInfo = (os.name,
|
||||
0,
|
||||
0,
|
||||
0)
|
||||
cpuSpeed = (0, 0)
|
||||
numCpuCores = 0
|
||||
numLogicalCpus = 0
|
||||
apiName = 'None'
|
||||
if getattr(base, 'pipe', None):
|
||||
di = base.pipe.getDisplayInformation()
|
||||
if di.getDisplayState() == DisplayInformation.DSSuccess:
|
||||
vendorId = di.getVendorId()
|
||||
deviceId = di.getDeviceId()
|
||||
di.updateMemoryInformation()
|
||||
oomb = 1.0 / (1024.0 * 1024.0)
|
||||
processMemory = di.getProcessMemory() * oomb
|
||||
pageFileUsage = di.getPageFileUsage() * oomb
|
||||
physicalMemory = di.getPhysicalMemory() * oomb
|
||||
pageFaultCount = di.getPageFaultCount() / 1000.0
|
||||
osInfo = (os.name,
|
||||
di.getOsPlatformId(),
|
||||
di.getOsVersionMajor(),
|
||||
di.getOsVersionMinor())
|
||||
if sys.platform == 'darwin':
|
||||
osInfo = self.getMacOsInfo(osInfo)
|
||||
di.updateCpuFrequency(0)
|
||||
ooghz = 1e-09
|
||||
cpuSpeed = (di.getMaximumCpuFrequency() * ooghz, di.getCurrentCpuFrequency() * ooghz)
|
||||
numCpuCores = di.getNumCpuCores()
|
||||
numLogicalCpus = di.getNumLogicalCpus()
|
||||
apiName = base.pipe.getInterfaceName()
|
||||
self.d_setFrameRate(max(0, globalClock.getAverageFrameRate()), max(0, globalClock.calcFrameRateDeviation()), len(Avatar.ActiveAvatars), base.locationCode or '', max(0, time.time() - base.locationCodeChanged), max(0, globalClock.getRealTime()), base.gameOptionsCode, vendorId, deviceId, processMemory, pageFileUsage, physicalMemory, pageFaultCount, osInfo, cpuSpeed, numCpuCores, numLogicalCpus, apiName)
|
||||
return task.again
|
||||
|
||||
def d_setFrameRate(self, fps, deviation, numAvs, locationCode, timeInLocation, timeInGame, gameOptionsCode, vendorId, deviceId, processMemory, pageFileUsage, physicalMemory, pageFaultCount, osInfo, cpuSpeed, numCpuCores, numLogicalCpus, apiName):
|
||||
info = '%0.1f fps|%0.3fd|%s avs|%s|%d|%d|%s|0x%04x|0x%04x|%0.1fMB|%0.1fMB|%0.1fMB|%d|%s|%s|%s cpus|%s' % (fps,
|
||||
deviation,
|
||||
numAvs,
|
||||
locationCode,
|
||||
timeInLocation,
|
||||
timeInGame,
|
||||
gameOptionsCode,
|
||||
vendorId,
|
||||
deviceId,
|
||||
processMemory,
|
||||
pageFileUsage,
|
||||
physicalMemory,
|
||||
pageFaultCount,
|
||||
'%s.%d.%d.%d' % osInfo,
|
||||
'%0.03f,%0.03f' % cpuSpeed,
|
||||
'%d,%d' % (numCpuCores, numLogicalCpus),
|
||||
apiName)
|
||||
print 'frame rate: %s' % info
|
||||
self.sendUpdate('setFrameRate', [fps,
|
||||
deviation,
|
||||
numAvs,
|
||||
locationCode,
|
||||
timeInLocation,
|
||||
timeInGame,
|
||||
gameOptionsCode,
|
||||
vendorId,
|
||||
deviceId,
|
||||
processMemory,
|
||||
pageFileUsage,
|
||||
physicalMemory,
|
||||
pageFaultCount,
|
||||
osInfo,
|
||||
cpuSpeed,
|
||||
numCpuCores,
|
||||
numLogicalCpus,
|
||||
apiName])
|
||||
|
||||
if __dev__:
|
||||
|
||||
def handleDetectGarbageHotkey(self):
|
||||
self._numClientGarbage = GarbageReport.b_checkForGarbageLeaks(wantReply=True)
|
||||
if self._numClientGarbage:
|
||||
s = '%s client garbage cycles found, see log' % self._numClientGarbage
|
||||
else:
|
||||
s = '0 client garbage cycles found'
|
||||
localAvatar.setChatAbsolute(s, CFSpeech | CFTimeout)
|
||||
|
||||
def d_checkForGarbageLeaks(self, wantReply):
|
||||
self.sendUpdate('checkForGarbageLeaks', [wantReply])
|
||||
|
||||
def setNumAIGarbageLeaks(self, numLeaks):
|
||||
if self._numClientGarbage and numLeaks:
|
||||
s = '%s client and %s AI garbage cycles found, see logs' % (self._numClientGarbage, numLeaks)
|
||||
elif numLeaks:
|
||||
s = '0 client and %s AI garbage cycles found, see log' % numLeaks
|
||||
else:
|
||||
s = '0 client and 0 AI garbage cycles found'
|
||||
localAvatar.setChatAbsolute(s, CFSpeech | CFTimeout)
|
||||
|
||||
def d_setClientGarbageLeak(self, num, description):
|
||||
self.sendUpdate('setClientGarbageLeak', [num, description])
|
||||
|
||||
def getMacOsInfo(self, defaultOsInfo):
|
||||
result = defaultOsInfo
|
||||
try:
|
||||
theFile = open('/System/Library/CoreServices/SystemVersion.plist')
|
||||
except IOError:
|
||||
pass
|
||||
else:
|
||||
key = re.search('<key>ProductUserVisibleVersion</key>\\s*' + '<string>(.*?)</string>', theFile.read())
|
||||
theFile.close()
|
||||
if key is not None:
|
||||
try:
|
||||
verString = key.group(1)
|
||||
parts = verString.split('.')
|
||||
major = int(parts[0])
|
||||
minor = int(parts[1])
|
||||
bugfix = int(parts[2])
|
||||
result = (sys.platform,
|
||||
bugfix,
|
||||
major,
|
||||
minor)
|
||||
except Exception, e:
|
||||
self.notify.debug('getMacOsInfo %s' % str(e))
|
||||
|
||||
self.notify.debug('getMacOsInfo returning %s' % str(result))
|
||||
return result
|
||||
|
||||
def checkAvOnDistrict(self, av, context):
|
||||
self.sendUpdate('checkAvOnDistrict', [context, av.doId])
|
42
otp/ai/TimeManagerAI.py
Normal file
42
otp/ai/TimeManagerAI.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.distributed.DistributedObjectAI import DistributedObjectAI
|
||||
from direct.distributed.ClockDelta import globalClockDelta
|
||||
import time
|
||||
|
||||
class TimeManagerAI(DistributedObjectAI):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("TimeManagerAI")
|
||||
|
||||
def requestServerTime(self, context):
|
||||
self.sendUpdateToAvatarId(self.air.getAvatarIdFromSender(),
|
||||
'serverTime', [context,
|
||||
globalClockDelta.getRealNetworkTime(bits=32),
|
||||
int(time.time())])
|
||||
|
||||
def setDisconnectReason(self, reason):
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
self.air.writeServerEvent('disconnect-reason', avId, reason)
|
||||
|
||||
def setExceptionInfo(self, exception):
|
||||
avId = self.air.getAvatarIdFromSender()
|
||||
self.air.writeServerEvent('client-exception', avId, exception)
|
||||
|
||||
def setSignature(self, todo0, todo1, todo2):
|
||||
pass
|
||||
|
||||
def setFrameRate(self, todo0, todo1, todo2, todo3, todo4, todo5, todo6, todo7, todo8, todo9, todo10, todo11, todo12, todo13, todo14, todo15, todo16, todo17):
|
||||
pass
|
||||
|
||||
def setCpuInfo(self, todo0, todo1):
|
||||
pass
|
||||
|
||||
def checkForGarbageLeaks(self, todo0):
|
||||
pass
|
||||
|
||||
def setNumAIGarbageLeaks(self, todo0):
|
||||
pass
|
||||
|
||||
def setClientGarbageLeak(self, todo0, todo1):
|
||||
pass
|
||||
|
||||
def checkAvOnDistrict(self, todo0, todo1):
|
||||
pass
|
0
otp/ai/__init__.py
Normal file
0
otp/ai/__init__.py
Normal file
664
otp/avatar/Avatar.py
Normal file
664
otp/avatar/Avatar.py
Normal file
|
@ -0,0 +1,664 @@
|
|||
from direct.actor.Actor import Actor
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.distributed import ClockDelta
|
||||
from direct.showbase.PythonUtil import recordCreationStack
|
||||
from pandac.PandaModules import *
|
||||
import random
|
||||
|
||||
from otp.ai import MagicWordManager
|
||||
from otp.ai.MagicWordGlobal import *
|
||||
from otp.avatar.ShadowCaster import ShadowCaster
|
||||
from otp.otpbase import OTPGlobals
|
||||
from otp.otpbase import OTPLocalizer
|
||||
from otp.otpbase import OTPRender
|
||||
from toontown.chat.ChatGlobals import *
|
||||
from toontown.nametag import NametagGlobals
|
||||
from toontown.nametag.NametagGroup import NametagGroup
|
||||
|
||||
|
||||
teleportNotify = DirectNotifyGlobal.directNotify.newCategory('Teleport')
|
||||
teleportNotify.showTime = True
|
||||
if config.GetBool('want-teleport-debug', 1):
|
||||
teleportNotify.setDebug(1)
|
||||
|
||||
def reconsiderAllUnderstandable():
|
||||
for av in Avatar.ActiveAvatars:
|
||||
av.considerUnderstandable()
|
||||
|
||||
|
||||
class Avatar(Actor, ShadowCaster):
|
||||
notify = directNotify.newCategory('Avatar')
|
||||
ActiveAvatars = []
|
||||
ManagesNametagAmbientLightChanged = False
|
||||
|
||||
def __init__(self, other = None):
|
||||
self.name = ''
|
||||
try:
|
||||
self.Avatar_initialized
|
||||
return
|
||||
except:
|
||||
self.Avatar_initialized = 1
|
||||
|
||||
Actor.__init__(self, None, None, other, flattenable=0, setFinal=1)
|
||||
ShadowCaster.__init__(self)
|
||||
self.__font = OTPGlobals.getInterfaceFont()
|
||||
self.soundChatBubble = None
|
||||
self.avatarType = ''
|
||||
self.nametagNodePath = None
|
||||
self.__nameVisible = 1
|
||||
self.nametag = NametagGroup()
|
||||
self.nametag.setAvatar(self)
|
||||
interfaceFont = OTPGlobals.getInterfaceFont()
|
||||
self.nametag.setFont(interfaceFont)
|
||||
self.nametag.setChatFont(interfaceFont)
|
||||
self.nametag3d = self.attachNewNode('nametag3d')
|
||||
self.nametag3d.setTag('cam', 'nametag')
|
||||
self.nametag3d.setLightOff()
|
||||
if self.ManagesNametagAmbientLightChanged:
|
||||
self.acceptNametagAmbientLightChange()
|
||||
OTPRender.renderReflection(False, self.nametag3d, 'otp_avatar_nametag', None)
|
||||
self.getGeomNode().showThrough(OTPRender.ShadowCameraBitmask)
|
||||
self.nametag3d.hide(OTPRender.ShadowCameraBitmask)
|
||||
self.collTube = None
|
||||
self.battleTube = None
|
||||
self.scale = 1.0
|
||||
self.nametagScale = 1.0
|
||||
self.height = 0.0
|
||||
self.battleTubeHeight = 0.0
|
||||
self.battleTubeRadius = 0.0
|
||||
self.style = None
|
||||
self.commonChatFlags = 0
|
||||
self.understandable = 1
|
||||
self.setPlayerType(NametagGlobals.CCNormal)
|
||||
self.ghostMode = 0
|
||||
self.__chatParagraph = None
|
||||
self.__chatMessage = None
|
||||
self.__chatFlags = 0
|
||||
self.__chatPageNumber = None
|
||||
self.__chatAddressee = None
|
||||
self.__chatDialogueList = []
|
||||
self.__chatSet = 0
|
||||
self.__chatLocal = 0
|
||||
self.__chatQuitButton = False
|
||||
self.__currentDialogue = None
|
||||
self.whitelistChatFlags = 0
|
||||
|
||||
def delete(self):
|
||||
try:
|
||||
self.Avatar_deleted
|
||||
except:
|
||||
self.deleteNametag3d()
|
||||
Actor.cleanup(self)
|
||||
if self.ManagesNametagAmbientLightChanged:
|
||||
self.ignoreNametagAmbientLightChange()
|
||||
self.Avatar_deleted = 1
|
||||
del self.__font
|
||||
del self.style
|
||||
del self.soundChatBubble
|
||||
self.nametag.destroy()
|
||||
del self.nametag
|
||||
self.nametag3d.removeNode()
|
||||
ShadowCaster.delete(self)
|
||||
Actor.delete(self)
|
||||
|
||||
def acceptNametagAmbientLightChange(self):
|
||||
self.accept('nametagAmbientLightChanged', self.nametagAmbientLightChanged)
|
||||
|
||||
def ignoreNametagAmbientLightChange(self):
|
||||
self.ignore('nametagAmbientLightChanged')
|
||||
|
||||
def isLocal(self):
|
||||
return 0
|
||||
|
||||
def isPet(self):
|
||||
return False
|
||||
|
||||
def isProxy(self):
|
||||
return False
|
||||
|
||||
def setPlayerType(self, playerType):
|
||||
self.playerType = playerType
|
||||
if not hasattr(self, 'nametag'):
|
||||
self.notify.warning('no nametag attributed, but would have been used.')
|
||||
return
|
||||
if self.isUnderstandable():
|
||||
nametagColor = NametagGlobals.NametagColors[self.playerType]
|
||||
self.nametag.setNametagColor(nametagColor)
|
||||
chatColor = NametagGlobals.ChatColors[self.playerType]
|
||||
self.nametag.setChatColor(chatColor)
|
||||
else:
|
||||
nametagColor = NametagGlobals.NametagColors[NametagGlobals.CCNoChat]
|
||||
self.nametag.setNametagColor(nametagColor)
|
||||
chatColor = NametagGlobals.ChatColors[NametagGlobals.CCNoChat]
|
||||
self.nametag.setChatColor(chatColor)
|
||||
self.nametag.updateAll()
|
||||
|
||||
def setCommonChatFlags(self, commonChatFlags):
|
||||
self.commonChatFlags = commonChatFlags
|
||||
self.considerUnderstandable()
|
||||
if self == base.localAvatar:
|
||||
reconsiderAllUnderstandable()
|
||||
|
||||
def setWhitelistChatFlags(self, whitelistChatFlags):
|
||||
self.whitelistChatFlags = whitelistChatFlags
|
||||
self.considerUnderstandable()
|
||||
if self == base.localAvatar:
|
||||
reconsiderAllUnderstandable()
|
||||
|
||||
def considerUnderstandable(self):
|
||||
if self.playerType in (NametagGlobals.CCNormal, NametagGlobals.CCFreeChat, NametagGlobals.CCSpeedChat):
|
||||
self.setPlayerType(NametagGlobals.CCSpeedChat)
|
||||
if hasattr(base, 'localAvatar') and (self == base.localAvatar):
|
||||
self.understandable = 1
|
||||
self.setPlayerType(NametagGlobals.CCFreeChat)
|
||||
elif self.playerType == NametagGlobals.CCSuit:
|
||||
self.understandable = 1
|
||||
self.setPlayerType(NametagGlobals.CCSuit)
|
||||
elif self.playerType not in (NametagGlobals.CCNormal, NametagGlobals.CCFreeChat, NametagGlobals.CCSpeedChat):
|
||||
self.understandable = 1
|
||||
self.setPlayerType(NametagGlobals.CCNoChat)
|
||||
elif hasattr(base, 'localAvatar') and self.commonChatFlags & base.localAvatar.commonChatFlags & OTPGlobals.CommonChat:
|
||||
self.understandable = 1
|
||||
self.setPlayerType(NametagGlobals.CCFreeChat)
|
||||
elif self.commonChatFlags & OTPGlobals.SuperChat:
|
||||
self.understandable = 1
|
||||
self.setPlayerType(NametagGlobals.CCFreeChat)
|
||||
elif hasattr(base, 'localAvatar') and base.localAvatar.commonChatFlags & OTPGlobals.SuperChat:
|
||||
self.understandable = 1
|
||||
self.setPlayerType(NametagGlobals.CCFreeChat)
|
||||
elif base.cr.getFriendFlags(self.doId) & OTPGlobals.FriendChat:
|
||||
self.understandable = 1
|
||||
self.setPlayerType(NametagGlobals.CCFreeChat)
|
||||
elif base.cr.playerFriendsManager.findPlayerIdFromAvId(self.doId) is not None:
|
||||
playerInfo = base.cr.playerFriendsManager.findPlayerInfoFromAvId(self.doId)
|
||||
if playerInfo.openChatFriendshipYesNo:
|
||||
self.understandable = 1
|
||||
nametagColor = NametagGlobals.NametagColors[NametagGlobals.CCFreeChat]
|
||||
self.nametag.setNametagColor(nametagColor)
|
||||
chatColor = NametagGlobals.ChatColors[NametagGlobals.CCFreeChat]
|
||||
self.nametag.setChatColor(chatColor)
|
||||
self.nametag.updateAll()
|
||||
elif playerInfo.isUnderstandable():
|
||||
self.understandable = 1
|
||||
else:
|
||||
self.understandable = 0
|
||||
elif hasattr(base, 'localAvatar') and self.whitelistChatFlags & base.localAvatar.whitelistChatFlags:
|
||||
self.understandable = 1
|
||||
else:
|
||||
self.understandable = 0
|
||||
if not hasattr(self, 'nametag'):
|
||||
self.notify.warning('no nametag attributed, but would have been used')
|
||||
else:
|
||||
nametagColor = NametagGlobals.NametagColors[self.playerType]
|
||||
self.nametag.setNametagColor(nametagColor)
|
||||
chatColor = NametagGlobals.ChatColors[self.playerType]
|
||||
self.nametag.setChatColor(chatColor)
|
||||
self.nametag.updateAll()
|
||||
|
||||
def isUnderstandable(self):
|
||||
return self.understandable
|
||||
|
||||
def setDNAString(self, dnaString):
|
||||
pass
|
||||
|
||||
def setDNA(self, dna):
|
||||
pass
|
||||
|
||||
def getAvatarScale(self):
|
||||
return self.scale
|
||||
|
||||
def setAvatarScale(self, scale):
|
||||
if self.scale != scale:
|
||||
self.scale = scale
|
||||
self.getGeomNode().setScale(scale)
|
||||
self.setHeight(self.height)
|
||||
|
||||
def getNametagScale(self):
|
||||
return self.nametagScale
|
||||
|
||||
def setNametagScale(self, scale):
|
||||
self.nametagScale = scale
|
||||
self.nametag3d.setScale(scale)
|
||||
|
||||
def adjustNametag3d(self, parentScale = 1.0):
|
||||
self.nametag3d.setPos(0, 0, self.height + 0.5)
|
||||
|
||||
def getHeight(self):
|
||||
return self.height
|
||||
|
||||
def setHeight(self, height):
|
||||
self.height = height
|
||||
self.adjustNametag3d()
|
||||
if self.collTube:
|
||||
self.collTube.setPointB(0, 0, height - self.getRadius())
|
||||
if self.collNodePath:
|
||||
self.collNodePath.forceRecomputeBounds()
|
||||
if self.battleTube:
|
||||
self.battleTube.setPointB(0, 0, height - self.getRadius())
|
||||
|
||||
def getRadius(self):
|
||||
return OTPGlobals.AvatarDefaultRadius
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def getType(self):
|
||||
return self.avatarType
|
||||
|
||||
def setName(self, name):
|
||||
if hasattr(self, 'isDisguised'):
|
||||
if self.isDisguised:
|
||||
return
|
||||
self.name = name
|
||||
if hasattr(self, 'nametag'):
|
||||
self.nametag.setText(name)
|
||||
|
||||
def setDisplayName(self, str):
|
||||
if hasattr(self, 'isDisguised'):
|
||||
if self.isDisguised:
|
||||
return
|
||||
self.nametag.setText(str)
|
||||
|
||||
def getFont(self):
|
||||
return self.__font
|
||||
|
||||
def setFont(self, font):
|
||||
self.__font = font
|
||||
self.nametag.setFont(font)
|
||||
self.nametag.setChatFont(font)
|
||||
|
||||
def getStyle(self):
|
||||
return self.style
|
||||
|
||||
def setStyle(self, style):
|
||||
self.style = style
|
||||
|
||||
def getDialogueArray(self):
|
||||
return None
|
||||
|
||||
def playCurrentDialogue(self, dialogue, chatFlags, interrupt = 1):
|
||||
if interrupt and self.__currentDialogue is not None:
|
||||
self.__currentDialogue.stop()
|
||||
self.__currentDialogue = dialogue
|
||||
if dialogue:
|
||||
base.playSfx(dialogue, node=self)
|
||||
elif chatFlags & CFSpeech != 0 and self.nametag.getNumChatPages() > 0:
|
||||
self.playDialogueForString(self.nametag.getChatText())
|
||||
if self.soundChatBubble != None:
|
||||
base.playSfx(self.soundChatBubble, node=self)
|
||||
|
||||
def playDialogueForString(self, chatString):
|
||||
searchString = chatString.lower()
|
||||
if searchString.find(OTPLocalizer.DialogSpecial) >= 0:
|
||||
type = 'special'
|
||||
elif searchString.find(OTPLocalizer.DialogExclamation) >= 0:
|
||||
type = 'exclamation'
|
||||
elif searchString.find(OTPLocalizer.DialogQuestion) >= 0:
|
||||
type = 'question'
|
||||
elif random.randint(0, 1):
|
||||
type = 'statementA'
|
||||
else:
|
||||
type = 'statementB'
|
||||
stringLength = len(chatString)
|
||||
if stringLength <= OTPLocalizer.DialogLength1:
|
||||
length = 1
|
||||
elif stringLength <= OTPLocalizer.DialogLength2:
|
||||
length = 2
|
||||
elif stringLength <= OTPLocalizer.DialogLength3:
|
||||
length = 3
|
||||
else:
|
||||
length = 4
|
||||
self.playDialogue(type, length)
|
||||
|
||||
def playDialogue(self, type, length):
|
||||
dialogueArray = self.getDialogueArray()
|
||||
if dialogueArray == None:
|
||||
return
|
||||
sfxIndex = None
|
||||
if type == 'statementA' or type == 'statementB':
|
||||
if length == 1:
|
||||
sfxIndex = 0
|
||||
elif length == 2:
|
||||
sfxIndex = 1
|
||||
elif length >= 3:
|
||||
sfxIndex = 2
|
||||
elif type == 'question':
|
||||
sfxIndex = 3
|
||||
elif type == 'exclamation':
|
||||
sfxIndex = 4
|
||||
elif type == 'special':
|
||||
sfxIndex = 5
|
||||
else:
|
||||
notify.error('unrecognized dialogue type: ', type)
|
||||
if sfxIndex != None and sfxIndex < len(dialogueArray) and dialogueArray[sfxIndex] != None:
|
||||
base.playSfx(dialogueArray[sfxIndex], node=self)
|
||||
return
|
||||
|
||||
def getDialogueSfx(self, type, length):
|
||||
retval = None
|
||||
dialogueArray = self.getDialogueArray()
|
||||
if dialogueArray == None:
|
||||
return
|
||||
sfxIndex = None
|
||||
if type == 'statementA' or type == 'statementB':
|
||||
if length == 1:
|
||||
sfxIndex = 0
|
||||
elif length == 2:
|
||||
sfxIndex = 1
|
||||
elif length >= 3:
|
||||
sfxIndex = 2
|
||||
elif type == 'question':
|
||||
sfxIndex = 3
|
||||
elif type == 'exclamation':
|
||||
sfxIndex = 4
|
||||
elif type == 'special':
|
||||
sfxIndex = 5
|
||||
else:
|
||||
notify.error('unrecognized dialogue type: ', type)
|
||||
if sfxIndex != None and sfxIndex < len(dialogueArray) and dialogueArray[sfxIndex] != None:
|
||||
retval = dialogueArray[sfxIndex]
|
||||
return retval
|
||||
|
||||
def setChatAbsolute(self, chatString, chatFlags, dialogue=None, interrupt=1):
|
||||
self.clearChat()
|
||||
|
||||
if chatFlags & CFQuicktalker:
|
||||
self.nametag.setChatType(NametagGlobals.SPEEDCHAT)
|
||||
else:
|
||||
self.nametag.setChatType(NametagGlobals.CHAT)
|
||||
|
||||
if chatFlags & CFThought:
|
||||
self.nametag.setChatBalloonType(NametagGlobals.THOUGHT_BALLOON)
|
||||
else:
|
||||
self.nametag.setChatBalloonType(NametagGlobals.CHAT_BALLOON)
|
||||
|
||||
if chatFlags & CFPageButton:
|
||||
self.nametag.setChatButton(NametagGlobals.pageButton)
|
||||
else:
|
||||
self.nametag.setChatButton(NametagGlobals.noButton)
|
||||
|
||||
if chatFlags & CFReversed:
|
||||
self.nametag.setChatReversed(True)
|
||||
else:
|
||||
self.nametag.setChatReversed(False)
|
||||
|
||||
self.nametag.setChatText(chatString, timeout=(chatFlags & CFTimeout))
|
||||
self.playCurrentDialogue(dialogue, chatFlags, interrupt)
|
||||
|
||||
def setChatMuted(self, chatString, chatFlags, dialogue = None, interrupt = 1, quiet = 0):
|
||||
pass
|
||||
|
||||
def displayTalk(self, chatString):
|
||||
if not base.cr.avatarFriendsManager.checkIgnored(self.doId):
|
||||
self.clearChat()
|
||||
self.nametag.setChatType(NametagGlobals.CHAT)
|
||||
self.nametag.setChatButton(NametagGlobals.noButton)
|
||||
if base.talkAssistant.isThought(chatString):
|
||||
chatString = base.talkAssistant.removeThoughtPrefix(chatString)
|
||||
self.nametag.setChatBalloonType(NametagGlobals.THOUGHT_BALLOON)
|
||||
self.nametag.setChatText(chatString)
|
||||
else:
|
||||
self.nametag.setChatBalloonType(NametagGlobals.CHAT_BALLOON)
|
||||
self.nametag.setChatText(chatString, timeout=True)
|
||||
|
||||
def clearChat(self):
|
||||
self.nametag.clearChatText()
|
||||
|
||||
def isInView(self):
|
||||
pos = self.getPos(camera)
|
||||
eyePos = Point3(pos[0], pos[1], pos[2] + self.getHeight())
|
||||
return base.camNode.isInView(eyePos)
|
||||
|
||||
def getNameVisible(self):
|
||||
return self.__nameVisible
|
||||
|
||||
def setNameVisible(self, bool):
|
||||
self.__nameVisible = bool
|
||||
if bool:
|
||||
self.showName()
|
||||
if not bool:
|
||||
self.hideName()
|
||||
|
||||
def hideName(self):
|
||||
nametag3d = self.nametag.getNametag3d()
|
||||
nametag3d.hideNametag()
|
||||
nametag3d.showChat()
|
||||
nametag3d.showThought()
|
||||
nametag3d.update()
|
||||
|
||||
def showName(self):
|
||||
if self.__nameVisible and (not self.ghostMode):
|
||||
nametag3d = self.nametag.getNametag3d()
|
||||
nametag3d.showNametag()
|
||||
nametag3d.showChat()
|
||||
nametag3d.showThought()
|
||||
nametag3d.update()
|
||||
|
||||
def hideNametag2d(self):
|
||||
nametag2d = self.nametag.getNametag2d()
|
||||
nametag2d.hideNametag()
|
||||
nametag2d.hideChat()
|
||||
nametag2d.update()
|
||||
|
||||
def showNametag2d(self):
|
||||
nametag2d = self.nametag.getNametag2d()
|
||||
if not self.ghostMode:
|
||||
nametag2d.showNametag()
|
||||
nametag2d.showChat()
|
||||
else:
|
||||
nametag2d.hideNametag()
|
||||
nametag2d.hideChat()
|
||||
nametag2d.update()
|
||||
|
||||
def hideNametag3d(self):
|
||||
nametag3d = self.nametag.getNametag3d()
|
||||
nametag3d.hideNametag()
|
||||
nametag3d.hideChat()
|
||||
nametag3d.hideThought()
|
||||
nametag3d.update()
|
||||
|
||||
def showNametag3d(self):
|
||||
nametag3d = self.nametag.getNametag3d()
|
||||
if self.__nameVisible and (not self.ghostMode):
|
||||
nametag3d.showNametag()
|
||||
nametag3d.showChat()
|
||||
nametag3d.showThought()
|
||||
else:
|
||||
nametag3d.hideNametag()
|
||||
nametag3d.hideChat()
|
||||
nametag3d.hideThought()
|
||||
nametag3d.update()
|
||||
|
||||
def setPickable(self, flag):
|
||||
self.nametag.setActive(flag)
|
||||
|
||||
def clickedNametag(self):
|
||||
MagicWordManager.lastClickedNametag = self
|
||||
if self.nametag.getChatText() and self.nametag.hasChatButton():
|
||||
self.advancePageNumber()
|
||||
elif self.nametag.getActive():
|
||||
messenger.send('clickedNametag', [self])
|
||||
|
||||
def setPageChat(self, addressee, paragraph, message, quitButton,
|
||||
extraChatFlags=None, dialogueList=[], pageButton=True):
|
||||
self.__chatAddressee = addressee
|
||||
self.__chatPageNumber = None
|
||||
self.__chatParagraph = paragraph
|
||||
self.__chatMessage = message
|
||||
self.__chatFlags = CFSpeech
|
||||
if extraChatFlags is not None:
|
||||
self.__chatFlags |= extraChatFlags
|
||||
self.__chatDialogueList = dialogueList
|
||||
self.__chatSet = 0
|
||||
self.__chatLocal = 0
|
||||
self.__updatePageChat()
|
||||
if addressee == base.localAvatar.doId:
|
||||
if pageButton:
|
||||
self.__chatFlags |= CFPageButton
|
||||
self.__chatQuitButton = quitButton
|
||||
self.b_setPageNumber(self.__chatParagraph, 0)
|
||||
|
||||
def setLocalPageChat(self, message, quitButton, extraChatFlags=None,
|
||||
dialogueList=[]):
|
||||
self.__chatAddressee = base.localAvatar.doId
|
||||
self.__chatPageNumber = None
|
||||
self.__chatParagraph = None
|
||||
self.__chatMessage = message
|
||||
self.__chatFlags = CFSpeech
|
||||
if extraChatFlags is not None:
|
||||
self.__chatFlags |= extraChatFlags
|
||||
self.__chatDialogueList = dialogueList
|
||||
self.__chatSet = 1
|
||||
self.__chatLocal = 1
|
||||
self.__chatFlags |= CFPageButton
|
||||
self.__chatQuitButton = quitButton
|
||||
if len(dialogueList) > 0:
|
||||
dialogue = dialogueList[0]
|
||||
else:
|
||||
dialogue = None
|
||||
self.clearChat()
|
||||
self.setChatAbsolute(message, self.__chatFlags, dialogue)
|
||||
self.setPageNumber(None, 0)
|
||||
|
||||
def setPageNumber(self, paragraph, pageNumber, timestamp=None):
|
||||
if timestamp is None:
|
||||
elapsed = 0.0
|
||||
else:
|
||||
elapsed = ClockDelta.globalClockDelta.localElapsedTime(timestamp)
|
||||
self.__chatPageNumber = [paragraph, pageNumber]
|
||||
self.__updatePageChat()
|
||||
if hasattr(self, 'uniqueName'):
|
||||
if pageNumber >= 0:
|
||||
messenger.send(self.uniqueName('nextChatPage'), [pageNumber, elapsed])
|
||||
else:
|
||||
messenger.send(self.uniqueName('doneChatPage'), [elapsed])
|
||||
elif pageNumber >= 0:
|
||||
messenger.send('nextChatPage', [pageNumber, elapsed])
|
||||
else:
|
||||
messenger.send('doneChatPage', [elapsed])
|
||||
|
||||
def advancePageNumber(self):
|
||||
if (self.__chatAddressee == base.localAvatar.doId) and (
|
||||
self.__chatPageNumber is not None) and (
|
||||
self.__chatPageNumber[0] == self.__chatParagraph):
|
||||
pageNumber = self.__chatPageNumber[1]
|
||||
if pageNumber >= 0:
|
||||
pageNumber += 1
|
||||
if pageNumber >= self.nametag.getNumChatPages():
|
||||
pageNumber = -1
|
||||
if self.__chatQuitButton:
|
||||
if pageNumber == self.nametag.getNumChatPages() - 1:
|
||||
self.nametag.setChatButton(NametagGlobals.quitButton)
|
||||
if self.__chatLocal:
|
||||
self.setPageNumber(self.__chatParagraph, pageNumber)
|
||||
else:
|
||||
self.b_setPageNumber(self.__chatParagraph, pageNumber)
|
||||
|
||||
def __updatePageChat(self):
|
||||
if (self.__chatPageNumber is not None) and (
|
||||
self.__chatPageNumber[0] == self.__chatParagraph):
|
||||
pageNumber = self.__chatPageNumber[1]
|
||||
if pageNumber >= 0:
|
||||
if not self.__chatSet:
|
||||
if len(self.__chatDialogueList) > 0:
|
||||
dialogue = self.__chatDialogueList[0]
|
||||
else:
|
||||
dialogue = None
|
||||
self.setChatAbsolute(self.__chatMessage, self.__chatFlags, dialogue)
|
||||
self.__chatSet = 1
|
||||
if pageNumber < self.nametag.getNumChatPages():
|
||||
if (self.__chatAddressee == base.localAvatar.doId) and self.__chatQuitButton:
|
||||
if pageNumber == self.nametag.getNumChatPages() - 1:
|
||||
self.nametag.setChatButton(NametagGlobals.quitButton)
|
||||
self.nametag.setChatPageIndex(pageNumber)
|
||||
if pageNumber > 0:
|
||||
if len(self.__chatDialogueList) > pageNumber:
|
||||
dialogue = self.__chatDialogueList[pageNumber]
|
||||
else:
|
||||
dialogue = None
|
||||
self.playCurrentDialogue(dialogue, self.__chatFlags)
|
||||
else:
|
||||
self.clearChat()
|
||||
else:
|
||||
self.clearChat()
|
||||
|
||||
def getAirborneHeight(self):
|
||||
height = self.getPos(self.shadowPlacer.shadowNodePath)
|
||||
return height.getZ() + 0.025
|
||||
|
||||
def initializeNametag3d(self):
|
||||
self.deleteNametag3d()
|
||||
nametagNode = self.nametag.getNametag3d()
|
||||
self.nametagNodePath = self.nametag3d.attachNewNode(nametagNode)
|
||||
iconNodePath = self.nametag.getIcon()
|
||||
for cJoint in self.getNametagJoints():
|
||||
cJoint.clearNetTransforms()
|
||||
cJoint.addNetTransform(nametagNode)
|
||||
|
||||
def nametagAmbientLightChanged(self, newlight):
|
||||
self.nametag3d.setLightOff()
|
||||
if newlight:
|
||||
self.nametag3d.setLight(newlight)
|
||||
|
||||
def deleteNametag3d(self):
|
||||
if self.nametagNodePath:
|
||||
self.nametagNodePath.removeNode()
|
||||
self.nametagNodePath = None
|
||||
|
||||
def initializeBodyCollisions(self, collIdStr):
|
||||
self.collTube = CollisionTube(0, 0, 0.5, 0, 0, self.height - self.getRadius(), self.getRadius())
|
||||
self.collNode = CollisionNode(collIdStr)
|
||||
self.collNode.addSolid(self.collTube)
|
||||
self.collNodePath = self.attachNewNode(self.collNode)
|
||||
if self.ghostMode:
|
||||
self.collNode.setCollideMask(OTPGlobals.GhostBitmask)
|
||||
else:
|
||||
self.collNode.setCollideMask(OTPGlobals.WallBitmask)
|
||||
|
||||
def stashBodyCollisions(self):
|
||||
if hasattr(self, 'collNodePath'):
|
||||
self.collNodePath.stash()
|
||||
|
||||
def unstashBodyCollisions(self):
|
||||
if hasattr(self, 'collNodePath'):
|
||||
self.collNodePath.unstash()
|
||||
|
||||
def disableBodyCollisions(self):
|
||||
if hasattr(self, 'collNodePath'):
|
||||
self.collNodePath.removeNode()
|
||||
del self.collNodePath
|
||||
self.collTube = None
|
||||
return
|
||||
|
||||
def addActive(self):
|
||||
if base.wantNametags:
|
||||
try:
|
||||
Avatar.ActiveAvatars.remove(self)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
Avatar.ActiveAvatars.append(self)
|
||||
self.nametag.manage(base.marginManager)
|
||||
self.accept(self.nametag.getUniqueName(), self.clickedNametag)
|
||||
|
||||
def removeActive(self):
|
||||
if base.wantNametags:
|
||||
try:
|
||||
Avatar.ActiveAvatars.remove(self)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
self.nametag.unmanage(base.marginManager)
|
||||
self.ignore(self.nametag.getUniqueName())
|
||||
|
||||
def loop(self, animName, restart = 1, partName = None, fromFrame = None, toFrame = None):
|
||||
return Actor.loop(self, animName, restart, partName, fromFrame, toFrame)
|
||||
|
||||
|
||||
@magicWord(category=CATEGORY_COMMUNITY_MANAGER)
|
||||
def target():
|
||||
"""
|
||||
Returns the current Spellbook target.
|
||||
"""
|
||||
target = spellbook.getTarget()
|
||||
return 'Target: %s-%d [%d]' % (target.getName(), target.doId, target.getAdminAccess())
|
26
otp/avatar/AvatarDNA.py
Normal file
26
otp/avatar/AvatarDNA.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
from pandac.PandaModules import *
|
||||
from direct.directnotify.DirectNotifyGlobal import *
|
||||
import random
|
||||
from direct.distributed.PyDatagram import PyDatagram
|
||||
from direct.distributed.PyDatagramIterator import PyDatagramIterator
|
||||
notify = directNotify.newCategory('AvatarDNA')
|
||||
|
||||
class AvatarDNA:
|
||||
|
||||
def __str__(self):
|
||||
return 'avatar parent class: type undefined'
|
||||
|
||||
def makeNetString(self):
|
||||
notify.error('called makeNetString on avatarDNA parent class')
|
||||
|
||||
def printNetString(self):
|
||||
string = self.makeNetString()
|
||||
dg = PyDatagram(string)
|
||||
dg.dumpHex(ostream)
|
||||
|
||||
def makeFromNetString(self, string):
|
||||
notify.error('called makeFromNetString on avatarDNA parent class')
|
||||
|
||||
def getType(self):
|
||||
notify.error('Invalid DNA type: ', self.type)
|
||||
return type
|
51
otp/avatar/AvatarDetail.py
Normal file
51
otp/avatar/AvatarDetail.py
Normal file
|
@ -0,0 +1,51 @@
|
|||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||
from otp.avatar import Avatar
|
||||
|
||||
class AvatarDetail:
|
||||
notify = directNotify.newCategory('AvatarDetail')
|
||||
|
||||
def __init__(self, doId, callWhenDone):
|
||||
self.id = doId
|
||||
self.callWhenDone = callWhenDone
|
||||
self.enterQuery()
|
||||
|
||||
def isReady(self):
|
||||
return true
|
||||
|
||||
def getId(self):
|
||||
return self.id
|
||||
|
||||
def enterQuery(self):
|
||||
self.avatar = base.cr.doId2do.get(self.id)
|
||||
if self.avatar != None and not self.avatar.ghostMode:
|
||||
self.createdAvatar = 0
|
||||
dclass = self.getDClass()
|
||||
self.__handleResponse(True, self.avatar, dclass)
|
||||
else:
|
||||
self.avatar = self.createHolder()
|
||||
self.createdAvatar = 1
|
||||
self.avatar.doId = self.id
|
||||
dclass = self.getDClass()
|
||||
base.cr.getAvatarDetails(self.avatar, self.__handleResponse, dclass)
|
||||
return
|
||||
|
||||
def exitQuery(self):
|
||||
return true
|
||||
|
||||
def createHolder(self):
|
||||
pass
|
||||
|
||||
def getDClass(self):
|
||||
pass
|
||||
|
||||
def __handleResponse(self, gotData, avatar, dclass):
|
||||
if avatar != self.avatar:
|
||||
self.notify.warning('Ignoring unexpected request for avatar %s' % avatar.doId)
|
||||
return
|
||||
if gotData:
|
||||
self.callWhenDone(self.avatar)
|
||||
del self.callWhenDone
|
||||
else:
|
||||
self.callWhenDone(None)
|
||||
del self.callWhenDone
|
||||
return
|
24
otp/avatar/AvatarHandle.py
Normal file
24
otp/avatar/AvatarHandle.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
|
||||
|
||||
class AvatarHandle:
|
||||
dclassName = 'AvatarHandle'
|
||||
|
||||
def getName(self):
|
||||
if __dev__:
|
||||
pass
|
||||
return ''
|
||||
|
||||
def isOnline(self):
|
||||
if __dev__:
|
||||
pass
|
||||
return False
|
||||
|
||||
def isUnderstandable(self):
|
||||
if __dev__:
|
||||
pass
|
||||
return True
|
||||
|
||||
def setTalkWhisper(self, fromAV, fromAC, avatarName, chat, mods, flags):
|
||||
newText, scrubbed = localAvatar.scrubTalk(chat, mods)
|
||||
base.talkAssistant.receiveWhisperTalk(fromAV, avatarName, fromAC, None, self.avatarId, self.getName(), newText, scrubbed)
|
||||
return
|
75
otp/avatar/AvatarPanel.py
Normal file
75
otp/avatar/AvatarPanel.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
from pandac.PandaModules import *
|
||||
from direct.gui.DirectGui import *
|
||||
from direct.showbase import DirectObject
|
||||
import Avatar
|
||||
from direct.distributed import DistributedObject
|
||||
|
||||
class AvatarPanel(DirectObject.DirectObject):
|
||||
currentAvatarPanel = None
|
||||
|
||||
def __init__(self, avatar, FriendsListPanel = None):
|
||||
if AvatarPanel.currentAvatarPanel:
|
||||
AvatarPanel.currentAvatarPanel.cleanup()
|
||||
AvatarPanel.currentAvatarPanel = self
|
||||
self.friendsListShown = False
|
||||
self.FriendsListPanel = FriendsListPanel
|
||||
if FriendsListPanel:
|
||||
self.friendsListShown = FriendsListPanel.isFriendsListShown()
|
||||
FriendsListPanel.hideFriendsList()
|
||||
if avatar:
|
||||
self.avatar = avatar
|
||||
self.avName = avatar.getName()
|
||||
else:
|
||||
self.avatar = None
|
||||
self.avName = 'Player'
|
||||
if hasattr(avatar, 'uniqueName'):
|
||||
self.avId = avatar.doId
|
||||
self.avDisableName = avatar.uniqueName('disable')
|
||||
self.avGenerateName = avatar.uniqueName('generate')
|
||||
self.avHpChangeName = avatar.uniqueName('hpChange')
|
||||
if self.avId in base.cr.doId2do:
|
||||
self.avatar = base.cr.doId2do[self.avId]
|
||||
else:
|
||||
self.avDisableName = None
|
||||
self.avGenerateName = None
|
||||
self.avHpChangeName = None
|
||||
self.avId = None
|
||||
if self.avDisableName:
|
||||
self.accept(self.avDisableName, self.__handleDisableAvatar)
|
||||
return
|
||||
|
||||
def cleanup(self):
|
||||
if AvatarPanel.currentAvatarPanel != self:
|
||||
return
|
||||
if self.avDisableName:
|
||||
self.ignore(self.avDisableName)
|
||||
if self.avGenerateName:
|
||||
self.ignore(self.avGenerateName)
|
||||
if self.avHpChangeName:
|
||||
self.ignore(self.avHpChangeName)
|
||||
AvatarPanel.currentAvatarPanel = None
|
||||
return
|
||||
|
||||
def __handleClose(self):
|
||||
self.cleanup()
|
||||
AvatarPanel.currentAvatarPanel = None
|
||||
if self.friendsListShown:
|
||||
self.FriendsListPanel.showFriendsList()
|
||||
return
|
||||
|
||||
def __handleDisableAvatar(self):
|
||||
if AvatarPanel.currentAvatarPanel:
|
||||
AvatarPanel.currentAvatarPanel.handleDisableAvatar()
|
||||
else:
|
||||
self.handleDisableAvatar()
|
||||
|
||||
def handleDisableAvatar(self):
|
||||
self.cleanup()
|
||||
AvatarPanel.currentAvatarPanel = None
|
||||
return
|
||||
|
||||
def isHidden(self):
|
||||
return 1
|
||||
|
||||
def getType(self):
|
||||
return None
|
329
otp/avatar/DistributedAvatar.py
Normal file
329
otp/avatar/DistributedAvatar.py
Normal file
|
@ -0,0 +1,329 @@
|
|||
from direct.actor.DistributedActor import DistributedActor
|
||||
from direct.distributed import DistributedNode
|
||||
from direct.interval.IntervalGlobal import *
|
||||
from direct.showbase import PythonUtil
|
||||
from direct.task import Task
|
||||
from pandac.PandaModules import *
|
||||
|
||||
from Avatar import Avatar
|
||||
from otp.ai.MagicWordGlobal import *
|
||||
from otp.otpbase import OTPGlobals
|
||||
from toontown.battle.BattleProps import globalPropPool
|
||||
|
||||
|
||||
class DistributedAvatar(DistributedActor, Avatar):
|
||||
HpTextGenerator = TextNode('HpTextGenerator')
|
||||
HpTextEnabled = 1
|
||||
ManagesNametagAmbientLightChanged = True
|
||||
|
||||
def __init__(self, cr):
|
||||
try:
|
||||
self.DistributedAvatar_initialized
|
||||
return
|
||||
except:
|
||||
self.DistributedAvatar_initialized = 1
|
||||
|
||||
Avatar.__init__(self)
|
||||
DistributedActor.__init__(self, cr)
|
||||
self.hpText = None
|
||||
self.hp = None
|
||||
self.maxHp = None
|
||||
return
|
||||
|
||||
def disable(self):
|
||||
try:
|
||||
del self.DistributedAvatar_announced
|
||||
except:
|
||||
return
|
||||
|
||||
self.reparentTo(hidden)
|
||||
self.removeActive()
|
||||
self.disableBodyCollisions()
|
||||
self.hideHpText()
|
||||
self.hp = None
|
||||
self.ignore('nameTagShowAvId')
|
||||
self.ignore('nameTagShowName')
|
||||
DistributedActor.disable(self)
|
||||
return
|
||||
|
||||
def delete(self):
|
||||
try:
|
||||
self.DistributedAvatar_deleted
|
||||
except:
|
||||
self.DistributedAvatar_deleted = 1
|
||||
Avatar.delete(self)
|
||||
DistributedActor.delete(self)
|
||||
|
||||
def generate(self):
|
||||
DistributedActor.generate(self)
|
||||
if not self.isLocal():
|
||||
self.addActive()
|
||||
self.considerUnderstandable()
|
||||
self.setParent(OTPGlobals.SPHidden)
|
||||
self.setTag('avatarDoId', str(self.doId))
|
||||
self.accept('nameTagShowAvId', self.__nameTagShowAvId)
|
||||
self.accept('nameTagShowName', self.__nameTagShowName)
|
||||
|
||||
def announceGenerate(self):
|
||||
try:
|
||||
self.DistributedAvatar_announced
|
||||
return
|
||||
except:
|
||||
self.DistributedAvatar_announced = 1
|
||||
|
||||
if not self.isLocal():
|
||||
self.initializeBodyCollisions('distAvatarCollNode-' + str(self.doId))
|
||||
DistributedActor.announceGenerate(self)
|
||||
|
||||
def __setTags(self, extra = None):
|
||||
if hasattr(base, 'idTags'):
|
||||
if base.idTags:
|
||||
self.__nameTagShowAvId()
|
||||
else:
|
||||
self.__nameTagShowName()
|
||||
|
||||
def do_setParent(self, parentToken):
|
||||
if not self.isDisabled():
|
||||
nametag2d = self.nametag.getNametag2d()
|
||||
if parentToken == OTPGlobals.SPHidden:
|
||||
nametag2d.hideNametag()
|
||||
else:
|
||||
nametag2d.showNametag()
|
||||
nametag2d.update()
|
||||
DistributedActor.do_setParent(self, parentToken)
|
||||
self.__setTags()
|
||||
|
||||
def toonUp(self, hpGained):
|
||||
if self.hp == None or hpGained < 0:
|
||||
return
|
||||
oldHp = self.hp
|
||||
if self.hp + hpGained <= 0:
|
||||
self.hp += hpGained
|
||||
else:
|
||||
self.hp = min(max(self.hp, 0) + hpGained, self.maxHp)
|
||||
hpGained = self.hp - max(oldHp, 0)
|
||||
if hpGained > 0:
|
||||
self.showHpText(hpGained)
|
||||
self.hpChange(quietly=0)
|
||||
return
|
||||
|
||||
def takeDamage(self, hpLost, bonus = 0):
|
||||
if self.hp == None or hpLost < 0:
|
||||
return
|
||||
oldHp = self.hp
|
||||
self.hp = max(self.hp - hpLost, 0)
|
||||
hpLost = oldHp - self.hp
|
||||
if hpLost > 0:
|
||||
self.showHpText(-hpLost, bonus)
|
||||
self.hpChange(quietly=0)
|
||||
if self.hp <= 0 and oldHp > 0:
|
||||
self.died()
|
||||
return
|
||||
|
||||
def setHp(self, hitPoints):
|
||||
justRanOutOfHp = (hitPoints is not None and self.hp is not None and self.hp - hitPoints > 0) and (hitPoints <= 0)
|
||||
self.hp = hitPoints
|
||||
self.hpChange(quietly=1)
|
||||
if justRanOutOfHp:
|
||||
self.died()
|
||||
return
|
||||
|
||||
def hpChange(self, quietly = 0):
|
||||
if hasattr(self, 'doId'):
|
||||
if self.hp != None and self.maxHp != None:
|
||||
messenger.send(self.uniqueName('hpChange'), [self.hp, self.maxHp, quietly])
|
||||
if self.hp != None and self.hp > 0:
|
||||
messenger.send(self.uniqueName('positiveHP'))
|
||||
return
|
||||
|
||||
def died(self):
|
||||
pass
|
||||
|
||||
def getHp(self):
|
||||
return self.hp
|
||||
|
||||
def setMaxHp(self, hitPoints):
|
||||
self.maxHp = hitPoints
|
||||
self.hpChange()
|
||||
|
||||
def getMaxHp(self):
|
||||
return self.maxHp
|
||||
|
||||
def getName(self):
|
||||
return Avatar.getName(self)
|
||||
|
||||
def setName(self, name):
|
||||
try:
|
||||
self.node().setName('%s-%d' % (name, self.doId))
|
||||
self.gotName = 1
|
||||
except:
|
||||
pass
|
||||
|
||||
return Avatar.setName(self, name)
|
||||
|
||||
def showHpText(self, number, bonus = 0, scale = 1):
|
||||
if self.HpTextEnabled and not self.ghostMode:
|
||||
if number != 0:
|
||||
if self.hpText:
|
||||
self.hideHpText()
|
||||
self.HpTextGenerator.setFont(OTPGlobals.getSignFont())
|
||||
if number < 0:
|
||||
self.HpTextGenerator.setText(str(number))
|
||||
else:
|
||||
self.HpTextGenerator.setText('+' + str(number))
|
||||
self.HpTextGenerator.clearShadow()
|
||||
self.HpTextGenerator.setAlign(TextNode.ACenter)
|
||||
if bonus == 1:
|
||||
r = 1.0
|
||||
g = 1.0
|
||||
b = 0
|
||||
a = 1
|
||||
elif bonus == 2:
|
||||
r = 1.0
|
||||
g = 0.5
|
||||
b = 0
|
||||
a = 1
|
||||
elif number < 0:
|
||||
r = 0.9
|
||||
g = 0
|
||||
b = 0
|
||||
a = 1
|
||||
else:
|
||||
r = 0
|
||||
g = 0.9
|
||||
b = 0
|
||||
a = 1
|
||||
self.HpTextGenerator.setTextColor(r, g, b, a)
|
||||
self.hpTextNode = self.HpTextGenerator.generate()
|
||||
self.hpText = self.attachNewNode(self.hpTextNode)
|
||||
self.hpText.setScale(scale)
|
||||
self.hpText.setBillboardPointEye()
|
||||
self.hpText.setBin('fixed', 100)
|
||||
self.hpText.setPos(0, 0, self.height / 2)
|
||||
seq = Sequence(self.hpText.posInterval(1.0, Point3(0, 0, self.height + 1.5), blendType='easeOut'), Wait(0.85), self.hpText.colorInterval(0.1, Vec4(r, g, b, 0)), Func(self.hideHpText))
|
||||
seq.start()
|
||||
|
||||
def showHpString(self, text, duration = 0.85, scale = 0.7):
|
||||
if self.HpTextEnabled and not self.ghostMode:
|
||||
if text != '':
|
||||
if self.hpText:
|
||||
self.hideHpText()
|
||||
self.HpTextGenerator.setFont(OTPGlobals.getSignFont())
|
||||
self.HpTextGenerator.setText(text)
|
||||
self.HpTextGenerator.clearShadow()
|
||||
self.HpTextGenerator.setAlign(TextNode.ACenter)
|
||||
r = a = 1.0
|
||||
g = b = 0.0
|
||||
self.HpTextGenerator.setTextColor(r, g, b, a)
|
||||
self.hpTextNode = self.HpTextGenerator.generate()
|
||||
self.hpText = self.attachNewNode(self.hpTextNode)
|
||||
self.hpText.setScale(scale)
|
||||
self.hpText.setBillboardAxis()
|
||||
self.hpText.setPos(0, 0, self.height / 2)
|
||||
seq = Sequence(self.hpText.posInterval(1.0, Point3(0, 0, self.height + 1.5), blendType='easeOut'), Wait(duration), self.hpText.colorInterval(0.1, Vec4(r, g, b, 0)), Func(self.hideHpText))
|
||||
seq.start()
|
||||
|
||||
def hideHpText(self):
|
||||
if self.hpText:
|
||||
taskMgr.remove(self.uniqueName('hpText'))
|
||||
self.hpText.removeNode()
|
||||
self.hpText = None
|
||||
return
|
||||
|
||||
def getStareAtNodeAndOffset(self):
|
||||
return (self, Point3(0, 0, self.height))
|
||||
|
||||
def getAvIdName(self):
|
||||
return '%s\n%s' % (self.getName(), self.doId)
|
||||
|
||||
def __nameTagShowAvId(self, extra = None):
|
||||
self.setDisplayName(self.getAvIdName())
|
||||
|
||||
def __nameTagShowName(self, extra = None):
|
||||
self.setDisplayName(self.getName())
|
||||
|
||||
def askAvOnShard(self, avId):
|
||||
if base.cr.doId2do.get(avId):
|
||||
messenger.send('AvOnShard%s' % avId, [True])
|
||||
else:
|
||||
self.sendUpdate('checkAvOnShard', [avId])
|
||||
|
||||
def confirmAvOnShard(self, avId, onShard = True):
|
||||
messenger.send('AvOnShard%s' % avId, [onShard])
|
||||
|
||||
def getDialogueArray(self):
|
||||
return None
|
||||
|
||||
|
||||
@magicWord(category=CATEGORY_COMMUNITY_MANAGER)
|
||||
def warp():
|
||||
"""
|
||||
warp the target to the invoker's current position, and rotation.
|
||||
"""
|
||||
invoker = spellbook.getInvoker()
|
||||
target = spellbook.getTarget()
|
||||
if invoker.doId == target.doId:
|
||||
return "You can't warp yourself!"
|
||||
target.setPosHpr(invoker.getPos(), invoker.getHpr())
|
||||
|
||||
|
||||
@magicWord(category=CATEGORY_COMMUNITY_MANAGER, types=[str])
|
||||
def loop(anim):
|
||||
"""
|
||||
animate the target using animation [anim] on the entire actor.
|
||||
"""
|
||||
target = spellbook.getTarget()
|
||||
target.loop(anim)
|
||||
|
||||
|
||||
@magicWord(category=CATEGORY_COMMUNITY_MANAGER, types=[str, int, str])
|
||||
def pose(anim, frame, part=None):
|
||||
"""
|
||||
freeze the target on frame [frame] of animation [anim] on the entire actor,
|
||||
or optional [part] of the actor.
|
||||
"""
|
||||
target = spellbook.getTarget()
|
||||
target.pose(anim, frame, partName=part)
|
||||
|
||||
|
||||
@magicWord(category=CATEGORY_COMMUNITY_MANAGER, types=[str, int, int, str])
|
||||
def pingpong(anim, start=None, end=None, part=None):
|
||||
"""
|
||||
animate the target by bouncing back and forth between the start and end, or
|
||||
the optional frames <start>, and [end] of animation [anim] on the entire
|
||||
actor, or optional <part> of the actor.
|
||||
"""
|
||||
target = spellbook.getTarget()
|
||||
target.pingpong(anim, partName=part, fromFrame=start, toFrame=end)
|
||||
|
||||
@magicWord(category=CATEGORY_COMMUNITY_MANAGER, types=[str])
|
||||
def rightHand(prop=None):
|
||||
"""
|
||||
parents the optional <prop> to the target's right hand node.
|
||||
"""
|
||||
target = spellbook.getTarget()
|
||||
rightHand = target.find('**/rightHand')
|
||||
if prop is None:
|
||||
for child in rightHand.getChildren():
|
||||
child.removeNode()
|
||||
else:
|
||||
for child in rightHand.getChildren():
|
||||
child.removeNode()
|
||||
requestedProp = globalPropPool.getProp(prop)
|
||||
requestedProp.reparentTo(rightHand)
|
||||
|
||||
@magicWord(category=CATEGORY_COMMUNITY_MANAGER, types=[str])
|
||||
def leftHand(prop=None):
|
||||
"""
|
||||
parents the optional <prop> to the target's left hand node.
|
||||
"""
|
||||
target = spellbook.getTarget()
|
||||
leftHand = target.find('**/leftHand')
|
||||
if prop is None:
|
||||
for child in leftHand.getChildren():
|
||||
child.removeNode()
|
||||
else:
|
||||
for child in leftHand.getChildren():
|
||||
child.removeNode()
|
||||
requestedProp = globalPropPool.getProp(prop)
|
||||
requestedProp.reparentTo(leftHand)
|
101
otp/avatar/DistributedAvatarAI.py
Normal file
101
otp/avatar/DistributedAvatarAI.py
Normal file
|
@ -0,0 +1,101 @@
|
|||
from otp.ai.AIBaseGlobal import *
|
||||
from otp.otpbase import OTPGlobals
|
||||
from direct.fsm import ClassicFSM
|
||||
from direct.fsm import State
|
||||
from direct.distributed import DistributedNodeAI
|
||||
from direct.task import Task
|
||||
|
||||
class DistributedAvatarAI(DistributedNodeAI.DistributedNodeAI):
|
||||
|
||||
def __init__(self, air):
|
||||
DistributedNodeAI.DistributedNodeAI.__init__(self, air)
|
||||
self.hp = 0
|
||||
self.maxHp = 0
|
||||
|
||||
def b_setName(self, name):
|
||||
self.setName(name)
|
||||
self.d_setName(name)
|
||||
|
||||
def d_setName(self, name):
|
||||
self.sendUpdate('setName', [name])
|
||||
|
||||
def setName(self, name):
|
||||
self.name = name
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def b_setMaxHp(self, maxHp):
|
||||
self.d_setMaxHp(maxHp)
|
||||
self.setMaxHp(maxHp)
|
||||
|
||||
def d_setMaxHp(self, maxHp):
|
||||
self.sendUpdate('setMaxHp', [maxHp])
|
||||
|
||||
def setMaxHp(self, maxHp):
|
||||
self.maxHp = maxHp
|
||||
|
||||
def getMaxHp(self):
|
||||
return self.maxHp
|
||||
|
||||
def b_setHp(self, hp):
|
||||
self.d_setHp(hp)
|
||||
self.setHp(hp)
|
||||
|
||||
def d_setHp(self, hp):
|
||||
self.sendUpdate('setHp', [hp])
|
||||
|
||||
def setHp(self, hp):
|
||||
self.hp = hp
|
||||
|
||||
def getHp(self):
|
||||
return self.hp
|
||||
|
||||
def b_setLocationName(self, locationName):
|
||||
self.d_setLocationName(locationName)
|
||||
self.setLocationName(locationName)
|
||||
|
||||
def d_setLocationName(self, locationName):
|
||||
pass
|
||||
|
||||
def setLocationName(self, locationName):
|
||||
self.locationName = locationName
|
||||
|
||||
def getLocationName(self):
|
||||
return self.locationName
|
||||
|
||||
def b_setActivity(self, activity):
|
||||
self.d_setActivity(activity)
|
||||
self.setActivity(activity)
|
||||
|
||||
def d_setActivity(self, activity):
|
||||
pass
|
||||
|
||||
def setActivity(self, activity):
|
||||
self.activity = activity
|
||||
|
||||
def getActivity(self):
|
||||
return self.activity
|
||||
|
||||
def toonUp(self, num):
|
||||
if self.hp >= self.maxHp:
|
||||
return
|
||||
self.hp = min(self.hp + num, self.maxHp)
|
||||
self.b_setHp(self.hp)
|
||||
|
||||
def getRadius(self):
|
||||
return OTPGlobals.AvatarDefaultRadius
|
||||
|
||||
def checkAvOnShard(self, avId):
|
||||
senderId = self.air.getAvatarIdFromSender()
|
||||
onShard = False
|
||||
if simbase.air.doId2do.get(avId):
|
||||
onShard = True
|
||||
self.sendUpdateToAvatarId(senderId, 'confirmAvOnShard', [avId, onShard])
|
||||
|
||||
def setParentStr(self, parentToken):
|
||||
if parentToken:
|
||||
senderId = self.air.getAvatarIdFromSender()
|
||||
self.air.writeServerEvent('Admin chat warning', senderId, 'using setParentStr to send "%s"' % parentToken)
|
||||
self.notify.warning('Admin chat warning: %s using setParentStr to send "%s"' % (senderId, parentToken))
|
||||
DistributedNodeAI.DistributedNodeAI.setParentStr(self, parentToken)
|
18
otp/avatar/DistributedAvatarUD.py
Normal file
18
otp/avatar/DistributedAvatarUD.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.distributed.DistributedObjectUD import DistributedObjectUD
|
||||
|
||||
class DistributedAvatarUD(DistributedObjectUD):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedAvatarUD")
|
||||
|
||||
def setName(self, todo0):
|
||||
pass
|
||||
|
||||
def friendsNotify(self, todo0, todo1):
|
||||
pass
|
||||
|
||||
def checkAvOnShard(self, todo0):
|
||||
pass
|
||||
|
||||
def confirmAvOnShard(self, todo0, todo1):
|
||||
pass
|
||||
|
463
otp/avatar/DistributedPlayer.py
Normal file
463
otp/avatar/DistributedPlayer.py
Normal file
|
@ -0,0 +1,463 @@
|
|||
from direct.showbase import PythonUtil
|
||||
from direct.task import Task
|
||||
from pandac.PandaModules import *
|
||||
import string
|
||||
import time
|
||||
|
||||
from otp.ai.MagicWordGlobal import *
|
||||
from otp.avatar import Avatar, PlayerBase
|
||||
from otp.avatar import DistributedAvatar
|
||||
from otp.avatar.Avatar import teleportNotify
|
||||
from otp.chat import ChatGarbler
|
||||
from otp.chat import TalkAssistant
|
||||
from otp.distributed.TelemetryLimited import TelemetryLimited
|
||||
from otp.otpbase import OTPGlobals
|
||||
from otp.otpbase import OTPLocalizer
|
||||
from otp.speedchat import SCDecoders
|
||||
from toontown.chat.ChatGlobals import *
|
||||
from toontown.chat.WhisperPopup import WhisperPopup
|
||||
|
||||
|
||||
if base.config.GetBool('want-chatfilter-hacks', 0):
|
||||
from otp.switchboard import badwordpy
|
||||
import os
|
||||
badwordpy.init(os.environ.get('OTP') + '\\src\\switchboard\\', '')
|
||||
|
||||
class DistributedPlayer(DistributedAvatar.DistributedAvatar, PlayerBase.PlayerBase, TelemetryLimited):
|
||||
TeleportFailureTimeout = 60.0
|
||||
chatGarbler = ChatGarbler.ChatGarbler()
|
||||
|
||||
def __init__(self, cr):
|
||||
try:
|
||||
self.DistributedPlayer_initialized
|
||||
except:
|
||||
self.DistributedPlayer_initialized = 1
|
||||
DistributedAvatar.DistributedAvatar.__init__(self, cr)
|
||||
PlayerBase.PlayerBase.__init__(self)
|
||||
TelemetryLimited.__init__(self)
|
||||
self.__teleportAvailable = 0
|
||||
self.inventory = None
|
||||
self.experience = None
|
||||
self.friendsList = []
|
||||
self.oldFriendsList = None
|
||||
self.timeFriendsListChanged = None
|
||||
self.ignoreList = []
|
||||
self.lastFailedTeleportMessage = {}
|
||||
self._districtWeAreGeneratedOn = None
|
||||
self.DISLname = ''
|
||||
self.DISLid = 0
|
||||
self.adminAccess = 0
|
||||
self.autoRun = 0
|
||||
self.whiteListEnabled = base.config.GetBool('whitelist-chat-enabled', 1)
|
||||
self.lastTeleportQuery = time.time()
|
||||
|
||||
@staticmethod
|
||||
def GetPlayerGenerateEvent():
|
||||
return 'DistributedPlayerGenerateEvent'
|
||||
|
||||
@staticmethod
|
||||
def GetPlayerNetworkDeleteEvent():
|
||||
return 'DistributedPlayerNetworkDeleteEvent'
|
||||
|
||||
@staticmethod
|
||||
def GetPlayerDeleteEvent():
|
||||
return 'DistributedPlayerDeleteEvent'
|
||||
|
||||
def networkDelete(self):
|
||||
DistributedAvatar.DistributedAvatar.networkDelete(self)
|
||||
messenger.send(self.GetPlayerNetworkDeleteEvent(), [self])
|
||||
|
||||
def disable(self):
|
||||
DistributedAvatar.DistributedAvatar.disable(self)
|
||||
messenger.send(self.GetPlayerDeleteEvent(), [self])
|
||||
|
||||
def delete(self):
|
||||
try:
|
||||
self.DistributedPlayer_deleted
|
||||
except:
|
||||
self.DistributedPlayer_deleted = 1
|
||||
del self.experience
|
||||
if self.inventory:
|
||||
self.inventory.unload()
|
||||
del self.inventory
|
||||
DistributedAvatar.DistributedAvatar.delete(self)
|
||||
|
||||
def generate(self):
|
||||
DistributedAvatar.DistributedAvatar.generate(self)
|
||||
|
||||
def announceGenerate(self):
|
||||
DistributedAvatar.DistributedAvatar.announceGenerate(self)
|
||||
messenger.send(self.GetPlayerGenerateEvent(), [self])
|
||||
|
||||
def setLocation(self, parentId, zoneId):
|
||||
DistributedAvatar.DistributedAvatar.setLocation(self, parentId, zoneId)
|
||||
if not (parentId in (0, None) and zoneId in (0, None)):
|
||||
if not self.cr._isValidPlayerLocation(parentId, zoneId):
|
||||
self.cr.disableDoId(self.doId)
|
||||
self.cr.deleteObject(self.doId)
|
||||
return None
|
||||
|
||||
def isGeneratedOnDistrict(self, districtId = None):
|
||||
return True # fix for the task button
|
||||
if districtId is None:
|
||||
return self._districtWeAreGeneratedOn is not None
|
||||
else:
|
||||
return self._districtWeAreGeneratedOn == districtId
|
||||
return
|
||||
|
||||
def getArrivedOnDistrictEvent(self, districtId = None):
|
||||
if districtId is None:
|
||||
return 'arrivedOnDistrict'
|
||||
else:
|
||||
return 'arrivedOnDistrict-%s' % districtId
|
||||
return
|
||||
|
||||
def arrivedOnDistrict(self, districtId):
|
||||
curFrameTime = globalClock.getFrameTime()
|
||||
if hasattr(self, 'frameTimeWeArrivedOnDistrict') and curFrameTime == self.frameTimeWeArrivedOnDistrict:
|
||||
if districtId == 0 and self._districtWeAreGeneratedOn:
|
||||
self.notify.warning('ignoring arrivedOnDistrict 0, since arrivedOnDistrict %d occured on the same frame' % self._districtWeAreGeneratedOn)
|
||||
return
|
||||
self._districtWeAreGeneratedOn = districtId
|
||||
self.frameTimeWeArrivedOnDistrict = globalClock.getFrameTime()
|
||||
messenger.send(self.getArrivedOnDistrictEvent(districtId))
|
||||
messenger.send(self.getArrivedOnDistrictEvent())
|
||||
|
||||
def setLeftDistrict(self):
|
||||
self._districtWeAreGeneratedOn = None
|
||||
return
|
||||
|
||||
def hasParentingRules(self):
|
||||
if self is localAvatar:
|
||||
return True
|
||||
|
||||
def setAccountName(self, accountName):
|
||||
self.accountName = accountName
|
||||
|
||||
def setSystemMessage(self, aboutId, chatString, whisperType = WTSystem):
|
||||
self.displayWhisper(aboutId, chatString, whisperType)
|
||||
|
||||
def displayWhisper(self, fromId, chatString, whisperType):
|
||||
print 'Whisper type %s from %s: %s' % (whisperType, fromId, chatString)
|
||||
|
||||
def displayWhisperPlayer(self, playerId, chatString, whisperType):
|
||||
print 'WhisperPlayer type %s from %s: %s' % (whisperType, playerId, chatString)
|
||||
|
||||
def whisperSCTo(self, msgIndex, sendToId, toPlayer):
|
||||
messenger.send('wakeup')
|
||||
base.cr.ttuFriendsManager.d_whisperSCTo(sendToId, msgIndex)
|
||||
|
||||
def setWhisperSCFrom(self, fromId, msgIndex):
|
||||
handle = base.cr.identifyAvatar(fromId)
|
||||
if handle == None:
|
||||
return
|
||||
if base.cr.avatarFriendsManager.checkIgnored(fromId):
|
||||
self.d_setWhisperIgnored(fromId)
|
||||
return
|
||||
if fromId in self.ignoreList:
|
||||
self.d_setWhisperIgnored(fromId)
|
||||
return
|
||||
chatString = SCDecoders.decodeSCStaticTextMsg(msgIndex)
|
||||
if chatString:
|
||||
self.displayWhisper(fromId, chatString, WTQuickTalker)
|
||||
base.talkAssistant.receiveAvatarWhisperSpeedChat(TalkAssistant.SPEEDCHAT_NORMAL, msgIndex, fromId)
|
||||
return
|
||||
|
||||
def whisperSCCustomTo(self, msgIndex, sendToId, toPlayer):
|
||||
messenger.send('wakeup')
|
||||
base.cr.ttuFriendsManager.d_whisperSCCustomTo(sendToId, msgIndex)
|
||||
|
||||
def _isValidWhisperSource(self, source):
|
||||
return True
|
||||
|
||||
def setWhisperSCCustomFrom(self, fromId, msgIndex):
|
||||
handle = base.cr.identifyAvatar(fromId)
|
||||
if handle == None:
|
||||
return
|
||||
if not self._isValidWhisperSource(handle):
|
||||
self.notify.warning('displayWhisper from non-toon %s' % fromId)
|
||||
return
|
||||
if base.cr.avatarFriendsManager.checkIgnored(fromId):
|
||||
self.d_setWhisperIgnored(fromId)
|
||||
return
|
||||
if fromId in self.ignoreList:
|
||||
self.d_setWhisperIgnored(fromId)
|
||||
return
|
||||
chatString = SCDecoders.decodeSCCustomMsg(msgIndex)
|
||||
if chatString:
|
||||
self.displayWhisper(fromId, chatString, WTQuickTalker)
|
||||
base.talkAssistant.receiveAvatarWhisperSpeedChat(TalkAssistant.SPEEDCHAT_CUSTOM, msgIndex, fromId)
|
||||
return
|
||||
|
||||
def whisperSCEmoteTo(self, emoteId, sendToId, toPlayer):
|
||||
messenger.send('wakeup')
|
||||
base.cr.ttuFriendsManager.d_whisperSCEmoteTo(sendToId, emoteId)
|
||||
|
||||
def setWhisperSCEmoteFrom(self, fromId, emoteId):
|
||||
handle = base.cr.identifyAvatar(fromId)
|
||||
if handle == None:
|
||||
return
|
||||
if base.cr.avatarFriendsManager.checkIgnored(fromId):
|
||||
self.d_setWhisperIgnored(fromId)
|
||||
return
|
||||
chatString = SCDecoders.decodeSCEmoteWhisperMsg(emoteId, handle.getName())
|
||||
if chatString:
|
||||
self.displayWhisper(fromId, chatString, WTEmote)
|
||||
base.talkAssistant.receiveAvatarWhisperSpeedChat(TalkAssistant.SPEEDCHAT_EMOTE, emoteId, fromId)
|
||||
return
|
||||
|
||||
def d_setWhisperIgnored(self, sendToId):
|
||||
pass
|
||||
|
||||
def setChatAbsolute(self, chatString, chatFlags, dialogue = None, interrupt = 1, quiet = 0):
|
||||
DistributedAvatar.DistributedAvatar.setChatAbsolute(self, chatString, chatFlags, dialogue, interrupt)
|
||||
if not quiet:
|
||||
pass
|
||||
|
||||
def b_setChat(self, chatString, chatFlags):
|
||||
if self.cr.wantMagicWords and len(chatString) > 0 and chatString[0] == '~':
|
||||
messenger.send('magicWord', [chatString])
|
||||
else:
|
||||
if base.config.GetBool('want-chatfilter-hacks', 0):
|
||||
if base.config.GetBool('want-chatfilter-drop-offending', 0):
|
||||
if badwordpy.test(chatString):
|
||||
return
|
||||
else:
|
||||
chatString = badwordpy.scrub(chatString)
|
||||
messenger.send('wakeup')
|
||||
self.setChatAbsolute(chatString, chatFlags)
|
||||
self.d_setChat(chatString, chatFlags)
|
||||
|
||||
def d_setChat(self, chatString, chatFlags):
|
||||
self.sendUpdate('setChat', [chatString, chatFlags, 0])
|
||||
|
||||
def setTalk(self, fromAV, fromAC, avatarName, chat, mods, flags):
|
||||
newText, scrubbed = self.scrubTalk(chat, mods)
|
||||
self.displayTalk(newText)
|
||||
if base.talkAssistant.isThought(newText):
|
||||
newText = base.talkAssistant.removeThoughtPrefix(newText)
|
||||
base.talkAssistant.receiveThought(fromAV, avatarName, fromAC, None, newText, scrubbed)
|
||||
else:
|
||||
base.talkAssistant.receiveOpenTalk(fromAV, avatarName, fromAC, None, newText, scrubbed)
|
||||
return
|
||||
|
||||
def setTalkWhisper(self, fromAV, fromAC, avatarName, chat, mods, flags):
|
||||
newText, scrubbed = self.scrubTalk(chat, mods)
|
||||
self.displayTalkWhisper(fromAV, avatarName, chat, mods)
|
||||
base.talkAssistant.receiveWhisperTalk(fromAV, avatarName, fromAC, None, self.doId, self.getName(), newText, scrubbed)
|
||||
return
|
||||
|
||||
def displayTalkWhisper(self, fromId, avatarName, chatString, mods):
|
||||
print 'TalkWhisper from %s: %s' % (fromId, chatString)
|
||||
|
||||
def scrubTalk(self, chat, mods):
|
||||
return chat
|
||||
|
||||
def setChat(self, chatString, chatFlags, DISLid):
|
||||
self.notify.error('Should call setTalk')
|
||||
chatString = base.talkAssistant.whiteListFilterMessage(chatString)
|
||||
if base.cr.avatarFriendsManager.checkIgnored(self.doId):
|
||||
return
|
||||
if base.localAvatar.garbleChat and not self.isUnderstandable():
|
||||
chatString = self.chatGarbler.garble(self, chatString)
|
||||
chatFlags &= ~(CFQuicktalker | CFPageButton | CFQuitButton)
|
||||
if chatFlags & CFThought:
|
||||
chatFlags &= ~(CFSpeech | CFTimeout)
|
||||
else:
|
||||
chatFlags |= CFSpeech | CFTimeout
|
||||
self.setChatAbsolute(chatString, chatFlags)
|
||||
|
||||
def b_setSC(self, msgIndex):
|
||||
self.setSC(msgIndex)
|
||||
self.d_setSC(msgIndex)
|
||||
|
||||
def d_setSC(self, msgIndex):
|
||||
messenger.send('wakeup')
|
||||
self.sendUpdate('setSC', [msgIndex])
|
||||
|
||||
def setSC(self, msgIndex):
|
||||
if base.cr.avatarFriendsManager.checkIgnored(self.doId):
|
||||
return
|
||||
if self.doId in base.localAvatar.ignoreList:
|
||||
return
|
||||
chatString = SCDecoders.decodeSCStaticTextMsg(msgIndex)
|
||||
if chatString:
|
||||
self.setChatAbsolute(chatString, CFSpeech | CFQuicktalker | CFTimeout, quiet=1)
|
||||
base.talkAssistant.receiveOpenSpeedChat(TalkAssistant.SPEEDCHAT_NORMAL, msgIndex, self.doId)
|
||||
|
||||
def b_setSCCustom(self, msgIndex):
|
||||
self.setSCCustom(msgIndex)
|
||||
self.d_setSCCustom(msgIndex)
|
||||
|
||||
def d_setSCCustom(self, msgIndex):
|
||||
messenger.send('wakeup')
|
||||
self.sendUpdate('setSCCustom', [msgIndex])
|
||||
|
||||
def setSCCustom(self, msgIndex):
|
||||
if base.cr.avatarFriendsManager.checkIgnored(self.doId):
|
||||
return
|
||||
if self.doId in base.localAvatar.ignoreList:
|
||||
return
|
||||
chatString = SCDecoders.decodeSCCustomMsg(msgIndex)
|
||||
if chatString:
|
||||
self.setChatAbsolute(chatString, CFSpeech | CFQuicktalker | CFTimeout)
|
||||
base.talkAssistant.receiveOpenSpeedChat(TalkAssistant.SPEEDCHAT_CUSTOM, msgIndex, self.doId)
|
||||
|
||||
def b_setSCEmote(self, emoteId):
|
||||
self.b_setEmoteState(emoteId, animMultiplier=self.animMultiplier)
|
||||
|
||||
def d_friendsNotify(self, avId, status):
|
||||
self.sendUpdate('friendsNotify', [avId, status])
|
||||
|
||||
def friendsNotify(self, avId, status):
|
||||
avatar = base.cr.identifyFriend(avId)
|
||||
if avatar != None:
|
||||
if status == 1:
|
||||
self.setSystemMessage(avId, OTPLocalizer.WhisperNoLongerFriend % avatar.getName())
|
||||
elif status == 2:
|
||||
self.setSystemMessage(avId, OTPLocalizer.WhisperNowSpecialFriend % avatar.getName())
|
||||
return
|
||||
|
||||
def d_teleportQuery(self, requesterId, sendToId = None):
|
||||
lastQuery = self.lastTeleportQuery
|
||||
currentQuery = time.time()
|
||||
|
||||
if currentQuery - lastQuery < 0.1: # Oh boy! We found a skid!
|
||||
self.cr.stopReaderPollTask()
|
||||
self.cr.lostConnection()
|
||||
|
||||
self.lastTeleportQuery = time.time()
|
||||
|
||||
base.cr.ttuFriendsManager.d_teleportQuery(sendToId)
|
||||
|
||||
def teleportQuery(self, requesterId):
|
||||
teleportNotify.debug('receieved teleportQuery(%s)' % requesterId)
|
||||
avatar = base.cr.playerFriendsManager.identifyFriend(requesterId)
|
||||
if avatar != None:
|
||||
teleportNotify.debug('avatar is not None')
|
||||
if base.cr.avatarFriendsManager.checkIgnored(requesterId):
|
||||
teleportNotify.debug('avatar ignored via avatarFriendsManager')
|
||||
self.d_teleportResponse(self.doId, 2, 0, 0, 0, sendToId=requesterId)
|
||||
return
|
||||
if requesterId in self.ignoreList:
|
||||
teleportNotify.debug('avatar ignored via ignoreList')
|
||||
self.d_teleportResponse(self.doId, 2, 0, 0, 0, sendToId=requesterId)
|
||||
return
|
||||
if hasattr(base, 'distributedParty'):
|
||||
if base.distributedParty.partyInfo.isPrivate:
|
||||
if requesterId not in base.distributedParty.inviteeIds:
|
||||
teleportNotify.debug('avatar not in inviteeIds')
|
||||
self.d_teleportResponse(self.doId, 0, 0, 0, 0, sendToId=requesterId)
|
||||
return
|
||||
if base.distributedParty.isPartyEnding:
|
||||
teleportNotify.debug('party is ending')
|
||||
self.d_teleportResponse(self.doId, 0, 0, 0, 0, sendToId=requesterId)
|
||||
return
|
||||
if self.__teleportAvailable and not self.ghostMode and base.config.GetBool('can-be-teleported-to', 1):
|
||||
teleportNotify.debug('teleport initiation successful')
|
||||
self.setSystemMessage(requesterId, OTPLocalizer.WhisperComingToVisit % avatar.getName())
|
||||
messenger.send('teleportQuery', [avatar, self])
|
||||
return
|
||||
teleportNotify.debug('teleport initiation failed')
|
||||
if self.failedTeleportMessageOk(requesterId):
|
||||
self.setSystemMessage(requesterId, OTPLocalizer.WhisperFailedVisit % avatar.getName())
|
||||
teleportNotify.debug('sending try-again-later message')
|
||||
self.d_teleportResponse(self.doId, 0, 0, 0, 0, sendToId=requesterId)
|
||||
return
|
||||
|
||||
def failedTeleportMessageOk(self, fromId):
|
||||
now = globalClock.getFrameTime()
|
||||
lastTime = self.lastFailedTeleportMessage.get(fromId, None)
|
||||
if lastTime != None:
|
||||
elapsed = now - lastTime
|
||||
if elapsed < self.TeleportFailureTimeout:
|
||||
return 0
|
||||
self.lastFailedTeleportMessage[fromId] = now
|
||||
return 1
|
||||
|
||||
def d_teleportResponse(self, avId, available, shardId, hoodId, zoneId, sendToId):
|
||||
teleportNotify.debug('sending teleportResponse%s' % ((avId, available,
|
||||
shardId, hoodId, zoneId, sendToId),)
|
||||
)
|
||||
|
||||
base.cr.ttuFriendsManager.d_teleportResponse(sendToId, available,
|
||||
shardId, hoodId, zoneId
|
||||
)
|
||||
|
||||
def teleportResponse(self, avId, available, shardId, hoodId, zoneId):
|
||||
teleportNotify.debug('received teleportResponse%s' % ((avId, available,
|
||||
shardId, hoodId, zoneId),)
|
||||
)
|
||||
|
||||
messenger.send('teleportResponse', [avId, available, shardId, hoodId, zoneId])
|
||||
|
||||
def d_teleportGiveup(self, requesterId, sendToId):
|
||||
teleportNotify.debug('sending teleportGiveup(%s) to %s' % (requesterId, sendToId))
|
||||
|
||||
base.cr.ttuFriendsManager.d_teleportGiveup(sendToId)
|
||||
|
||||
def teleportGiveup(self, requesterId):
|
||||
teleportNotify.debug('received teleportGiveup(%s)' % (requesterId,))
|
||||
avatar = base.cr.identifyAvatar(requesterId)
|
||||
|
||||
if not self._isValidWhisperSource(avatar):
|
||||
self.notify.warning('teleportGiveup from non-toon %s' % requesterId)
|
||||
return
|
||||
|
||||
if avatar is not None:
|
||||
self.setSystemMessage(requesterId,
|
||||
OTPLocalizer.WhisperGiveupVisit % avatar.getName()
|
||||
)
|
||||
|
||||
def b_teleportGreeting(self, avId):
|
||||
if hasattr(self, 'ghostMode') and self.ghostMode:
|
||||
return
|
||||
self.d_teleportGreeting(avId)
|
||||
self.teleportGreeting(avId)
|
||||
|
||||
def d_teleportGreeting(self, avId):
|
||||
self.sendUpdate('teleportGreeting', [avId])
|
||||
|
||||
def teleportGreeting(self, avId):
|
||||
avatar = base.cr.getDo(avId)
|
||||
if isinstance(avatar, Avatar.Avatar):
|
||||
self.setChatAbsolute(OTPLocalizer.TeleportGreeting % avatar.getName(), CFSpeech | CFTimeout)
|
||||
elif avatar is not None:
|
||||
self.notify.warning('got teleportGreeting from %s referencing non-toon %s' % (self.doId, avId))
|
||||
return
|
||||
|
||||
def setTeleportAvailable(self, available):
|
||||
self.__teleportAvailable = available
|
||||
|
||||
def getTeleportAvailable(self):
|
||||
return self.__teleportAvailable
|
||||
|
||||
def getFriendsList(self):
|
||||
return self.friendsList
|
||||
|
||||
def setFriendsList(self, friendsList):
|
||||
self.oldFriendsList = self.friendsList
|
||||
self.friendsList = friendsList
|
||||
self.timeFriendsListChanged = globalClock.getFrameTime()
|
||||
messenger.send('friendsListChanged')
|
||||
Avatar.reconsiderAllUnderstandable()
|
||||
|
||||
def setDISLname(self, name):
|
||||
self.DISLname = name
|
||||
|
||||
def setDISLid(self, id):
|
||||
self.DISLid = id
|
||||
|
||||
def setAdminAccess(self, access):
|
||||
self.adminAccess = access
|
||||
if self.isLocal():
|
||||
self.cr.wantMagicWords = self.adminAccess >= MINIMUM_MAGICWORD_ACCESS
|
||||
|
||||
def getAdminAccess(self):
|
||||
return self.adminAccess
|
||||
|
||||
def setAutoRun(self, value):
|
||||
self.autoRun = value
|
||||
|
||||
def getAutoRun(self):
|
||||
return self.autoRun
|
264
otp/avatar/DistributedPlayerAI.py
Normal file
264
otp/avatar/DistributedPlayerAI.py
Normal file
|
@ -0,0 +1,264 @@
|
|||
from direct.showbase import GarbageReport
|
||||
from direct.distributed.PyDatagram import PyDatagram
|
||||
from direct.distributed.MsgTypes import CLIENTAGENT_EJECT
|
||||
|
||||
from otp.ai.AIBaseGlobal import *
|
||||
from otp.ai.MagicWordGlobal import *
|
||||
from otp.avatar import DistributedAvatarAI
|
||||
from otp.avatar import PlayerBase
|
||||
from otp.distributed import OtpDoGlobals
|
||||
from otp.distributed.ClsendTracker import ClsendTracker
|
||||
from otp.otpbase import OTPLocalizer
|
||||
|
||||
|
||||
class DistributedPlayerAI(DistributedAvatarAI.DistributedAvatarAI, PlayerBase.PlayerBase, ClsendTracker):
|
||||
def __init__(self, air):
|
||||
DistributedAvatarAI.DistributedAvatarAI.__init__(self, air)
|
||||
PlayerBase.PlayerBase.__init__(self)
|
||||
ClsendTracker.__init__(self)
|
||||
self.friendsList = []
|
||||
self.DISLname = ''
|
||||
self.DISLid = 0
|
||||
self.adminAccess = 0
|
||||
|
||||
if __dev__:
|
||||
|
||||
def generate(self):
|
||||
self._sentExitServerEvent = False
|
||||
DistributedAvatarAI.DistributedAvatarAI.generate(self)
|
||||
|
||||
def announceGenerate(self):
|
||||
DistributedAvatarAI.DistributedAvatarAI.announceGenerate(self)
|
||||
ClsendTracker.announceGenerate(self)
|
||||
self._doPlayerEnter()
|
||||
|
||||
def _announceArrival(self):
|
||||
self.sendUpdate('arrivedOnDistrict', [self.air.districtId])
|
||||
|
||||
def _announceExit(self):
|
||||
self.sendUpdate('arrivedOnDistrict', [0])
|
||||
|
||||
def _sendExitServerEvent(self):
|
||||
self.air.writeServerEvent('avatarExit', self.doId, '')
|
||||
if __dev__:
|
||||
self._sentExitServerEvent = True
|
||||
|
||||
def delete(self):
|
||||
if __dev__:
|
||||
del self._sentExitServerEvent
|
||||
self._doPlayerExit()
|
||||
ClsendTracker.destroy(self)
|
||||
if __dev__:
|
||||
GarbageReport.checkForGarbageLeaks()
|
||||
DistributedAvatarAI.DistributedAvatarAI.delete(self)
|
||||
|
||||
def isPlayerControlled(self):
|
||||
return True
|
||||
|
||||
def setLocation(self, parentId, zoneId):
|
||||
DistributedAvatarAI.DistributedAvatarAI.setLocation(self, parentId, zoneId)
|
||||
if self.isPlayerControlled():
|
||||
if not self.air._isValidPlayerLocation(parentId, zoneId):
|
||||
self.notify.info('booting player %s for doing setLocation to (%s, %s)' % (self.doId, parentId, zoneId))
|
||||
self.air.writeServerEvent('suspicious', self.doId, 'invalid setLocation: (%s, %s)' % (parentId, zoneId))
|
||||
self.requestDelete()
|
||||
|
||||
def _doPlayerEnter(self):
|
||||
self.incrementPopulation()
|
||||
self._announceArrival()
|
||||
|
||||
def _doPlayerExit(self):
|
||||
self._announceExit()
|
||||
self.decrementPopulation()
|
||||
|
||||
def incrementPopulation(self):
|
||||
self.air.incrementPopulation()
|
||||
|
||||
def decrementPopulation(self):
|
||||
simbase.air.decrementPopulation()
|
||||
|
||||
def b_setChat(self, chatString, chatFlags):
|
||||
self.setChat(chatString, chatFlags)
|
||||
self.d_setChat(chatString, chatFlags)
|
||||
|
||||
def d_setChat(self, chatString, chatFlags):
|
||||
self.sendUpdate('setChat', [chatString, chatFlags])
|
||||
|
||||
def setChat(self, chatString, chatFlags):
|
||||
pass
|
||||
|
||||
def d_setMaxHp(self, maxHp):
|
||||
DistributedAvatarAI.DistributedAvatarAI.d_setMaxHp(self, maxHp)
|
||||
self.air.writeServerEvent('setMaxHp', self.doId, '%s' % maxHp)
|
||||
|
||||
def d_setSystemMessage(self, aboutId, chatString):
|
||||
self.sendUpdate('setSystemMessage', [aboutId, chatString])
|
||||
|
||||
def d_setCommonChatFlags(self, flags):
|
||||
self.sendUpdate('setCommonChatFlags', [flags])
|
||||
|
||||
def setCommonChatFlags(self, flags):
|
||||
pass
|
||||
|
||||
def d_friendsNotify(self, avId, status):
|
||||
self.sendUpdate('friendsNotify', [avId, status])
|
||||
|
||||
def friendsNotify(self, avId, status):
|
||||
pass
|
||||
|
||||
def setAccountName(self, accountName):
|
||||
self.accountName = accountName
|
||||
|
||||
def getAccountName(self):
|
||||
return self.accountName
|
||||
|
||||
def setDISLid(self, id):
|
||||
self.DISLid = id
|
||||
|
||||
def getDISLid(self):
|
||||
return self.DISLid
|
||||
|
||||
def d_setFriendsList(self, friendsList):
|
||||
self.sendUpdate('setFriendsList', [friendsList])
|
||||
|
||||
def setFriendsList(self, friendsList):
|
||||
self.friendsList = friendsList
|
||||
self.notify.debug('setting friends list to %s' % self.friendsList)
|
||||
|
||||
def getFriendsList(self):
|
||||
return self.friendsList
|
||||
|
||||
def setAdminAccess(self, access):
|
||||
self.adminAccess = access
|
||||
|
||||
def d_setAdminAccess(self, access):
|
||||
self.sendUpdate('setAdminAccess', [access])
|
||||
|
||||
def b_setAdminAccess(self, access):
|
||||
self.setAdminAccess(access)
|
||||
self.d_setAdminAccess(access)
|
||||
|
||||
def getAdminAccess(self):
|
||||
return self.adminAccess
|
||||
|
||||
def extendFriendsList(self, friendId, friendCode):
|
||||
for i in xrange(len(self.friendsList)):
|
||||
friendPair = self.friendsList[i]
|
||||
if friendPair[0] == friendId:
|
||||
self.friendsList[i] = (friendId, friendCode)
|
||||
return
|
||||
|
||||
self.friendsList.append((friendId, friendCode))
|
||||
|
||||
|
||||
@magicWord(category=CATEGORY_SYSTEM_ADMINISTRATOR, types=[str])
|
||||
def system(message):
|
||||
"""
|
||||
Broadcast a <message> to the game server.
|
||||
"""
|
||||
message = 'ADMIN: ' + message
|
||||
dclass = simbase.air.dclassesByName['ClientServicesManager']
|
||||
dg = dclass.aiFormatUpdate('systemMessage',
|
||||
OtpDoGlobals.OTP_DO_ID_CLIENT_SERVICES_MANAGER,
|
||||
10, 1000000, [message])
|
||||
simbase.air.send(dg)
|
||||
|
||||
@magicWord(category=CATEGORY_SYSTEM_ADMINISTRATOR, types=[int])
|
||||
def maintenance(minutes):
|
||||
"""
|
||||
Initiate the maintenance message sequence. It will last for the specified
|
||||
amount of <minutes>.
|
||||
"""
|
||||
def disconnect(task):
|
||||
dg = PyDatagram()
|
||||
dg.addServerHeader(10, simbase.air.ourChannel, CLIENTAGENT_EJECT)
|
||||
dg.addUint16(154)
|
||||
dg.addString('Toontown Unlimited is now closed for maintenance.')
|
||||
simbase.air.send(dg)
|
||||
return Task.done
|
||||
|
||||
def countdown(minutes):
|
||||
if minutes > 0:
|
||||
system(OTPLocalizer.CRMaintenanceCountdownMessage % minutes)
|
||||
else:
|
||||
system(OTPLocalizer.CRMaintenanceMessage)
|
||||
taskMgr.doMethodLater(10, disconnect, 'maintenance-disconnection')
|
||||
if minutes <= 5:
|
||||
next = 60
|
||||
minutes -= 1
|
||||
elif minutes % 5:
|
||||
next = 60 * (minutes%5)
|
||||
minutes -= minutes % 5
|
||||
else:
|
||||
next = 300
|
||||
minutes -= 5
|
||||
if minutes >= 0:
|
||||
taskMgr.doMethodLater(next, countdown, 'maintenance-task',
|
||||
extraArgs=[minutes])
|
||||
|
||||
|
||||
countdown(minutes)
|
||||
|
||||
@magicWord(category=CATEGORY_ADMINISTRATOR, types=[str, str, int])
|
||||
def accessLevel(accessLevel, storage='PERSISTENT', showGM=1):
|
||||
"""
|
||||
Modify the target's access level.
|
||||
"""
|
||||
accessName2Id = {
|
||||
'user': CATEGORY_USER.defaultAccess,
|
||||
'u': CATEGORY_USER.defaultAccess,
|
||||
'communitymanager': CATEGORY_COMMUNITY_MANAGER.defaultAccess,
|
||||
'community': CATEGORY_COMMUNITY_MANAGER.defaultAccess,
|
||||
'c': CATEGORY_COMMUNITY_MANAGER.defaultAccess,
|
||||
'moderator': CATEGORY_MODERATOR.defaultAccess,
|
||||
'mod': CATEGORY_MODERATOR.defaultAccess,
|
||||
'm': CATEGORY_MODERATOR.defaultAccess,
|
||||
'creative': CATEGORY_CREATIVE.defaultAccess,
|
||||
'creativity': CATEGORY_CREATIVE.defaultAccess,
|
||||
'c': CATEGORY_CREATIVE.defaultAccess,
|
||||
'programmer': CATEGORY_PROGRAMMER.defaultAccess,
|
||||
'coder': CATEGORY_PROGRAMMER.defaultAccess,
|
||||
'p': CATEGORY_PROGRAMMER.defaultAccess,
|
||||
'administrator': CATEGORY_ADMINISTRATOR.defaultAccess,
|
||||
'admin': CATEGORY_ADMINISTRATOR.defaultAccess,
|
||||
'a': CATEGORY_ADMINISTRATOR.defaultAccess,
|
||||
'systemadministrator': CATEGORY_SYSTEM_ADMINISTRATOR.defaultAccess,
|
||||
'systemadmin': CATEGORY_SYSTEM_ADMINISTRATOR.defaultAccess,
|
||||
'sysadministrator': CATEGORY_SYSTEM_ADMINISTRATOR.defaultAccess,
|
||||
'sysadmin': CATEGORY_SYSTEM_ADMINISTRATOR.defaultAccess,
|
||||
'system': CATEGORY_SYSTEM_ADMINISTRATOR.defaultAccess,
|
||||
'sys': CATEGORY_SYSTEM_ADMINISTRATOR.defaultAccess,
|
||||
's': CATEGORY_SYSTEM_ADMINISTRATOR.defaultAccess
|
||||
}
|
||||
try:
|
||||
accessLevel = int(accessLevel)
|
||||
except:
|
||||
if accessLevel not in accessName2Id:
|
||||
return 'Invalid access level!'
|
||||
accessLevel = accessName2Id[accessLevel]
|
||||
if accessLevel not in accessName2Id.values():
|
||||
return 'Invalid access level!'
|
||||
target = spellbook.getTarget()
|
||||
invoker = spellbook.getInvoker()
|
||||
if invoker == target:
|
||||
return "You can't set your own access level!"
|
||||
if not accessLevel < invoker.getAdminAccess():
|
||||
return "The target's access level must be lower than yours!"
|
||||
if target.getAdminAccess() == accessLevel:
|
||||
return "%s's access level is already %d!" % (target.getName(), accessLevel)
|
||||
target.b_setAdminAccess(accessLevel)
|
||||
if showGM:
|
||||
target.b_setGM(accessLevel)
|
||||
temporary = storage.upper() in ('SESSION', 'TEMP', 'TEMPORARY')
|
||||
if not temporary:
|
||||
target.air.dbInterface.updateObject(
|
||||
target.air.dbId,
|
||||
target.getDISLid(),
|
||||
target.air.dclassesByName['AccountAI'],
|
||||
{'ADMIN_ACCESS': accessLevel})
|
||||
if not temporary:
|
||||
target.d_setSystemMessage(0, '%s set your access level to %d!' % (invoker.getName(), accessLevel))
|
||||
return "%s's access level has been set to %d." % (target.getName(), accessLevel)
|
||||
else:
|
||||
target.d_setSystemMessage(0, '%s set your access level to %d temporarily!' % (invoker.getName(), accessLevel))
|
||||
return "%s's access level has been set to %d temporarily." % (target.getName(), accessLevel)
|
22
otp/avatar/Emote.py
Normal file
22
otp/avatar/Emote.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
from otp.otpbase import OTPLocalizer
|
||||
import types
|
||||
|
||||
class Emote:
|
||||
EmoteClear = -1
|
||||
EmoteEnableStateChanged = 'EmoteEnableStateChanged'
|
||||
|
||||
def __init__(self):
|
||||
self.emoteFunc = None
|
||||
return
|
||||
|
||||
def isEnabled(self, index):
|
||||
if isinstance(index, types.StringType):
|
||||
index = OTPLocalizer.EmoteFuncDict[index]
|
||||
if self.emoteFunc == None:
|
||||
return 0
|
||||
elif self.emoteFunc[index][1] == 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
globalEmote = None
|
1275
otp/avatar/LocalAvatar.py
Normal file
1275
otp/avatar/LocalAvatar.py
Normal file
File diff suppressed because it is too large
Load diff
18
otp/avatar/PlayerBase.py
Normal file
18
otp/avatar/PlayerBase.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
|
||||
|
||||
class PlayerBase:
|
||||
|
||||
def __init__(self):
|
||||
self.gmState = False
|
||||
|
||||
def atLocation(self, locationId):
|
||||
return True
|
||||
|
||||
def getLocation(self):
|
||||
return []
|
||||
|
||||
def setAsGM(self, state):
|
||||
self.gmState = state
|
||||
|
||||
def isGM(self):
|
||||
return self.gmState
|
94
otp/avatar/PositionExaminer.py
Normal file
94
otp/avatar/PositionExaminer.py
Normal file
|
@ -0,0 +1,94 @@
|
|||
from pandac.PandaModules import *
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from otp.otpbase import OTPGlobals
|
||||
|
||||
class PositionExaminer(DirectObject, NodePath):
|
||||
|
||||
def __init__(self):
|
||||
try:
|
||||
self.__initialized
|
||||
return
|
||||
except:
|
||||
self.__initialized = 1
|
||||
|
||||
NodePath.__init__(self, hidden.attachNewNode('PositionExaminer'))
|
||||
self.cRay = CollisionRay(0.0, 0.0, 6.0, 0.0, 0.0, -1.0)
|
||||
self.cRayNode = CollisionNode('cRayNode')
|
||||
self.cRayNode.addSolid(self.cRay)
|
||||
self.cRayNodePath = self.attachNewNode(self.cRayNode)
|
||||
self.cRayNodePath.hide()
|
||||
self.cRayBitMask = OTPGlobals.FloorBitmask
|
||||
self.cRayNode.setFromCollideMask(self.cRayBitMask)
|
||||
self.cRayNode.setIntoCollideMask(BitMask32.allOff())
|
||||
self.cSphere = CollisionSphere(0.0, 0.0, 0.0, 1.5)
|
||||
self.cSphereNode = CollisionNode('cSphereNode')
|
||||
self.cSphereNode.addSolid(self.cSphere)
|
||||
self.cSphereNodePath = self.attachNewNode(self.cSphereNode)
|
||||
self.cSphereNodePath.hide()
|
||||
self.cSphereBitMask = OTPGlobals.WallBitmask
|
||||
self.cSphereNode.setFromCollideMask(self.cSphereBitMask)
|
||||
self.cSphereNode.setIntoCollideMask(BitMask32.allOff())
|
||||
self.ccLine = CollisionSegment(0.0, 0.0, 0.0, 1.0, 0.0, 0.0)
|
||||
self.ccLineNode = CollisionNode('ccLineNode')
|
||||
self.ccLineNode.addSolid(self.ccLine)
|
||||
self.ccLineNodePath = self.attachNewNode(self.ccLineNode)
|
||||
self.ccLineNodePath.hide()
|
||||
self.ccLineBitMask = OTPGlobals.CameraBitmask
|
||||
self.ccLineNode.setFromCollideMask(self.ccLineBitMask)
|
||||
self.ccLineNode.setIntoCollideMask(BitMask32.allOff())
|
||||
self.cRayTrav = CollisionTraverser('PositionExaminer.cRayTrav')
|
||||
self.cRayTrav.setRespectPrevTransform(False)
|
||||
self.cRayQueue = CollisionHandlerQueue()
|
||||
self.cRayTrav.addCollider(self.cRayNodePath, self.cRayQueue)
|
||||
self.cSphereTrav = CollisionTraverser('PositionExaminer.cSphereTrav')
|
||||
self.cSphereTrav.setRespectPrevTransform(False)
|
||||
self.cSphereQueue = CollisionHandlerQueue()
|
||||
self.cSphereTrav.addCollider(self.cSphereNodePath, self.cSphereQueue)
|
||||
self.ccLineTrav = CollisionTraverser('PositionExaminer.ccLineTrav')
|
||||
self.ccLineTrav.setRespectPrevTransform(False)
|
||||
self.ccLineQueue = CollisionHandlerQueue()
|
||||
self.ccLineTrav.addCollider(self.ccLineNodePath, self.ccLineQueue)
|
||||
|
||||
def delete(self):
|
||||
del self.cRay
|
||||
del self.cRayNode
|
||||
self.cRayNodePath.removeNode()
|
||||
del self.cRayNodePath
|
||||
del self.cSphere
|
||||
del self.cSphereNode
|
||||
self.cSphereNodePath.removeNode()
|
||||
del self.cSphereNodePath
|
||||
del self.ccLine
|
||||
del self.ccLineNode
|
||||
self.ccLineNodePath.removeNode()
|
||||
del self.ccLineNodePath
|
||||
del self.cRayTrav
|
||||
del self.cRayQueue
|
||||
del self.cSphereTrav
|
||||
del self.cSphereQueue
|
||||
del self.ccLineTrav
|
||||
del self.ccLineQueue
|
||||
|
||||
def consider(self, node, pos, eyeHeight):
|
||||
self.reparentTo(node)
|
||||
self.setPos(pos)
|
||||
result = None
|
||||
self.cRayTrav.traverse(render)
|
||||
if self.cRayQueue.getNumEntries() != 0:
|
||||
self.cRayQueue.sortEntries()
|
||||
floorPoint = self.cRayQueue.getEntry(0).getSurfacePoint(self.cRayNodePath)
|
||||
if abs(floorPoint[2]) <= 4.0:
|
||||
pos += floorPoint
|
||||
self.setPos(pos)
|
||||
self.cSphereTrav.traverse(render)
|
||||
if self.cSphereQueue.getNumEntries() == 0:
|
||||
self.ccLine.setPointA(0, 0, eyeHeight)
|
||||
self.ccLine.setPointB(-pos[0], -pos[1], eyeHeight)
|
||||
self.ccLineTrav.traverse(render)
|
||||
if self.ccLineQueue.getNumEntries() == 0:
|
||||
result = pos
|
||||
self.reparentTo(hidden)
|
||||
self.cRayQueue.clearEntries()
|
||||
self.cSphereQueue.clearEntries()
|
||||
self.ccLineQueue.clearEntries()
|
||||
return result
|
128
otp/avatar/ShadowCaster.py
Normal file
128
otp/avatar/ShadowCaster.py
Normal file
|
@ -0,0 +1,128 @@
|
|||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.showbase.ShadowPlacer import ShadowPlacer
|
||||
from pandac.PandaModules import *
|
||||
|
||||
from otp.otpbase import OTPGlobals
|
||||
|
||||
|
||||
globalDropShadowFlag = 1
|
||||
def setGlobalDropShadowFlag(flag):
|
||||
global globalDropShadowFlag
|
||||
if flag != globalDropShadowFlag:
|
||||
globalDropShadowFlag = flag
|
||||
messenger.send('globalDropShadowFlagChanged')
|
||||
|
||||
|
||||
globalDropShadowGrayLevel = 0.5
|
||||
def setGlobalDropShadowGrayLevel(grayLevel):
|
||||
global globalDropShadowGrayLevel
|
||||
if grayLevel != globalDropShadowGrayLevel:
|
||||
globalDropShadowGrayLevel = grayLevel
|
||||
messenger.send('globalDropShadowGrayLevelChanged')
|
||||
|
||||
|
||||
class ShadowCaster:
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('ShadowCaster')
|
||||
|
||||
def __init__(self, squareShadow = False):
|
||||
if squareShadow:
|
||||
self.shadowFileName = 'phase_3/models/props/square_drop_shadow'
|
||||
else:
|
||||
self.shadowFileName = 'phase_3/models/props/drop_shadow'
|
||||
self.dropShadow = None
|
||||
self.shadowPlacer = None
|
||||
self.activeShadow = 0
|
||||
self.wantsActive = 1
|
||||
self.storedActiveState = 0
|
||||
if hasattr(base, 'wantDynamicShadows') and base.wantDynamicShadows:
|
||||
messenger.accept('globalDropShadowFlagChanged', self, self.__globalDropShadowFlagChanged)
|
||||
messenger.accept('globalDropShadowGrayLevelChanged', self, self.__globalDropShadowGrayLevelChanged)
|
||||
|
||||
def delete(self):
|
||||
if hasattr(base, 'wantDynamicShadows') and base.wantDynamicShadows:
|
||||
messenger.ignore('globalDropShadowFlagChanged', self)
|
||||
messenger.ignore('globalDropShadowGrayLevelChanged', self)
|
||||
self.deleteDropShadow()
|
||||
self.shadowJoint = None
|
||||
|
||||
def initializeDropShadow(self, hasGeomNode = True):
|
||||
self.deleteDropShadow()
|
||||
if hasGeomNode:
|
||||
self.getGeomNode().setTag('cam', 'caster')
|
||||
dropShadow = loader.loadModel(self.shadowFileName)
|
||||
dropShadow.setScale(0.4)
|
||||
dropShadow.flattenMedium()
|
||||
dropShadow.setBillboardAxis(2)
|
||||
dropShadow.setColor(0.0, 0.0, 0.0, globalDropShadowGrayLevel, 1)
|
||||
self.shadowPlacer = ShadowPlacer(base.shadowTrav, dropShadow, OTPGlobals.WallBitmask, OTPGlobals.FloorBitmask)
|
||||
self.dropShadow = dropShadow
|
||||
if not globalDropShadowFlag:
|
||||
self.dropShadow.hide()
|
||||
if self.getShadowJoint():
|
||||
dropShadow.reparentTo(self.getShadowJoint())
|
||||
else:
|
||||
self.dropShadow.hide()
|
||||
self.setActiveShadow(self.wantsActive)
|
||||
self.__globalDropShadowFlagChanged()
|
||||
self.__globalDropShadowGrayLevelChanged()
|
||||
|
||||
def update(self):
|
||||
pass
|
||||
|
||||
def deleteDropShadow(self):
|
||||
if self.shadowPlacer:
|
||||
self.shadowPlacer.delete()
|
||||
self.shadowPlacer = None
|
||||
if self.dropShadow:
|
||||
self.dropShadow.removeNode()
|
||||
self.dropShadow = None
|
||||
|
||||
def setActiveShadow(self, isActive = 1):
|
||||
isActive = isActive and self.wantsActive
|
||||
if not globalDropShadowFlag:
|
||||
self.storedActiveState = isActive
|
||||
if self.shadowPlacer != None:
|
||||
isActive = isActive and globalDropShadowFlag
|
||||
if self.activeShadow != isActive:
|
||||
self.activeShadow = isActive
|
||||
if isActive:
|
||||
self.shadowPlacer.on()
|
||||
else:
|
||||
self.shadowPlacer.off()
|
||||
|
||||
def setShadowHeight(self, shadowHeight):
|
||||
if self.dropShadow:
|
||||
self.dropShadow.setZ(-shadowHeight)
|
||||
|
||||
def getShadowJoint(self):
|
||||
if hasattr(self, 'shadowJoint'):
|
||||
return self.shadowJoint
|
||||
shadowJoint = self.find('**/attachShadow')
|
||||
if shadowJoint.isEmpty():
|
||||
self.shadowJoint = NodePath(self)
|
||||
else:
|
||||
self.shadowJoint = shadowJoint
|
||||
return self.shadowJoint
|
||||
|
||||
def hideShadow(self):
|
||||
self.dropShadow.hide()
|
||||
|
||||
def showShadow(self):
|
||||
if not globalDropShadowFlag:
|
||||
self.dropShadow.hide()
|
||||
else:
|
||||
self.dropShadow.show()
|
||||
|
||||
def __globalDropShadowFlagChanged(self):
|
||||
if self.dropShadow != None:
|
||||
if globalDropShadowFlag == 0:
|
||||
if self.activeShadow == 1:
|
||||
self.storedActiveState = 1
|
||||
self.setActiveShadow(0)
|
||||
elif self.activeShadow == 0:
|
||||
self.setActiveShadow(1)
|
||||
self.showShadow()
|
||||
|
||||
def __globalDropShadowGrayLevelChanged(self):
|
||||
if self.dropShadow != None:
|
||||
self.dropShadow.setColor(0.0, 0.0, 0.0, globalDropShadowGrayLevel, 1)
|
0
otp/avatar/__init__.py
Normal file
0
otp/avatar/__init__.py
Normal file
20
otp/chat/ChatAgent.py
Normal file
20
otp/chat/ChatAgent.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
from direct.distributed.DistributedObjectGlobal import DistributedObjectGlobal
|
||||
from pandac.PandaModules import *
|
||||
from otp.otpbase import OTPGlobals
|
||||
|
||||
class ChatAgent(DistributedObjectGlobal):
|
||||
def __init__(self, cr):
|
||||
DistributedObjectGlobal.__init__(self, cr)
|
||||
|
||||
def delete(self):
|
||||
self.ignoreAll()
|
||||
self.cr.chatManager = None
|
||||
DistributedObjectGlobal.delete(self)
|
||||
return
|
||||
|
||||
def adminChat(self, aboutId, message):
|
||||
self.notify.warning('Admin Chat(%s): %s' % (aboutId, message))
|
||||
messenger.send('adminChat', [aboutId, message])
|
||||
|
||||
def sendChatMessage(self, message):
|
||||
self.sendUpdate('chatMessage', [message])
|
15
otp/chat/ChatAgentAI.py
Normal file
15
otp/chat/ChatAgentAI.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
from direct.directnotify import DirectNotifyGlobal
|
||||
# TODO: OTP should not depend on Toontown... Hrrm.
|
||||
from toontown.chat.TTWhiteList import TTWhiteList
|
||||
|
||||
class ChatAgentAI:
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("ChatAgentAI")
|
||||
|
||||
def announceGenerate(self):
|
||||
pass
|
||||
|
||||
def chatMessage(self, todo0):
|
||||
pass
|
||||
|
||||
def setWhiteList(self, todo0):
|
||||
pass
|
42
otp/chat/ChatAgentUD.py
Normal file
42
otp/chat/ChatAgentUD.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.distributed.DistributedObjectGlobalUD import DistributedObjectGlobalUD
|
||||
# TODO: OTP should not depend on Toontown... Hrrm.
|
||||
from toontown.chat.TTWhiteList import TTWhiteList
|
||||
|
||||
class ChatAgentUD(DistributedObjectGlobalUD):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("ChatAgentUD")
|
||||
|
||||
def announceGenerate(self):
|
||||
DistributedObjectGlobalUD.announceGenerate(self)
|
||||
|
||||
self.whiteList = TTWhiteList()
|
||||
|
||||
def chatMessage(self, message):
|
||||
sender = self.air.getAvatarIdFromSender()
|
||||
if sender == 0:
|
||||
self.air.writeServerEvent('suspicious', self.air.getAccountIdFromSender(),
|
||||
'Account sent chat without an avatar', message)
|
||||
return
|
||||
|
||||
modifications = []
|
||||
words = message.split(' ')
|
||||
offset = 0
|
||||
WantWhitelist = config.GetBool('want-whitelist', 1)
|
||||
for word in words:
|
||||
if word and not self.whiteList.isWord(word) and WantWhitelist:
|
||||
modifications.append((offset, offset+len(word)-1))
|
||||
offset += len(word) + 1
|
||||
|
||||
cleanMessage = message
|
||||
for modStart, modStop in modifications:
|
||||
cleanMessage = cleanMessage[:modStart] + '*'*(modStop-modStart+1) + cleanMessage[modStop+1:]
|
||||
|
||||
self.air.writeServerEvent('chat-said', sender, message, cleanMessage)
|
||||
|
||||
# TODO: The above is probably a little too ugly for my taste... Maybe AIR
|
||||
# should be given an API for sending updates for unknown objects?
|
||||
DistributedAvatar = self.air.dclassesByName['DistributedAvatarUD']
|
||||
dg = DistributedAvatar.aiFormatUpdate('setTalk', sender, sender,
|
||||
self.air.ourChannel,
|
||||
[0, 0, '', cleanMessage, modifications, 0])
|
||||
self.air.send(dg)
|
29
otp/chat/ChatGarbler.py
Normal file
29
otp/chat/ChatGarbler.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
import string
|
||||
import random
|
||||
from otp.otpbase import OTPLocalizer
|
||||
|
||||
class ChatGarbler:
|
||||
|
||||
def garble(self, avatar, message):
|
||||
newMessage = ''
|
||||
numWords = random.randint(1, 7)
|
||||
wordlist = OTPLocalizer.ChatGarblerDefault
|
||||
for i in xrange(1, numWords + 1):
|
||||
wordIndex = random.randint(0, len(wordlist) - 1)
|
||||
newMessage = newMessage + wordlist[wordIndex]
|
||||
if i < numWords:
|
||||
newMessage = newMessage + ' '
|
||||
|
||||
return newMessage
|
||||
|
||||
def garbleSingle(self, avatar, message):
|
||||
newMessage = ''
|
||||
numWords = 1
|
||||
wordlist = OTPLocalizer.ChatGarblerDefault
|
||||
for i in xrange(1, numWords + 1):
|
||||
wordIndex = random.randint(0, len(wordlist) - 1)
|
||||
newMessage = newMessage + wordlist[wordIndex]
|
||||
if i < numWords:
|
||||
newMessage = newMessage + ' '
|
||||
|
||||
return newMessage
|
53
otp/chat/ChatGlobals.py
Normal file
53
otp/chat/ChatGlobals.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
import string
|
||||
NORMAL_CHAT = 1
|
||||
WHISPER_CHAT = 2
|
||||
GUILD_CHAT = 3
|
||||
CREW_CHAT = 4
|
||||
SHIPPVP_CHAT = 5
|
||||
ERROR_NONE = None
|
||||
ERROR_NO_OPEN_CHAT = 1
|
||||
ERROR_NOT_FRIENDS = 2
|
||||
ERROR_NO_RECEIVER = 3
|
||||
ERROR_NO_GUILD_CHAT = 4
|
||||
ERROR_NO_CREW_CHAT = 5
|
||||
ERROR_NO_SHIPPVP_CHAT = 6
|
||||
TYPEDCHAT = 0
|
||||
SPEEDCHAT_NORMAL = 1
|
||||
SPEEDCHAT_EMOTE = 2
|
||||
SPEEDCHAT_CUSTOM = 3
|
||||
SYSTEMCHAT = 4
|
||||
GAMECHAT = 5
|
||||
GUILDCHAT = 6
|
||||
PARTYCHAT = 7
|
||||
SPEEDCHAT_QUEST = 8
|
||||
FRIEND_UPDATE = 9
|
||||
CREW_UPDATE = 10
|
||||
GUILD_UPDATE = 11
|
||||
AVATAR_UNAVAILABLE = 12
|
||||
SHIPPVPCHAT = 13
|
||||
GMCHAT = 14
|
||||
ChatEvent = 'ChatEvent'
|
||||
NormalChatEvent = 'NormalChatEvent'
|
||||
SCChatEvent = 'SCChatEvent'
|
||||
SCCustomChatEvent = 'SCCustomChatEvent'
|
||||
SCEmoteChatEvent = 'SCEmoteChatEvent'
|
||||
SCQuestEvent = 'SCQuestEvent'
|
||||
OnScreen = 0
|
||||
OffScreen = 1
|
||||
Thought = 2
|
||||
ThoughtPrefix = '.'
|
||||
|
||||
def isThought(message):
|
||||
if len(message) == 0:
|
||||
return 0
|
||||
elif message.find(ThoughtPrefix, 0, len(ThoughtPrefix)) >= 0:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
def removeThoughtPrefix(message):
|
||||
if isThought(message):
|
||||
return message[len(ThoughtPrefix):]
|
||||
else:
|
||||
return message
|
122
otp/chat/ChatInputNormal.py
Normal file
122
otp/chat/ChatInputNormal.py
Normal file
|
@ -0,0 +1,122 @@
|
|||
from direct.gui.DirectGui import *
|
||||
from direct.showbase import DirectObject
|
||||
from pandac.PandaModules import *
|
||||
import sys
|
||||
|
||||
from otp.otpbase import OTPGlobals
|
||||
from otp.otpbase import OTPLocalizer
|
||||
from toontown.chat.ChatGlobals import *
|
||||
|
||||
|
||||
class ChatInputNormal(DirectObject.DirectObject):
|
||||
def __init__(self, chatMgr):
|
||||
self.chatMgr = chatMgr
|
||||
self.normalPos = Vec3(-1.083, 0, 0.804)
|
||||
self.whisperPos = Vec3(0.0, 0, 0.71)
|
||||
self.whisperAvatarName = None
|
||||
self.whisperAvatarId = None
|
||||
self.toPlayer = 0
|
||||
wantHistory = 0
|
||||
if __dev__:
|
||||
wantHistory = 1
|
||||
self.wantHistory = base.config.GetBool('want-chat-history', wantHistory)
|
||||
self.history = ['']
|
||||
self.historySize = base.config.GetInt('chat-history-size', 10)
|
||||
self.historyIndex = 0
|
||||
return
|
||||
|
||||
def typeCallback(self, extraArgs):
|
||||
messenger.send('enterNormalChat')
|
||||
|
||||
def delete(self):
|
||||
self.ignore('arrow_up-up')
|
||||
self.ignore('arrow_down-up')
|
||||
self.chatFrame.destroy()
|
||||
del self.chatFrame
|
||||
del self.chatButton
|
||||
del self.cancelButton
|
||||
del self.chatEntry
|
||||
del self.whisperLabel
|
||||
del self.chatMgr
|
||||
|
||||
def activateByData(self, whisperAvatarId = None, toPlayer = 0):
|
||||
self.toPlayer = toPlayer
|
||||
self.whisperAvatarId = whisperAvatarId
|
||||
if self.whisperAvatarId:
|
||||
self.whisperAvatarName = base.talkAssistant.findName(self.whisperAvatarId, self.toPlayer)
|
||||
self.chatFrame.setPos(self.whisperPos)
|
||||
self.whisperLabel['text'] = OTPLocalizer.ChatInputWhisperLabel % self.whisperAvatarName
|
||||
self.whisperLabel.show()
|
||||
else:
|
||||
self.chatFrame.setPos(self.normalPos)
|
||||
self.whisperLabel.hide()
|
||||
self.chatEntry['focus'] = 1
|
||||
self.chatFrame.show()
|
||||
if self.wantHistory:
|
||||
self.accept('arrow_up-up', self.getPrevHistory)
|
||||
self.accept('arrow_down-up', self.getNextHistory)
|
||||
return True
|
||||
|
||||
def deactivate(self):
|
||||
self.chatEntry.set('')
|
||||
self.chatEntry['focus'] = 0
|
||||
self.chatFrame.hide()
|
||||
self.whisperLabel.hide()
|
||||
base.win.closeIme()
|
||||
self.ignore('arrow_up-up')
|
||||
self.ignore('arrow_down-up')
|
||||
|
||||
def checkForOverRide(self):
|
||||
return False
|
||||
|
||||
def sendChat(self, text):
|
||||
if self.checkForOverRide():
|
||||
self.chatEntry.enterText('')
|
||||
return
|
||||
self.deactivate()
|
||||
self.chatMgr.fsm.request('mainMenu')
|
||||
if text:
|
||||
if self.toPlayer:
|
||||
if self.whisperAvatarId:
|
||||
self.whisperAvatarName = None
|
||||
self.whisperAvatarId = None
|
||||
self.toPlayer = 0
|
||||
elif self.whisperAvatarId:
|
||||
self.chatMgr.sendWhisperString(text, self.whisperAvatarId)
|
||||
self.whisperAvatarName = None
|
||||
self.whisperAvatarId = None
|
||||
else:
|
||||
base.talkAssistant.sendOpenTalk(text)
|
||||
if self.wantHistory:
|
||||
self.addToHistory(text)
|
||||
return
|
||||
|
||||
def chatOverflow(self, overflowText):
|
||||
self.sendChat(self.chatEntry.get())
|
||||
|
||||
def cancelButtonPressed(self):
|
||||
self.chatEntry.set('')
|
||||
self.chatMgr.fsm.request('mainMenu')
|
||||
|
||||
def chatButtonPressed(self):
|
||||
self.sendChat(self.chatEntry.get())
|
||||
|
||||
def addToHistory(self, text):
|
||||
self.history = [text] + self.history[:self.historySize - 1]
|
||||
self.historyIndex = 0
|
||||
|
||||
def getPrevHistory(self):
|
||||
self.chatEntry.set(self.history[self.historyIndex])
|
||||
self.historyIndex += 1
|
||||
self.historyIndex %= len(self.history)
|
||||
|
||||
def getNextHistory(self):
|
||||
self.chatEntry.set(self.history[self.historyIndex])
|
||||
self.historyIndex -= 1
|
||||
self.historyIndex %= len(self.history)
|
||||
|
||||
def setPos(self, posX, posY = None, posZ = None):
|
||||
if posX and posY and posZ:
|
||||
self.chatFrame.setPos(posX, posY, posZ)
|
||||
else:
|
||||
self.chatFrame.setPos(posX)
|
142
otp/chat/ChatInputTyped.py
Normal file
142
otp/chat/ChatInputTyped.py
Normal file
|
@ -0,0 +1,142 @@
|
|||
from direct.gui.DirectGui import *
|
||||
from direct.showbase import DirectObject
|
||||
from pandac.PandaModules import *
|
||||
import sys
|
||||
|
||||
from otp.otpbase import OTPGlobals
|
||||
from otp.otpbase import OTPLocalizer
|
||||
from toontown.chat.ChatGlobals import *
|
||||
|
||||
|
||||
class ChatInputTyped(DirectObject.DirectObject):
|
||||
def __init__(self, mainEntry = 0):
|
||||
self.whisperName = None
|
||||
self.whisperId = None
|
||||
self.toPlayer = 0
|
||||
self.mainEntry = mainEntry
|
||||
wantHistory = 0
|
||||
if __dev__:
|
||||
wantHistory = 1
|
||||
self.wantHistory = base.config.GetBool('want-chat-history', wantHistory)
|
||||
self.history = ['']
|
||||
self.historySize = base.config.GetInt('chat-history-size', 10)
|
||||
self.historyIndex = 0
|
||||
return
|
||||
|
||||
def typeCallback(self, extraArgs):
|
||||
self.activate()
|
||||
|
||||
def delete(self):
|
||||
self.ignore('arrow_up-up')
|
||||
self.ignore('arrow_down-up')
|
||||
self.chatFrame.destroy()
|
||||
del self.chatFrame
|
||||
del self.chatButton
|
||||
del self.cancelButton
|
||||
del self.chatEntry
|
||||
del self.whisperLabel
|
||||
del self.chatMgr
|
||||
|
||||
def show(self, whisperId = None, toPlayer = 0):
|
||||
self.toPlayer = toPlayer
|
||||
self.whisperId = whisperId
|
||||
self.whisperName = None
|
||||
if self.whisperId:
|
||||
self.whisperName = base.talkAssistant.findName(whisperId, toPlayer)
|
||||
if hasattr(self, 'whisperPos'):
|
||||
self.chatFrame.setPos(self.whisperPos)
|
||||
self.whisperLabel['text'] = OTPLocalizer.ChatInputWhisperLabel % self.whisperName
|
||||
self.whisperLabel.show()
|
||||
else:
|
||||
if hasattr(self, 'normalPos'):
|
||||
self.chatFrame.setPos(self.normalPos)
|
||||
self.whisperLabel.hide()
|
||||
self.chatEntry['focus'] = 1
|
||||
self.chatEntry.set('')
|
||||
self.chatFrame.show()
|
||||
self.chatEntry.show()
|
||||
self.cancelButton.show()
|
||||
self.typedChatButton.hide()
|
||||
self.typedChatBar.hide()
|
||||
if self.wantHistory:
|
||||
self.accept('arrow_up-up', self.getPrevHistory)
|
||||
self.accept('arrow_down-up', self.getNextHistory)
|
||||
return
|
||||
|
||||
def hide(self):
|
||||
self.chatEntry.set('')
|
||||
self.chatEntry['focus'] = 0
|
||||
self.chatFrame.hide()
|
||||
self.chatEntry.hide()
|
||||
self.cancelButton.hide()
|
||||
self.typedChatButton.show()
|
||||
self.typedChatBar.show()
|
||||
self.ignore('arrow_up-up')
|
||||
self.ignore('arrow_down-up')
|
||||
|
||||
def activate(self):
|
||||
self.chatEntry.set('')
|
||||
self.chatEntry['focus'] = 1
|
||||
self.chatFrame.show()
|
||||
self.chatEntry.show()
|
||||
self.cancelButton.show()
|
||||
self.typedChatButton.hide()
|
||||
self.typedChatBar.hide()
|
||||
if self.whisperId:
|
||||
if self.toPlayer:
|
||||
if not base.talkAssistant.checkWhisperTypedChatPlayer(self.whisperId):
|
||||
messenger.send('Chat-Failed player typed chat test')
|
||||
self.deactivate()
|
||||
elif not base.talkAssistant.checkWhisperTypedChatAvatar(self.whisperId):
|
||||
messenger.send('Chat-Failed avatar typed chat test')
|
||||
self.deactivate()
|
||||
elif not base.talkAssistant.checkOpenTypedChat():
|
||||
messenger.send('Chat-Failed open typed chat test')
|
||||
self.deactivate()
|
||||
|
||||
def deactivate(self):
|
||||
self.chatEntry.set('')
|
||||
self.chatEntry['focus'] = 0
|
||||
self.chatFrame.show()
|
||||
self.chatEntry.hide()
|
||||
self.cancelButton.hide()
|
||||
self.typedChatButton.show()
|
||||
self.typedChatBar.show()
|
||||
|
||||
def sendChat(self, text):
|
||||
self.deactivate()
|
||||
if text:
|
||||
if self.toPlayer:
|
||||
if self.whisperId:
|
||||
pass
|
||||
elif self.whisperId:
|
||||
pass
|
||||
else:
|
||||
base.talkAssistant.sendOpenTalk(text)
|
||||
if self.wantHistory:
|
||||
self.addToHistory(text)
|
||||
self.chatEntry.set('')
|
||||
|
||||
def chatOverflow(self, overflowText):
|
||||
self.sendChat(self.chatEntry.get())
|
||||
|
||||
def cancelButtonPressed(self):
|
||||
self.chatEntry.set('')
|
||||
self.deactivate()
|
||||
|
||||
def chatButtonPressed(self):
|
||||
self.sendChat(self.chatEntry.get())
|
||||
|
||||
def addToHistory(self, text):
|
||||
self.history = [text] + self.history[:self.historySize - 1]
|
||||
self.historyIndex = 0
|
||||
|
||||
def getPrevHistory(self):
|
||||
self.chatEntry.set(self.history[self.historyIndex])
|
||||
self.historyIndex += 1
|
||||
self.historyIndex %= len(self.history)
|
||||
|
||||
def getNextHistory(self):
|
||||
self.chatEntry.set(self.history[self.historyIndex])
|
||||
self.historyIndex -= 1
|
||||
self.historyIndex %= len(self.history)
|
306
otp/chat/ChatInputWhiteListFrame.py
Normal file
306
otp/chat/ChatInputWhiteListFrame.py
Normal file
|
@ -0,0 +1,306 @@
|
|||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.fsm import FSM
|
||||
from direct.gui.DirectGui import *
|
||||
from direct.task import Task
|
||||
from pandac.PandaModules import *
|
||||
import sys
|
||||
|
||||
from otp.chat.ChatInputTyped import ChatInputTyped
|
||||
from otp.otpbase import OTPGlobals
|
||||
from otp.otpbase import OTPLocalizer
|
||||
from toontown.chat.ChatGlobals import *
|
||||
|
||||
|
||||
class ChatInputWhiteListFrame(FSM.FSM, DirectFrame):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('ChatInputWhiteList')
|
||||
|
||||
def __init__(self, entryOptions, parent = None, **kw):
|
||||
FSM.FSM.__init__(self, 'ChatInputWhiteListFrame')
|
||||
self.okayToSubmit = True
|
||||
self.receiverId = None
|
||||
DirectFrame.__init__(self, parent=aspect2dp, pos=(0, 0, 0.3), relief=None, image=DGG.getDefaultDialogGeom(), image_scale=(1.6, 1, 1.4), image_pos=(0, 0, -0.05), image_color=OTPGlobals.GlobalDialogColor, borderWidth=(0.01, 0.01))
|
||||
optiondefs = {'parent': self,
|
||||
'relief': DGG.SUNKEN,
|
||||
'scale': 0.05,
|
||||
'frameSize': (-0.2,
|
||||
25.3,
|
||||
-0.5,
|
||||
1.2),
|
||||
'borderWidth': (0.1, 0.1),
|
||||
'frameColor': (0.9, 0.9, 0.85, 0.8),
|
||||
'pos': (-0.2, 0, 0.11),
|
||||
'entryFont': OTPGlobals.getInterfaceFont(),
|
||||
'width': 8.6,
|
||||
'numLines': 3,
|
||||
'cursorKeys': 1,
|
||||
'backgroundFocus': 0,
|
||||
'suppressKeys': 1,
|
||||
'suppressMouse': 1,
|
||||
'command': self.sendChat,
|
||||
'failedCommand': self.sendFailed,
|
||||
'focus': 0,
|
||||
'text': '',
|
||||
'sortOrder': DGG.FOREGROUND_SORT_INDEX}
|
||||
entryOptions['parent'] = self
|
||||
self.chatEntry = DirectEntry(**entryOptions)
|
||||
self.whisperId = None
|
||||
self.chatEntry.bind(DGG.OVERFLOW, self.chatOverflow)
|
||||
wantHistory = 0
|
||||
if __dev__:
|
||||
wantHistory = 1
|
||||
self.wantHistory = base.config.GetBool('want-chat-history', wantHistory)
|
||||
self.history = ['']
|
||||
self.historySize = base.config.GetInt('chat-history-size', 10)
|
||||
self.historyIndex = 0
|
||||
self.promoteWhiteList = 0
|
||||
self.checkBeforeSend = base.config.GetBool('white-list-check-before-send', 0)
|
||||
self.whiteList = None
|
||||
self.active = 0
|
||||
self.autoOff = 0
|
||||
self.sendBy = 'Mode'
|
||||
self.prefilter = 1
|
||||
from direct.gui import DirectGuiGlobals
|
||||
self.chatEntry.bind(DirectGuiGlobals.TYPE, self.applyFilter)
|
||||
self.chatEntry.bind(DirectGuiGlobals.ERASE, self.applyFilter)
|
||||
tpMgr = TextPropertiesManager.getGlobalPtr()
|
||||
Red = tpMgr.getProperties('red')
|
||||
Red.setTextColor(1.0, 0.0, 0.0, 1)
|
||||
tpMgr.setProperties('WLRed', Red)
|
||||
del tpMgr
|
||||
self.origFrameColor = self.chatEntry['frameColor']
|
||||
return
|
||||
|
||||
def destroy(self):
|
||||
from direct.gui import DirectGuiGlobals
|
||||
self.chatEntry.unbind(DGG.OVERFLOW)
|
||||
self.chatEntry.unbind(DirectGuiGlobals.TYPE)
|
||||
self.chatEntry.unbind(DirectGuiGlobals.ERASE)
|
||||
self.chatEntry.ignoreAll()
|
||||
DirectFrame.destroy(self)
|
||||
|
||||
def delete(self):
|
||||
self.ignore('arrow_up-up')
|
||||
self.ignore('arrow_down-up')
|
||||
|
||||
def requestMode(self, mode, *args):
|
||||
return self.request(mode, *args)
|
||||
|
||||
def defaultFilter(self, request, *args):
|
||||
if request == 'AllChat':
|
||||
if not base.talkAssistant.checkAnyTypedChat():
|
||||
messenger.send('Chat-Failed open typed chat test')
|
||||
self.notify.warning('Chat-Failed open typed chat test')
|
||||
return None
|
||||
elif request == 'PlayerWhisper':
|
||||
if not base.talkAssistant.checkWhisperTypedChatPlayer(self.whisperId):
|
||||
messenger.send('Chat-Failed player typed chat test')
|
||||
self.notify.warning('Chat-Failed player typed chat test')
|
||||
return None
|
||||
elif request == 'AvatarWhisper':
|
||||
if not base.talkAssistant.checkWhisperTypedChatAvatar(self.whisperId):
|
||||
messenger.send('Chat-Failed avatar typed chat test')
|
||||
self.notify.warning('Chat-Failed avatar typed chat test')
|
||||
return None
|
||||
return FSM.FSM.defaultFilter(self, request, *args)
|
||||
|
||||
def enterOff(self):
|
||||
self.deactivate()
|
||||
localAvatar.chatMgr.fsm.request('mainMenu')
|
||||
|
||||
def exitOff(self):
|
||||
self.activate()
|
||||
|
||||
def enterAllChat(self):
|
||||
self.chatEntry['focus'] = 1
|
||||
self.show()
|
||||
|
||||
def exitAllChat(self):
|
||||
pass
|
||||
|
||||
def enterGuildChat(self):
|
||||
self['focus'] = 1
|
||||
self.show()
|
||||
|
||||
def exitGuildChat(self):
|
||||
pass
|
||||
|
||||
def enterCrewChat(self):
|
||||
self['focus'] = 1
|
||||
self.show()
|
||||
|
||||
def exitCrewChat(self):
|
||||
pass
|
||||
|
||||
def enterPlayerWhisper(self):
|
||||
self.tempText = self.chatEntry.get()
|
||||
self.activate()
|
||||
|
||||
def exitPlayerWhisper(self):
|
||||
self.chatEntry.set(self.tempText)
|
||||
self.whisperId = None
|
||||
return
|
||||
|
||||
def enterAvatarWhisper(self):
|
||||
self.tempText = self.chatEntry.get()
|
||||
self.activate()
|
||||
|
||||
def exitAvatarWhisper(self):
|
||||
self.chatEntry.set(self.tempText)
|
||||
self.whisperId = None
|
||||
return
|
||||
|
||||
def activateByData(self, receiverId = None, toPlayer = 0):
|
||||
self.receiverId = receiverId
|
||||
self.toPlayer = toPlayer
|
||||
result = None
|
||||
if not self.receiverId:
|
||||
result = self.requestMode('AllChat')
|
||||
elif self.receiverId and not self.toPlayer:
|
||||
self.whisperId = receiverId
|
||||
result = self.requestMode('AvatarWhisper')
|
||||
elif self.receiverId and self.toPlayer:
|
||||
self.whisperId = receiverId
|
||||
result = self.requestMode('PlayerWhisper')
|
||||
return result
|
||||
|
||||
def activate(self):
|
||||
self.chatEntry['focus'] = 1
|
||||
self.show()
|
||||
self.active = 1
|
||||
self.chatEntry.guiItem.setAcceptEnabled(False)
|
||||
|
||||
def deactivate(self):
|
||||
self.chatEntry.set('')
|
||||
self.chatEntry['focus'] = 0
|
||||
self.hide()
|
||||
self.active = 0
|
||||
|
||||
def isActive(self):
|
||||
return self.active
|
||||
|
||||
def sendChat(self, text, overflow = False):
|
||||
if not (len(text) > 0 and text[0] in ['~', '>']):
|
||||
if self.prefilter:
|
||||
words = text.split(' ')
|
||||
newwords = []
|
||||
for word in words:
|
||||
if word == '' or self.whiteList.isWord(word) or self.promoteWhiteList:
|
||||
newwords.append(word)
|
||||
else:
|
||||
newwords.append(base.whiteList.defaultWord)
|
||||
|
||||
text = ' '.join(newwords)
|
||||
else:
|
||||
text = self.chatEntry.get(plain=True)
|
||||
|
||||
if text:
|
||||
self.chatEntry.set('')
|
||||
self.sendChatBySwitch(text)
|
||||
if self.wantHistory:
|
||||
self.addToHistory(text)
|
||||
else:
|
||||
localAvatar.chatMgr.deactivateChat()
|
||||
|
||||
if not overflow:
|
||||
self.hide()
|
||||
if self.autoOff:
|
||||
self.requestMode('Off')
|
||||
|
||||
localAvatar.chatMgr.messageSent()
|
||||
|
||||
def sendChatBySwitch(self, text):
|
||||
if len(text) > 0 and text[0] == '~':
|
||||
base.talkAssistant.sendOpenTalk(text)
|
||||
elif self.sendBy == 'Mode':
|
||||
self.sendChatByMode(text)
|
||||
elif self.sendBy == 'Data':
|
||||
self.sendChatByData(text)
|
||||
else:
|
||||
self.sendChatByMode(text)
|
||||
|
||||
def sendChatByData(self, text):
|
||||
if not self.receiverId:
|
||||
base.talkAssistant.sendOpenTalk(text)
|
||||
elif self.receiverId and not self.toPlayer:
|
||||
base.talkAssistant.sendWhisperTalk(text, self.receiverId)
|
||||
elif self.receiverId and self.toPlayer:
|
||||
base.talkAssistant.sendAccountTalk(text, self.receiverId)
|
||||
|
||||
def sendChatByMode(self, text):
|
||||
state = self.getCurrentOrNextState()
|
||||
messenger.send('sentRegularChat')
|
||||
if state == 'PlayerWhisper':
|
||||
base.talkAssistant.sendPlayerWhisperWLChat(text, self.whisperId)
|
||||
elif state == 'AvatarWhisper':
|
||||
base.talkAssistant.sendAvatarWhisperWLChat(text, self.whisperId)
|
||||
elif state == 'GuildChat':
|
||||
base.talkAssistant.sendAvatarGuildWLChat(text)
|
||||
elif state == 'CrewChat':
|
||||
base.talkAssistant.sendAvatarCrewWLChat(text)
|
||||
elif len(text) > 0 and text[0] == '~':
|
||||
base.talkAssistant.sendOpenTalk(text)
|
||||
else:
|
||||
base.talkAssistant.sendOpenTalk(text)
|
||||
|
||||
def sendFailed(self, text):
|
||||
if not self.checkBeforeSend:
|
||||
self.sendChat(text)
|
||||
return
|
||||
self.chatEntry['frameColor'] = (0.9, 0.0, 0.0, 0.8)
|
||||
|
||||
def resetFrameColor(task = None):
|
||||
self.chatEntry['frameColor'] = self.origFrameColor
|
||||
return Task.done
|
||||
|
||||
taskMgr.doMethodLater(0.1, resetFrameColor, 'resetFrameColor')
|
||||
self.applyFilter(keyArgs=None, strict=True)
|
||||
self.okayToSubmit = True
|
||||
self.chatEntry.guiItem.setAcceptEnabled(True)
|
||||
return
|
||||
|
||||
def chatOverflow(self, overflowText):
|
||||
self.notify.debug('chatOverflow')
|
||||
self.sendChat(self.chatEntry.get(plain=True), overflow=True)
|
||||
|
||||
def addToHistory(self, text):
|
||||
self.history = [text] + self.history[:self.historySize - 1]
|
||||
self.historyIndex = 0
|
||||
|
||||
def getPrevHistory(self):
|
||||
self.chatEntry.set(self.history[self.historyIndex])
|
||||
self.historyIndex += 1
|
||||
self.historyIndex %= len(self.history)
|
||||
|
||||
def getNextHistory(self):
|
||||
self.chatEntry.set(self.history[self.historyIndex])
|
||||
self.historyIndex -= 1
|
||||
self.historyIndex %= len(self.history)
|
||||
|
||||
def applyFilter(self, keyArgs, strict = False):
|
||||
text = self.chatEntry.get(plain=True)
|
||||
if text.startswith('~'):
|
||||
self.okayToSubmit = True
|
||||
else:
|
||||
words = text.split(' ')
|
||||
newwords = []
|
||||
self.notify.debug('%s' % words)
|
||||
self.okayToSubmit = True
|
||||
for word in words:
|
||||
if word == '' or self.whiteList.isWord(word):
|
||||
newwords.append(word)
|
||||
else:
|
||||
if self.checkBeforeSend:
|
||||
self.okayToSubmit = False
|
||||
else:
|
||||
self.okayToSubmit = True
|
||||
newwords.append('\x01WLEnter\x01' + word + '\x02')
|
||||
|
||||
if not strict:
|
||||
lastword = words[-1]
|
||||
if lastword == '' or self.whiteList.isPrefix(lastword):
|
||||
newwords[-1] = lastword
|
||||
else:
|
||||
newwords[-1] = '\x01WLEnter\x01' + lastword + '\x02'
|
||||
newtext = ' '.join(newwords)
|
||||
self.chatEntry.set(newtext)
|
||||
self.chatEntry.guiItem.setAcceptEnabled(self.okayToSubmit)
|
516
otp/chat/ChatManager.py
Normal file
516
otp/chat/ChatManager.py
Normal file
|
@ -0,0 +1,516 @@
|
|||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.fsm import ClassicFSM
|
||||
from direct.fsm import State
|
||||
from direct.gui.DirectGui import *
|
||||
from direct.showbase import DirectObject
|
||||
from pandac.PandaModules import *
|
||||
|
||||
from otp.login import LeaveToPayDialog
|
||||
from otp.login import PrivacyPolicyPanel
|
||||
from otp.login import SecretFriendsInfoPanel
|
||||
from otp.otpbase import OTPLocalizer
|
||||
from toontown.chat.ChatGlobals import *
|
||||
|
||||
|
||||
ChatEvent = 'ChatEvent'
|
||||
NormalChatEvent = 'NormalChatEvent'
|
||||
SCChatEvent = 'SCChatEvent'
|
||||
SCCustomChatEvent = 'SCCustomChatEvent'
|
||||
SCEmoteChatEvent = 'SCEmoteChatEvent'
|
||||
OnScreen = 0
|
||||
OffScreen = 1
|
||||
Thought = 2
|
||||
ThoughtPrefix = '.'
|
||||
|
||||
def isThought(message):
|
||||
if len(message) == 0:
|
||||
return 0
|
||||
elif message.find(ThoughtPrefix, 0, len(ThoughtPrefix)) >= 0:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
def removeThoughtPrefix(message):
|
||||
if isThought(message):
|
||||
return message[len(ThoughtPrefix):]
|
||||
else:
|
||||
return message
|
||||
|
||||
|
||||
class ChatManager(DirectObject.DirectObject):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('ChatManager')
|
||||
|
||||
def __init__(self, cr, localAvatar):
|
||||
self.cr = cr
|
||||
self.localAvatar = localAvatar
|
||||
self.wantBackgroundFocus = 1
|
||||
self.__scObscured = 0
|
||||
self.__normalObscured = 0
|
||||
self.openChatWarning = None
|
||||
self.unpaidChatWarning = None
|
||||
self.teaser = None
|
||||
self.paidNoParentPassword = None
|
||||
self.noSecretChatAtAll = None
|
||||
self.noSecretChatAtAllAndNoWhitelist = None
|
||||
self.noSecretChatWarning = None
|
||||
self.activateChatGui = None
|
||||
self.chatMoreInfo = None
|
||||
self.chatPrivacyPolicy = None
|
||||
self.secretChatActivated = None
|
||||
self.problemActivatingChat = None
|
||||
self.leaveToPayDialog = None
|
||||
self.fsm = ClassicFSM.ClassicFSM('chatManager', [State.State('off', self.enterOff, self.exitOff),
|
||||
State.State('mainMenu', self.enterMainMenu, self.exitMainMenu),
|
||||
State.State('speedChat', self.enterSpeedChat, self.exitSpeedChat),
|
||||
State.State('normalChat', self.enterNormalChat, self.exitNormalChat),
|
||||
State.State('whisper', self.enterWhisper, self.exitWhisper),
|
||||
State.State('whisperChat', self.enterWhisperChat, self.exitWhisperChat),
|
||||
State.State('whisperChatPlayer', self.enterWhisperChatPlayer, self.exitWhisperChatPlayer),
|
||||
State.State('whisperSpeedChat', self.enterWhisperSpeedChat, self.exitWhisperSpeedChat),
|
||||
State.State('whisperSpeedChatPlayer', self.enterWhisperSpeedChatPlayer, self.exitWhisperSpeedChatPlayer),
|
||||
State.State('openChatWarning', self.enterOpenChatWarning, self.exitOpenChatWarning),
|
||||
State.State('leaveToPayDialog', self.enterLeaveToPayDialog, self.exitLeaveToPayDialog),
|
||||
State.State('unpaidChatWarning', self.enterUnpaidChatWarning, self.exitUnpaidChatWarning),
|
||||
State.State('noSecretChatAtAll', self.enterNoSecretChatAtAll, self.exitNoSecretChatAtAll),
|
||||
State.State('noSecretChatAtAllAndNoWhitelist', self.enterNoSecretChatAtAllAndNoWhitelist, self.exitNoSecretChatAtAllAndNoWhitelist),
|
||||
State.State('noSecretChatWarning', self.enterNoSecretChatWarning, self.exitNoSecretChatWarning),
|
||||
State.State('noFriendsWarning', self.enterNoFriendsWarning, self.exitNoFriendsWarning),
|
||||
State.State('otherDialog', self.enterOtherDialog, self.exitOtherDialog),
|
||||
State.State('activateChat', self.enterActivateChat, self.exitActivateChat),
|
||||
State.State('chatMoreInfo', self.enterChatMoreInfo, self.exitChatMoreInfo),
|
||||
State.State('chatPrivacyPolicy', self.enterChatPrivacyPolicy, self.exitChatPrivacyPolicy),
|
||||
State.State('secretChatActivated', self.enterSecretChatActivated, self.exitSecretChatActivated),
|
||||
State.State('problemActivatingChat', self.enterProblemActivatingChat, self.exitProblemActivatingChat),
|
||||
State.State('whiteListOpenChat', self.enterWhiteListOpenChat, self.exitWhiteListOpenChat),
|
||||
State.State('whiteListAvatarChat', self.enterWhiteListAvatarChat, self.exitWhiteListAvatarChat),
|
||||
State.State('whiteListPlayerChat', self.enterWhiteListPlayerChat, self.exitWhiteListPlayerChat),
|
||||
State.State('trueFriendTeaserPanel', self.enterTrueFriendTeaserPanel, self.exitTrueFriendTeaserPanel)], 'off', 'off')
|
||||
self.fsm.enterInitialState()
|
||||
return
|
||||
|
||||
def delete(self):
|
||||
self.ignoreAll()
|
||||
del self.fsm
|
||||
if hasattr(self.chatInputNormal, 'destroy'):
|
||||
self.chatInputNormal.destroy()
|
||||
self.chatInputNormal.delete()
|
||||
del self.chatInputNormal
|
||||
self.chatInputSpeedChat.delete()
|
||||
del self.chatInputSpeedChat
|
||||
if self.openChatWarning:
|
||||
self.openChatWarning.destroy()
|
||||
self.openChatWarning = None
|
||||
if self.unpaidChatWarning:
|
||||
self.payButton = None
|
||||
self.unpaidChatWarning.destroy()
|
||||
self.unpaidChatWarning = None
|
||||
if self.teaser:
|
||||
self.teaser.cleanup()
|
||||
self.teaser.unload()
|
||||
self.teaser = None
|
||||
if self.noSecretChatAtAll:
|
||||
self.noSecretChatAtAll.destroy()
|
||||
self.noSecretChatAtAll = None
|
||||
if self.noSecretChatAtAllAndNoWhitelist:
|
||||
self.noSecretChatAtAllAndNoWhitelist.destroy()
|
||||
self.noSecretChatAtAllAndNoWhitelist = None
|
||||
if self.noSecretChatWarning:
|
||||
self.noSecretChatWarning.destroy()
|
||||
self.noSecretChatWarning = None
|
||||
if self.activateChatGui:
|
||||
self.activateChatGui.destroy()
|
||||
self.activateChatGui = None
|
||||
if self.chatMoreInfo:
|
||||
self.chatMoreInfo.destroy()
|
||||
self.chatMoreInfo = None
|
||||
if self.chatPrivacyPolicy:
|
||||
self.chatPrivacyPolicy.destroy()
|
||||
self.chatPrivacyPolicy = None
|
||||
if self.secretChatActivated:
|
||||
self.secretChatActivated.destroy()
|
||||
self.secretChatActivated = None
|
||||
if self.problemActivatingChat:
|
||||
self.problemActivatingChat.destroy()
|
||||
self.problemActivatingChat = None
|
||||
del self.localAvatar
|
||||
del self.cr
|
||||
return
|
||||
|
||||
def obscure(self, normal, sc):
|
||||
self.__scObscured = sc
|
||||
if self.__scObscured:
|
||||
self.scButton.hide()
|
||||
self.__normalObscured = normal
|
||||
if self.__normalObscured:
|
||||
self.normalButton.hide()
|
||||
|
||||
def isObscured(self):
|
||||
return (self.__normalObscured, self.__scObscured)
|
||||
|
||||
def stop(self):
|
||||
self.fsm.request('off')
|
||||
self.ignoreAll()
|
||||
|
||||
def start(self):
|
||||
self.fsm.request('mainMenu')
|
||||
|
||||
def announceChat(self):
|
||||
messenger.send(ChatEvent)
|
||||
|
||||
def announceSCChat(self):
|
||||
messenger.send(SCChatEvent)
|
||||
self.announceChat()
|
||||
|
||||
def sendChatString(self, message):
|
||||
chatFlags = CFSpeech | CFTimeout
|
||||
if base.cr.wantSwitchboardHacks:
|
||||
from otp.switchboard import badwordpy
|
||||
badwordpy.init('', '')
|
||||
message = badwordpy.scrub(message)
|
||||
if isThought(message):
|
||||
message = removeThoughtPrefix(message)
|
||||
chatFlags = CFThought
|
||||
messenger.send(NormalChatEvent)
|
||||
self.announceChat()
|
||||
|
||||
def sendWhisperString(self, message, whisperAvatarId):
|
||||
pass
|
||||
|
||||
def sendSCChatMessage(self, msgIndex):
|
||||
base.talkAssistant.sendOpenSpeedChat(1, msgIndex)
|
||||
|
||||
def sendSCWhisperMessage(self, msgIndex, whisperAvatarId, toPlayer):
|
||||
if toPlayer:
|
||||
base.talkAssistant.sendPlayerWhisperSpeedChat(1, msgIndex, whisperAvatarId)
|
||||
else:
|
||||
base.talkAssistant.sendAvatarWhisperSpeedChat(1, msgIndex, whisperAvatarId)
|
||||
|
||||
def sendSCCustomChatMessage(self, msgIndex):
|
||||
base.talkAssistant.sendOpenSpeedChat(3, msgIndex)
|
||||
|
||||
def sendSCCustomWhisperMessage(self, msgIndex, whisperAvatarId, toPlayer):
|
||||
if toPlayer:
|
||||
base.talkAssistant.sendPlayerWhisperSpeedChat(3, msgIndex, whisperAvatarId)
|
||||
else:
|
||||
base.talkAssistant.sendAvatarWhisperSpeedChat(3, msgIndex, whisperAvatarId)
|
||||
|
||||
def sendSCEmoteChatMessage(self, emoteId):
|
||||
base.talkAssistant.sendOpenSpeedChat(2, emoteId)
|
||||
|
||||
def sendSCEmoteWhisperMessage(self, emoteId, whisperAvatarId, toPlayer):
|
||||
if toPlayer:
|
||||
base.talkAssistant.sendPlayerWhisperSpeedChat(2, emoteId, whisperAvatarId)
|
||||
else:
|
||||
base.talkAssistant.sendAvatarWhisperSpeedChat(2, emoteId, whisperAvatarId)
|
||||
|
||||
def enterOff(self):
|
||||
self.scButton.hide()
|
||||
self.normalButton.hide()
|
||||
self.ignoreAll()
|
||||
|
||||
def exitOff(self):
|
||||
pass
|
||||
|
||||
def enterMainMenu(self):
|
||||
self.checkObscurred()
|
||||
if self.localAvatar.canChat() or self.cr.wantMagicWords:
|
||||
if self.wantBackgroundFocus:
|
||||
self.chatInputNormal.chatEntry['backgroundFocus'] = 1
|
||||
self.acceptOnce('enterNormalChat', self.fsm.request, ['normalChat'])
|
||||
|
||||
def checkObscurred(self):
|
||||
if not self.__scObscured:
|
||||
self.scButton.show()
|
||||
if not self.__normalObscured:
|
||||
self.normalButton.show()
|
||||
|
||||
def exitMainMenu(self):
|
||||
self.scButton.hide()
|
||||
self.normalButton.hide()
|
||||
self.ignore('enterNormalChat')
|
||||
if self.wantBackgroundFocus:
|
||||
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
|
||||
|
||||
def whisperTo(self, avatarName, avatarId, playerId = None):
|
||||
self.fsm.request('whisper', [avatarName, avatarId, playerId])
|
||||
|
||||
def noWhisper(self):
|
||||
self.fsm.request('mainMenu')
|
||||
|
||||
def handleWhiteListSelect(self):
|
||||
self.fsm.request('whiteListOpenChat')
|
||||
|
||||
def enterWhiteListOpenChat(self):
|
||||
self.checkObscurred()
|
||||
if self.wantBackgroundFocus:
|
||||
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
|
||||
base.localAvatar.chatMgr.chatInputWhiteList.activateByData()
|
||||
|
||||
def exitWhiteListOpenChat(self):
|
||||
pass
|
||||
|
||||
def enterWhiteListAvatarChat(self, receiverId):
|
||||
if self.wantBackgroundFocus:
|
||||
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
|
||||
base.localAvatar.chatMgr.chatInputWhiteList.activateByData(receiverId, 0)
|
||||
|
||||
def exitWhiteListAvatarChat(self):
|
||||
pass
|
||||
|
||||
def enterWhiteListPlayerChat(self, receiverId):
|
||||
if self.wantBackgroundFocus:
|
||||
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
|
||||
base.localAvatar.chatMgr.chatInputWhiteList.activateByData(receiverId, 1)
|
||||
|
||||
def exitWhiteListPlayerChat(self):
|
||||
pass
|
||||
|
||||
def enterWhisper(self, avatarName, avatarId, playerId = None):
|
||||
self.whisperScButton['extraArgs'] = [avatarName, avatarId, playerId]
|
||||
self.whisperButton['extraArgs'] = [avatarName, avatarId, playerId]
|
||||
playerName = None
|
||||
chatToToon = 1
|
||||
online = 0
|
||||
if avatarId in self.cr.doId2do:
|
||||
online = 1
|
||||
elif self.cr.isFriend(avatarId):
|
||||
online = self.cr.isFriendOnline(avatarId)
|
||||
hasManager = hasattr(base.cr, 'playerFriendsManager')
|
||||
if hasManager:
|
||||
if base.cr.playerFriendsManager.askAvatarOnline(avatarId):
|
||||
online = 1
|
||||
avatarUnderstandable = 0
|
||||
playerUnderstandable = 0
|
||||
av = None
|
||||
if avatarId:
|
||||
av = self.cr.identifyAvatar(avatarId)
|
||||
if av != None:
|
||||
avatarUnderstandable = av.isUnderstandable()
|
||||
if playerId:
|
||||
if playerId in base.cr.playerFriendsManager.playerId2Info:
|
||||
playerInfo = base.cr.playerFriendsManager.playerId2Info.get(playerId)
|
||||
playerName = playerInfo.playerName
|
||||
online = 1
|
||||
playerUnderstandable = playerInfo.understandableYesNo
|
||||
if playerUnderstandable or not avatarId:
|
||||
chatToToon = 0
|
||||
if chatToToon:
|
||||
chatName = avatarName
|
||||
else:
|
||||
chatName = playerName
|
||||
normalButtonObscured, scButtonObscured = self.isObscured()
|
||||
if (avatarUnderstandable or playerUnderstandable) and online and not normalButtonObscured:
|
||||
self.whisperButton['state'] = 'normal'
|
||||
self.enablewhisperButton()
|
||||
else:
|
||||
self.whisperButton['state'] = 'inactive'
|
||||
self.disablewhisperButton()
|
||||
if online:
|
||||
self.whisperScButton['state'] = 'normal'
|
||||
self.whisperButton['state'] = 'normal'
|
||||
self.changeFrameText(OTPLocalizer.ChatManagerWhisperToName % chatName)
|
||||
else:
|
||||
self.whisperScButton['state'] = 'inactive'
|
||||
self.whisperButton['state'] = 'inactive'
|
||||
self.changeFrameText(OTPLocalizer.ChatManagerWhisperOffline % chatName)
|
||||
self.whisperFrame.show()
|
||||
self.refreshWhisperFrame()
|
||||
if avatarUnderstandable or playerUnderstandable:
|
||||
if playerId and not chatToToon:
|
||||
if self.wantBackgroundFocus:
|
||||
self.chatInputNormal.chatEntry['backgroundFocus'] = 1
|
||||
self.acceptOnce('enterNormalChat', self.fsm.request, ['whisperChatPlayer', [avatarName, playerId]])
|
||||
elif online and chatToToon:
|
||||
if self.wantBackgroundFocus:
|
||||
self.chatInputNormal.chatEntry['backgroundFocus'] = 1
|
||||
self.acceptOnce('enterNormalChat', self.fsm.request, ['whisperChat', [avatarName, avatarId]])
|
||||
return
|
||||
|
||||
def disablewhisperButton(self):
|
||||
pass
|
||||
|
||||
def enablewhisperButton(self):
|
||||
pass
|
||||
|
||||
def refreshWhisperFrame(self):
|
||||
pass
|
||||
|
||||
def changeFrameText(self, newText):
|
||||
self.whisperFrame['text'] = newText
|
||||
|
||||
def exitWhisper(self):
|
||||
self.whisperFrame.hide()
|
||||
self.ignore('enterNormalChat')
|
||||
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
|
||||
|
||||
def enterWhisperSpeedChat(self, avatarId):
|
||||
self.whisperFrame.show()
|
||||
if self.wantBackgroundFocus:
|
||||
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
|
||||
self.chatInputSpeedChat.show(avatarId)
|
||||
|
||||
def exitWhisperSpeedChat(self):
|
||||
self.whisperFrame.hide()
|
||||
self.chatInputSpeedChat.hide()
|
||||
|
||||
def enterWhisperSpeedChatPlayer(self, playerId):
|
||||
self.whisperFrame.show()
|
||||
if self.wantBackgroundFocus:
|
||||
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
|
||||
self.chatInputSpeedChat.show(playerId, 1)
|
||||
|
||||
def exitWhisperSpeedChatPlayer(self):
|
||||
self.whisperFrame.hide()
|
||||
self.chatInputSpeedChat.hide()
|
||||
|
||||
def enterWhisperChat(self, avatarName, avatarId):
|
||||
result = self.chatInputNormal.activateByData(avatarId)
|
||||
return result
|
||||
|
||||
def exitWhisperChat(self):
|
||||
self.chatInputNormal.deactivate()
|
||||
|
||||
def enterWhisperChatPlayer(self, avatarName, playerId):
|
||||
playerInfo = base.cr.playerFriendsManager.getFriendInfo(playerId)
|
||||
if playerInfo:
|
||||
avatarName = playerInfo.playerName
|
||||
result = self.chatInputNormal.activateByData(playerId, 1)
|
||||
return result
|
||||
|
||||
def exitWhisperChatPlayer(self):
|
||||
self.chatInputNormal.deactivate()
|
||||
|
||||
def enterSpeedChat(self):
|
||||
messenger.send('enterSpeedChat')
|
||||
if not self.__scObscured:
|
||||
self.scButton.show()
|
||||
if not self.__normalObscured:
|
||||
self.normalButton.show()
|
||||
if self.wantBackgroundFocus:
|
||||
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
|
||||
self.chatInputSpeedChat.show()
|
||||
|
||||
def exitSpeedChat(self):
|
||||
self.scButton.hide()
|
||||
self.normalButton.hide()
|
||||
self.chatInputSpeedChat.hide()
|
||||
|
||||
def enterNormalChat(self):
|
||||
result = self.chatInputNormal.activateByData()
|
||||
return result
|
||||
|
||||
def exitNormalChat(self):
|
||||
self.chatInputNormal.deactivate()
|
||||
|
||||
def enterOpenChatWarning(self):
|
||||
self.notify.error('called enterOpenChatWarning() on parent class')
|
||||
|
||||
def exitOpenChatWarning(self):
|
||||
self.notify.error('called exitOpenChatWarning() on parent class')
|
||||
|
||||
def enterLeaveToPayDialog(self):
|
||||
if self.leaveToPayDialog == None:
|
||||
self.leaveToPayDialog = LeaveToPayDialog.LeaveToPayDialog(self.paidNoParentPassword)
|
||||
self.leaveToPayDialog.setCancel(self.__handleLeaveToPayCancel)
|
||||
self.leaveToPayDialog.show()
|
||||
return
|
||||
|
||||
def exitLeaveToPayDialog(self):
|
||||
if self.leaveToPayDialog:
|
||||
self.leaveToPayDialog.destroy()
|
||||
self.leaveToPayDialog = None
|
||||
return
|
||||
|
||||
def enterUnpaidChatWarning(self):
|
||||
self.notify.error('called enterUnpaidChatWarning() on parent class')
|
||||
|
||||
def exitUnpaidChatWarning(self):
|
||||
self.notify.error('called exitUnpaidChatWarning() on parent class')
|
||||
|
||||
def enterNoSecretChatAtAll(self):
|
||||
self.notify.error('called enterNoSecretChatAtAll() on parent class')
|
||||
|
||||
def exitNoSecretChatAtAll(self):
|
||||
self.notify.error('called exitNoSecretChatAtAll() on parent class')
|
||||
|
||||
def enterNoSecretChatAtAllAndNoWhitelist(self):
|
||||
self.notify.error('called enterNoSecretChatAtAllAndNoWhitelist() on parent class')
|
||||
|
||||
def exitNoSecretChatAtAllAndNoWhitelist(self):
|
||||
self.notify.error('called exitNoSecretChatAtAllAndNoWhitelist() on parent class')
|
||||
|
||||
def enterNoSecretChatWarning(self):
|
||||
self.notify.error('called enterNoSecretChatWarning() on parent class')
|
||||
|
||||
def exitNoSecretChatWarning(self):
|
||||
self.notify.error('called exitNoSecretChatWarning() on parent class')
|
||||
|
||||
def enterNoFriendsWarning(self):
|
||||
self.notify.error('called enterNoFriendsWarning() on parent class')
|
||||
|
||||
def exitNoFriendsWarning(self):
|
||||
self.notify.error('called exitNoFriendsWarning() on parent class')
|
||||
|
||||
def enterActivateChat(self):
|
||||
self.notify.error('called enterActivateChat() on parent class')
|
||||
|
||||
def exitActivateChat(self):
|
||||
self.notify.error('called exitActivateChat() on parent class')
|
||||
|
||||
def enterOtherDialog(self):
|
||||
pass
|
||||
|
||||
def exitOtherDialog(self):
|
||||
pass
|
||||
|
||||
def enterChatMoreInfo(self):
|
||||
if self.chatMoreInfo == None:
|
||||
self.chatMoreInfo = SecretFriendsInfoPanel.SecretFriendsInfoPanel('secretFriendsInfoDone')
|
||||
self.chatMoreInfo.show()
|
||||
self.accept('secretFriendsInfoDone', self.__secretFriendsInfoDone)
|
||||
return
|
||||
|
||||
def exitChatMoreInfo(self):
|
||||
self.chatMoreInfo.hide()
|
||||
self.ignore('secretFriendsInfoDone')
|
||||
|
||||
def enterChatPrivacyPolicy(self):
|
||||
if self.chatPrivacyPolicy == None:
|
||||
self.chatPrivacyPolicy = PrivacyPolicyPanel.PrivacyPolicyPanel('privacyPolicyDone')
|
||||
self.chatPrivacyPolicy.show()
|
||||
self.accept('privacyPolicyDone', self.__privacyPolicyDone)
|
||||
return
|
||||
|
||||
def exitChatPrivacyPolicy(self):
|
||||
cleanupDialog('privacyPolicyDialog')
|
||||
self.chatPrivacyPolicy = None
|
||||
self.ignore('privacyPolicyDone')
|
||||
return
|
||||
|
||||
def enterSecretChatActivated(self):
|
||||
self.notify.error('called enterSecretChatActivated() on parent class')
|
||||
|
||||
def exitSecretChatActivated(self):
|
||||
self.notify.error('called exitSecretChatActivated() on parent class')
|
||||
|
||||
def enterProblemActivatingChat(self):
|
||||
self.notify.error('called enterProblemActivatingChat() on parent class')
|
||||
|
||||
def exitProblemActivatingChat(self):
|
||||
self.notify.error('called exitProblemActivatingChat() on parent class')
|
||||
|
||||
def enterTrueFriendTeaserPanel(self):
|
||||
self.notify.error('called enterTrueFriendTeaserPanel () on parent class')
|
||||
|
||||
def exitTrueFriendTeaserPanel(self):
|
||||
self.notify.error('called exitTrueFriendTeaserPanel () on parent class')
|
||||
|
||||
def __handleLeaveToPayCancel(self):
|
||||
self.fsm.request('mainMenu')
|
||||
|
||||
def __secretFriendsInfoDone(self):
|
||||
self.fsm.request('activateChat')
|
||||
|
||||
def __privacyPolicyDone(self):
|
||||
self.fsm.request('activateChat')
|
704
otp/chat/TalkAssistant.py
Normal file
704
otp/chat/TalkAssistant.py
Normal file
|
@ -0,0 +1,704 @@
|
|||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.showbase import DirectObject
|
||||
from pandac.PandaModules import *
|
||||
import sys
|
||||
import time
|
||||
|
||||
from otp.chat.ChatGlobals import *
|
||||
from otp.chat.TalkGlobals import *
|
||||
from otp.chat.TalkHandle import TalkHandle
|
||||
from otp.chat.TalkMessage import TalkMessage
|
||||
from otp.otpbase import OTPGlobals
|
||||
from otp.otpbase import OTPLocalizer
|
||||
from otp.speedchat import SCDecoders
|
||||
from toontown.chat.ChatGlobals import *
|
||||
from toontown.chat.TTWhiteList import TTWhiteList
|
||||
|
||||
|
||||
ThoughtPrefix = '.'
|
||||
|
||||
|
||||
class TalkAssistant(DirectObject.DirectObject):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('TalkAssistant')
|
||||
|
||||
def __init__(self):
|
||||
self.logWhispers = 1
|
||||
self.whiteList = None
|
||||
self.clearHistory()
|
||||
self.zeroTimeDay = time.time()
|
||||
self.zeroTimeGame = globalClock.getRealTime()
|
||||
self.floodThreshold = 10.0
|
||||
self.useWhiteListFilter = base.config.GetBool('white-list-filter-openchat', 0)
|
||||
self.lastWhisperDoId = None
|
||||
self.lastWhisperPlayerId = None
|
||||
self.lastWhisper = None
|
||||
self.SCDecoder = SCDecoders
|
||||
self.whiteList = TTWhiteList()
|
||||
return
|
||||
|
||||
def clearHistory(self):
|
||||
self.historyComplete = []
|
||||
self.historyOpen = []
|
||||
self.historyUpdates = []
|
||||
self.historyGuild = []
|
||||
self.historyByDoId = {}
|
||||
self.historyByDISLId = {}
|
||||
self.floodDataByDoId = {}
|
||||
self.spamDictByDoId = {}
|
||||
self.labelGuild = OTPLocalizer.TalkGuild
|
||||
self.handleDict = {}
|
||||
self.messageCount = 0
|
||||
self.shownWhiteListWarning = 0
|
||||
|
||||
def delete(self):
|
||||
self.ignoreAll()
|
||||
self.clearHistory()
|
||||
|
||||
def start(self):
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
def countMessage(self):
|
||||
self.messageCount += 1
|
||||
return self.messageCount - 1
|
||||
|
||||
def getOpenText(self, numLines, startPoint = 0):
|
||||
return self.historyOpen[startPoint:startPoint + numLines]
|
||||
|
||||
def getSizeOpenText(self):
|
||||
return len(self.historyOpen)
|
||||
|
||||
def getCompleteText(self, numLines, startPoint = 0):
|
||||
return self.historyComplete[startPoint:startPoint + numLines]
|
||||
|
||||
def getCompleteTextFromRecent(self, numLines, startPoint = 0):
|
||||
start = len(self.historyComplete) - startPoint
|
||||
if start < 0:
|
||||
start = 0
|
||||
backStart = max(start - numLines, 0)
|
||||
text = self.historyComplete[backStart:start]
|
||||
text.reverse()
|
||||
return text
|
||||
|
||||
def getAllCompleteText(self):
|
||||
return self.historyComplete
|
||||
|
||||
def getAllHistory(self):
|
||||
return self.historyComplete
|
||||
|
||||
def getSizeCompleteText(self):
|
||||
return len(self.historyComplete)
|
||||
|
||||
def getHandle(self, doId):
|
||||
return self.handleDict.get(doId)
|
||||
|
||||
def doWhiteListWarning(self):
|
||||
pass
|
||||
|
||||
def addToHistoryDoId(self, message, doId, scrubbed = 0):
|
||||
if message.getTalkType() == TALK_WHISPER and doId != localAvatar.doId:
|
||||
self.lastWhisperDoId = doId
|
||||
self.lastWhisper = self.lastWhisperDoId
|
||||
if doId not in self.historyByDoId:
|
||||
self.historyByDoId[doId] = []
|
||||
self.historyByDoId[doId].append(message)
|
||||
if not self.shownWhiteListWarning and scrubbed and doId == localAvatar.doId:
|
||||
self.doWhiteListWarning()
|
||||
self.shownWhiteListWarning = 1
|
||||
if doId not in self.floodDataByDoId:
|
||||
self.floodDataByDoId[doId] = [0.0, self.stampTime(), message]
|
||||
else:
|
||||
oldTime = self.floodDataByDoId[doId][1]
|
||||
newTime = self.stampTime()
|
||||
timeDiff = newTime - oldTime
|
||||
oldRating = self.floodDataByDoId[doId][0]
|
||||
contentMult = 1.0
|
||||
if len(message.getBody()) < 6:
|
||||
contentMult += 0.2 * float(6 - len(message.getBody()))
|
||||
if self.floodDataByDoId[doId][2].getBody() == message.getBody():
|
||||
contentMult += 1.0
|
||||
floodRating = max(0, 3.0 * contentMult + oldRating - timeDiff)
|
||||
self.floodDataByDoId[doId] = [floodRating, self.stampTime(), message]
|
||||
if floodRating > self.floodThreshold:
|
||||
if oldRating < self.floodThreshold:
|
||||
self.floodDataByDoId[doId] = [floodRating + 3.0, self.stampTime(), message]
|
||||
return 1
|
||||
else:
|
||||
self.floodDataByDoId[doId] = [oldRating - timeDiff, self.stampTime(), message]
|
||||
return 2
|
||||
return 0
|
||||
|
||||
def addToHistoryDISLId(self, message, dISLId, scrubbed = 0):
|
||||
if message.getTalkType() == TALK_ACCOUNT:
|
||||
self.lastWhisperPlayerId = dISLId
|
||||
self.lastWhisper = self.lastWhisperPlayerId
|
||||
if dISLId not in self.historyByDISLId:
|
||||
self.historyByDISLId[dISLId] = []
|
||||
self.historyByDISLId[dISLId].append(message)
|
||||
|
||||
def addHandle(self, doId, message):
|
||||
if doId == localAvatar.doId:
|
||||
return
|
||||
handle = self.handleDict.get(doId)
|
||||
if not handle:
|
||||
handle = TalkHandle(doId, message)
|
||||
self.handleDict[doId] = handle
|
||||
else:
|
||||
handle.addMessageInfo(message)
|
||||
|
||||
def stampTime(self):
|
||||
return globalClock.getRealTime() - self.zeroTimeGame
|
||||
|
||||
def findName(self, id, isPlayer = 0):
|
||||
if isPlayer:
|
||||
return self.findPlayerName(id)
|
||||
else:
|
||||
return self.findAvatarName(id)
|
||||
|
||||
def findAvatarName(self, id):
|
||||
info = base.cr.identifyAvatar(id)
|
||||
if info:
|
||||
return info.getName()
|
||||
else:
|
||||
return ''
|
||||
|
||||
def findPlayerName(self, id):
|
||||
info = base.cr.playerFriendsManager.getFriendInfo(id)
|
||||
if info:
|
||||
return info.playerName
|
||||
else:
|
||||
return ''
|
||||
|
||||
def whiteListFilterMessage(self, text):
|
||||
if not self.useWhiteListFilter:
|
||||
return text
|
||||
elif not base.whiteList:
|
||||
return 'no list'
|
||||
words = text.split(' ')
|
||||
newwords = []
|
||||
for word in words:
|
||||
if word == '' or base.whiteList.isWord(word):
|
||||
newwords.append(word)
|
||||
else:
|
||||
newwords.append(base.whiteList.defaultWord)
|
||||
|
||||
newText = ' '.join(newwords)
|
||||
return newText
|
||||
|
||||
def colorMessageByWhiteListFilter(self, text):
|
||||
if not base.whiteList:
|
||||
return text
|
||||
words = text.split(' ')
|
||||
newwords = []
|
||||
for word in words:
|
||||
if word == '' or base.whiteList.isWord(word):
|
||||
newwords.append(word)
|
||||
else:
|
||||
newwords.append('\x01WLRed\x01' + word + '\x02')
|
||||
|
||||
newText = ' '.join(newwords)
|
||||
return newText
|
||||
|
||||
def isThought(self, message):
|
||||
if not message:
|
||||
return 0
|
||||
elif len(message) == 0:
|
||||
return 0
|
||||
elif message.find(ThoughtPrefix, 0, len(ThoughtPrefix)) >= 0:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def removeThoughtPrefix(self, message):
|
||||
if self.isThought(message):
|
||||
return message[len(ThoughtPrefix):]
|
||||
else:
|
||||
return message
|
||||
|
||||
def fillWithTestText(self):
|
||||
hold = self.floodThreshold
|
||||
self.floodThreshold = 1000.0
|
||||
self.receiveOpenTalk(1001, 'Bob the Ghost', None, None, 'Hello from the machine')
|
||||
self.receiveOpenTalk(1001, 'Bob the Ghost', None, None, 'More text for ya!')
|
||||
self.receiveOpenTalk(1001, 'Bob the Ghost', None, None, 'Hope this makes life easier')
|
||||
self.receiveOpenTalk(1002, 'Doug the Spirit', None, None, 'Now we need some longer text that will spill over onto two lines')
|
||||
self.receiveOpenTalk(1002, 'Doug the Spirit', None, None, 'Maybe I will tell you')
|
||||
self.receiveOpenTalk(1001, 'Bob the Ghost', None, None, 'If you are seeing this text it is because you are cool')
|
||||
self.receiveOpenTalk(1002, 'Doug the Spirit', None, None, "That's right, there is no need to call tech support")
|
||||
self.receiveOpenTalk(localAvatar.doId, localAvatar.getName, None, None, "Okay I won't call tech support, because I am cool")
|
||||
self.receiveGMTalk(1003, 'God of Text', None, None, 'Good because I have seen it already')
|
||||
self.floodThreshold = hold
|
||||
return
|
||||
|
||||
def printHistoryComplete(self):
|
||||
print 'HISTORY COMPLETE'
|
||||
for message in self.historyComplete:
|
||||
print '%s %s %s\n%s\n' % (message.getTimeStamp(),
|
||||
message.getSenderAvatarName(),
|
||||
message.getSenderAccountName(),
|
||||
message.getBody())
|
||||
|
||||
def checkOpenTypedChat(self):
|
||||
if base.localAvatar.commonChatFlags & OTPGlobals.CommonChat:
|
||||
return True
|
||||
return False
|
||||
|
||||
def checkAnyTypedChat(self):
|
||||
if base.localAvatar.commonChatFlags & OTPGlobals.CommonChat:
|
||||
return True
|
||||
if base.localAvatar.canChat():
|
||||
return True
|
||||
return False
|
||||
|
||||
def checkOpenSpeedChat(self):
|
||||
return True
|
||||
|
||||
def checkWhisperTypedChatAvatar(self, avatarId):
|
||||
remoteAvatar = base.cr.doId2do.get(avatarId)
|
||||
if remoteAvatar:
|
||||
if remoteAvatar.isUnderstandable():
|
||||
return True
|
||||
if base.localAvatar.commonChatFlags & OTPGlobals.SuperChat:
|
||||
return True
|
||||
remoteAvatarOrHandleOrInfo = base.cr.identifyAvatar(avatarId)
|
||||
if remoteAvatarOrHandleOrInfo and hasattr(remoteAvatarOrHandleOrInfo, 'isUnderstandable'):
|
||||
if remoteAvatarOrHandleOrInfo.isUnderstandable():
|
||||
return True
|
||||
info = base.cr.playerFriendsManager.findPlayerInfoFromAvId(avatarId)
|
||||
if info:
|
||||
if info.understandableYesNo:
|
||||
return True
|
||||
info = base.cr.avatarFriendsManager.getFriendInfo(avatarId)
|
||||
if info:
|
||||
if info.understandableYesNo:
|
||||
return True
|
||||
if base.cr.getFriendFlags(avatarId) & OTPGlobals.FriendChat:
|
||||
return True
|
||||
return False
|
||||
|
||||
def checkWhisperSpeedChatAvatar(self, avatarId):
|
||||
return True
|
||||
|
||||
def checkWhisperTypedChatPlayer(self, playerId):
|
||||
info = base.cr.playerFriendsManager.getFriendInfo(playerId)
|
||||
if info:
|
||||
if info.understandableYesNo:
|
||||
return True
|
||||
return False
|
||||
|
||||
def checkWhisperSpeedChatPlayer(self, playerId):
|
||||
if base.cr.playerFriendsManager.isPlayerFriend(playerId):
|
||||
return True
|
||||
return False
|
||||
|
||||
def checkOpenSpeedChat(self):
|
||||
return True
|
||||
|
||||
def checkWhisperSpeedChatAvatar(self, avatarId):
|
||||
return True
|
||||
|
||||
def checkWhisperSpeedChatPlayer(self, playerId):
|
||||
if base.cr.playerFriendsManager.isPlayerFriend(playerId):
|
||||
return True
|
||||
return False
|
||||
|
||||
def checkGuildTypedChat(self):
|
||||
if localAvatar.guildId:
|
||||
return True
|
||||
return False
|
||||
|
||||
def checkGuildSpeedChat(self):
|
||||
if localAvatar.guildId:
|
||||
return True
|
||||
return False
|
||||
|
||||
def receiveOpenTalk(self, senderAvId, avatarName, accountId, accountName, message, scrubbed = 0):
|
||||
error = None
|
||||
if not avatarName and senderAvId:
|
||||
localAvatar.sendUpdate('logSuspiciousEvent', ['receiveOpenTalk: invalid avatar name (%s)' % senderAvId])
|
||||
avatarName = self.findAvatarName(senderAvId)
|
||||
if not accountName and accountId:
|
||||
accountName = self.findPlayerName(accountId)
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, senderAvId, avatarName, accountId, accountName, None, None, None, None, TALK_OPEN, None)
|
||||
if senderAvId != localAvatar.doId:
|
||||
self.addHandle(senderAvId, newMessage)
|
||||
reject = 0
|
||||
if senderAvId:
|
||||
reject = self.addToHistoryDoId(newMessage, senderAvId, scrubbed)
|
||||
if accountId:
|
||||
self.addToHistoryDISLId(newMessage, accountId)
|
||||
if reject == 1:
|
||||
newMessage.setBody(OTPLocalizer.AntiSpamInChat)
|
||||
if reject != 2:
|
||||
isSpam = self.spamDictByDoId.get(senderAvId) and reject
|
||||
if not isSpam:
|
||||
self.historyComplete.append(newMessage)
|
||||
self.historyOpen.append(newMessage)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
if newMessage.getBody() == OTPLocalizer.AntiSpamInChat:
|
||||
self.spamDictByDoId[senderAvId] = 1
|
||||
else:
|
||||
self.spamDictByDoId[senderAvId] = 0
|
||||
return error
|
||||
|
||||
def receiveWhisperTalk(self, avatarId, avatarName, accountId, accountName, toId, toName, message, scrubbed = 0):
|
||||
error = None
|
||||
if not avatarName and avatarId:
|
||||
avatarName = self.findAvatarName(avatarId)
|
||||
if not accountName and accountId:
|
||||
accountName = self.findPlayerName(accountId)
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, avatarId, avatarName, accountId, accountName, toId, toName, None, None, TALK_WHISPER, None)
|
||||
if avatarId == localAvatar.doId:
|
||||
self.addHandle(toId, newMessage)
|
||||
else:
|
||||
self.addHandle(avatarId, newMessage)
|
||||
self.historyComplete.append(newMessage)
|
||||
if avatarId:
|
||||
self.addToHistoryDoId(newMessage, avatarId, scrubbed)
|
||||
if accountId:
|
||||
self.addToHistoryDISLId(newMessage, accountId)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return error
|
||||
|
||||
def receiveAccountTalk(self, avatarId, avatarName, accountId, accountName, toId, toName, message, scrubbed = 0):
|
||||
if not accountName and base.cr.playerFriendsManager.playerId2Info.get(accountId):
|
||||
accountName = base.cr.playerFriendsManager.playerId2Info.get(accountId).playerName
|
||||
error = None
|
||||
if not avatarName and avatarId:
|
||||
avatarName = self.findAvatarName(avatarId)
|
||||
if not accountName and accountId:
|
||||
accountName = self.findPlayerName(accountId)
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, avatarId, avatarName, accountId, accountName, None, None, toId, toName, TALK_ACCOUNT, None)
|
||||
self.historyComplete.append(newMessage)
|
||||
if avatarId:
|
||||
self.addToHistoryDoId(newMessage, avatarId, scrubbed)
|
||||
if accountId:
|
||||
self.addToHistoryDISLId(newMessage, accountId, scrubbed)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return error
|
||||
|
||||
def receiveGuildTalk(self, senderAvId, fromAC, avatarName, message, scrubbed = 0):
|
||||
error = None
|
||||
if not self.isThought(message):
|
||||
accountName = self.findName(fromAC, 1)
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, senderAvId, avatarName, fromAC, accountName, None, None, None, None, TALK_GUILD, None)
|
||||
reject = self.addToHistoryDoId(newMessage, senderAvId)
|
||||
if reject == 1:
|
||||
newMessage.setBody(OTPLocalizer.AntiSpamInChat)
|
||||
if reject != 2:
|
||||
isSpam = self.spamDictByDoId.get(senderAvId) and reject
|
||||
if not isSpam:
|
||||
self.historyComplete.append(newMessage)
|
||||
self.historyGuild.append(newMessage)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
if newMessage.getBody() == OTPLocalizer.AntiSpamInChat:
|
||||
self.spamDictByDoId[senderAvId] = 1
|
||||
else:
|
||||
self.spamDictByDoId[senderAvId] = 0
|
||||
return error
|
||||
|
||||
def receiveGMTalk(self, avatarId, avatarName, accountId, accountName, message, scrubbed = 0):
|
||||
error = None
|
||||
if not avatarName and avatarId:
|
||||
avatarName = self.findAvatarName(avatarId)
|
||||
if not accountName and accountId:
|
||||
accountName = self.findPlayerName(accountId)
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, avatarId, avatarName, accountId, accountName, None, None, None, None, TALK_GM, None)
|
||||
self.historyComplete.append(newMessage)
|
||||
self.historyOpen.append(newMessage)
|
||||
if avatarId:
|
||||
self.addToHistoryDoId(newMessage, avatarId)
|
||||
if accountId:
|
||||
self.addToHistoryDISLId(newMessage, accountId)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return error
|
||||
|
||||
def receiveThought(self, avatarId, avatarName, accountId, accountName, message, scrubbed = 0):
|
||||
error = None
|
||||
if not avatarName and avatarId:
|
||||
avatarName = self.findAvatarName(avatarId)
|
||||
if not accountName and accountId:
|
||||
accountName = self.findPlayerName(accountId)
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, avatarId, avatarName, accountId, accountName, None, None, None, None, AVATAR_THOUGHT, None)
|
||||
if avatarId != localAvatar.doId:
|
||||
self.addHandle(avatarId, newMessage)
|
||||
reject = 0
|
||||
if avatarId:
|
||||
reject = self.addToHistoryDoId(newMessage, avatarId, scrubbed)
|
||||
if accountId:
|
||||
self.addToHistoryDISLId(newMessage, accountId)
|
||||
if reject == 1:
|
||||
newMessage.setBody(OTPLocalizer.AntiSpamInChat)
|
||||
if reject != 2:
|
||||
self.historyComplete.append(newMessage)
|
||||
self.historyOpen.append(newMessage)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return error
|
||||
|
||||
def receiveGameMessage(self, message):
|
||||
error = None
|
||||
if not self.isThought(message):
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, None, None, None, None, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, INFO_GAME, None)
|
||||
self.historyComplete.append(newMessage)
|
||||
self.historyUpdates.append(newMessage)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return error
|
||||
|
||||
def receiveSystemMessage(self, message):
|
||||
error = None
|
||||
if not self.isThought(message):
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, None, None, None, None, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, INFO_SYSTEM, None)
|
||||
self.historyComplete.append(newMessage)
|
||||
self.historyUpdates.append(newMessage)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return error
|
||||
|
||||
def receiveDeveloperMessage(self, message):
|
||||
error = None
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, None, None, None, None, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, INFO_DEV, None)
|
||||
self.historyComplete.append(newMessage)
|
||||
self.historyUpdates.append(newMessage)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return error
|
||||
|
||||
def receiveGuildMessage(self, message, senderAvId, senderName):
|
||||
error = None
|
||||
if not self.isThought(message):
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, senderAvId, senderName, None, None, None, None, None, None, TALK_GUILD, None)
|
||||
self.historyComplete.append(newMessage)
|
||||
self.historyGuild.append(newMessage)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return error
|
||||
|
||||
def receiveGuildUpdateMessage(self, message, senderId, senderName, receiverId, receiverName, extraInfo = None):
|
||||
error = None
|
||||
if not self.isThought(message):
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, senderId, senderName, None, None, receiverId, receiverName, None, None, INFO_GUILD, extraInfo)
|
||||
self.historyComplete.append(newMessage)
|
||||
self.historyGuild.append(newMessage)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return error
|
||||
|
||||
def receiveFriendUpdate(self, friendId, friendName, isOnline):
|
||||
if isOnline:
|
||||
onlineMessage = OTPLocalizer.FriendOnline
|
||||
else:
|
||||
onlineMessage = OTPLocalizer.FriendOffline
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), onlineMessage, friendId, friendName, None, None, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, UPDATE_FRIEND, None)
|
||||
self.addHandle(friendId, newMessage)
|
||||
self.historyComplete.append(newMessage)
|
||||
self.historyUpdates.append(newMessage)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return
|
||||
|
||||
def receiveFriendAccountUpdate(self, friendId, friendName, isOnline):
|
||||
if isOnline:
|
||||
onlineMessage = OTPLocalizer.FriendOnline
|
||||
else:
|
||||
onlineMessage = OTPLocalizer.FriendOffline
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), onlineMessage, None, None, friendId, friendName, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, UPDATE_FRIEND, None)
|
||||
self.historyComplete.append(newMessage)
|
||||
self.historyUpdates.append(newMessage)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return
|
||||
|
||||
def receiveGuildUpdate(self, memberId, memberName, isOnline):
|
||||
if base.cr.identifyFriend(memberId) is None:
|
||||
if isOnline:
|
||||
onlineMessage = OTPLocalizer.GuildMemberOnline
|
||||
else:
|
||||
onlineMessage = OTPLocalizer.GuildMemberOffline
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), onlineMessage, memberId, memberName, None, None, None, None, None, None, UPDATE_GUILD, None)
|
||||
self.addHandle(memberId, newMessage)
|
||||
self.historyComplete.append(newMessage)
|
||||
self.historyUpdates.append(newMessage)
|
||||
self.historyGuild.append(newMessage)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return
|
||||
|
||||
def receiveOpenSpeedChat(self, type, messageIndex, senderAvId, name = None):
|
||||
error = None
|
||||
if not name and senderAvId:
|
||||
name = self.findName(senderAvId, 0)
|
||||
if type == SPEEDCHAT_NORMAL:
|
||||
message = self.SCDecoder.decodeSCStaticTextMsg(messageIndex)
|
||||
elif type == SPEEDCHAT_EMOTE:
|
||||
message = self.SCDecoder.decodeSCEmoteWhisperMsg(messageIndex, name)
|
||||
elif type == SPEEDCHAT_CUSTOM:
|
||||
message = self.SCDecoder.decodeSCCustomMsg(messageIndex)
|
||||
if message in (None, ''):
|
||||
return
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, senderAvId, name, None, None, None, None, None, None, TALK_OPEN, None)
|
||||
self.historyComplete.append(newMessage)
|
||||
self.historyOpen.append(newMessage)
|
||||
self.addToHistoryDoId(newMessage, senderAvId)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return error
|
||||
|
||||
def receiveAvatarWhisperSpeedChat(self, type, messageIndex, senderAvId, name = None):
|
||||
error = None
|
||||
if not name and senderAvId:
|
||||
name = self.findName(senderAvId, 0)
|
||||
if type == SPEEDCHAT_NORMAL:
|
||||
message = self.SCDecoder.decodeSCStaticTextMsg(messageIndex)
|
||||
elif type == SPEEDCHAT_EMOTE:
|
||||
message = self.SCDecoder.decodeSCEmoteWhisperMsg(messageIndex, name)
|
||||
elif type == SPEEDCHAT_CUSTOM:
|
||||
message = self.SCDecoder.decodeSCCustomMsg(messageIndex)
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, senderAvId, name, None, None, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, TALK_WHISPER, None)
|
||||
self.historyComplete.append(newMessage)
|
||||
self.historyOpen.append(newMessage)
|
||||
self.addToHistoryDoId(newMessage, senderAvId)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return error
|
||||
|
||||
def receivePlayerWhisperSpeedChat(self, type, messageIndex, senderAvId, name = None):
|
||||
error = None
|
||||
if not name and senderAvId:
|
||||
name = self.findName(senderAvId, 1)
|
||||
if type == SPEEDCHAT_NORMAL:
|
||||
message = self.SCDecoder.decodeSCStaticTextMsg(messageIndex)
|
||||
elif type == SPEEDCHAT_EMOTE:
|
||||
message = self.SCDecoder.decodeSCEmoteWhisperMsg(messageIndex, name)
|
||||
elif type == SPEEDCHAT_CUSTOM:
|
||||
message = self.SCDecoder.decodeSCCustomMsg(messageIndex)
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, None, None, senderAvId, name, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, TALK_WHISPER, None)
|
||||
self.historyComplete.append(newMessage)
|
||||
self.historyOpen.append(newMessage)
|
||||
self.addToHistoryDISLId(newMessage, senderAvId)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return error
|
||||
|
||||
def sendOpenTalk(self, message):
|
||||
error = None
|
||||
doId = base.localAvatar.doId
|
||||
if base.config.GetBool('want-talkative-tyler', False):
|
||||
if base.localAvatar.zoneId == 2000:
|
||||
tyler = base.cr.doFind('Talkative Tyler')
|
||||
if tyler:
|
||||
tyler.sendUpdate('talkMessage', [doId, message])
|
||||
if base.cr.wantMagicWords and len(message) > 0 and message[0] == '~':
|
||||
messenger.send('magicWord', [message])
|
||||
self.receiveDeveloperMessage(message)
|
||||
else:
|
||||
chatFlags = CFSpeech | CFTimeout
|
||||
if self.isThought(message):
|
||||
chatFlags = CFThought
|
||||
base.cr.chatAgent.sendChatMessage(message)
|
||||
messenger.send('chatUpdate', [message, chatFlags])
|
||||
return error
|
||||
|
||||
def sendWhisperTalk(self, message, receiverAvId):
|
||||
modifications = []
|
||||
words = message.split(' ')
|
||||
offset = 0
|
||||
WantWhitelist = config.GetBool('want-whitelist', 1)
|
||||
for word in words:
|
||||
if word and not self.whiteList.isWord(word) and WantWhitelist:
|
||||
modifications.append((offset, offset+len(word)-1))
|
||||
offset += len(word) + 1
|
||||
|
||||
cleanMessage = message
|
||||
for modStart, modStop in modifications:
|
||||
cleanMessage = cleanMessage[:modStart] + '*'*(modStop-modStart+1) + cleanMessage[modStop+1:]
|
||||
|
||||
message, scrubbed = base.localAvatar.scrubTalk(cleanMessage, modifications)
|
||||
|
||||
base.cr.ttuFriendsManager.sendUpdate('sendTalkWhisper', [receiverAvId, message])
|
||||
|
||||
def sendAccountTalk(self, message, receiverAccount):
|
||||
error = None
|
||||
base.cr.playerFriendsManager.sendUpdate('setTalkAccount', [receiverAccount,
|
||||
0,
|
||||
'',
|
||||
message,
|
||||
[],
|
||||
0])
|
||||
return error
|
||||
|
||||
def sendGuildTalk(self, message):
|
||||
error = None
|
||||
if self.checkGuildTypedChat():
|
||||
base.cr.guildManager.sendTalk(message)
|
||||
else:
|
||||
print 'Guild chat error'
|
||||
error = ERROR_NO_GUILD_CHAT
|
||||
return error
|
||||
|
||||
def sendOpenSpeedChat(self, type, messageIndex):
|
||||
error = None
|
||||
if type == SPEEDCHAT_NORMAL:
|
||||
messenger.send(SCChatEvent)
|
||||
messenger.send('chatUpdateSC', [messageIndex])
|
||||
base.localAvatar.b_setSC(messageIndex)
|
||||
elif type == SPEEDCHAT_EMOTE:
|
||||
messenger.send('chatUpdateSCEmote', [messageIndex])
|
||||
messenger.send(SCEmoteChatEvent)
|
||||
base.localAvatar.b_setSCEmote(messageIndex)
|
||||
elif type == SPEEDCHAT_CUSTOM:
|
||||
messenger.send('chatUpdateSCCustom', [messageIndex])
|
||||
messenger.send(SCCustomChatEvent)
|
||||
base.localAvatar.b_setSCCustom(messageIndex)
|
||||
return error
|
||||
|
||||
def sendAvatarWhisperSpeedChat(self, type, messageIndex, receiverId):
|
||||
error = None
|
||||
if type == SPEEDCHAT_NORMAL:
|
||||
base.localAvatar.whisperSCTo(messageIndex, receiverId, 0)
|
||||
message = self.SCDecoder.decodeSCStaticTextMsg(messageIndex)
|
||||
elif type == SPEEDCHAT_EMOTE:
|
||||
base.localAvatar.whisperSCEmoteTo(messageIndex, receiverId, 0)
|
||||
message = self.SCDecoder.decodeSCEmoteWhisperMsg(messageIndex, localAvatar.getName())
|
||||
elif type == SPEEDCHAT_CUSTOM:
|
||||
base.localAvatar.whisperSCCustomTo(messageIndex, receiverId, 0)
|
||||
message = self.SCDecoder.decodeSCCustomMsg(messageIndex)
|
||||
if self.logWhispers:
|
||||
avatarName = None
|
||||
accountId = None
|
||||
avatar = base.cr.identifyAvatar(receiverId)
|
||||
if avatar:
|
||||
avatarName = avatar.getName()
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, receiverId, avatarName, None, None, TALK_WHISPER, None)
|
||||
self.historyComplete.append(newMessage)
|
||||
self.addToHistoryDoId(newMessage, localAvatar.doId)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return error
|
||||
|
||||
def sendPlayerWhisperSpeedChat(self, type, messageIndex, receiverId):
|
||||
error = None
|
||||
if type == SPEEDCHAT_NORMAL:
|
||||
base.cr.speedchatRelay.sendSpeedchat(receiverId, messageIndex)
|
||||
message = self.SCDecoder.decodeSCStaticTextMsg(messageIndex)
|
||||
elif type == SPEEDCHAT_EMOTE:
|
||||
base.cr.speedchatRelay.sendSpeedchatEmote(receiverId, messageIndex)
|
||||
message = self.SCDecoder.decodeSCEmoteWhisperMsg(messageIndex, localAvatar.getName())
|
||||
return
|
||||
elif type == SPEEDCHAT_CUSTOM:
|
||||
base.cr.speedchatRelay.sendSpeedchatCustom(receiverId, messageIndex)
|
||||
message = self.SCDecoder.decodeSCCustomMsg(messageIndex)
|
||||
if self.logWhispers:
|
||||
receiverName = self.findName(receiverId, 1)
|
||||
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, None, None, receiverId, receiverName, TALK_ACCOUNT, None)
|
||||
self.historyComplete.append(newMessage)
|
||||
self.addToHistoryDoId(newMessage, localAvatar.doId)
|
||||
messenger.send('NewOpenMessage', [newMessage])
|
||||
return error
|
||||
|
||||
def sendGuildSpeedChat(self, type, msgIndex):
|
||||
error = None
|
||||
if self.checkGuildSpeedChat():
|
||||
base.cr.guildManager.sendSC(msgIndex)
|
||||
else:
|
||||
print 'Guild Speedchat error'
|
||||
error = ERROR_NO_GUILD_CHAT
|
||||
return error
|
||||
|
||||
def getWhisperReplyId(self):
|
||||
if self.lastWhisper:
|
||||
toPlayer = 0
|
||||
if self.lastWhisper == self.lastWhisperPlayerId:
|
||||
toPlayer = 1
|
||||
return (self.lastWhisper, toPlayer)
|
||||
return (0, 0)
|
19
otp/chat/TalkGlobals.py
Normal file
19
otp/chat/TalkGlobals.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
TALK_NONE = 0
|
||||
TALK_OPEN = 1
|
||||
TALK_WHISPER = 2
|
||||
TALK_ACCOUNT = 13
|
||||
TALK_GM = 14
|
||||
AVATAR_THOUGHT = 16
|
||||
TALK_GUILD = 3
|
||||
TALK_PARTY = 4
|
||||
TALK_PVP = 5
|
||||
UPDATE_GUILD = 6
|
||||
UPDATE_FRIEND = 7
|
||||
UPDATE_PARTY = 8
|
||||
UPDATE_PVP = 9
|
||||
INFO_SYSTEM = 10
|
||||
INFO_GAME = 11
|
||||
INFO_AVATAR_UNAVAILABLE = 12
|
||||
INFO_OPEN = 15
|
||||
INFO_DEV = 17
|
||||
INFO_GUILD = 18
|
41
otp/chat/TalkHandle.py
Normal file
41
otp/chat/TalkHandle.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
from otp.avatar.AvatarHandle import AvatarHandle
|
||||
|
||||
class TalkHandle(AvatarHandle):
|
||||
|
||||
def __init__(self, doId, message):
|
||||
self.avatarId = doId
|
||||
self.avatarName = None
|
||||
self.accountId = None
|
||||
self.accountName = None
|
||||
self.addMessageInfo(message)
|
||||
return
|
||||
|
||||
def getName(self):
|
||||
return self.avatarName
|
||||
|
||||
def isUnderstandable(self):
|
||||
return False
|
||||
|
||||
def isOnline(self):
|
||||
return False
|
||||
|
||||
def addMessageInfo(self, message):
|
||||
if self.avatarId == message.getSenderAvatarId():
|
||||
if not self.avatarName and message.getSenderAvatarName():
|
||||
self.avatarName = message.getSenderAvatarName()
|
||||
if not self.accountId and message.getSenderAccountId():
|
||||
self.accountId = message.getSenderAccountId()
|
||||
if not self.accountName and message.getSenderAccountName():
|
||||
self.accountName = message.getSenderAccountName()
|
||||
elif self.avatarId == message.getReceiverAvatarId():
|
||||
if not self.avatarName and message.getReceiverAvatarName():
|
||||
self.avatarName = message.getReceiverAvatarName()
|
||||
if not self.accountId and message.getReceiverAccountId():
|
||||
self.accountId = message.getReceiverAccountId()
|
||||
if not self.accountName and message.getReceiverAccountName():
|
||||
self.accountName = message.getReceiverAccountName()
|
||||
|
||||
def setTalkWhisper(self, fromAV, fromAC, avatarName, chat, mods, flags):
|
||||
newText, scrubbed = localAvatar.scrubTalk(chat, mods)
|
||||
base.talkAssistant.receiveWhisperTalk(fromAV, avatarName, fromAC, None, self.avatarId, self.getName(), newText, scrubbed)
|
||||
return
|
93
otp/chat/TalkMessage.py
Normal file
93
otp/chat/TalkMessage.py
Normal file
|
@ -0,0 +1,93 @@
|
|||
class TalkMessage:
|
||||
def __init__(self, messageId, timeStamp, body, senderAvatarId, senderAvatarName, senderAccountId, senderAccountName, receiverAvatarId, receiverAvatarName, receiverAccountId, receiverAccountName, talkType, extraInfo = None):
|
||||
self.timeStamp = timeStamp
|
||||
self.body = body
|
||||
self.senderAvatarId = senderAvatarId
|
||||
self.senderAvatarName = senderAvatarName
|
||||
self.senderAccountId = senderAccountId
|
||||
self.senderAccountName = senderAccountName
|
||||
self.receiverAvatarId = receiverAvatarId
|
||||
self.receiverAvatarName = receiverAvatarName
|
||||
self.receiverAccountId = receiverAccountId
|
||||
self.receiverAccountName = receiverAccountName
|
||||
self.talkType = talkType
|
||||
self.extraInfo = extraInfo
|
||||
self.messageId = messageId
|
||||
|
||||
def getMessageId(self):
|
||||
return self.messageId
|
||||
|
||||
def setMessageId(self, id):
|
||||
self.messageId = id
|
||||
|
||||
def getTimeStamp(self):
|
||||
return self.timeStamp
|
||||
|
||||
def setTimeStamp(self, timeStamp):
|
||||
self.timeStamp = timeStamp
|
||||
|
||||
def getBody(self):
|
||||
return self.body
|
||||
|
||||
def setBody(self, body):
|
||||
self.body = body
|
||||
|
||||
def getSenderAvatarId(self):
|
||||
return self.senderAvatarId
|
||||
|
||||
def setSenderAvatarId(self, senderAvatarId):
|
||||
self.senderAvatarId = senderAvatarId
|
||||
|
||||
def getSenderAvatarName(self):
|
||||
return self.senderAvatarName
|
||||
|
||||
def setSenderAvatarName(self, senderAvatarName):
|
||||
self.senderAvatarName = senderAvatarName
|
||||
|
||||
def getSenderAccountId(self):
|
||||
return self.senderAccountId
|
||||
|
||||
def setSenderAccountId(self, senderAccountId):
|
||||
self.senderAccountId = senderAccountId
|
||||
|
||||
def getSenderAccountName(self):
|
||||
return self.senderAccountName
|
||||
|
||||
def setSenderAccountName(self, senderAccountName):
|
||||
self.senderAccountName = senderAccountName
|
||||
|
||||
def getReceiverAvatarId(self):
|
||||
return self.receiverAvatarId
|
||||
|
||||
def setReceiverAvatarId(self, receiverAvatarId):
|
||||
self.receiverAvatarId = receiverAvatarId
|
||||
|
||||
def getReceiverAvatarName(self):
|
||||
return self.receiverAvatarName
|
||||
|
||||
def setReceiverAvatarName(self, receiverAvatarName):
|
||||
self.receiverAvatarName = receiverAvatarName
|
||||
|
||||
def getReceiverAccountId(self):
|
||||
return self.receiverAccountId
|
||||
|
||||
def setReceiverAccountId(self, receiverAccountId):
|
||||
self.receiverAccountId = receiverAccountId
|
||||
|
||||
def getReceiverAccountName(self):
|
||||
return self.receiverAccountName
|
||||
|
||||
def setReceiverAccountName(self, receiverAccountName):
|
||||
self.receiverAccountName = receiverAccountName
|
||||
|
||||
def getTalkType(self):
|
||||
return self.talkType
|
||||
|
||||
def setTalkType(self, talkType):
|
||||
self.talkType = talkType
|
||||
|
||||
def getExtraInfo(self):
|
||||
return self.extraInfo
|
||||
|
||||
def setExtraInfo(self, extraInfo):
|
||||
self.extraInfo = extraInfo
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue