Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions commands/cch.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from commands.cpu import handle_cpu
from response import ExtensionResponse
from typing import TYPE_CHECKING

from utils.filter import ProfanityModel

if TYPE_CHECKING:
from server import CafeServer
from asyncio import StreamWriter
Expand All @@ -11,11 +14,14 @@ async def handle_cch(server: 'CafeServer', client: 'StreamWriter', *params: str)
player = server.clients[address]

message = params[1]
original_message = message

for other_player in player.room.clients:
if other_player != player.client:
response = ExtensionResponse('cch', '-1', '0', str(player.id), message)
await server.send_response(other_player, response)
pf = ProfanityModel()

response = ExtensionResponse('cch', '-1', '0', str(player.id), message)
await server.send_response(client, response)
if pf.has_profanity(message):
message = pf.censor(message)
await handle_cpu(server, client, 3, pf.detect_words(original_message))

for other_player in player.room.clients:
response = ExtensionResponse('cch', '-1', '0', str(player.id), message)
await server.send_response(other_player, response)
9 changes: 5 additions & 4 deletions commands/cha.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ async def handle_cha(server: 'CafeServer', client: 'StreamWriter', *params: str)
if player.avatar.gender == '0':
player.avatar.gender = old_gender

for user in player.room.clients:
if user != client:
response = ExtensionResponse('cha', '-1', '0', params[1],
if player.room:
for user in player.room.clients:
if user != client:
response = ExtensionResponse('cha', '-1', '0', params[1],
str(server.clients[client.get_extra_info('peername')].id))
await server.send_response(user, response)
await server.send_response(user, response)

server.db.update_player(player.id, gender=player.avatar.gender, top_color=player.avatar.top_color,
skin_color=player.avatar.skin_color, hair_color=player.avatar.hair_color,
Expand Down
20 changes: 20 additions & 0 deletions commands/ctf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import TYPE_CHECKING

from objects.customer import spawn_cycle
from asyncio import create_task

if TYPE_CHECKING:
from server import CafeServer
from asyncio import StreamWriter


async def handle_ctf(server: 'CafeServer', client: 'StreamWriter', *params: str) -> None:
address = client.get_extra_info('peername')
player = server.clients[address]

player.xp = 10

server.db.update_player(player.id, xp=player.xp)

print(f'created customer cycle\nused this player\'s cafe: f{player.avatar.username}')
player.customer_cycle = create_task(spawn_cycle(server, player.cafe))
10 changes: 5 additions & 5 deletions commands/jca.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ async def handle_jca(server: 'CafeServer', client: 'StreamWriter', *params: str)

# TODO: Broken for other player's cafe
# Tries to use player's cafe objects instead of the other player's
if not wanted_player.customer_cycle:
print(f'created waiter cycle\nused this player\'s cafe: f{wanted_player.avatar.username}')
# TODO: add random customers
wanted_player.customer_cycle = create_task(spawn_cycle(server, wanted_player.cafe))
if not wanted_player.cafe.customer_cycle:
if not player.first_login:
print(f'created waiter cycle\nused this player\'s cafe: f{wanted_player.avatar.username}')
# TODO: add random customers
wanted_player.customer_cycle = create_task(spawn_cycle(server, wanted_player.cafe))
else:
customers = wanted_player.cafe.customers

Expand Down Expand Up @@ -78,4 +79,3 @@ async def handle_jca(server: 'CafeServer', client: 'StreamWriter', *params: str)

await server.send_response(client, response_spawn)
await server.send_response(client, response)

12 changes: 6 additions & 6 deletions commands/lca.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,24 @@
from objects.player import Player
from objects.avatar import Avatar
from objects.cafe import Cafe
from random import randint

if TYPE_CHECKING:
from server import CafeServer
from asyncio import StreamWriter


async def handle_lca(server: 'CafeServer', client: 'StreamWriter', *params: str) -> None:
response = ExtensionResponse('lca', '-1', '0', 'user1', '1')
await server.send_response(client, response)
base_name = "Guest"
guest_name = f'{base_name}_{randint(10000000, 99999999)}'

avatar = Avatar.from_string(params[1])
new_player = Player.new_user(avatar.username)
new_player.avatar = avatar
new_player.cafe = Cafe.get_starting_cafe()
new_player.cafe.owner_name = avatar.username
new_player.client = client
new_player.online = True

address = client.get_extra_info('peername')
server.clients[address] = new_player
server.players.append(new_player)

response = ExtensionResponse('lca', '-1', '0', guest_name, '1')
await server.send_response(client, response)
157 changes: 150 additions & 7 deletions commands/lre.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,167 @@
import re
from random import randint
from typing import TYPE_CHECKING

from commands.ifr import handle_ifr
from commands.lmi import handle_lmi
from commands.rlu import handle_rlu
from commands.sbc import handle_sbc
from response import ExtensionResponse
from commands.sgc import handle_sgc
from commands.gui import handle_gui
from objects.cafe import Cafe
from objects.player import Player
from utils.filter import ProfanityModel

if TYPE_CHECKING:
from server import CafeServer
from asyncio import StreamWriter


async def handle_lre(server: 'CafeServer', client: 'StreamWriter', *params: str) -> None:
response = ExtensionResponse('lre', '-1', '0')
await server.send_response(client, response)
class ErrorCodes:
USERNAME_WRONG = 1
USERNAME_SHORT = 2
USERNAME_LONG = 3
EMAIL_WRONG = 4
PASSWORD_WRONG = 5
ACCEPT_TERMS = 98
PASSWORD_SHORT = 96
PASSWORD_INVALID = 10
EMAIL_LONG = 94
EMAIL_INVALID = 14
ACCOUNT_EXIST = 13
BAD_WORD = 93


invalidChars = ["+", "%", "&", "*", "/", "(", ")", "[", "]", "{", "}", "\"", "'",
"\\", "´", "`", "^", "°", "§", "€", "²", "³", ",", ";", "µ", "$"]


def contains_invalid_chars(text):
return any(char in invalidChars for char in text)


def is_valid_email(email):
regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,7}\b'
return bool(re.fullmatch(regex, email))


def generate_usernames(username):
available_names = []
max_suffix_length = 24 - len(username) - 1

for _ in range(5):
suffix_length = min(max_suffix_length, 4)
suffix = randint(0, 10 ** suffix_length - 1)
new_name = f'{username}_{suffix}'
if len(new_name) <= 24:
available_names.append(new_name)

return '#'.join(available_names)


async def handle_lre(server: 'CafeServer', client: 'StreamWriter', *params: str) -> None:
address = client.get_extra_info('peername')
player = server.clients[address]
player.avatar.username = params[1]

username = params[1]
email = params[2]
password = params[3]
player.cafe.owner_name = player.avatar.username
accepted_terms = params[4]

if not username or username == '.' or contains_invalid_chars(username):
response = ExtensionResponse('lre', '-1', str(ErrorCodes.USERNAME_WRONG))
await server.send_response(client, response)
return

if len(username) < 4:
response = ExtensionResponse('lre', '-1', str(ErrorCodes.USERNAME_SHORT))
await server.send_response(client, response)
return

if len(username) > 24:
response = ExtensionResponse('lre', '-1', str(ErrorCodes.USERNAME_LONG))
await server.send_response(client, response)
return

if not email or email == '.' or contains_invalid_chars(email):
response = ExtensionResponse('lre', '-1', str(ErrorCodes.EMAIL_WRONG))
await server.send_response(client, response)
return

if len(email) > 320:
response = ExtensionResponse('lre', '-1', str(ErrorCodes.EMAIL_LONG))
await server.send_response(client, response)
return

if not is_valid_email(email):
response = ExtensionResponse('lre', '-1', str(ErrorCodes.EMAIL_INVALID))
await server.send_response(client, response)
return

if not password or password == '.':
response = ExtensionResponse('lre', '-1', str(ErrorCodes.PASSWORD_WRONG))
await server.send_response(client, response)
return

if len(password) < 4:
response = ExtensionResponse('lre', '-1', str(ErrorCodes.PASSWORD_SHORT))
await server.send_response(client, response)
return

if contains_invalid_chars(password):
response = ExtensionResponse('lre', '-1', str(ErrorCodes.PASSWORD_INVALID))
await server.send_response(client, response)
return

if accepted_terms == '0':
response = ExtensionResponse('lre', '-1', str(ErrorCodes.ACCEPT_TERMS))
await server.send_response(client, response)
return

if server.db.username_exist(username):
available_usernames = generate_usernames(username)

response = ExtensionResponse('lre', '-1', '12', available_usernames)
await server.send_response(client, response)
return

if server.db.email_exist(email):
response = ExtensionResponse('lre', '-1', str(ErrorCodes.ACCOUNT_EXIST))
await server.send_response(client, response)
return

pf = ProfanityModel()
if pf.has_profanity(username):
response = ExtensionResponse('lre', '-1', str(ErrorCodes.BAD_WORD), pf.detect_words(username),
generate_usernames('Guest'))
await server.send_response(client, response)
return

server.db.new_player(username, password, email)
player.id = server.db.get_player_id(username)

player.online = True
player.first_login = True

player.cafe = Cafe.get_starting_cafe()
player.cafe.player_id = player.id
player.cafe.user_id = player.id
player.cafe.owner_name = username

player.avatar.username = username

server.players.append(player)

server.db.new_cafe(player.id, username, player.cafe.get_waiters_as_json())

response = ExtensionResponse('lre', '-1', '0')
await server.send_response(client, response)

await handle_rlu(server, client, 'lgn', *params)

await handle_gui(server, client, *params)

await handle_sbc(server, client, *params)

await handle_lmi(server, client, *params)

await handle_ifr(server, client, *params)
19 changes: 17 additions & 2 deletions database.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,9 @@ def get_player_by_id(self, player_id: int) -> Player:
def new_player(self, username: str, password: str, email: str) -> None:
self.cursor.execute("INSERT INTO player (username, password, email) VALUES (?, ?, ?)", (username, password, email))

def new_cafe(self, player_id: int) -> None:
pass
def new_cafe(self, player_id: int, owner_name: str, waiters) -> None:
self.cursor.execute("INSERT INTO cafe (player_id, owner_name, waiters) VALUES (?, ?, ?)",
(player_id, owner_name, waiters))

def update_player(self, player_id: int, **kwargs):
columns = ", ".join([f"{key} = ?" for key in kwargs.keys()])
Expand All @@ -108,3 +109,17 @@ def update_cafe(self, player_id: int, **kwargs):
values = [*kwargs.values(), player_id]

self.cursor.execute(query, values)

def username_exist(self, username: str):
self.cursor.execute("SELECT 1 FROM player WHERE username=?", (username,))
return self.cursor.fetchone() is not None

def email_exist(self, email: str):
self.cursor.execute("SELECT 1 FROM player WHERE email=?", (email,))
return self.cursor.fetchone() is not None

def get_player_id(self, username: str):
self.cursor.execute("SELECT id FROM player WHERE username=?", (username,))
player_id = self.cursor.fetchone()

return player_id[0]
4 changes: 4 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
from server import CafeServer
from asyncio import run

from utils.filter import ProfanityModel

if __name__ == '__main__':
server = CafeServer()

profanity_model = ProfanityModel()

try:
run(server.start())
except KeyboardInterrupt:
Expand Down
2 changes: 2 additions & 0 deletions objects/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ def __init__(self):

self.mastery: dict[int, int] = {num: 0 for num in range(1201, 1256)}

self.first_login = False

self.customer_cycle: Optional['Task'] = None

def build_mastery(self) -> str:
Expand Down
Loading