ohaiderstudios wrote:
GAAAAHH!!! TOO MUCH RAW CODE!!! MY EYES!!!
jk![]()
Alright, I'll try to understand all of this![]()
Hehe, I've been going through my old files and I've found much cleaner code than the old Mirror code. If you want, I can post it.
Offline
Magnie wrote:
ohaiderstudios wrote:
GAAAAHH!!! TOO MUCH RAW CODE!!! MY EYES!!!
jk![]()
Alright, I'll try to understand all of this![]()
Hehe, I've been going through my old files and I've found much cleaner code than the old Mirror code. If you want, I can post it.
Sure...man this is harder than I thought
Offline
I just barely started modifying the code for the client:
# Scratch Mirror
# Version 1.5.0
# By: Magnie
import socket # Network base
import time # For delaying purposes mostly.
import threading # So it can send and receive at the same time anytime.
# ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### #
# CHOST is the IP Scratch is running on, if you are running it #
# on this computer, then the IP is 127.0.0.1 #
# Theoretically you could run this Mirror on another computer. #
# ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### #
# CPOST is the port Scratch is listening on, the default is #
# 42001. Usually this is only change by a Scratcher who knows a #
# about Squeak and networking with sockets. #
# ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### #
CHOST = '127.0.0.1'
CPORT = 42001
# ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### #
# SHOST is the IP the server is running on. #
# ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### #
# SPORT is the port that the server is using. 42002 is the #
# unofficial port for Scratch Servers. The host will need to make #
# sure to port-forward the port so people can connect from the #
# internet. #
# ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### #
SHOST = '127.0.0.1'
SPORT = 42002
# ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### #
# Some extra settings that are more for advanced users are below. #
# ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### #
# Time between checking the threads for broken ones.
THREADCHECK = 5
class Client(threading.Thread): # This class listens for messages sent from Scratch and sends it to the Server.
def __init__(self, CHOST, CPORT):
threading.Thread.__init__(self) # Initialize it, basically just separate it from the main thread.
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Defines the type of connection ( UPD, TCP on IPv4 or IPv6 )
print("Connecting to Scratch...")
self.sock.connect((CHOST, CPORT)) # Connect to Scratch
print("Connected to Scratch!")
def run(self):
global running
print "Listening for Scratch messages."
while running:
data = self.sock.recv(1024) # Wait for something to be sent to the mirror
self.send(data)
def send(self, message):
server.sock.send(message) # Send the data to the server.
class Server(threading.Thread, SHOST, SPORT): # This class listens for messages from the Server and sends it to Scratch.
def __init__(self):
threading.Thread.__init__(self) # Initialize it, basically just separate it from the main thread.
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Defines the type of connection ( UPD, TCP on IPv4 or IPv6 )
print("Connecting to Scratch Server...")
self.sock.connect((SHOST, SPORT)) # Connect to the Server.
print("Connected to Server!")
def run(self):
global running
print "Listening for Server messages."
while running:
data = self.sock.recv(1024) # Listens for messages sent from the Server.
self.send(data)
def send(self, message):
scratch.sock.send(message) # Sends messages to Scratch.
running = 1
scratch = Client(CHOST, CPORT) # Start up the class for Scratch
scratch.start() # This starts the 'run' function.
server = Server(SHOST, SPORT) # Start up the class for Server
server.start() # This starts the 'run' function on the class as well.
while running:
time.sleep(THREADCHECK) # The longer the wait time, the less CPU is used I think.
try: # Check if the either thread died ( or exists anymore ).
if scratch: pass
if server: pass
except: # If either are dead, end the program.
running = 0
print "Finished running."I'll need to add comments to the server to explain all the stuff.
Offline
Here is the server, most of the un-commented code in the client class should be self explanatory:
# Scratch Server
# Version 1.0.0
# By: Magnie
import threading
import socket
import sys
from array import array
class Server:
def __init__(self):
# Server Information
self.host = '' # Game host
self.port = 42002 # Game port
self.backlog = 5 # Maximum clients?
self.size = 1024 # Maximum receive size
self.server = None
self.threads = [] # Client threads ( just a record )
# Game Information
def open_socket(self):
try: # Try settings up the connection
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Define socket type
self.server.bind((self.host,self.port)) # Bind server to port
self.server.listen( self.backlog ) # Wait for clients to connect
except socket.error, (value,message): # If it can't connect Then print out the error and shut down the server.
if self.server:
self.server.close()
print "Could not open socket: " + message
sys.exit(1)
def run(self):
self.open_socket()
running = 1
id = 0 # To define each client.
while running:
id += 1 # Increase so no client has the same ID.
c = Client(self.server.accept(), id) # Waits for a client then accepts it.
c.start() # Starts it.
self.threads.append(c) # Adds it to a list so the variable c and be used for the next client.
# Disconnect all clients.
self.server.close() # Disconnect socket.
for c in self.threads: # For each thread
c.join() # End that thread.
class Client(threading.Thread):
def __init__(self,(client,address), id):
threading.Thread.__init__(self)
self.client = client
self.address = address
self.size = 1024
self.id = id
self.x = 0
self.y = 0
self.life = 10
self.up = 0
self.down = 0
self.left = 0
self.right = 0
print self.address, 'has connected.'
def run(self):
running = 1
while running:
data = self.client.recv(self.size) # Wait for data.
data = parseScratchCommand(data) # Parse the data.
print data # Print it
if data[0] == 'sensor-update': # If a variable is updated
if data[1] == '"up"' and data[2] == '1':
self.up = 1
if data[1] == '"up"' and data[2] == '0':
self.up = 0
elif data[0] == 'broadcast': # If a broadcast is sent
if data[1] == '"settings"':
self.client.send( sendScratchCommand('sensor-update "id" '+str(self.id)) )
self.client.send( sendScratchCommand('sensor-update "p1x" 0') )
self.client.send( sendScratchCommand('sensor-update "p1y" 0') )
self.client.send( sendScratchCommand('sensor-update "p2x" 0') )
self.client.send( sendScratchCommand('sensor-update "p2y" 0') )
if data[1] == '"update"':
if self.up == 1:
self.y += 1
for p in s.threads:
self.client.send( sendScratchCommand('sensor-update "p'+str(p.id)+'x" '+str(p.x)) )
self.client.send( sendScratchCommand('sensor-update "p'+str(p.id)+'y" '+str(p.y)) )
else:
self.client.close() # Close the connection.
print self.address, 'has closed the connection.' # Debugging purposes and just informative if you are watching it.
running = 0
def parseScratchCommand(cmd):
cmd = cmd[4:] # Remove the first four letters ( it's annoying to deal with )
cmd = cmd.split(' ') # Split the string where there is a space. It helps to find out broadcasts.
return cmd # Return the list.
def sendScratchCommand(cmd): # I was never sure what this did, but it's required.
n = len(cmd)
a = array('c')
a.append(chr((n >> 24) & 0xFF))
a.append(chr((n >> 16) & 0xFF))
a.append(chr((n >> 8) & 0xFF))
a.append(chr(n & 0xFF))
return (a.tostring() + cmd)
if __name__ == "__main__":
s = Server()
s.run()Offline
When I run the client, I get the following message:
Python Shell wrote:
Traceback (most recent call last):
File "C:\fakepath\tynyclient.py", line 59, in <module>
class Server(threading.Thread, SHOST, SPORT): # This class listens for messages from the Server and sends it to Scratch.
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
now on to the server!
Offline
self.backlog = 5
So if I want, say, 10 people to be able to connect at a time, then I would change it to
self.backlog = 10
Right?
Offline
ohaiderstudios wrote:
Code:
self.backlog = 5So if I want, say, 10 people to be able to connect at a time, then I would change it to
Code:
self.backlog = 10Right?
Yeah, but I've got more clients to connect even though the backlog was less than clients. You would probably need to add an extra limit to it with your own coding.
Offline
ohaiderstudios wrote:
When I run the client, I get the following message:
Python Shell wrote:
Traceback (most recent call last):
File "C:\fakepath\tynyclient.py", line 59, in <module>
class Server(threading.Thread, SHOST, SPORT): # This class listens for messages from the Server and sends it to Scratch.
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its basesnow on to the server!
I'd like this error straightened out!
Offline
ohaiderstudios wrote:
When I run the client, I get the following message:
Python Shell wrote:
Traceback (most recent call last):
File "C:\fakepath\tynyclient.py", line 59, in <module>
class Server(threading.Thread, SHOST, SPORT): # This class listens for messages from the Server and sends it to Scratch.
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its basesnow on to the server!
what server
Offline
ohaiderstudios wrote:
ohaiderstudios wrote:
When I run the client, I get the following message:
Python Shell wrote:
Traceback (most recent call last):
File "C:\fakepath\tynyclient.py", line 59, in <module>
class Server(threading.Thread, SHOST, SPORT): # This class listens for messages from the Server and sends it to Scratch.
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its basesnow on to the server!
I'd like this error straightened out!
![]()
Whoops, I put the ,SHOST, SPORT in the wrong spot, it's supposed to go in the init:
class Server(threading.Thread): # This class listens for messages from the Server and sends it to Scratch.
def __init__(self, SHOST, SPORT):
threading.Thread.__init__(self) # Initialize it, basically just separate it from the main thread.
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Defines the type of connection ( UPD, TCP on IPv4 or IPv6 )
print("Connecting to Scratch Server...")
self.sock.connect((SHOST, SPORT)) # Connect to the Server.
print("Connected to Server!")
def run(self):
global running
print "Listening for Server messages."
while running:
data = self.sock.recv(1024) # Listens for messages sent from the Server.
self.send(data)
def send(self, message):
scratch.sock.send(message) # Sends messages to Scratch.That's the fixed Class.
Offline
Magnie wrote:
ohaiderstudios wrote:
ohaiderstudios wrote:
When I run the client, I get the following message:
now on to the server!I'd like this error straightened out!
![]()
Whoops, I put the ,SHOST, SPORT in the wrong spot, it's supposed to go in the init:
Code:
class Server(threading.Thread): # This class listens for messages from the Server and sends it to Scratch. def __init__(self, SHOST, SPORT): threading.Thread.__init__(self) # Initialize it, basically just separate it from the main thread. self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Defines the type of connection ( UPD, TCP on IPv4 or IPv6 ) print("Connecting to Scratch Server...") self.sock.connect((SHOST, SPORT)) # Connect to the Server. print("Connected to Server!") def run(self): global running print "Listening for Server messages." while running: data = self.sock.recv(1024) # Listens for messages sent from the Server. self.send(data) def send(self, message): scratch.sock.send(message) # Sends messages to Scratch.That's the fixed Class.
Alrighty it works!
I'm taking a break from the client/server coding, and am making an example game for this!
Offline
flashgocrazy wrote:
ohaiderstudios wrote:
When I run the client, I get the following message:
Python Shell wrote:
Traceback (most recent call last):
File "C:\fakepath\tynyclient.py", line 59, in <module>
class Server(threading.Thread, SHOST, SPORT): # This class listens for messages from the Server and sends it to Scratch.
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its basesnow on to the server!
what server
The Python code that Magnie posted for the server.
Offline
Okay, I have created the Scratch Live Clone for the Python Server:
# Scratch Server
# Version 1.0.0
# By: Magnie
import threading
import socket
import sys
from array import array
class Server:
def __init__(self):
# Server Information
self.host = '' # Game host
self.port = 42002 # Game port
self.backlog = 5 # Maximum clients?
self.size = 1024 # Maximum receive size
self.server = None
self.threads = [] # Client threads ( just a record )
self.variables = {} # user : value
# Game Information
def open_socket(self):
try: # Try settings up the connection
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Define socket type
self.server.bind((self.host,self.port)) # Bind server to port
self.server.listen( self.backlog ) # Wait for clients to connect
except socket.error, (value,message): # If it can't connect Then print out the error and shut down the server.
if self.server:
self.server.close()
print "Could not open socket: " + message
sys.exit(1)
def run(self):
self.open_socket()
running = 1
id = 0 # To define each client.
while running:
id += 1 # Increase so no client has the same ID.
c = Client(self.server.accept()) # Waits for a client then accepts it.
c.start() # Starts it.
self.threads.append(c) # Adds it to a list so the variable c and be used for the next client.
# Disconnect all clients.
self.server.close() # Disconnect socket.
for c in self.threads: # For each thread
c.join() # End that thread.
class Client(threading.Thread):
def __init__(self,(client,address)):
threading.Thread.__init__(self)
self.client = client
self.address = address
self.size = 1024
print self.address, 'has connected.'
def run(self):
running = 1
while running:
data = self.client.recv(self.size) # Wait for data.
data = parseScratchCommand(data) # Parse the data.
print data # Print it
if data[0] == 'sensor-update': # If a variable is updated
continue
elif data[0] == 'broadcast': # If a broadcast is sent
data[1] = data[1][1:]
data[-1] = data[-1][:-1]
print data
if data[1][0] == '<' or data[1][0] == '>':
if data[1][1:] not in s.variables:
s.variables[ data[1] ] = ""
if data[1][0] == '>':
vari = data[1][1:]
value = s.variables[ vari ]
self.client.send( sendScratchCommand('sensor-update "'+vari+'" '+value) )
elif data[1][0] == '<':
vari = data[1][1:]
value = ' '.join( data[2:] )
s.variables[ vari ] = value
self.client.send( sendScratchCommand('sensor-update "'+vari+'" '+value) )
else:
continue
else:
self.client.close() # Close the connection.
print self.address, 'has closed the connection.' # Debugging purposes and just informative if you are watching it.
running = 0
def parseScratchCommand(cmd):
cmd = cmd[4:] # Remove the first four letters ( it's annoying to deal with )
cmd = cmd.split(' ') # Split the string where there is a space. It helps to find out broadcasts.
return cmd # Return the list. ['broadcast/sensor-update', 'valueWord1', 'valueWord2']
def sendScratchCommand(cmd): # I was never sure what this did, but it's required.
n = len(cmd)
a = array('c')
a.append(chr((n >> 24) & 0xFF))
a.append(chr((n >> 16) & 0xFF))
a.append(chr((n >> 8) & 0xFF))
a.append(chr(n & 0xFF))
return (a.tostring() + cmd)
if __name__ == "__main__":
s = Server()
s.run()Will run on Windows and I see no reason it shouldn't on any other OS. You set variables by broadcasting "<var value" and you get variables with ">var". "<" set; ">" get. Now all I need to add it the "global broadcast" system, where if the user decides to "follow" a variable, then the user will be sent the update when it is updated.
This will probably be the hardest part.
Edit: Or it won't... Added "global broadcast" and fixed a few bugs in the first one:
# Scratch Server
# Version 1.0.0
# By: Magnie
import threading
import socket
import sys
from array import array
class Server:
def __init__(self):
# Server Information
self.host = '' # Game host
self.port = 42002 # Game port
self.backlog = 5 # Maximum clients?
self.size = 1024 # Maximum receive size
self.server = None
self.threads = [] # Client threads ( just a record )
self.variables = {} # user : value
# Game Information
def open_socket(self):
try: # Try settings up the connection
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Define socket type
self.server.bind((self.host,self.port)) # Bind server to port
self.server.listen( self.backlog ) # Wait for clients to connect
except socket.error, (value,message): # If it can't connect Then print out the error and shut down the server.
if self.server:
self.server.close()
print "Could not open socket: " + message
sys.exit(1)
def run(self):
self.open_socket()
running = 1
id = 0 # To define each client.
while running:
id += 1 # Increase so no client has the same ID.
c = Client(self.server.accept()) # Waits for a client then accepts it.
c.start() # Starts it.
self.threads.append(c) # Adds it to a list so the variable c and be used for the next client.
# Disconnect all clients.
self.server.close() # Disconnect socket.
for c in self.threads: # For each thread
c.join() # End that thread.
class Client(threading.Thread):
def __init__(self,(client,address)):
threading.Thread.__init__(self)
self.client = client
self.address = address
self.size = 1024
self.follow = []
print self.address, 'has connected.'
def run(self):
running = 1
while running:
data = self.client.recv(self.size) # Wait for data.
data = parseScratchCommand(data) # Parse the data.
print data # Print it
if data[0] == 'sensor-update': # If a variable is updated
continue
elif data[0] == 'broadcast': # If a broadcast is sent
data[1] = data[1][1:]
data[-1] = data[-1][:-1]
print data
if data[1] == '': continue
if data[1][0] == '<' or data[1][0] == '>':
if data[1][1:] not in s.variables:
s.variables[ data[1][1:] ] = ""
if data[1][0] == '>':
vari = data[1][1:]
value = s.variables[ vari ]
self.client.send( sendScratchCommand('sensor-update "'+vari+'" "'+value+'"') )
for follow in s.threads:
follow.follow_update(vari)
elif data[1][0] == '<':
vari = data[1][1:]
value = ' '.join( data[2:] )
s.variables[ vari ] = value
self.client.send( sendScratchCommand('sensor-update "'+vari+'" "'+value+'"') )
for follow in s.threads:
follow.follow_update(vari)
elif data[1][0] == '^':
vari = data[1][1:]
self.follow.append( vari )
else:
continue
else:
self.client.close() # Close the connection.
print self.address, 'has closed the connection.' # Debugging purposes and just informative if you are watching it.
running = 0
def follow_update(self, vari):
if vari in self.follow:
value = s.variables[ vari ]
self.client.send( sendScratchCommand('sensor-update "'+vari+'" "'+value+'"') )
self.client.send( sendScratchCommand('broadcast "^follow_update"') )
def parseScratchCommand(cmd):
cmd = cmd[4:] # Remove the first four letters ( it's annoying to deal with )
cmd = cmd.split(' ') # Split the string where there is a space. It helps to find out broadcasts.
return cmd # Return the list. ['broadcast/sensor-update', 'valueWord1', 'valueWord2']
def sendScratchCommand(cmd): # I was never sure what this did, but it's required.
n = len(cmd)
a = array('c')
a.append(chr((n >> 24) & 0xFF))
a.append(chr((n >> 16) & 0xFF))
a.append(chr((n >> 8) & 0xFF))
a.append(chr(n & 0xFF))
return (a.tostring() + cmd)
if __name__ == "__main__":
s = Server()
s.run()Broadcast Cheat Sheet:
^var = Follow var
>var = Get var
<var value = Set var to value
Basically send a broadcast with one of the special ( >/</^ ) characters at the beginning to set/get/follow a variable. Variables can only be one word long.
Could you test it and find bugs?
Last edited by Magnie (2011-12-01 19:40:21)
Offline
Pecola1 wrote:
flashgocrazy wrote:
here is about mesh
lets make a world wide mesh system that's easier to use and install.developers
flashgocrazy Director
we need..
a html designer
a php designer
a squeak/blocks designer
and somebody to write tutorials how to use/install
apply to be a dev in a reply!it would have ....
password protected wwms
php codding
and more!
if your a dev, post your code/tuts for wwm
down there!
|
|
|
UEver heard of Scratch Live? Its in claw, it basically posts variables online.
Then, you'd have to make the client in combined Claw and Panther.


Offline
Magnie wrote:
Okay, I have created the Scratch Live Clone for the Python Server:
Code:
# Scratch Server # Version 1.0.0 # By: Magnie import threading import socket import sys from array import array class Server: def __init__(self): # Server Information self.host = '' # Game host self.port = 42002 # Game port self.backlog = 5 # Maximum clients? self.size = 1024 # Maximum receive size self.server = None self.threads = [] # Client threads ( just a record ) self.variables = {} # user : value # Game Information def open_socket(self): try: # Try settings up the connection self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Define socket type self.server.bind((self.host,self.port)) # Bind server to port self.server.listen( self.backlog ) # Wait for clients to connect except socket.error, (value,message): # If it can't connect Then print out the error and shut down the server. if self.server: self.server.close() print "Could not open socket: " + message sys.exit(1) def run(self): self.open_socket() running = 1 id = 0 # To define each client. while running: id += 1 # Increase so no client has the same ID. c = Client(self.server.accept()) # Waits for a client then accepts it. c.start() # Starts it. self.threads.append(c) # Adds it to a list so the variable c and be used for the next client. # Disconnect all clients. self.server.close() # Disconnect socket. for c in self.threads: # For each thread c.join() # End that thread. class Client(threading.Thread): def __init__(self,(client,address)): threading.Thread.__init__(self) self.client = client self.address = address self.size = 1024 print self.address, 'has connected.' def run(self): running = 1 while running: data = self.client.recv(self.size) # Wait for data. data = parseScratchCommand(data) # Parse the data. print data # Print it if data[0] == 'sensor-update': # If a variable is updated continue elif data[0] == 'broadcast': # If a broadcast is sent data[1] = data[1][1:] data[-1] = data[-1][:-1] print data if data[1][0] == '<' or data[1][0] == '>': if data[1][1:] not in s.variables: s.variables[ data[1] ] = "" if data[1][0] == '>': vari = data[1][1:] value = s.variables[ vari ] self.client.send( sendScratchCommand('sensor-update "'+vari+'" '+value) ) elif data[1][0] == '<': vari = data[1][1:] value = ' '.join( data[2:] ) s.variables[ vari ] = value self.client.send( sendScratchCommand('sensor-update "'+vari+'" '+value) ) else: continue else: self.client.close() # Close the connection. print self.address, 'has closed the connection.' # Debugging purposes and just informative if you are watching it. running = 0 def parseScratchCommand(cmd): cmd = cmd[4:] # Remove the first four letters ( it's annoying to deal with ) cmd = cmd.split(' ') # Split the string where there is a space. It helps to find out broadcasts. return cmd # Return the list. ['broadcast/sensor-update', 'valueWord1', 'valueWord2'] def sendScratchCommand(cmd): # I was never sure what this did, but it's required. n = len(cmd) a = array('c') a.append(chr((n >> 24) & 0xFF)) a.append(chr((n >> 16) & 0xFF)) a.append(chr((n >> 8) & 0xFF)) a.append(chr(n & 0xFF)) return (a.tostring() + cmd) if __name__ == "__main__": s = Server() s.run()Will run on Windows and I see no reason it shouldn't on any other OS. You set variables by broadcasting "<var value" and you get variables with ">var". "<" set; ">" get. Now all I need to add it the "global broadcast" system, where if the user decides to "follow" a variable, then the user will be sent the update when it is updated.
This will probably be the hardest part.
Edit: Or it won't... Added "global broadcast" and fixed a few bugs in the first one:Code:
# Scratch Server # Version 1.0.0 # By: Magnie import threading import socket import sys from array import array class Server: def __init__(self): # Server Information self.host = '' # Game host self.port = 42002 # Game port self.backlog = 5 # Maximum clients? self.size = 1024 # Maximum receive size self.server = None self.threads = [] # Client threads ( just a record ) self.variables = {} # user : value # Game Information def open_socket(self): try: # Try settings up the connection self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Define socket type self.server.bind((self.host,self.port)) # Bind server to port self.server.listen( self.backlog ) # Wait for clients to connect except socket.error, (value,message): # If it can't connect Then print out the error and shut down the server. if self.server: self.server.close() print "Could not open socket: " + message sys.exit(1) def run(self): self.open_socket() running = 1 id = 0 # To define each client. while running: id += 1 # Increase so no client has the same ID. c = Client(self.server.accept()) # Waits for a client then accepts it. c.start() # Starts it. self.threads.append(c) # Adds it to a list so the variable c and be used for the next client. # Disconnect all clients. self.server.close() # Disconnect socket. for c in self.threads: # For each thread c.join() # End that thread. class Client(threading.Thread): def __init__(self,(client,address)): threading.Thread.__init__(self) self.client = client self.address = address self.size = 1024 self.follow = [] print self.address, 'has connected.' def run(self): running = 1 while running: data = self.client.recv(self.size) # Wait for data. data = parseScratchCommand(data) # Parse the data. print data # Print it if data[0] == 'sensor-update': # If a variable is updated continue elif data[0] == 'broadcast': # If a broadcast is sent data[1] = data[1][1:] data[-1] = data[-1][:-1] print data if data[1] == '': continue if data[1][0] == '<' or data[1][0] == '>': if data[1][1:] not in s.variables: s.variables[ data[1][1:] ] = "" if data[1][0] == '>': vari = data[1][1:] value = s.variables[ vari ] self.client.send( sendScratchCommand('sensor-update "'+vari+'" "'+value+'"') ) for follow in s.threads: follow.follow_update(vari) elif data[1][0] == '<': vari = data[1][1:] value = ' '.join( data[2:] ) s.variables[ vari ] = value self.client.send( sendScratchCommand('sensor-update "'+vari+'" "'+value+'"') ) for follow in s.threads: follow.follow_update(vari) elif data[1][0] == '^': vari = data[1][1:] self.follow.append( vari ) else: continue else: self.client.close() # Close the connection. print self.address, 'has closed the connection.' # Debugging purposes and just informative if you are watching it. running = 0 def follow_update(self, vari): if vari in self.follow: value = s.variables[ vari ] self.client.send( sendScratchCommand('sensor-update "'+vari+'" "'+value+'"') ) self.client.send( sendScratchCommand('broadcast "^follow_update"') ) def parseScratchCommand(cmd): cmd = cmd[4:] # Remove the first four letters ( it's annoying to deal with ) cmd = cmd.split(' ') # Split the string where there is a space. It helps to find out broadcasts. return cmd # Return the list. ['broadcast/sensor-update', 'valueWord1', 'valueWord2'] def sendScratchCommand(cmd): # I was never sure what this did, but it's required. n = len(cmd) a = array('c') a.append(chr((n >> 24) & 0xFF)) a.append(chr((n >> 16) & 0xFF)) a.append(chr((n >> 8) & 0xFF)) a.append(chr(n & 0xFF)) return (a.tostring() + cmd) if __name__ == "__main__": s = Server() s.run()Broadcast Cheat Sheet:
^var = Follow var
>var = Get var
<var value = Set var to value
Basically send a broadcast with one of the special ( >/</^ ) characters at the beginning to set/get/follow a variable. Variables can only be one word long.
Could you test it and find bugs?
I get the error:
Python Shell wrote:
Could not open socket: Only one usage of each socket address (protocol/network address/port) is normally permitted
Traceback (most recent call last):
File "C:/fakepath/slserver.py", line 134, in <module>
s.run()
File "C:/fakepath/slserver.py", line 36, in run
self.open_socket()
File "C:/fakepath/slserver.py", line 33, in open_socket
sys.exit(1)
SystemExit: 1
Offline
ohaiderstudios wrote:
I get the error:
Python Shell wrote:
Could not open socket: Only one usage of each socket address (protocol/network address/port) is normally permitted
Traceback (most recent call last):
File "C:/fakepath/slserver.py", line 134, in <module>
s.run()
File "C:/fakepath/slserver.py", line 36, in run
self.open_socket()
File "C:/fakepath/slserver.py", line 33, in open_socket
sys.exit(1)
SystemExit: 1
You are running a program using the same port ( 42002 ).
Offline
I'm working on a PHP program that will create custom Python code based on Magnie's original client and server codes, but switching out the generic variables that Magnie included (x, y, health, etc) with custom ones, like speed, direction, scrollX, etc, based on form input!
Offline
ohaiderstudios wrote:
I'm working on a PHP program that will create custom Python code based on Magnie's original client and server codes, but switching out the generic variables that Magnie included (x, y, health, etc) with custom ones, like speed, direction, scrollX, etc, based on form input!
Oh, that's cool.
Offline
Magnie wrote:
ohaiderstudios wrote:
I get the error:
Python Shell wrote:
Could not open socket: Only one usage of each socket address (protocol/network address/port) is normally permitted
Traceback (most recent call last):
File "C:/fakepath/slserver.py", line 134, in <module>
s.run()
File "C:/fakepath/slserver.py", line 36, in run
self.open_socket()
File "C:/fakepath/slserver.py", line 33, in open_socket
sys.exit(1)
SystemExit: 1You are running a program using the same port ( 42002 ).
Okay...how do I fix that? Does it involve me having a Panther project with Remote Sensor Connections enabled open at the same time as I run the module?
Offline
ohaiderstudios wrote:
Magnie wrote:
ohaiderstudios wrote:
I get the error:
You are running a program using the same port ( 42002 ).
Okay...how do I fix that? Does it involve me having a Panther project with Remote Sensor Connections enabled open at the same time as I run the module?
Not unless Panther is using 42002 as well. You are going to probably have to find the program that's using the same port.
Offline
Magnie wrote:
ohaiderstudios wrote:
Magnie wrote:
You are running a program using the same port ( 42002 ).Okay...how do I fix that? Does it involve me having a Panther project with Remote Sensor Connections enabled open at the same time as I run the module?
Not unless Panther is using 42002 as well. You are going to probably have to find the program that's using the same port.
Hold on...if a port isn't officially closed, say, from running one of your other Python modules, would that port still officially be open, even if the module is no longer running?
Offline
ohaiderstudios wrote:
Magnie wrote:
ohaiderstudios wrote:
Okay...how do I fix that? Does it involve me having a Panther project with Remote Sensor Connections enabled open at the same time as I run the module?Not unless Panther is using 42002 as well. You are going to probably have to find the program that's using the same port.
Hold on...if a port isn't officially closed, say, from running one of your other Python modules, would that port still officially be open, even if the module is no longer running?
Yeah, if you are already running one of my servers then you would probably need to close that first then run the other one. Or you can change the port to 42003 on the server and SHOST for the client.
Offline
So...
for my example project, it's pretty complicated. Basically, it's a kind of two-player battle engine, so players who are online are matched up with each other to compete. So I need a way to have the server match up unmatched users, and to control matched users' competitions at the same time.
I need a way to...
1) Tell if users are unmatched or matched (maybe using variables like "self.matched"?)
2) Tell if two unmatched users are online and match them
3) Control each individual game
Magnie (or someone else), please tell me the best way to go about doing this.
Offline
ohaiderstudios wrote:
So...
for my example project, it's pretty complicated. Basically, it's a kind of two-player battle engine, so players who are online are matched up with each other to compete. So I need a way to have the server match up unmatched users, and to control matched users' competitions at the same time.
I need a way to...
1) Tell if users are unmatched or matched (maybe using variables like "self.matched"?)
2) Tell if two unmatched users are online and match them
3) Control each individual game
Magnie (or someone else), please tell me the best way to go about doing this.
I think you are going in the right direction with the self.match variable. In the __init__ function of the Client class, I would do something like:
class Client(threading.Thread):
def __init__(self,(client,address)):
threading.Thread.__init__(self)
self.client = client
self.address = address
self.size = 1024
self.match = False # Set that the player is not in a match/has been matched up.
self.opponent = "" # Opponent the player will be facing.
for player in s.threads: # Goes through all the players and finds one that hasn't been matched up.
if player.match == False:
self.match = True
self.opponent = player
break # Not sure if this will break out of the loop though.
def run(self):
running = 1
while running:
data = self.client.recv(self.size) # Wait for data.
data = parseScratchCommand(data) # Parse the data.
if data[0] == 'sensor-update': # If a variable is updated
pass # Sensor-update control code
elif data[0] == 'broadcast': # If a broadcast is sent
pass # Broadcast control code
else:
self.client.close()
running = 0That's how I would probably match up players. Or the basic idea.
Offline
Magnie wrote:
ohaiderstudios wrote:
So...
for my example project, it's pretty complicated. Basically, it's a kind of two-player battle engine, so players who are online are matched up with each other to compete. So I need a way to have the server match up unmatched users, and to control matched users' competitions at the same time.
I need a way to...
1) Tell if users are unmatched or matched (maybe using variables like "self.matched"?)
2) Tell if two unmatched users are online and match them
3) Control each individual game
Magnie (or someone else), please tell me the best way to go about doing this.I think you are going in the right direction with the self.match variable. In the __init__ function of the Client class, I would do something like:
Code:
class Client(threading.Thread): def __init__(self,(client,address)): threading.Thread.__init__(self) self.client = client self.address = address self.size = 1024 self.match = False # Set that the player is not in a match/has been matched up. self.opponent = "" # Opponent the player will be facing. for player in s.threads: # Goes through all the players and finds one that hasn't been matched up. if player.match == False: self.match = True self.opponent = player break # Not sure if this will break out of the loop though. def run(self): running = 1 while running: data = self.client.recv(self.size) # Wait for data. data = parseScratchCommand(data) # Parse the data. if data[0] == 'sensor-update': # If a variable is updated pass # Sensor-update control code elif data[0] == 'broadcast': # If a broadcast is sent pass # Broadcast control code else: self.client.close() running = 0That's how I would probably match up players. Or the basic idea.
Thanks...I'm just about finished with my code generator! Expect it either in a little while, or about 18 hours, depending on if I finish it tonight, or tomorrow after school.
Offline