This is a read-only archive of the old Scratch 1.x Forums.
Try searching the current Scratch discussion forums.

#51 2011-12-01 13:47:28

Magnie
Scratcher
Registered: 2007-12-12
Posts: 1000+

Re: Lets make a wwm!!

ohaiderstudios wrote:

GAAAAHH!!! TOO MUCH RAW CODE!!! MY EYES!!!
jk  tongue
Alright, I'll try to understand all of this  smile

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

 

#52 2011-12-01 14:13:20

ohaiderstudios
Scratcher
Registered: 2010-10-31
Posts: 100+

Re: Lets make a wwm!!

Magnie wrote:

ohaiderstudios wrote:

GAAAAHH!!! TOO MUCH RAW CODE!!! MY EYES!!!
jk  tongue
Alright, I'll try to understand all of this  smile

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  big_smile


Fork Clamor on GitHub!

Offline

 

#53 2011-12-01 14:50:40

Magnie
Scratcher
Registered: 2007-12-12
Posts: 1000+

Re: Lets make a wwm!!

I just barely started modifying the code for the client:

Code:

# 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

 

#54 2011-12-01 15:14:21

Magnie
Scratcher
Registered: 2007-12-12
Posts: 1000+

Re: Lets make a wwm!!

Here is the server, most of the un-commented code in the client class should be self explanatory:

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 )

        # 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

 

#55 2011-12-01 15:36:28

ohaiderstudios
Scratcher
Registered: 2010-10-31
Posts: 100+

Re: Lets make a wwm!!

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!


Fork Clamor on GitHub!

Offline

 

#56 2011-12-01 15:40:48

ohaiderstudios
Scratcher
Registered: 2010-10-31
Posts: 100+

Re: Lets make a wwm!!

Code:

self.backlog = 5

So if I want, say, 10 people to be able to connect at a time, then I would change it to

Code:

self.backlog = 10

Right?


Fork Clamor on GitHub!

Offline

 

#57 2011-12-01 16:06:21

Magnie
Scratcher
Registered: 2007-12-12
Posts: 1000+

Re: Lets make a wwm!!

ohaiderstudios wrote:

Code:

self.backlog = 5

So if I want, say, 10 people to be able to connect at a time, then I would change it to

Code:

self.backlog = 10

Right?

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

 

#58 2011-12-01 17:30:57

ohaiderstudios
Scratcher
Registered: 2010-10-31
Posts: 100+

Re: Lets make a wwm!!

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 bases

now on to the server!

I'd like this error straightened out!  wink


Fork Clamor on GitHub!

Offline

 

#59 2011-12-01 17:31:56

flashgocrazy
Scratcher
Registered: 2011-01-12
Posts: 500+

Re: Lets make a wwm!!

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 bases

now on to the server!

what server


◕‿◕

Offline

 

#60 2011-12-01 17:36:34

Magnie
Scratcher
Registered: 2007-12-12
Posts: 1000+

Re: Lets make a wwm!!

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 bases

now on to the server!

I'd like this error straightened out!  wink

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.

Offline

 

#61 2011-12-01 18:45:01

ohaiderstudios
Scratcher
Registered: 2010-10-31
Posts: 100+

Re: Lets make a wwm!!

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!  wink

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!


Fork Clamor on GitHub!

Offline

 

#62 2011-12-01 18:46:06

ohaiderstudios
Scratcher
Registered: 2010-10-31
Posts: 100+

Re: Lets make a wwm!!

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 bases

now on to the server!

what server

The Python code that Magnie posted for the server.


Fork Clamor on GitHub!

Offline

 

#63 2011-12-01 19:06:36

Magnie
Scratcher
Registered: 2007-12-12
Posts: 1000+

Re: Lets make a wwm!!

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.  smile  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?

Last edited by Magnie (2011-12-01 19:40:21)

Offline

 

#64 2011-12-01 19:42:34

cocolover76
Scratcher
Registered: 2011-10-09
Posts: 500+

Re: Lets make a wwm!!

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!
|
|
|
U

Ever 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.


http://i.imgur.com/HfEPZ.gifhttp://i.imgur.com/pvKb6.png

Offline

 

#65 2011-12-01 19:48:55

ohaiderstudios
Scratcher
Registered: 2010-10-31
Posts: 100+

Re: Lets make a wwm!!

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.  smile  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


Fork Clamor on GitHub!

Offline

 

#66 2011-12-01 19:53:37

Magnie
Scratcher
Registered: 2007-12-12
Posts: 1000+

Re: Lets make a wwm!!

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

 

#67 2011-12-01 19:55:43

ohaiderstudios
Scratcher
Registered: 2010-10-31
Posts: 100+

Re: Lets make a wwm!!

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!


Fork Clamor on GitHub!

Offline

 

#68 2011-12-01 19:56:46

Magnie
Scratcher
Registered: 2007-12-12
Posts: 1000+

Re: Lets make a wwm!!

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

 

#69 2011-12-01 19:57:43

ohaiderstudios
Scratcher
Registered: 2010-10-31
Posts: 100+

Re: Lets make a wwm!!

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: 1

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?


Fork Clamor on GitHub!

Offline

 

#70 2011-12-01 20:00:03

Magnie
Scratcher
Registered: 2007-12-12
Posts: 1000+

Re: Lets make a wwm!!

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

 

#71 2011-12-01 20:03:48

ohaiderstudios
Scratcher
Registered: 2010-10-31
Posts: 100+

Re: Lets make a wwm!!

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?


Fork Clamor on GitHub!

Offline

 

#72 2011-12-01 20:06:09

Magnie
Scratcher
Registered: 2007-12-12
Posts: 1000+

Re: Lets make a wwm!!

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

 

#73 2011-12-01 23:19:59

ohaiderstudios
Scratcher
Registered: 2010-10-31
Posts: 100+

Re: Lets make a wwm!!

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.


Fork Clamor on GitHub!

Offline

 

#74 2011-12-02 00:15:36

Magnie
Scratcher
Registered: 2007-12-12
Posts: 1000+

Re: Lets make a wwm!!

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 = 0

That's how I would probably match up players. Or the basic idea.

Offline

 

#75 2011-12-02 00:33:02

ohaiderstudios
Scratcher
Registered: 2010-10-31
Posts: 100+

Re: Lets make a wwm!!

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 = 0

That'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.


Fork Clamor on GitHub!

Offline

 

Board footer