mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-12-23 11:42:39 -06:00
parent
b5c8ba3fcb
commit
c8f5d19c11
9 changed files with 33 additions and 243 deletions
|
@ -255,10 +255,8 @@ dclass MagicWordManager : DistributedObject {
|
|||
};
|
||||
|
||||
dclass ChatAgent : DistributedObject {
|
||||
adminChat(uint32 aboutId, string message);
|
||||
chatMessage(string(0-256) message, uint8 chatMode) clsend;
|
||||
whisperMessage(uint32 receiverAvId, string(0-256) message) clsend;
|
||||
sfWhisperMessage(uint32 receiverAvId, string(0-256) message) clsend;
|
||||
adminChat(uint32, string);
|
||||
chatMessage(string(0-256)) clsend;
|
||||
};
|
||||
|
||||
dclass FriendManager : DistributedObject {
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
from direct.distributed.DistributedObjectGlobal import DistributedObjectGlobal
|
||||
from pandac.PandaModules import *
|
||||
from otp.otpbase import OTPGlobals
|
||||
from otp.ai.MagicWordGlobal import *
|
||||
|
||||
class ChatAgent(DistributedObjectGlobal):
|
||||
def __init__(self, cr):
|
||||
DistributedObjectGlobal.__init__(self, cr)
|
||||
self.chatMode = 0
|
||||
|
||||
def delete(self):
|
||||
self.ignoreAll()
|
||||
self.cr.chatManager = None
|
||||
self.cr.chatAgent = None
|
||||
DistributedObjectGlobal.delete(self)
|
||||
return
|
||||
|
||||
|
@ -20,35 +17,4 @@ class ChatAgent(DistributedObjectGlobal):
|
|||
messenger.send('adminChat', [aboutId, message])
|
||||
|
||||
def sendChatMessage(self, message):
|
||||
self.sendUpdate('chatMessage', [message, self.chatMode])
|
||||
|
||||
def sendWhisperMessage(self, receiverAvId, message):
|
||||
self.sendUpdate('whisperMessage', [receiverAvId, message])
|
||||
|
||||
def sendSFWhisperMessage(self, receiverAvId, message):
|
||||
self.sendUpdate('sfWhisperMessage', [receiverAvId, message])
|
||||
|
||||
@magicWord(category=CATEGORY_MODERATOR, types=[int])
|
||||
def chatmode(mode=-1):
|
||||
""" Set the chat mode of the current avatar. """
|
||||
mode2name = {
|
||||
0 : "user",
|
||||
1 : "moderator",
|
||||
2 : "administrator",
|
||||
3 : "system administrator",
|
||||
}
|
||||
if base.cr.chatAgent is None:
|
||||
return "No ChatAgent found."
|
||||
if mode == -1:
|
||||
return "You are currently talking in the %s chat mode." % mode2name.get(base.cr.chatAgent.chatMode, "N/A")
|
||||
if not 0 <= mode <= 3:
|
||||
return "Invalid chat mode specified."
|
||||
if mode == 3 and spellbook.getInvoker().getAdminAccess() < 500:
|
||||
return "Chat mode 3 is reserved for system administrators."
|
||||
if mode == 2 and spellbook.getInvoker().getAdminAccess() < 400:
|
||||
return "Chat mode 2 is reserved for administrators."
|
||||
if mode == 1 and spellbook.getInvoker().getAdminAccess() < 200:
|
||||
# Like this will ever happen, but whatever.
|
||||
return "Chat mode 1 is reserved for moderators."
|
||||
base.cr.chatAgent.chatMode = mode
|
||||
return "You are now talking in the %s chat mode." % mode2name.get(mode, "N/A")
|
||||
self.sendUpdate('chatMessage', [message])
|
||||
|
|
|
@ -2,151 +2,41 @@ 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
|
||||
from toontown.chat.TTSequenceList import TTSequenceList
|
||||
from otp.distributed import OtpDoGlobals
|
||||
import time
|
||||
|
||||
class ChatAgentUD(DistributedObjectGlobalUD):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("ChatAgentUD")
|
||||
|
||||
def announceGenerate(self):
|
||||
DistributedObjectGlobalUD.announceGenerate(self)
|
||||
self.wantBlacklistSequence = config.GetBool('want-blacklist-sequence', True)
|
||||
self.wantWhitelist = config.GetBool('want-whitelist', True)
|
||||
if self.wantWhitelist:
|
||||
self.whiteList = TTWhiteList()
|
||||
if self.wantBlacklistSequence:
|
||||
self.sequenceList = TTSequenceList()
|
||||
self.chatMode2channel = {
|
||||
1 : OtpDoGlobals.OTP_MOD_CHANNEL,
|
||||
2 : OtpDoGlobals.OTP_ADMIN_CHANNEL,
|
||||
3 : OtpDoGlobals.OTP_SYSADMIN_CHANNEL,
|
||||
}
|
||||
self.chatMode2prefix = {
|
||||
1 : "[MOD] ",
|
||||
2 : "[ADMIN] ",
|
||||
3 : "[SYSADMIN] ",
|
||||
}
|
||||
|
||||
self.muted = {}
|
||||
|
||||
def muteAccount(self, account, howLong):
|
||||
print ['muteAccount', account, howLong]
|
||||
self.muted[account] = int(time.time()/60) + howLong
|
||||
self.whiteList = TTWhiteList()
|
||||
|
||||
def unmuteAccount(self, account):
|
||||
print ['unmuteAccount', account]
|
||||
if account in self.muted:
|
||||
del self.muted[account]
|
||||
# Open chat
|
||||
def chatMessage(self, message, chatMode):
|
||||
def chatMessage(self, message):
|
||||
sender = self.air.getAvatarIdFromSender()
|
||||
if sender == 0:
|
||||
self.air.writeServerEvent('suspicious', accId=self.air.getAccountIdFromSender(),
|
||||
issue='Account sent chat without an avatar', message=message)
|
||||
return
|
||||
|
||||
if sender in self.muted and int(time.time()/60) < self.muted[sender]:
|
||||
return
|
||||
|
||||
if self.wantWhitelist:
|
||||
cleanMessage, modifications = self.cleanWhitelist(message)
|
||||
else:
|
||||
cleanMessage, modifications = message, []
|
||||
self.air.writeServerEvent('chat-said', avId=sender, chatMode=chatMode, msg=message, cleanMsg=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?
|
||||
if chatMode != 0:
|
||||
# Staff messages do not need to be cleaned. [TODO: Blacklist this?]
|
||||
if message.startswith('.'):
|
||||
# This is a thought bubble, move the point to the start.
|
||||
cleanMessage = '.' + self.chatMode2prefix.get(chatMode, "") + message[1:]
|
||||
else:
|
||||
cleanMessage = self.chatMode2prefix.get(chatMode, "") + message
|
||||
modifications = []
|
||||
DistributedAvatar = self.air.dclassesByName['DistributedAvatarUD']
|
||||
dg = DistributedAvatar.aiFormatUpdate('setTalk', sender, self.chatMode2channel.get(chatMode, sender),
|
||||
self.air.ourChannel,
|
||||
[0, 0, '', cleanMessage, modifications, 0])
|
||||
self.air.send(dg)
|
||||
self.air.csm.accountDB.persistChat(sender, message, self.air.ourChannel)
|
||||
|
||||
# Regular filtered chat
|
||||
def whisperMessage(self, receiverAvId, message):
|
||||
sender = self.air.getAvatarIdFromSender()
|
||||
if sender == 0:
|
||||
self.air.writeServerEvent('suspicious', accId=self.air.getAccountIdFromSender(),
|
||||
issue='Account sent chat without an avatar', message=message)
|
||||
self.air.writeServerEvent('suspicious', self.air.getAccountIdFromSender(),
|
||||
'Account sent chat without an avatar', message)
|
||||
return
|
||||
|
||||
cleanMessage, modifications = self.cleanWhitelist(message)
|
||||
# Maybe a better "cleaner" way of doing this, but it works
|
||||
self.air.writeServerEvent('whisper-said', avId=sender, reciever=receiverAvId, msg=message, cleanMsg=cleanMessage)
|
||||
DistributedAvatar = self.air.dclassesByName['DistributedAvatarUD']
|
||||
dg = DistributedAvatar.aiFormatUpdate('setTalkWhisper', receiverAvId, receiverAvId, self.air.ourChannel,
|
||||
[sender, sender, '', cleanMessage, modifications, 0])
|
||||
self.air.send(dg)
|
||||
|
||||
# True friend unfiltered chat
|
||||
def sfWhisperMessage(self, receiverAvId, message):
|
||||
sender = self.air.getAvatarIdFromSender()
|
||||
if sender == 0:
|
||||
self.air.writeServerEvent('suspicious', accId=self.air.getAccountIdFromSender(),
|
||||
issue='Account sent chat without an avatar', message=message)
|
||||
return
|
||||
|
||||
cleanMessage = self.cleanBlacklist(message)
|
||||
|
||||
self.air.writeServerEvent('sf-whisper-said', avId=sender, reciever=receiverAvId, msg=message, cleanMsg=cleanMessage)
|
||||
DistributedAvatar = self.air.dclassesByName['DistributedAvatarUD']
|
||||
dg = DistributedAvatar.aiFormatUpdate('setTalkWhisper', receiverAvId, receiverAvId, self.air.ourChannel,
|
||||
[sender, sender, '', cleanMessage, [], 0])
|
||||
self.air.send(dg)
|
||||
|
||||
# Filter the chat message
|
||||
def cleanWhitelist(self, message):
|
||||
modifications = []
|
||||
words = message.split(' ')
|
||||
offset = 0
|
||||
WantWhitelist = config.GetBool('want-whitelist', 1)
|
||||
for word in words:
|
||||
if word and not self.whiteList.isWord(word):
|
||||
if word and not self.whiteList.isWord(word) and WantWhitelist:
|
||||
modifications.append((offset, offset+len(word)-1))
|
||||
offset += len(word) + 1
|
||||
|
||||
cleanMessage = message
|
||||
if self.wantBlacklistSequence:
|
||||
modifications += self.cleanSequences(cleanMessage)
|
||||
|
||||
for modStart, modStop in modifications:
|
||||
# Traverse through modification list and replace the characters of non-whitelisted words and/or blacklisted sequences with asterisks.
|
||||
cleanMessage = cleanMessage[:modStart] + '*' * (modStop - modStart + 1) + cleanMessage[modStop + 1:]
|
||||
cleanMessage = cleanMessage[:modStart] + '*'*(modStop-modStart+1) + cleanMessage[modStop+1:]
|
||||
|
||||
return (cleanMessage, modifications)
|
||||
self.air.writeServerEvent('chat-said', sender, message, cleanMessage)
|
||||
|
||||
# Check the black list for black-listed words
|
||||
def cleanBlacklist(self, message):
|
||||
# We don't have a black list so we just return the full message
|
||||
return message
|
||||
|
||||
# Check for black-listed word sequences and scrub accordingly.
|
||||
def cleanSequences(self, message):
|
||||
modifications = []
|
||||
offset = 0
|
||||
words = message.split()
|
||||
for wordit in xrange(len(words)):
|
||||
word = words[wordit].lower()
|
||||
seqlist = self.sequenceList.getList(word)
|
||||
if len(seqlist) > 0:
|
||||
for seqit in xrange(len(seqlist)):
|
||||
sequence = seqlist[seqit]
|
||||
splitseq = sequence.split()
|
||||
if len(words) - (wordit + 1) >= len(splitseq):
|
||||
cmplist = words[wordit + 1:]
|
||||
del cmplist[len(splitseq):]
|
||||
cmplist = [word.lower() for word in cmplist]
|
||||
if cmp(cmplist, splitseq) == 0:
|
||||
modifications.append((offset, offset + len(word) + len(sequence) - 1))
|
||||
offset += len(word) + 1
|
||||
|
||||
return modifications
|
||||
# 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)
|
|
@ -1,15 +0,0 @@
|
|||
class SequenceList:
|
||||
|
||||
def __init__(self, wordlist):
|
||||
self.list = {}
|
||||
for line in wordlist:
|
||||
if line is '':
|
||||
continue
|
||||
split = line.split(':')
|
||||
self.list[split[0].lower()] = [word.rstrip('\r\n').lower() for word in split[1].split(',')]
|
||||
|
||||
def getList(self, word):
|
||||
if word in self.list:
|
||||
return self.list[word]
|
||||
else:
|
||||
return []
|
|
@ -1,55 +1,22 @@
|
|||
from bisect import bisect_left
|
||||
import string
|
||||
import sys
|
||||
import os
|
||||
|
||||
class WhiteList:
|
||||
|
||||
def __init__(self, wordlist):
|
||||
self.words = []
|
||||
for line in wordlist:
|
||||
self.words.append(line.strip('\n\r').lower())
|
||||
|
||||
self.words.sort()
|
||||
def __init__(self, words):
|
||||
self.words = words
|
||||
self.numWords = len(self.words)
|
||||
|
||||
def cleanText(self, text):
|
||||
text = text.strip('.,?!')
|
||||
text = text.lower()
|
||||
return text
|
||||
return text.lower()
|
||||
|
||||
def isWord(self, text):
|
||||
try:
|
||||
text = self.cleanText(text)
|
||||
i = bisect_left(self.words, text)
|
||||
if i == self.numWords:
|
||||
return False
|
||||
return self.words[i] == text
|
||||
except UnicodeDecodeError:
|
||||
return False # Lets not open ourselves up to obscure keyboards...
|
||||
|
||||
return self.cleanText(text) in self.words
|
||||
|
||||
def isPrefix(self, text):
|
||||
text = self.cleanText(text)
|
||||
i = bisect_left(self.words, text)
|
||||
|
||||
if i == self.numWords:
|
||||
return False
|
||||
return self.words[i].startswith(text)
|
||||
|
||||
def prefixCount(self, text):
|
||||
text = self.cleanText(text)
|
||||
i = bisect_left(self.words, text)
|
||||
j = i
|
||||
while j < self.numWords and self.words[j].startswith(text):
|
||||
j += 1
|
||||
|
||||
return j - i
|
||||
|
||||
def prefixList(self, text):
|
||||
text = self.cleanText(text)
|
||||
i = bisect_left(self.words, text)
|
||||
j = i
|
||||
while j < self.numWords and self.words[j].startswith(text):
|
||||
j += 1
|
||||
|
||||
return self.words[i:j]
|
||||
return self.words[i].startswith(text)
|
|
@ -2,7 +2,7 @@
|
|||
from pandac.PandaModules import *
|
||||
|
||||
|
||||
hashVal = 4270694562L
|
||||
hashVal = 598642574
|
||||
|
||||
|
||||
from toontown.coghq import DistributedCashbotBossSafe, DistributedCashbotBossCrane, DistributedBattleFactory, DistributedCashbotBossTreasure, DistributedCogHQDoor, DistributedSellbotHQDoor, DistributedFactoryElevatorExt, DistributedMintElevatorExt, DistributedLawOfficeElevatorExt, DistributedLawOfficeElevatorInt, LobbyManager, DistributedMegaCorp, DistributedFactory, DistributedLawOffice, DistributedLawOfficeFloor, DistributedLift, DistributedDoorEntity, DistributedSwitch, DistributedButton, DistributedTrigger, DistributedCrushableEntity, DistributedCrusherEntity, DistributedStomper, DistributedStomperPair, DistributedLaserField, DistributedGolfGreenGame, DistributedSecurityCamera, DistributedMover, DistributedElevatorMarker, DistributedBarrelBase, DistributedGagBarrel, DistributedBeanBarrel, DistributedHealBarrel, DistributedGrid, ActiveCell, DirectionalCell, CrusherCell, DistributedCrate, DistributedSinkingPlatform, BattleBlocker, DistributedMint, DistributedMintRoom, DistributedMintBattle, DistributedStage, DistributedStageRoom, DistributedStageBattle, DistributedLawbotBossGavel, DistributedLawbotCannon, DistributedLawbotChair, DistributedCogKart, DistributedCountryClub, DistributedCountryClubRoom, DistributedMoleField, DistributedCountryClubBattle, DistributedMaze, DistributedFoodBelt, DistributedBanquetTable, DistributedGolfSpot
|
||||
|
|
|
@ -88,6 +88,4 @@ OTP_ZONE_ID_DISTRICTS = 3
|
|||
OTP_ZONE_ID_DISTRICTS_STATS = 4
|
||||
OTP_ZONE_ID_ELEMENTS = 5
|
||||
OTP_NET_MESSENGER_CHANNEL = (OTP_DO_ID_UBER_DOG << 32) + OTP_ZONE_ID_MANAGEMENT
|
||||
OTP_MOD_CHANNEL = 6200
|
||||
OTP_ADMIN_CHANNEL = 6400
|
||||
OTP_SYSADMIN_CHANNEL = 6500
|
||||
OTP_STAFF_CHANNEL = 6200
|
||||
|
|
|
@ -35,7 +35,6 @@ if args.astron_ip: localconfig += 'air-connect %s\n' % args.astron_ip
|
|||
if args.eventlogger_ip: localconfig += 'eventlog-host %s\n' % args.eventlogger_ip
|
||||
loadPrcFileData('Command-line', localconfig)
|
||||
|
||||
|
||||
from otp.ai.AIBaseGlobal import *
|
||||
|
||||
from toontown.ai.ToontownAIRepository import ToontownAIRepository
|
||||
|
|
|
@ -422,26 +422,13 @@ class LoginAccountFSM(OperationFSM):
|
|||
datagram.addChannel(self.csm.GetAccountConnectionChannel(self.accountId))
|
||||
self.csm.air.send(datagram)
|
||||
|
||||
# Subscribe to any "staff" channels that the account has access to.
|
||||
access = self.account.get('ADMIN_ACCESS', 0)
|
||||
if access >= 200:
|
||||
# Subscribe to the moderator channel.
|
||||
dg = PyDatagram()
|
||||
dg.addServerHeader(self.target, self.csm.air.ourChannel, CLIENTAGENT_OPEN_CHANNEL)
|
||||
dg.addChannel(OtpDoGlobals.OTP_MOD_CHANNEL)
|
||||
self.csm.air.send(dg)
|
||||
if access >= 400:
|
||||
# Subscribe to the administrator channel.
|
||||
dg = PyDatagram()
|
||||
dg.addServerHeader(self.target, self.csm.air.ourChannel, CLIENTAGENT_OPEN_CHANNEL)
|
||||
dg.addChannel(OtpDoGlobals.OTP_ADMIN_CHANNEL)
|
||||
self.csm.air.send(dg)
|
||||
if access >= 500:
|
||||
# Subscribe to the system administrator channel.
|
||||
dg = PyDatagram()
|
||||
dg.addServerHeader(self.target, self.csm.air.ourChannel, CLIENTAGENT_OPEN_CHANNEL)
|
||||
dg.addChannel(OtpDoGlobals.OTP_SYSADMIN_CHANNEL)
|
||||
self.csm.air.send(dg)
|
||||
# Add this connection to extra channels which may be useful:
|
||||
if self.accessLevel > 100:
|
||||
datagram = PyDatagram()
|
||||
datagram.addServerHeader(self.target, self.csm.air.ourChannel,
|
||||
CLIENTAGENT_OPEN_CHANNEL)
|
||||
datagram.addChannel(OtpDoGlobals.OTP_STAFF_CHANNEL)
|
||||
self.csm.air.send(datagram)
|
||||
|
||||
# Now set their sender channel to represent their account affiliation:
|
||||
datagram = PyDatagram()
|
||||
|
|
Loading…
Reference in a new issue