2025/12/14 Here's a snippet of code I made while learning twisted :
The hardest part was making the client ! the pygame window captures the users input and puts them in variables that it then sends to the server
As for the server, it almost identical to the code you can find here (it's the second iteration of ChatServer)
This time, the server is responsible for creating a user object, such that the client can't just change its identity every message. You can till spoof other people by using their name when registering, and the server is very easy to break (doesn't handle disconnections), but it is an improvement from the first iteration !
import pygame
import twisted
from twisted.internet import reactor
from twisted.internet import task
from twisted.spread import pb
class ClientSideUser(pb.Referenceable):
def __init__(self, username='', message = '', group = ''):
self.name = username
self.group = group
self.message = message
self.STATE = 'GETUSERNAME'
def remote_receive_name_and_message(self, from_username, message):
print('\b \b'*1000+'<%s> : %s' %(from_username, message))
print('(%s in %s) send a message : %s' %(self.name, self.group, self.message), flush=True, end='')
def remote_receive_server_message(self, message):
print('*server* : %s' %message, )
class LoopHolder:
def __init__(self, loop=None):
self.loop = loop
self.deferred_originally_containing_root_object = None
self.clientsideuser = None
def handle_writing_to_screen_and_sending_messages(event, loop_holder):
clientsideuser = loop_holder.clientsideuser
deferred_originally_containing_root_object = loop_holder.deferred_originally_containing_root_object
group = clientsideuser.group
username = clientsideuser.name
message = clientsideuser.message
STATE = clientsideuser.STATE
if event.type == pygame.TEXTINPUT:
if STATE == 'GETUSERNAME':
clientsideuser.name += event.text
print(event.text, end='', flush=True)
if STATE == 'GETGROUP':
clientsideuser.group += event.text
print(event.text, end='', flush=True)
if STATE == 'MESSAGING':
clientsideuser.message += event.text
print(event.text, end='', flush=True)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
if STATE == 'MESSAGING':
alt_addCallback(
deferred_originally_containing_root_object, 'sendMessage', group, message)
clientsideuser.message = ''
elif STATE == 'GETGROUP':
alt_addCallback(deferred_originally_containing_root_object, 'joinGroup', group)
clientsideuser.STATE = 'MESSAGING'
print('\ngot group. You can now send a message : ', end='', flush=True)
elif STATE == 'GETUSERNAME':
alt_addCallback_and_store_returned_value(
deferred_originally_containing_root_object, 'init_user', username, clientsideuser)
clientsideuser.STATE = 'GETGROUP'
print('\nwhats the group you want to send a message in ? ', end='', flush=True)
def alt_addCallback(d, remote_func_name, *args):
def keep_reference(reference, *args):
reference.callRemote(remote_func_name, *args)
return reference
d.addCallback(keep_reference, *args)
def alt_addCallback_and_store_returned_value(d, remote_func_name, *args):
def keep_user(reference, *args):
user = reference.callRemote(remote_func_name, *args)
return user
d.addCallback(keep_user, *args)
def init():
pygame.init()
win = pygame.Window(resizable=True)
factory = pb.PBClientFactory()
reactor.connectTCP("192.168.1.81", 8800, factory)
loop_holder = LoopHolder()
loop_holder.deferred_originally_containing_root_object = factory.getRootObject()
loop_holder.clientsideuser = ClientSideUser()
loop_holder.loop = task.LoopingCall(lp, win, loop_holder)
loop_holder.loop.start(1/60)
print('whats your username ? ', end='', flush=True)
def lp(win, loop_holder):
clientsideuser = loop_holder.clientsideuser
deferred_originally_containing_root_object = loop_holder.deferred_originally_containing_root_object
group = clientsideuser.group
username = clientsideuser.name
message = clientsideuser.message
STATE = clientsideuser.STATE
win.get_surface().fill((44, 33, 11))
win.flip()
for event in pygame.event.get():
handle_writing_to_screen_and_sending_messages(event, loop_holder)
if event.type == pygame.WINDOWCLOSE:
id = event.window.id
print(f"WINDOWCLOSE event sent to Window #{id}.")
event.window.destroy()
if event.type == pygame.QUIT:
print(f"Last window is destroyed. QUIT event was sent.")
loop_holder.loop.stop()
reactor.stop()
init()
reactor.run()
2025/12/14 I'm making a python game ! it has many ambitions but notably it should support multiplayer which is not easy to figure out ! I'm using the python-twisted framework but struggled for a while because its never mentionned in the docs that they dont provide a way of capturing userinput ! This is why using pygame in conjuction with twisted is absolutely indispensible for me. I have no screenshot to provide as i didn't commit the latest working version of the game, so it will stay broken until I add multiplayer !
To learn more HTML/CSS, check out these tutorials!