From: <Blu...@us...> - 2010-08-01 22:16:26
|
Revision: 351 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=351&view=rev Author: BlueWolf_ Date: 2010-08-01 22:16:19 +0000 (Sun, 01 Aug 2010) Log Message: ----------- Code is still the same but I changed all tabs. 8 tabs are now 4 spaces. Modified Paths: -------------- trunk/client/VP.py trunk/client/core/__init__.py trunk/client/core/callback.py trunk/client/core/client.py trunk/client/core/parser.py trunk/client/functions.py trunk/client/gui.py trunk/client/layout.py trunk/client/playground.py trunk/client/windows.py Modified: trunk/client/VP.py =================================================================== --- trunk/client/VP.py 2010-08-01 21:27:14 UTC (rev 350) +++ trunk/client/VP.py 2010-08-01 22:16:19 UTC (rev 351) @@ -1,5 +1,22 @@ #!/usr/bin/env python +## This file is part of Virtual Playground +## Copyright (c) 2009 Jos Ratsma + Koen Koning + +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either +## version 2 of the License, or (at your option) any later version. + +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. + +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + from functions import * import core @@ -10,138 +27,135 @@ class Main(): - def __init__(self): - self.sh = {} - - # Fire up pygame - os.environ['SDL_VIDEO_CENTERED']='1' - pygame.init() - pygame.display.set_caption('Virtual Playground') - self.sh['screen'] = pygame.display.set_mode((1000, 700)) - #icon = load_image('img','icon.png') - #pygame.display.set_icon(icon) - pygame.key.set_repeat(250, 40) - pygame.scrap.init() - self.clock = pygame.time.Clock() - - self.sh['main'] = self - - # Give the surfaces a way to blit itself - self.sh['update'] = self.update - self.updaterect = [] - self.updatewaiting = False - - - # Create all our surfaces - self.sh['playground'] = Playground(self.sh) - self.sh['layout'] = Layout(self.sh) - self.sh['windows'] = Windows(self.sh) - - self.update() - - - # Connect to the server - self.sh['client'] = core.Client({ - 'app_name': "Virtual Playground", - 'app_version': VERSION}, - Callback(self.sh)) - - self.changestatus("connecting") - self.sh['client'].connect('localhost', 6653) - - - # Wait for all the events to come - try: - while 1: - ev = pygame.event.wait() - - if ev.type == QUIT: break - - if ev.type == MOUSEMOTION: - pos = pygame.mouse.get_pos() - pygame.event.clear(MOUSEMOTION) - - # Send through all the layers - if self.sh['windows'].event(ev): continue - if self.sh['layout'].event(ev): continue - if self.sh['playground'].event(ev): continue - - - except KeyboardInterrupt: # Note: this does not work properly - print - - # Someone decided to close VP (Why??) - try: self.sh['client'].close() - except: pass - sys.exit() - + def __init__(self): + self.sh = {} + + # Fire up pygame + os.environ['SDL_VIDEO_CENTERED']='1' + pygame.init() + pygame.display.set_caption('Virtual Playground') + self.sh['screen'] = pygame.display.set_mode((1000, 700)) + #icon = load_image('img','icon.png') + #pygame.display.set_icon(icon) + pygame.key.set_repeat(250, 40) + pygame.scrap.init() + self.clock = pygame.time.Clock() + + self.sh['main'] = self + + # Give the surfaces a way to blit itself + self.sh['update'] = self.update + self.updaterect = [] + self.updatewaiting = False + + + # Create all our surfaces + self.sh['playground'] = Playground(self.sh) + self.sh['layout'] = Layout(self.sh) + self.sh['windows'] = Windows(self.sh) + + self.update() + + + # Connect to the server + self.sh['client'] = core.Client({ + 'app_name': "Virtual Playground", + 'app_version': VERSION}, + Callback(self.sh)) + + self.changestatus("connecting") + self.sh['client'].connect('localhost', 6653) + + + # Wait for all the events to come + try: + while 1: + ev = pygame.event.wait() + + if ev.type == QUIT: break + + if ev.type == MOUSEMOTION: + pos = pygame.mouse.get_pos() + pygame.event.clear(MOUSEMOTION) + + # Send through all the layers + if self.sh['windows'].event(ev): continue + if self.sh['layout'].event(ev): continue + if self.sh['playground'].event(ev): continue + + + except KeyboardInterrupt: # Note: this does not work properly + print + + # Someone decided to close VP (Why??) + try: self.sh['client'].close() + except: pass + sys.exit() + - def update(self, rect = Rect(0,0, 1000, 700)): - """ - Blit all the surfaces (playground, layout and windows) together - and update the screen - """ - - # The following code will prevent it from going crazy on the cpu - # aka: using unlimited FPS. This will limit the FPS to 50 and - # will remember everything that should be updated in the mean - # time - - self.updaterect.append(rect) - if self.updatewaiting: - # Rect is saved. Will be updated once self.clock stops - # blocking - return - - # When there are more updates from here one, they will be saved - # without being updated immediately. We will do that once tick - # stops blocking - self.updatewaiting = True - self.clock.tick(50) - - # Get all the rects to update - if len(self.updaterect) == 1: - rects = self.updaterect[0] - else: - rects = self.updaterect[0].unionall(self.updaterect[1:]) - - self.updaterect = [] - self.updatewaiting = False - - - # The actual updating happens here - self.sh['screen'].blit(self.sh['playground'].surf, rect, rect) - self.sh['screen'].blit(self.sh['layout'].surf, rect, rect) - self.sh['screen'].blit(self.sh['windows'].surf, rect, rect) - - pygame.display.update(rect) - - def changestatus(self, status): - self.sh['playground'].changestatus(status) - self.sh['layout'].changestatus(status) - self.sh['windows'].changestatus(status) + def update(self, rect = Rect(0,0, 1000, 700)): + """ + Blit all the surfaces (playground, layout and windows) together + and update the screen + """ + + # The following code will prevent it from going crazy on the cpu. + # aka: using unlimited FPS. This will limit the FPS to 50 and will + # remember everything that should be updated in the mean time + + self.updaterect.append(rect) + if self.updatewaiting: + # Rect is saved. Will be updated once self.clock stops blocking + return + + # When there are more updates from here one, they will be saved without + # being updated immediately. We will do that once tick stops blocking + self.updatewaiting = True + self.clock.tick(50) + + # Get all the rects to update + if len(self.updaterect) == 1: + rects = self.updaterect[0] + else: + rects = self.updaterect[0].unionall(self.updaterect[1:]) + + self.updaterect = [] + self.updatewaiting = False + + + # The actual updating happens here + self.sh['screen'].blit(self.sh['playground'].surf, rect, rect) + self.sh['screen'].blit(self.sh['layout'].surf, rect, rect) + self.sh['screen'].blit(self.sh['windows'].surf, rect, rect) + + pygame.display.update(rect) + + def changestatus(self, status): + self.sh['playground'].changestatus(status) + self.sh['layout'].changestatus(status) + self.sh['windows'].changestatus(status) class Callback(core.Callback): - def __init__(self, sh): - self.sh = sh - - def data_received(self, data): - print " --> " + repr(data) - - def data_send(self, data): - print " <-- " + repr(data) - - def disconnect(self, reason): - print "Server disconnected: " + reason - - def received_rsa(self, public): - # We are connected - self.sh['main'].changestatus("login") - - def logged_in(self, username, cid, owner): - self.sh['main'].changestatus("playground") + def __init__(self, sh): + self.sh = sh + + def data_received(self, data): + print " --> " + repr(data) + + def data_send(self, data): + print " <-- " + repr(data) + + def disconnect(self, reason): + print "Server disconnected: " + reason + + def received_rsa(self, public): + # We are connected + self.sh['main'].changestatus("login") + + def logged_in(self, username, cid, owner): + self.sh['main'].changestatus("playground") if __name__ == "__main__": Main() Modified: trunk/client/core/__init__.py =================================================================== --- trunk/client/core/__init__.py 2010-08-01 21:27:14 UTC (rev 350) +++ trunk/client/core/__init__.py 2010-08-01 22:16:19 UTC (rev 351) @@ -28,10 +28,10 @@ The Client is the core. You need to create your own callback class, which should inherit the functions of Callback. You get feedback from your callback-class. >>> class callback(Callback): -... def connect(self): -... print "Connect!" -... def logged_in(self, username, uid, cid): - print "I'm logged in!" +... def connect(self): +... print "Connect!" +... def logged_in(self, username, uid, cid): + print "I'm logged in!" Because it inherits all the (empty) functions from Callback, you don't have to create all the functions yourself. Also, in help(Callback) you see all possible @@ -40,14 +40,14 @@ The next thing is the config. See help(Client) for all the available config-options. >>> config = { -... "app_name": "My awesome application", -... "app_version": "2.0" +... "app_name": "My awesome application", +... "app_version": "2.0" ... } Start the core. >>> client = Client(config, callback()) >>> client.connect("my.host.com", 1234, "Username", \ -... sha.new("Password").hexdigest()) +... sha.new("Password").hexdigest()) If you have the server online and your login is correct, it will print: Connect! Modified: trunk/client/core/callback.py =================================================================== --- trunk/client/core/callback.py 2010-08-01 21:27:14 UTC (rev 350) +++ trunk/client/core/callback.py 2010-08-01 22:16:19 UTC (rev 351) @@ -16,134 +16,126 @@ ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. class Callback: - def connected(self): - """ - When the connection is made, this will be called. Note that the - server can still kick the connection because it is full. You - should not client.login here, because the server still has to - send a rsa-key. See callback.received_rsa for this event. + def connected(self): + """ + When the connection is made, this will be called. Note that the server + can still kick the connection because it is full. You should not + client.login here, because the server still has to send a rsa-key. See + callback.received_rsa for this event. - This is a placeholder. If you want to catch this event, - overwrite this in your own callback - """ - pass - - def received_rsa(self, public): - """ - When a connection is made, the server will generate a rsa-key. - The client has to wait for this, before logging in. After this - event, you can use client.login (if you haven't specified a - login at client.connect) - - public: - The generated public rsa-key. It is a dict with 2 - values: e and n. It's used for encoding the password - - - This is a placeholder. If you want to catch this event, - overwrite this in your own callback - """ - pass - - def disconnected(self, reason): - """ - This is called when the connection dies. For example when you - close the connection manually, the server kicks you, your modem - explodes or your cat eates the LAN cable. - - reason: - A string, representing the reason why it disconnected. - It currently has these options: - * "closed" - Server dropped the connection - unexpectedly - * "full" - Server is full and does not except - - more connections - * "manual" - Client (you) closed the connection - with .close() - * "duplicate" - Another client has logged in on this - account. This connection has been - kicked - * "crash" - A crash happened on the server. Unless - you sent malicious data or you're not - admin of the server, there's nothing - you can do about it - * "gone offline"- The server has just gone offline - - - Return True if you want it to reconnect. To avoid unexpected - behaviour, you should *only* do this when reason is "closed" or - "gone offline"! - If you provided the login in client.connect, it logs in - automatically. - - This is a placeholder. If you want to catch this event, - overwrite this in your own callback - """ - pass - - def data_received(self, data): - """ - Called when we received data from the server. Normally, you - don't need this. - - data: - Dict with the data that has been received - - - This is a placeholder. If you want to catch this event, - overwrite this in your own callback - """ - pass - - def data_send(self, data): - """ - Called when we send data to the server. Normally, you - don't need this. - - data: - Dict with the data that will be send. - - - This is a placeholder. If you want to catch this event, - overwrite this in your own callback - """ - pass - - def logged_in(self, username, cid, owner): - """ - Called when we are logged in. - - username: - The username for this user. Use this, instead what the - user typed in, because this has the right caps. Also - available in client.username. - cid: - The unique client-id for this connection. Also available - in client.cid - owner: - This is the owner-username for this bot. This variable - will be None when you log in as a normal user - - This is a placeholder. If you want to catch this event, - overwrite this in your own callback - """ - - pass - - def failed_logging_in(self, reason): - """ - This happens when the user could not log in. You can safely use - client.login again. - - reason: - The reason why the user could not log in: - * "bad login" - The username and/or password is wrong. - * "login not allowed" - You may not log in right now - * "bot limit reached" - There're to much bots logged - in for your account - * "login blocked" - You (or your IP) are blocked - * "duplicate user" - There is already someone - online with this username - """ - - pass + This is a placeholder. If you want to catch this event, overwrite this + in your own callback + """ + pass + + def received_rsa(self, public): + """ + When a connection is made, the server will generate a rsa-key. The + client has to wait for this, before logging in. After this event, you + can use client.login (if you haven't specified a login at client.connect) + + public: + The generated public rsa-key. It is a dict with 2 values: e and n. + It's used for encoding the password + + + This is a placeholder. If you want to catch this event, overwrite this + in your own callback + """ + pass + + def disconnected(self, reason): + """ + This is called when the connection dies. For example when you close the + connection manually, the server kicks you, your modem explodes or your + cat ate the LAN cable. + + reason: + A string, representing the reason why it disconnected. + It currently has these options: + * "closed" - Server dropped the connection unexpectedly + * "full" - Server is full and does not except more + connections + * "manual" - Client (you) closed the connection with .close() + * "duplicate" - Another client has logged in on this account. + This connection has been kicked + * "crash" - A crash happened on the server. Unless you sent + malicious data or you're not admin of the server, + there's nothing you can do about it. Live with it. + * "gone offline"- The server has just gone offline + + + Return True if you want it to reconnect. To avoid unexpected behaviour, + you should *only* do this when reason is "closed" or "gone offline"! If + you provided the login in client.connect, it logs in automatically. + + This is a placeholder. If you want to catch this event, overwrite this + in your own callback + """ + pass + + def data_received(self, data): + """ + Called when we received data from the server. Normally, you don't need + this. + + data: + Dict with the data that has been received + + + This is a placeholder. If you want to catch this event, overwrite this + in your own callback + """ + pass + + def data_send(self, data): + """ + Called when we send data to the server. Normally, you don't need this. + + data: + Dict with the data that will be send. + + + This is a placeholder. If you want to catch this event, overwrite this + in your own callback + """ + pass + + def logged_in(self, username, cid, owner): + """ + Called when we are logged in. + + username: + The username for this user. Use this, instead what the user typed + in, because this has the right caps. Also available in + client.username + cid: + The unique client-id for this connection. Also available in + client.cid + owner: + This is the owner-username for this bot. This variable will be None + when you log in as a normal user + + This is a placeholder. If you want to catch this event, overwrite this + in your own callback + """ + + pass + + def failed_logging_in(self, reason): + """ + This happens when the user could not log in. You can safely use + client.login again + + reason: + The reason why the user could not log in: + * "bad login" - The username and/or password is wrong. + * "login not allowed" - You may not log in right now + * "bot limit reached" - There're to much bots logged in for + your account + * "login blocked" - You (or your IP) are blocked + * "duplicate user" - There is already someone online with + this username + """ + + pass Modified: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py 2010-08-01 21:27:14 UTC (rev 350) +++ trunk/client/core/client.py 2010-08-01 22:16:19 UTC (rev 351) @@ -24,356 +24,350 @@ class Client(threading.Thread): - """ - This is the client-core for Virtual Playground. This will handle the - connections and data to and from the server. - - config: - This should be a dict with settings for the client. See the - bottom of this documentation for a list of all possible - settings. - - callback_class: - The callback class will be used to notify you for certain events - that happens in the core. It has to look something like this: - - class Callback(core.Callback): - ... - - See the doc in core.Callback for more information about this. - - -------- - - The settings: - -app_name - The name of your program. Will be send when logging in. - -app_version - The version of your program. Will be send when logging - in. Should be a string. - """ - - def __init__(self, config, callback_class): - - self.__call = callback_class - self.__sock = None - self.__pinger = None - - # This will be available ([sh]ared) to al modules in the core - self.__sh = {} - - self.__sh['call'] = callback_class - self.__sh['core'] = self - self.__sh['isbot'] = None - - # Create all default settings - self.__config_default(config) - self.__sh['config'] = config - - # So the client knows if we are online. Is used for - # disconnecting - self.__sh['is_online'] = False - - # Treading-event so that run() waits before it's allowed to - # connect - self.__do_connect = threading.Event() - self.__do_connect.clear() - - # Auto log in after connecting. - self.__sh['auto_login'] = () - - # RSA - self.__sh['rsakey'] = None - - # Info after logging in - self.username = None - self.owner = None - self.cid = None # Connection-id - - # Class that parsers all incomming data - self.__parse = Parser(self.__sh) - - threading.Thread.__init__(self) - - self.setDaemon(True) - self.start() - - - def __config_default(self, config): - config['app_name'] = str(config.get('app_name', __name__)) - config['app_version'] = str(config.get('app_version', - __version__)) - - - def connect(self, host, port): - """ - Will (try to) connect to the server on `host`:`port`. - If you want to reconnect, you have to close the connection - first, if it's still open. - - You can do Client.login and Client.bot_login directly after - this. It will be done as soon as it has received a rsa-key. - """ - - self.__host = host - self.__port = port - - if self.__sock: - raise ConnectionError("You are already connected!") - - self.__do_connect.set() # Releasing the hounds - - - def run(self): - """ - Used by threading, not for external usage. - """ - while 1: - self.__do_connect.wait() # Wait to connect - - self.__sh['is_online'] = True - disconnect_reason = None - - self.__sock = socket.socket(socket.AF_INET, - socket.SOCK_STREAM) - - while 1: - try: - self.__sock.connect((self.__host, - self.__port)) - break - except: - time.sleep(1) - - self.__call.connected() - - self.__pinger = self.__Pinger(self.send) + """ + This is the client-core for Virtual Playground. This will handle the + connections and data to and from the server. + + config: + This should be a dict with settings for the client. See the bottom of + this documentation for a list of all possible settings. + + callback_class: + The callback class will be used to notify you for certain events that + happens in the core. It has to look something like this: + + class Callback(core.Callback): + ... + + See the doc in core.Callback for more information about this. + + -------- + + The settings: + -app_name + The name of your program. Will be send when logging in. + -app_version + The version of your program. Will be send when logging + in. Should be a string. + """ + + def __init__(self, config, callback_class): + + self.__call = callback_class + self.__sock = None + self.__pinger = None + + # This will be available ([sh]ared) to al modules in the core + self.__sh = {} + + self.__sh['call'] = callback_class + self.__sh['core'] = self + self.__sh['isbot'] = None + + # Create all default settings + self.__config_default(config) + self.__sh['config'] = config + + # So the client knows if we are online. Is used for + # disconnecting + self.__sh['is_online'] = False + + # Treading-event so that run() waits before it's allowed to connect + self.__do_connect = threading.Event() + self.__do_connect.clear() + + # Auto log in after connecting. + self.__sh['auto_login'] = () + + # RSA + self.__sh['rsakey'] = None + + # Info after logging in + self.username = None + self.owner = None + self.cid = None # Connection-id + + # Class that parsers all incomming data + self.__parse = Parser(self.__sh) + + threading.Thread.__init__(self) + + self.setDaemon(True) + self.start() + + + def __config_default(self, config): + config['app_name'] = str(config.get('app_name', __name__)) + config['app_version'] = str(config.get('app_version', __version__)) + + + def connect(self, host, port): + """ + Will (try to) connect to the server on `host`:`port`. If you want to + reconnect, you have to close the connection first, if it's still open. + + You can do Client.login and Client.bot_login directly after this. It + will be done as soon as it has received a rsa-key. + """ + + self.__host = host + self.__port = port + + if self.__sock: + raise ConnectionError("You are already connected!") + + self.__do_connect.set() # Releasing the hounds + + + def run(self): + """ + Used by threading, not for external usage. + """ + while 1: + self.__do_connect.wait() # Wait to connect + + self.__sh['is_online'] = True + disconnect_reason = None + + self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + while 1: + try: + self.__sock.connect((self.__host, self.__port)) + break + except: + time.sleep(1) + + self.__call.connected() + + self.__pinger = self.__Pinger(self.send) - - #Infinite loop that receives data - buffer = '' - while 1: - try: - data = self.__sock.recv(1024) - except: - disconnect_reason = "closed" - break - if not data: - disconnect_reason = "closed" - break - - buffer += data - - #Each dataset must end with a delimiter: chr(1) - if chr(1) not in buffer: continue - - data = buffer.split(chr(1)) - buffer = data[-1] - data = data[:-1] - - for msg in data: - self.__parse(simplejson.loads(msg)) - - if self.__sh['is_online']: - self.close(disconnect_reason) - - def login(self, usr, pwd): - """ - Log in to the server as a normal user. If the RSA-key wasn't - received yet, it will login after is has received the key. pwd - is expected to be sha1. - - >>> import hashlib - >>> hashlib.sha1("MyVerySecretPassword").hexdigest() - 'dc2275e9f1e53926dce503ec7d9df9ac9ce07dfc' - """ - - if self.cid != None: - raise LoginError("You are already logged in") - - # Save this - self.__sh['auto_login'] = (self.login, (usr, pwd)) - - # Wait for the rsa-key to arrive - if not self.__sh['rsakey']: return - - if not self.__sock: - raise ConnectionError("You are not connected!") - - self.__sh['isbot'] = False - - # Convert pwd - pwd = rsa.encrypt(pwd, self.__sh['rsakey']) - - # Log in - self.send("login", { - "usr": usr, - "pwd": pwd, - "bot": False, - "for": "VP", - "client": ( self.__sh['config']['app_name'], - self.__sh['config']['app_version'] - ), - "version": __version__ - }) - - def login_bot(self, owner, pwd, screenname): - """ - Log in as a bot. If the RSA-key wasn't received yet, it will - login after is has received the key. pwd is expected to be sha1. - - >>> import hashlib - >>> hashlib.sha1("MyVerySecretPassword").hexdigest() - 'dc2275e9f1e53926dce503ec7d9df9ac9ce07dfc' - """ - - if self.cid != None: - raise LoginError("You are already logged in") - - # Save this - self.__sh['auto_login'] = (self.login_bot, \ - (owner, pwd, screenname)) - - # Wait for the rsa-key to arrive - if not self.__sh['rsakey']: return - - if not self.__sock: - raise ConnectionError("You are not connected!") - - self.__sh['isbot'] = True - - # Convert pwd - pwd = rsa.encrypt(pwd, self.__sh['rsakey']) - - # Log in - self.send("login", { - "usr": owner, - "pwd": pwd, - "name": screenname, - "bot": True, - "for": "VP", - "client": ( self.__sh['config']['app_name'], - self.__sh['config']['app_version'] - ), - "version": __version__ - }) - - - def signup(self, usr, pwd, extra = {}): - """ - Create a new account with on the server. You should have a - connection first before using this. - """ - - # Convert pwd - pwd = rsa.encrypt(pwd, self.__sh['rsakey']) - - if self.cid != None: - raise SignupError("You are already logged in") - - - # Sign up - self.send("signup", { - "usr": usr, - "pwd": pwd, - "extra": extra - }) - - - - def send(self, data_header, data_body = {}): - """ - Sends `data_body` of type `data_header` to the server. It will - automatically be encoded as JSON, and the delimeter character - (chr(1)) will be send automatically too. - `Data_header` is a string, `data_body` a dict. - """ - - self.__call.data_send({data_header:data_body}) - data = simplejson.dumps({data_header:data_body}) - try: - self.__sock.send(data + chr(1)) - except: pass - - - def close(self, reason = "manual"): - """ - Will close the connection to the server. If the connection is - already down, it will raise an exception. This will trigger the - callback `disconnected`. It may reconnect, depending on the - callback. If not, you can reuse this class by calling `connect`. - """ - - if not self.__sh['is_online']: - if reason == "manual": - # Annoy the user - raise ConnectionError("The connection is " + \ - "already closed!") - else: - return; - - - self.__do_connect.clear() # Block the thread-loop - - self.__sh['is_online'] = False - - if self.__pinger != None: - self.__pinger.cancel() - self.__pinger = None - - # Reset variables - self.__sh['rsakey'] = None - self.username = None - self.owner = None - self.cid = None - - try: self.__sock.shutdown(0) - except: pass - self.__sock.close() - self.__sock = None - - if self.__call.disconnected(reason): - # Reconnect - self.__do_connect.set() - else: - # Remove auto-login - self.__sh['auto_login'] = () - - - class __Pinger(): - def __init__(self, send): - """ - Will ping every 30 seconds for food. If the server - doesn't receive anything from us for 45 sec, it will - drop the connection, because it thinks our computer blew - up or something... - """ - self.running = True + + #Infinite loop that receives data + buffer = '' + while 1: + try: + data = self.__sock.recv(1024) + except: + disconnect_reason = "closed" + break + if not data: + disconnect_reason = "closed" + break + + buffer += data + + #Each dataset must end with a delimiter: chr(1) + if chr(1) not in buffer: continue + + data = buffer.split(chr(1)) + buffer = data[-1] + data = data[:-1] + + for msg in data: + self.__parse(simplejson.loads(msg)) + + if self.__sh['is_online']: + self.close(disconnect_reason) + + def login(self, usr, pwd): + """ + Log in to the server as a normal user. If the RSA-key wasn't received + yet, it will login after is has received the key. pwd is expected to be sha1. + + >>> import hashlib + >>> hashlib.sha1("MyVerySecretPassword").hexdigest() + 'dc2275e9f1e53926dce503ec7d9df9ac9ce07dfc' + """ + + if self.cid != None: + raise LoginError("You are already logged in") + + # Save this + self.__sh['auto_login'] = (self.login, (usr, pwd)) + + # Wait for the rsa-key to arrive + if not self.__sh['rsakey']: return + + if not self.__sock: + raise ConnectionError("You are not connected!") + + self.__sh['isbot'] = False + + # Convert pwd + pwd = rsa.encrypt(pwd, self.__sh['rsakey']) + + # Log in + self.send("login", { + "usr": usr, + "pwd": pwd, + "bot": False, + "for": "VP", + "client": ( + self.__sh['config']['app_name'], + self.__sh['config']['app_version'] + ), + "version": __version__ + }) + + def login_bot(self, owner, pwd, screenname): + """ + Log in as a bot. If the RSA-key wasn't received yet, it will login after + is has received the key. pwd is expected to be sha1. + + >>> import hashlib + >>> hashlib.sha1("MyVerySecretPassword").hexdigest() + 'dc2275e9f1e53926dce503ec7d9df9ac9ce07dfc' + """ + + if self.cid != None: + raise LoginError("You are already logged in") + + # Save this + self.__sh['auto_login'] = (self.login_bot, (owner, pwd, screenname)) + + # Wait for the rsa-key to arrive + if not self.__sh['rsakey']: return + + if not self.__sock: + raise ConnectionError("You are not connected!") + + self.__sh['isbot'] = True + + # Convert pwd + pwd = rsa.encrypt(pwd, self.__sh['rsakey']) + + # Log in + self.send("login", { + "usr": owner, + "pwd": pwd, + "name": screenname, + "bot": True, + "for": "VP", + "client": ( + self.__sh['config']['app_name'], + self.__sh['config']['app_version'] + ), + "version": __version__ + }) + + + def signup(self, usr, pwd, extra = {}): + """ + Create a new account with on the server. You should have a connection + first before using this. + """ + + # Convert pwd + pwd = rsa.encrypt(pwd, self.__sh['rsakey']) + + if self.cid != None: + raise SignupError("You are already logged in") + + + # Sign up + self.send("signup", { + "usr": usr, + "pwd": pwd, + "extra": extra, + "version": __version__ + }) + + + + def send(self, data_header, data_body = {}): + """ + Sends `data_body` of type `data_header` to the server. It will + automatically be encoded as JSON, and the delimeter character (chr(1)) + will be send automatically too. `Data_header` is a string, `data_body` + a dict. + """ + + self.__call.data_send({data_header:data_body}) + data = simplejson.dumps({data_header:data_body}) + try: + self.__sock.send(data + chr(1)) + except: pass + + + def close(self, reason = "manual"): + """ + Will close the connection to the server. If the connection is already + down, it will raise an exception. This will trigger the callback + `disconnected`. It may reconnect, depending on the callback. If not, you + can reuse this class by calling `connect`. + """ + + if not self.__sh['is_online']: + if reason == "manual": + # Annoy the user + raise ConnectionError("The connection is " + \ + "already closed!") + else: + return; + + + self.__do_connect.clear() # Block the thread-loop + + self.__sh['is_online'] = False + + if self.__pinger != None: + self.__pinger.cancel() + self.__pinger = None + + # Reset variables + self.__sh['rsakey'] = None + self.username = None + self.owner = None + self.cid = None + + try: self.__sock.shutdown(0) + except: pass + self.__sock.close() + self.__sock = None + + if self.__call.disconnected(reason): + # Reconnect + self.__do_connect.set() + else: + # Remove auto-login + self.__sh['auto_login'] = () + + + class __Pinger(): + def __init__(self, send): + """ + Will ping every 30 seconds for food. If the server doesn't receive + anything from us for 45 sec, it will drop the connection, because it + thinks our computer blew up or something... + """ + self.running = True - self.send = send - self.timer = threading.Timer(30, self.run) - self.timer.start() + self.send = send + self.timer = threading.Timer(30, self.run) + self.timer.start() - def run(self): - if self.running == False: return + def run(self): + if self.running == False: return - #Ping! - self.send('ping', {}) + #Ping! + self.send('ping', {}) - #Start again - self.timer = threading.Timer(30, self.run) - self.timer.start() + #Start again + self.timer = threading.Timer(30, self.run) + self.timer.start() - def cancel(self): - if self.running: - self.timer.cancel() - self.running = False + def cancel(self): + if self.running: + self.timer.cancel() + self.running = False class ConnectionError(Exception): - pass + pass class LoginError(Exception): - pass - + pass + class SignupError(Exception): - pass + pass Modified: trunk/client/core/parser.py =================================================================== --- trunk/client/core/parser.py 2010-08-01 21:27:14 UTC (rev 350) +++ trunk/client/core/parser.py 2010-08-01 22:16:19 UTC (rev 351) @@ -16,146 +16,142 @@ ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. class Parser(): - def __init__(self, sh): - """ - This class parses all received messages from the server. - """ - self.sh = sh - self.call = sh['call'] - self.core = sh['core'] - - def __call__(self, msg): - self.call.data_received(msg) - - head = msg.keys()[0] - body = msg[head] - - func = getattr(self, str(head), None) - if (func): - func(body) - - def disconnect(self, msg): - """ - Called just before the server closes our connection. - * reason - Why the server disconnected us - "full" - Because the server is full - "duplicate" - Because another client has logged in - on the same account - "crash" - The server-parser has made a crash - "gone offline" - Server has just shutdown - """ - - self.core.close(msg["reason"]) - - def rsa(self, msg): - """ - Called when the connection has been made and a rsa-key has been - generated. We can now log in using this key - * public - The public rsa-key, which contains e & n - """ - - self.sh['rsakey'] = msg['public'] - - self.call.received_rsa(msg['public']) - - if self.core.cid == None and \ - self.sh['auto_login'] != (): - login = self.sh['auto_login'] - login[0](*login[1]) - - - def login(self, msg): - """ - Called when we can log in - * username - The username (with right caps) - * cid - The server's connection-id - * owner - The owner for this bot (only when logging in - as bot!) - """ - - if self.sh['isbot']: # Logging in as bot - self.core.owner = msg['owner'] - self.core.username = msg['username'] - self.core.cid = msg['cid'] - - self.call.logged_in(msg['username'], msg['cid'], - msg['owner']) - - else: # Logging in as user - self.core.username = msg['username'] - self.core.cid = msg['cid'] - - self.call.logged_in(msg['username'], msg['cid'], None) - - - def userlist(self, msg): - """ - Called after we've logged it. This contains a list with all - online users. This is a _list_ with: - * cid - The unique ID for this connection - * user - The username - * app - [Appname, Appversion] - * version - Which core it's using (string) - * bot - If it's a bot - * owner - The owner for this bot (only available when - bot = True) - * pos - [Z, X, Y] The position for this user. Is None - when you can't see this user. - """ - - # TODO - - pass - - def useronline(self, msg): - """ - Called after a user (or bot) has signed on. - * cid - The unique ID for this connection - * user - The username - * app - [Appname, Appversion] - * version - Which core it's using (string) - * bot - If it's a bot - * owner - The owner for this bot (only available when - bot = True) - * pos - [Z, X, Y] The position for this user. Is None - when you can't see this user. - """ - - # TODO - - pass - - def useroffline(self, msg): - """ - Some user has gone offline - * cid - The connection-id for this client - """ - - # TODO - - pass - - - def error(self, msg): - """ - Called when we did something wrong! - * reason - What we did wrong - "bad login" - Username/password wrong - "login not allowed" - User may not log in right now - "bot limit reached" - Too much bots logged in for this user - "login blocked" - The user (or IP) is blocked - "duplicate user" - There is already someone online with - this username - """ - - if msg['reason'] == "bad login": - self.call.failed_logging_in("bad login") - elif msg['reason'] == "login not allowed": - self.call.failed_logging_in("login not allowed") - elif msg['reason'] == "bot limit reached": - self.call.failed_logging_in("bot limit reached") - elif msg['reason'] == "login blocked": - self.call.failed_logging_in("login blocked") - elif msg['reason'] == "duplicate user": - self.call.failed_logging_in("duplicate user") - + def __init__(self, sh): + """ + This class parses all received messages from the server. + """ + self.sh = sh + self.call = sh['call'] + self.core = sh['core'] + + def __call__(self, msg): + self.call.data_received(msg) + + head = msg.keys()[0] + body = msg[head] + + func = getattr(self, str(head), None) + if (func): + func(body) + + def disconnect(self, msg): + """ + Called just before the server closes our connection. + * reason - Why the server disconnected us + "full - Because the server is full + "duplicate" - Because another client has logged in on the same + account + "crash" - The server-parser has made a crash + "gone offline"- Server has just shutdown + """ + + self.core.close(msg["reason"]) + + def rsa(self, msg): + """ + Called when the connection has been made and a rsa-key has been + generated. We can now log in using this key + * public - The public rsa-key, which contains e & n + """ + + self.sh['rsakey'] = msg['public'] + + self.call.received_rsa(msg['public']) + + if self.core.cid == None and self.sh['auto_login'] != (): + login = self.sh['auto_login'] + login[0](*login[1]) + + + def login(self, msg): + """ + Called when we can log in + * username - The username (with right caps) + * cid - The server's connection-id + * owner - The owner for this bot (only when logging in as bot!) + """ + + if self.sh['isbot']: # Logging in as bot + self.core.owner = msg['owner'] + self.core.username = msg['username'] + self.core.cid = msg['cid'] + + self.call.logged_in(msg['username'], msg['cid'], msg['owner']) + + else: # Logging in as user + self.core.username = msg['username'] + self.core.cid = msg['cid'] + + self.call.logged_in(msg['username'], msg['cid'], None) + + + def userlist(self, msg): + """ + Called after we've logged it. This contains a list with all + online users. This is a _list_ with: + * cid - The unique ID for this connection + * user - The username + * app - [Appname, Appversion] + * version - Which core it's using (string) + * bot - If it's a bot + * owner - The owner for this bot (only available when bot = True) + * pos - [Z, X, Y] The position for this user. Is None + when you can't see this user. + """ + + # TODO + + pass + + def useronline(self, msg): + """ + Called after a user (or bot) has signed on. + * cid - The unique ID for this connection + * user - The username + * app - [Appname, Appversion] + * version - Which core it's using (string) + * bot - If it's a bot + * owner - The owner for this bot (only available when + bot = True) + * pos - [Z, X, Y] The position for this user. Is None + when you can't see this user. + """ + + # TODO + + pass + + def useroffline(self, msg): + """ + Some user has gone offline + * cid - The connection-id for this client + """ + + # TODO + + pass + + + def error(self, msg): + """ + Called when we did something wrong! + * reason - What we did wrong + "bad login" - Username/password wrong + "login not allowed" - User may not log in right now + "bot limit reached" - Too much bots logged in for this user + "login blocked" - The user (or IP) is blocked + "duplicate user" - There is already someone online with this + username + """ + + if msg['reason'] == "bad login": + self.call.failed_logging_in("bad login") + elif msg['reason'] == "login not allowed": + self.call.failed_logging_in("login not allowed") + elif msg['reason'] == "bot limit reached": + self.call.failed_logging_in("bot limit reached") + elif msg['reason'] == "login blocked": + self.call.failed_logging_in("login blocked") + elif msg['reason'] == "duplicate user": + self.call.failed_logging_in("duplicate user") + Modified: trunk/client/functions.py =================================================================== --- trunk/client/functions.py 2010-08-01 21:27:14 UTC (rev 350) +++ trunk/client/functions.py 2010-08-01 22:16:19 UTC (rev 351) @@ -1,3 +1,20 @@ +## This file is part of Virtual Playground +## Copyright (c) 2009 Jos Ratsma + Koen Koning + +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either +## version 2 of the License, or (at your option) any later version. + +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. + +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + import pygame, os, sys, threading from pygame.locals import * from hashlib import sha1 @@ -4,31 +21,33 @@ import core import gui + VERSION = "0.0.1" # This will be used to [sh]are all variables, functions and classes across the # code sh = {} + def real_path(*dir): - """ - Get the real path to this file - """ - return os.path.join(sys.path[0], *dir) + """ + Get the real path to this file + """ + return os.path.join(sys.path[0], *dir) def load_image(alpha, *dir): - """ - This will load an image for pygame - """ - - fullname = real_path(*dir) - try: - image = pygame.image.load(fullname) - if image.get_alpha is None or alpha == False: - image = image.convert() - else: - image = image.convert_alpha() - except pygame.error, message: - print 'Cannot load image:', fullname - raise SystemExit, message - return image + """ + This will load an image for pygame + """ + + fullname = real_path(*dir) + try: + image = pygame.image.load(fullname) + if image.get_alpha is None or alpha == False: + image = image.convert() + else: + image = image.convert_alpha() + except pygame.error, message: + print 'Cannot load image:', fullname + raise SystemExit, message + return image Modified: trunk/client/gui.py =================================================================== --- trunk/client/gui.py 2010-08-01 21:27:14 UTC (rev 350) +++ trunk/client/gui.py 2010-08-01 22:16:19 UTC (rev 351) @@ -1,3 +1,20 @@ +## This file is part of Virtual Playground +## Copyright (c) 2009 Jos Ratsma + Koen Koning + +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either +## version 2 of the License, or (at your option) any later version. + +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. + +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + from functions import * class Plane(): @@ -2,81 +19,78 @@ - def __init__(self, update, width, height): - self.update = update - self.width = width - self.height = height - self.surf = pygame.Surface((self.width, self.height), \ - SRCALPHA).convert_alpha() - self.norender = True - - self.childs = {} - - def __getitem__(self, key): - return self.childs[key] - - def add(self, *objs): - for obj in objs: - self.childs[obj.name] = obj - - - def renderall(self): - self.norender = False - for child in self.childs.values(): - child.renderall(Rect(0,0,0,0), self.surf) - - self.update(Rect(0,0, self.width, self.height)) + def __init__(self, update, width, height): + self.update = update + self.width = width + self.height = height + self.surf = pygame.Surface((self.width, self.height), SRCALPHA) \ + .convert_alpha() + self.norender = True + + self.childs = {} + + def __getitem__(self, key): + return self.childs[key] + + def add(self, *objs): + for obj in objs: + self.childs[obj.name] = obj + + def renderall(self): + self.norender = False + for child in self.childs.values(): + child.renderall(Rect(0,0,0,0), self.surf) + + self.update(Rect(0,0, self.width, self.height)) - class Object(): - def __init__(self, name, rect): - self.name = name - self.rect = Rect(rect) - self.childs = {} - self.focus = False - self.hover = False - - # Load the defaults - self.__defaults__() + def __init__(self, name, rect): + self.name = name + self.rect = Rect(rect) + self.childs = {} + self.focus = False + self.hover = False + + # Load the defaults + self.__defaults__() - def __getitem__(self, key): - return self.childs[key] - - def add(self, *objs): - for obj in objs: - self.childs[obj.name] = obj - - def renderall(self, correction, surf): - # First render ourself - self.render(correction, surf) - - # Then render our childs - for child in self.childs.values(): - child.renderall(correction.move(self.rect.topleft), surf) - + def __getitem__(self, key): + return self.childs[key] + + def add(self, *objs): + for obj in objs: + self.childs[obj.name] = obj + + def renderall(self, correction, surf): + # First render ourself + self.render(correction, surf) + + # Then render our childs + for child in self.childs.values(): + child.renderall(correction.move(self.rect.topleft), surf) + - class Text(Object): - def __defaults__(self): - self.input = "" - self.cursorpos = 0 - - def render(self, correction, surf): - pos = correction.move(self.rect.topleft) - pos.size = self.rect.size - - surf.fill([255,0,0], pos) - - + def __defaults__(self): + self.input = "" + self.cursorpos = 0 + + def render(self, correction, surf): + pos = correction.move(self.rect.topleft) + pos.size = self.rect.size + + surf.fill([255,0,0], pos) + + class Button(Object): - def __defaults__(self): - self.caption = "" - - def render(self, correction, surf): - pos = correction.move(self.rect.topleft) - pos.size = self.rect.size - - surf.fill([0,0,255], pos) + def __defaults__(self): + self.caption = "" + + def render(self, correction, surf): + pos = correction.move(self.rect.topleft) + pos.size = self.rect.size + + surf.fill([0,0,255], pos) Modified: trunk/client/layout.py =================================================================== --- trunk/client/layout.py 2010-08-01 21:27:14 UTC (rev 350) +++ trunk/client/layout.py 2010-08-01 22:16:19 UTC (rev 351) @@ -1,3 +1,20 @@ +## This file is part of Virtual Playground +## Copyright (c) 2009 Jos Ratsma + Koen Koning + +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either +## version 2 of the License, or (at your option) any later version. + +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. + +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + from functions import * TOPBUTTONS = 3 @@ -4,105 +21,99 @@ TOPLEFT = 44 TOPBUTTONWIDTH = 304 TOPHEIGHT = 65 - + class Layout(): - - def __init__(self, sh): - self.sh = sh - - self.surf = pygame.Surface((1000, 700), \ - SRCALPHA).convert_alpha() - - self.status = None - - self.selected = None - self.hover = None - - # Login stuff - self.loginbg = None - self.loginfont = None - - # Playground stuff - self.topbar = None - - def event(self, ev): - if self.status == "playground": - if ev.type == MOUSEMOTION: - index = self.topbarcursor(ev.pos) - if index is not False: - if self.hover == index: return True - self.hover = index - self.updatetop() - - return True - else: - if self.hover == None: return - self.hover = None - self.updatetop() - - elif ev.type == ACTIVEEVENT: - if ev.state == 1: # Mouse events - if ev.gain == 0: # Lost mouse focus - if self.hover == None: return - self.hover = None - self.updatetop() - - elif ev.type == MOUSEBUTTONDOWN: - index = self.topbarcursor(ev.pos) - if index is False: return - - if self.selected == index: - self.selected = None - else: - self.selected = index - self.updatetop() - - return True - - - - - def changestatus(self, status): - login_list = ['connecting', 'login', 'logging in'] - if status in login_list and self.status not in login_list: - # (Un)load all the data - self.topbar = None - - elif status == "playground": - self.topbar = load_image(True, "images", "topbar.png") - - self.selected = None - self.hover = self.topbarcursor(pygame.mouse.get_pos()) - self.surf.blit(self.topbar, (0,0), (0,0,1000,TOPHEIGHT)) - self.updatetop() - - self.status = status - - - def updatetop(self): - for i in range(TOPBUTTONS): - left = TOPLEFT + (TOPBUTTONWIDTH*i) - rect = Rect(left, 0, TOPBUTTONWIDTH, TOPHEIGHT) - - self.surf.fill([0,0,0,0], rect) - - if self.selected is i: # This button is selected - rect2 = rect.move(0,TOPHEIGHT*2) - - elif self.hover is i: # This button is hovered - rect2 = rect.move(0,TOPHEIGHT) - - else: - rect2 = rect.move(0,0) - - self.surf.blit(self.topbar, rect, rect2) - - self.sh['update']((0,0, 1000, 65)) - - - def topbarcursor(self, pos): - if pos[0] > TOPLEFT and pos[0] < (TOPBUTTONWIDTH*TOPBUTTONS+TOPLEFT) \ - and pos[1] < 55: - return (pos[0]-TOPLEFT) / TOPBUTTONWIDTH - else: - return False + + def __init__(self, sh): + self.sh = sh + + self.surf = pygame.Surface((1000, 700), SRCALPHA).convert_alpha() + + self.status = None + + self.selected = None + self.hover = None + + # Login stuff + self.loginbg = None + self.loginfont = None + + # Playground stuff + self.topbar = None + + def event(self, ev): + if self.status == "playground": + if ev.type == MOUSEMOTION: + index = self.topbarcursor(ev.pos) + if index is not False: + if self.hover == index: return True + self.hover = index + self.updatetop() + + return True + else: + if self.hover == None: return + self.hover = None + self.updatetop() + + elif ev.type == ACTIVEEVENT: + if ev.state == 1: # Mouse events + if ev.gain == 0: # Lost mouse focus + if self.hover == None: return + self.hover = None + self.updatetop() + + elif ev.type == MOUSEBUTTONDOWN: + index = self.topbarcursor(ev.pos) + if index is False: return + + if self.selected == index: + self.selected = None + else: + self.selected = index + self.updatetop() + + return True + + def changestatus(... [truncated message content] |