Initial commit

This commit is contained in:
Loudrob 2015-03-03 17:10:12 -05:00
commit 02c7dc11e4
3305 changed files with 1122482 additions and 0 deletions

26
.gitignore vendored Normal file
View 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
View file

@ -0,0 +1 @@
"panda/python/ppython.exe"

12
README.md Normal file
View 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
View file

@ -0,0 +1,4 @@
astrond
astrond_debug
astrond.exe
astrond_debug.exe

BIN
astron/astrondlinux Normal file

Binary file not shown.

BIN
astron/astrondmac Normal file

Binary file not shown.

BIN
astron/astrondprod Normal file

Binary file not shown.

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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
View 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

View 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

View 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

View 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

View file

@ -0,0 +1,3 @@
#!/bin/sh
cd ..
./astrond --loglevel info config/cluster.yml

View 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
View file

@ -0,0 +1 @@
*.db

2
astron/databases/astrondb/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

497
astron/dclass/otp.dc Normal file
View 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

File diff suppressed because it is too large Load diff

BIN
astron/libeay32.dll Normal file

Binary file not shown.

View 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

View file

@ -0,0 +1,3 @@
#!/bin/sh
cd ..
./astrond --loglevel info config/cluster.yml

View 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

Binary file not shown.

BIN
astron/msvcr120.dll Normal file

Binary file not shown.

BIN
astron/ssleay32.dll Normal file

Binary file not shown.

View 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
View 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

View file

@ -0,0 +1,2 @@
want-christmas #t
active-holidays 4, 57

View file

@ -0,0 +1,2 @@
want-halloween #t
active-holidays 26, 27, 13

42
config/release/dev.prc Normal file
View 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
View file

@ -0,0 +1,2 @@
# Distribution:
distribution en

29
config/release/test.prc Normal file
View 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

View 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

View 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
View 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
View file

@ -0,0 +1,8 @@
unlimitedcipher
unlimitedcipher.exe
unlimited
unlimited.exe
upx.exe
src
build
dist

View 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
View 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
View 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)

View 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

View 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

View 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

View 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)

View 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)
{
}
};

View 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```

View 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 _(")_.

View 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

View 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
View 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
View file

179
otp/ai/AIBase.py Normal file
View 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
View 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()

View 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
View 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
View 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
View 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
View 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)

View 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
View 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

View 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))

View 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
View 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
View 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
View file

664
otp/avatar/Avatar.py Normal file
View 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
View 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

View 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

View 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
View 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

View 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)

View 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)

View 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

View 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

View 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
View 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

File diff suppressed because it is too large Load diff

18
otp/avatar/PlayerBase.py Normal file
View 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

View 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
View 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
View file

20
otp/chat/ChatAgent.py Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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)

View 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
View 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
View 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
View 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
View 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
View 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