You can subscribe to this list here.
2009 |
Jan
|
Feb
(9) |
Mar
(11) |
Apr
|
May
(4) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(9) |
Nov
(5) |
Dec
(18) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2010 |
Jan
(4) |
Feb
|
Mar
|
Apr
(4) |
May
|
Jun
|
Jul
(11) |
Aug
(33) |
Sep
(33) |
Oct
|
Nov
|
Dec
|
From: <Blu...@us...> - 2009-12-14 19:46:33
|
Revision: 313 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=313&view=rev Author: BlueWolf_ Date: 2009-12-14 19:46:21 +0000 (Mon, 14 Dec 2009) Log Message: ----------- * You can now log in as VP-client, as user (not as bot) * It uses the database to verify an user * It uses RSA to get the password from the user * client is now a dict, not a connection-class (the connection-class is now in client['con']) * In parser, it now calls the appropriate function Don't forget to insert database.sql in your database! Modified Paths: -------------- trunk/server/core/callback.py trunk/server/core/parser.py trunk/server/core/server.py Added Paths: ----------- trunk/server/core/database.py trunk/server/core/database.sql trunk/server/core/rsa.py Modified: trunk/server/core/callback.py =================================================================== --- trunk/server/core/callback.py 2009-11-29 20:26:22 UTC (rev 312) +++ trunk/server/core/callback.py 2009-12-14 19:46:21 UTC (rev 313) @@ -24,7 +24,7 @@ calling Server.start() - This is placeholder. If you want to catch this event, + This is a placeholder. If you want to catch this event, overwrite this in your own callback. """ pass @@ -39,14 +39,14 @@ The unique ID for this connection. This is usually 'ip:port'. client: - The client class. Normally, you don't need this. + The client info. Normally, you don't need this. host: The IP adress for this user. port: The current port for this connection. - This is placeholder. If you want to catch this event, + This is a placeholder. If you want to catch this event, overwrite this in your own callback. """ pass @@ -68,9 +68,12 @@ * "timeout" - Client timed out (No data for 45s) * "manual" - Server (you) closed the connection with .close() + * "duplicate" - Another client has logged in on this + account. This connection has been + kicked - This is placeholder. If you want to catch this event, + This is a placeholder. If you want to catch this event, overwrite this in your own callback. """ pass @@ -108,7 +111,7 @@ 'ip:port'. - This is placeholder. If you want to catch this event, + This is a placeholder. If you want to catch this event, overwrite this in your own callback. """ pass @@ -125,7 +128,7 @@ Dict with the data that will be send. - This is placeholder. If you want to catch this event, + This is a placeholder. If you want to catch this event, overwrite this in your own callback. """ pass Added: trunk/server/core/database.py =================================================================== --- trunk/server/core/database.py (rev 0) +++ trunk/server/core/database.py 2009-12-14 19:46:21 UTC (rev 313) @@ -0,0 +1,72 @@ +## 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;guaranteed if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +import MySQLdb + +class Database(): + def __init__(self, host, user, passwd, db): + self.host = host + self.user = user + self.passwd = passwd + self.db = db + + def connect(self): + try: + self.dbcon = MySQLdb.Connect( + host = self.host, + user = self.user, + passwd = self.passwd, + db = self.db + ) + self.db = self.dbcon.cursor(MySQLdb.cursors.DictCursor) + + except: + raise DBConnectionError( + "Could not connect to the database!") + + def __getattr__(self, attr): + """ + Called when a functions is not in our class. We pass everything + through to our MySQLdb + """ + + def exc(*arg): + """ + Will return the real function from MySQLdb. Will ping + before executing the command, so it will automatically + reconnect. + """ + + # Uncomment for raw mysql-debugging! Fun guaranteed! + # print '\tMySQLdb.' + attr + repr(arg) + + func = getattr(self.db, attr) + try: + dbfunc = func(*arg) + except MySQLdb.OperationalError, message: + if message[0] == 2006: # Mysql has gone away + self._connect() + dbfunc = func(*arg) + else: #Some other error we don't care about + raise MySQLdb.OperationalError, message + + return dbfunc + + return exc + +class DBConnectionError(Exception): + pass Added: trunk/server/core/database.sql =================================================================== --- trunk/server/core/database.sql (rev 0) +++ trunk/server/core/database.sql 2009-12-14 19:46:21 UTC (rev 313) @@ -0,0 +1,33 @@ +-- phpMyAdmin SQL Dump +-- version 3.1.2deb1ubuntu0.2 +-- http://www.phpmyadmin.net +-- +-- Host: localhost +-- Generation Time: Dec 14, 2009 at 08:38 PM +-- Server version: 5.0.75 +-- PHP Version: 5.2.6-3ubuntu4.4 + +SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; + +-- +-- Database: `VP` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `users` +-- + +CREATE TABLE IF NOT EXISTS `users` ( + `id` int(11) NOT NULL auto_increment COMMENT 'Also known as uid', + `username` varchar(255) NOT NULL, + `password` varchar(40) NOT NULL COMMENT 'Password in sha1', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ; Modified: trunk/server/core/parser.py =================================================================== --- trunk/server/core/parser.py 2009-11-29 20:26:22 UTC (rev 312) +++ trunk/server/core/parser.py 2009-12-14 19:46:21 UTC (rev 313) @@ -15,21 +15,98 @@ ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +import rsa + class Parser(): - def __init__(self, callback, clients): + def __init__(self, callback, server): """ - This class parses all received messages from client. - It may need a better name... + This class parses all received messages from the client. """ - self.__call = callback - self.__clients = clients + self.callback = callback + self.server = server + # Shortkeys + self.db = self.server.database + self.clients = self.server.clients + def __call__(self, uid, msg): - self.__call.data_received(uid, msg) + self.callback.data_received(uid, msg) head = msg.keys()[0] body = msg[head] - if head == 'PNG': #Ping - pass #Should this have it's own callback/do anything? + func = getattr(self, str(head), None) + if (func): + func(uid, body) + + + def login(self, uid, msg): + """ + Send when the users wants to log in + usr - The username + pwd - The (rsa encrypted) sha-password + bot - Whether the it's an bot or an user + for - For what services it's logging in + "VP" - VP client + client - list with [app_name, app_version] + """ + + client = self.clients[uid] + data = client['con'] + + # Ignore when user is already logged in + if client['status'] != "": return + + # Decrypt the password + pwd = rsa.decrypt(msg['pwd'], client['rsa']) + + if msg['for'] == 'VP': + + self.db.execute(""" + SELECT + id, username, password + FROM + users + WHERE + username = %(user)s + AND password = %(password)s + """, {'user': msg['usr'], 'password': pwd}) + user = self.db.fetchone() + + if user == None: # No login, bad user! + data.send("login", { + "succeed": False, + "reason": "bad login" + }) + return; + + + if msg['bot'] == False: # Just an ordinary user + + # Check if the user is already logged in + for id, cl in self.clients.items(): + if cl['status'] == "VP" and \ + cl['bot'] == False and \ + cl['id'] == user['id']: + # Disconnect user + cl['con'].send("disconnect", + {'reason':'duplicate'}) + cl['con'].close('duplicate') + + + # Log the user in + client['id'] = user['id'] + client['user'] = user['username'] + client['bot'] = False + client['status'] = "VP" + + data.send("login", { + "succeed": True, + "username": user['username'], + "uid": uid, + "id": user['id'] + }) + + else: # Client is bot + pass #TODO Added: trunk/server/core/rsa.py =================================================================== --- trunk/server/core/rsa.py (rev 0) +++ trunk/server/core/rsa.py 2009-12-14 19:46:21 UTC (rev 313) @@ -0,0 +1,427 @@ +"""RSA module + +Module for calculating large primes, and RSA encryption, decryption, +signing and verification. Includes generating public and private keys. +""" + +__author__ = "Sybren Stuvel, Marloes de Boer and Ivo Tamboer" +__date__ = "2009-01-22" + +# NOTE: Python's modulo can return negative numbers. We compensate for +# this behaviour using the abs() function + +from cPickle import dumps, loads +import base64 +import math +import os +import random +import sys +import types +import zlib + +def gcd(p, q): + """Returns the greatest common divisor of p and q + + + >>> gcd(42, 6) + 6 + """ + if p<q: return gcd(q, p) + if q == 0: return p + return gcd(q, abs(p%q)) + +def bytes2int(bytes): + """Converts a list of bytes or a string to an integer + + >>> (128*256 + 64)*256 + + 15 + 8405007 + >>> l = [128, 64, 15] + >>> bytes2int(l) + 8405007 + """ + + if not (type(bytes) is types.ListType or type(bytes) is types.StringType): + raise TypeError("You must pass a string or a list") + + # Convert byte stream to integer + integer = 0 + for byte in bytes: + integer *= 256 + if type(byte) is types.StringType: byte = ord(byte) + integer += byte + + return integer + +def int2bytes(number): + """Converts a number to a string of bytes + + >>> bytes2int(int2bytes(123456789)) + 123456789 + """ + + if not (type(number) is types.LongType or type(number) is types.IntType): + raise TypeError("You must pass a long or an int") + + string = "" + + while number > 0: + string = "%s%s" % (chr(number & 0xFF), string) + number /= 256 + + return string + +def fast_exponentiation(a, p, n): + """Calculates r = a^p mod n + """ + result = a % n + remainders = [] + while p != 1: + remainders.append(p & 1) + p = p >> 1 + while remainders: + rem = remainders.pop() + result = ((a ** rem) * result ** 2) % n + return result + +def read_random_int(nbits): + """Reads a random integer of approximately nbits bits rounded up + to whole bytes""" + + nbytes = ceil(nbits/8) + randomdata = os.urandom(nbytes) + return bytes2int(randomdata) + +def ceil(x): + """ceil(x) -> int(math.ceil(x))""" + + return int(math.ceil(x)) + +def randint(minvalue, maxvalue): + """Returns a random integer x with minvalue <= x <= maxvalue""" + + # Safety - get a lot of random data even if the range is fairly + # small + min_nbits = 32 + + # The range of the random numbers we need to generate + range = maxvalue - minvalue + + # Which is this number of bytes + rangebytes = ceil(math.log(range, 2) / 8) + + # Convert to bits, but make sure it's always at least min_nbits*2 + rangebits = max(rangebytes * 8, min_nbits * 2) + + # Take a random number of bits between min_nbits and rangebits + nbits = random.randint(min_nbits, rangebits) + + return (read_random_int(nbits) % range) + minvalue + +def fermat_little_theorem(p): + """Returns 1 if p may be prime, and something else if p definitely + is not prime""" + + a = randint(1, p-1) + return fast_exponentiation(a, p-1, p) + +def jacobi(a, b): + """Calculates the value of the Jacobi symbol (a/b) + """ + + if a % b == 0: + return 0 + result = 1 + while a > 1: + if a & 1: + if ((a-1)*(b-1) >> 2) & 1: + result = -result + b, a = a, b % a + else: + if ((b ** 2 - 1) >> 3) & 1: + result = -result + a = a >> 1 + return result + +def jacobi_witness(x, n): + """Returns False if n is an Euler pseudo-prime with base x, and + True otherwise. + """ + + j = jacobi(x, n) % n + f = fast_exponentiation(x, (n-1)/2, n) + + if j == f: return False + return True + +def randomized_primality_testing(n, k): + """Calculates whether n is composite (which is always correct) or + prime (which is incorrect with error probability 2**-k) + + Returns False if the number if composite, and True if it's + probably prime. + """ + + q = 0.5 # Property of the jacobi_witness function + + # t = int(math.ceil(k / math.log(1/q, 2))) + t = ceil(k / math.log(1/q, 2)) + for i in range(t+1): + x = randint(1, n-1) + if jacobi_witness(x, n): return False + + return True + +def is_prime(number): + """Returns True if the number is prime, and False otherwise. + + >>> is_prime(42) + 0 + >>> is_prime(41) + 1 + """ + + """ + if not fermat_little_theorem(number) == 1: + # Not prime, according to Fermat's little theorem + return False + """ + + if randomized_primality_testing(number, 5): + # Prime, according to Jacobi + return True + + # Not prime + return False + + +def getprime(nbits): + """Returns a prime number of max. 'math.ceil(nbits/8)*8' bits. In + other words: nbits is rounded up to whole bytes. + + >>> p = getprime(8) + >>> is_prime(p-1) + 0 + >>> is_prime(p) + 1 + >>> is_prime(p+1) + 0 + """ + + nbytes = int(math.ceil(nbits/8)) + + while True: + integer = read_random_int(nbits) + + # Make sure it's odd + integer |= 1 + + # Test for primeness + if is_prime(integer): break + + # Retry if not prime + + return integer + +def are_relatively_prime(a, b): + """Returns True if a and b are relatively prime, and False if they + are not. + + >>> are_relatively_prime(2, 3) + 1 + >>> are_relatively_prime(2, 4) + 0 + """ + + d = gcd(a, b) + return (d == 1) + +def find_p_q(nbits): + """Returns a tuple of two different primes of nbits bits""" + + p = getprime(nbits) + while True: + q = getprime(nbits) + if not q == p: break + + return (p, q) + +def extended_euclid_gcd(a, b): + """Returns a tuple (d, i, j) such that d = gcd(a, b) = ia + jb + """ + + if b == 0: + return (a, 1, 0) + + q = abs(a % b) + r = long(a / b) + (d, k, l) = extended_euclid_gcd(b, q) + + return (d, l, k - l*r) + +# Main function: calculate encryption and decryption keys +def calculate_keys(p, q, nbits): + """Calculates an encryption and a decryption key for p and q, and + returns them as a tuple (e, d)""" + + n = p * q + phi_n = (p-1) * (q-1) + + while True: + # Make sure e has enough bits so we ensure "wrapping" through + # modulo n + e = getprime(max(8, nbits/2)) + if are_relatively_prime(e, n) and are_relatively_prime(e, phi_n): break + + (d, i, j) = extended_euclid_gcd(e, phi_n) + + if not d == 1: + raise Exception("e (%d) and phi_n (%d) are not relatively prime" % (e, phi_n)) + + if not (e * i) % phi_n == 1: + raise Exception("e (%d) and i (%d) are not mult. inv. modulo phi_n (%d)" % (e, i, phi_n)) + + return (e, i) + + +def gen_keys(nbits): + """Generate RSA keys of nbits bits. Returns (p, q, e, d). + + Note: this can take a long time, depending on the key size. + """ + + while True: + (p, q) = find_p_q(nbits) + (e, d) = calculate_keys(p, q, nbits) + + # For some reason, d is sometimes negative. We don't know how + # to fix it (yet), so we keep trying until everything is shiny + if d > 0: break + + return (p, q, e, d) + +def gen_pubpriv_keys(nbits): + """Generates public and private keys, and returns them as (pub, + priv). + + The public key consists of a dict {e: ..., , n: ....). The private + key consists of a dict {d: ...., p: ...., q: ....). + """ + + (p, q, e, d) = gen_keys(nbits) + + return ( {'e': e, 'n': p*q}, {'d': d, 'p': p, 'q': q} ) + +def encrypt_int(message, ekey, n): + """Encrypts a message using encryption key 'ekey', working modulo + n""" + + if type(message) is types.IntType: + return encrypt_int(long(message), ekey, n) + + if not type(message) is types.LongType: + raise TypeError("You must pass a long or an int") + + if message > 0 and \ + math.floor(math.log(message, 2)) > math.floor(math.log(n, 2)): + raise OverflowError("The message is too long") + + return fast_exponentiation(message, ekey, n) + +def decrypt_int(cyphertext, dkey, n): + """Decrypts a cypher text using the decryption key 'dkey', working + modulo n""" + + return encrypt_int(cyphertext, dkey, n) + +def sign_int(message, dkey, n): + """Signs 'message' using key 'dkey', working modulo n""" + + return decrypt_int(message, dkey, n) + +def verify_int(signed, ekey, n): + """verifies 'signed' using key 'ekey', working modulo n""" + + return encrypt_int(signed, ekey, n) + +def picklechops(chops): + """Pickles and base64encodes it's argument chops""" + + value = zlib.compress(dumps(chops)) + encoded = base64.encodestring(value) + return encoded.strip() + +def unpicklechops(string): + """base64decodes and unpickes it's argument string into chops""" + + return loads(zlib.decompress(base64.decodestring(string))) + +def chopstring(message, key, n, funcref): + """Splits 'message' into chops that are at most as long as n, + converts these into integers, and calls funcref(integer, key, n) + for each chop. + + Used by 'encrypt' and 'sign'. + """ + + msglen = len(message) + mbits = msglen * 8 + nbits = int(math.floor(math.log(n, 2))) + nbytes = nbits / 8 + blocks = msglen / nbytes + + if msglen % nbytes > 0: + blocks += 1 + + cypher = [] + + for bindex in range(blocks): + offset = bindex * nbytes + block = message[offset:offset+nbytes] + value = bytes2int(block) + cypher.append(funcref(value, key, n)) + + return picklechops(cypher) + +def gluechops(chops, key, n, funcref): + """Glues chops back together into a string. calls + funcref(integer, key, n) for each chop. + + Used by 'decrypt' and 'verify'. + """ + message = "" + + chops = unpicklechops(chops) + + for cpart in chops: + mpart = funcref(cpart, key, n) + message += int2bytes(mpart) + + return message + +def encrypt(message, key): + """Encrypts a string 'message' with the public key 'key'""" + + return chopstring(message, key['e'], key['n'], encrypt_int) + +def sign(message, key): + """Signs a string 'message' with the private key 'key'""" + + return chopstring(message, key['d'], key['p']*key['q'], decrypt_int) + +def decrypt(cypher, key): + """Decrypts a cypher with the private key 'key'""" + + return gluechops(cypher, key['d'], key['p']*key['q'], decrypt_int) + +def verify(cypher, key): + """Verifies a cypher with the public key 'key'""" + + return gluechops(cypher, key['e'], key['n'], encrypt_int) + +# Do doctest if we're not imported +if __name__ == "__main__": + import doctest + doctest.testmod() + +__all__ = ["gen_pubpriv_keys", "encrypt", "decrypt", "sign", "verify"] + Modified: trunk/server/core/server.py =================================================================== --- trunk/server/core/server.py 2009-11-29 20:26:22 UTC (rev 312) +++ trunk/server/core/server.py 2009-12-14 19:46:21 UTC (rev 313) @@ -17,6 +17,8 @@ import simplejson, socket, threading, time, md5, random from parser import Parser +from database import Database +import rsa class Server(threading.Thread): """ @@ -60,11 +62,16 @@ (see callback `connection_limit_exceeded`). Should be int. If this value is either None or 0, there will be no limit. Default is 0. But it is wise to specify a limit. + + -rsa_bits: + How many bits the rsa uses for encrypting the password. + More = more secure but slower to generate. Default is 64 """ - def __init__(self, config, callback_class): + def __init__(self, config, callback_class, database): self.__sock = None + self.database = Database(**database) self.__call = callback_class # Create all default settings @@ -72,7 +79,7 @@ self.__config = config self.clients = {} - self.__parse = Parser(self.__call, self.clients) + self.__parse = Parser(self.__call, self) threading.Thread.__init__(self) @@ -83,6 +90,7 @@ config.setdefault('host', '') config.setdefault('port', 5162) config.setdefault('max_connections', 0) + config.setdefault('rsa_bits', 64) def start_server(self): @@ -95,6 +103,9 @@ if self.__sock: raise ConnectionError("The server is already online!") + # Connect to the database + self.database.connect() + #Load our server socket self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -153,16 +164,20 @@ uid = md5.new(addr[0] + str(addr[1]) + str(random.random())).hexdigest()[:8] - self.clients[uid] = Client(uid, sock, self.clients, - self.__call, self.__parse) + self.clients[uid] = { + "status": "", + "con": Client(uid, sock, self.clients, + self.__call, self.__parse, + self.__config) + } if self.__call.connection_opened(uid, self.clients[uid], *addr): #User returned True -> drop user - self.clients[uid].close() + self.clients[uid]['con'].close() continue - self.clients[uid].start() + self.clients[uid]['con'].start() @@ -172,13 +187,14 @@ Each client has it's own class. """ - def __init__(self, uid, sock, clients, callback, parser): + def __init__(self, uid, sock, clients, callback, parser, config): self.__uid = uid self.__sock = sock self.__clients = clients self.__call = callback self.__parser = parser + self.__config = config self.is_online = True threading.Thread.__init__(self) @@ -190,10 +206,19 @@ """ Used by threading, not for external usage. """ + #Client must ping (at least) every 30 seconds. So we set a #timeout of 45 seconds. self.__sock.settimeout(45) + # Before the client can log in, we first need to create a + # rsa-key + public, private = rsa.gen_pubpriv_keys( + self.__config['rsa_bits']) + self.__clients[self.__uid]['rsa'] = private + self.send("rsa", {"public": public}) + + #Infinite loop that receives data buffer = '' while 1: @@ -225,10 +250,12 @@ Closes the connection for this client and kills the socket. """ + if self.is_online == False: return + self.is_online = False + try: self.__sock.shutdown(0); except: pass self.__sock.close() - self.is_online = False self.__call.connection_closed(self.__uid, reason) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-11-29 20:26:34
|
Revision: 312 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=312&view=rev Author: BlueWolf_ Date: 2009-11-29 20:26:22 +0000 (Sun, 29 Nov 2009) Log Message: ----------- Server checks for an uid that does not exist yet, instead of just assigning a random one without checking Modified Paths: -------------- trunk/server/core/server.py Modified: trunk/server/core/server.py =================================================================== --- trunk/server/core/server.py 2009-11-28 23:30:52 UTC (rev 311) +++ trunk/server/core/server.py 2009-11-29 20:26:22 UTC (rev 312) @@ -15,7 +15,7 @@ ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -import simplejson, socket, threading, time, md5 +import simplejson, socket, threading, time, md5, random from parser import Parser class Server(threading.Thread): @@ -147,8 +147,12 @@ sock.close() continue - # Chozo wanted the 8 so badly... + # Create unique user-id uid = md5.new(addr[0] + str(addr[1])).hexdigest()[:8] + while uid in self.clients: + uid = md5.new(addr[0] + str(addr[1]) + + str(random.random())).hexdigest()[:8] + self.clients[uid] = Client(uid, sock, self.clients, self.__call, self.__parse) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-11-28 23:31:01
|
Revision: 311 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=311&view=rev Author: BlueWolf_ Date: 2009-11-28 23:30:52 +0000 (Sat, 28 Nov 2009) Log Message: ----------- Added reason 'full' to callback.connection_closed Modified Paths: -------------- trunk/client/core/callback.py trunk/client/core/client.py trunk/client/core/parser.py Modified: trunk/client/core/callback.py =================================================================== --- trunk/client/core/callback.py 2009-11-28 23:26:54 UTC (rev 310) +++ trunk/client/core/callback.py 2009-11-28 23:30:52 UTC (rev 311) @@ -35,8 +35,11 @@ reason: A string, representing the reason why it disconnected. - It currently only has two options: - * "server" - Server dropped the connection + 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() Modified: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py 2009-11-28 23:26:54 UTC (rev 310) +++ trunk/client/core/client.py 2009-11-28 23:30:52 UTC (rev 311) @@ -57,7 +57,6 @@ self.__parse = Parser(self.__call, self) self.__is_online = False - self.__disconnect_reason = None self.__do_connect = threading.Event() self.__do_connect.clear() @@ -97,7 +96,7 @@ self.__do_connect.wait() # Wait to connect self.__is_online = True - self.__disconnect_reason = None + disconnect_reason = None self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -121,11 +120,10 @@ try: data = self.__sock.recv(1024) except: - print 'except' - self.__disconnect_reason = "close" + disconnect_reason = "closed" break if not data: - self.__disconnect_reason = "close" + disconnect_reason = "closed" break buffer += data @@ -141,7 +139,7 @@ self.__parse(simplejson.loads(msg)) if self.__is_online: - self.close() + self.close(disconnect_reason) @@ -160,7 +158,7 @@ except: pass - def close(self): + def close(self, reason = "manual"): """ Will close the connection to the server. If the connection in already down, it will raise an exception. This will trigger the @@ -169,23 +167,22 @@ """ if not self.__is_online: - raise ConnectionError("The connection is already " \ - "closed!") + if reason == "manual": + # Annoy the user + raise ConnectionError("The connection is " + \ + "already closed!") + else: + return; - # What's the reason, the meaning of this? - if self.__disconnect_reason == "close": # 42 - reason = "server" - else: - reason = "manual" - self.__do_connect.clear() # Block the thread-loop self.__is_online = False self.__pinger.cancel() self.__pinger = None - self.__sock.shutdown(0) + try: self.__sock.shutdown(0) + except: pass self.__sock.close() self.__sock = None Modified: trunk/client/core/parser.py =================================================================== --- trunk/client/core/parser.py 2009-11-28 23:26:54 UTC (rev 310) +++ trunk/client/core/parser.py 2009-11-28 23:30:52 UTC (rev 311) @@ -30,4 +30,15 @@ head = msg.keys()[0] body = msg[head] - #handle data here later... + func = getattr(self, str(head), None) + if (func): + func(body) + + def disconnect(self, msg): + """ + Called just before the server closes our connection + """ + # reason - Why it's going to disconnect us + + if msg['reason'] == 'full': + self.__client.close("full") This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-11-28 23:27:02
|
Revision: 310 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=310&view=rev Author: BlueWolf_ Date: 2009-11-28 23:26:54 +0000 (Sat, 28 Nov 2009) Log Message: ----------- * uid is now a md5-hash, for privacy reasons * It will tell the client when the server is full * It will now kick a client properly after returning True in callback.connection_opened * Parser calls the function it needs * Changed the arguments in callback.connection_limit_exceeded * callback.connection_closed now has a reason! * Uses it own exceptions Modified Paths: -------------- trunk/server/core/callback.py trunk/server/core/server.py Modified: trunk/server/core/callback.py =================================================================== --- trunk/server/core/callback.py 2009-11-15 16:19:20 UTC (rev 309) +++ trunk/server/core/callback.py 2009-11-28 23:26:54 UTC (rev 310) @@ -41,9 +41,9 @@ client: The client class. Normally, you don't need this. host: - The IP adress for this user + The IP adress for this user. port: - The current port this connection uses. + The current port for this connection. This is placeholder. If you want to catch this event, @@ -51,7 +51,7 @@ """ pass - def connection_closed(self, uid): + def connection_closed(self, uid, reason): """ Called when a connection with a client is closed. This can be when they closed their connection themselves, or when we @@ -60,28 +60,37 @@ uid: The unique ID for this connection. This is usually 'ip:port'. + reason: + A string, representing the reason why it disconnected. + It currently has these options: + * "closed" - Client dropped the connection + unexpectedly + * "timeout" - Client timed out (No data for 45s) + * "manual" - Server (you) closed the connection + with .close() This is placeholder. If you want to catch this event, overwrite this in your own callback. """ - #TODO: Reason? pass - def connection_limit_exceeded(self, ip, current_connections, - max_connections): + def connection_limit_exceeded(self, current_connections, + max_connections, host, port): """ Called when a new client connects, but the maximum number of connections is exceeded. You can, however, still accept the connection by returning True in this function. - ip: - The IP-adress for this connection current_connections: Amount of current open connections max_connections: This is the same as in the config 'max_connections'. + host: + The IP adress for this user. + port: + The current port for this connection. This is placeholder. If you want to catch this event, Modified: trunk/server/core/server.py =================================================================== --- trunk/server/core/server.py 2009-11-15 16:19:20 UTC (rev 309) +++ trunk/server/core/server.py 2009-11-28 23:26:54 UTC (rev 310) @@ -15,7 +15,7 @@ ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -import simplejson, socket, threading, time +import simplejson, socket, threading, time, md5 from parser import Parser class Server(threading.Thread): @@ -93,7 +93,7 @@ #Isn't the server running already? if self.__sock: - raise Exception, "The server is already online!" + raise ConnectionError("The server is already online!") #Load our server socket self.__sock = socket.socket(socket.AF_INET, @@ -132,25 +132,34 @@ #We exceeded our connection limit, but maybe #this is a special occasion? Send callback! if not self.__call.connection_limit_exceeded( - addr[0], len(self.clients), - self.__config['max_connections']): + len(self.clients), + self.__config['max_connections'], + addr[0], addr[1]): #We're full, kick him out - #TODO: Tell him we're full? + #Tell him we're full + data = simplejson.dumps({ + "disconnect":{"reason":"full"} + }) + try: sock.send(data + chr(1)) + except: pass + sock.close() continue - uid = addr[0] + ':' + str(addr[1]) + # Chozo wanted the 8 so badly... + uid = md5.new(addr[0] + str(addr[1])).hexdigest()[:8] self.clients[uid] = Client(uid, sock, self.clients, self.__call, self.__parse) - self.clients[uid].start() if self.__call.connection_opened(uid, self.clients[uid], *addr): #User returned True -> drop user - time.sleep(0.1) #Let the `run` start self.clients[uid].close() + continue + self.clients[uid].start() + class Client(threading.Thread): @@ -186,12 +195,14 @@ while 1: try: data = self.__sock.recv(1024) + except socket.timeout: + if self.is_online: self.close("timeout") + return except: - #Ping timeout? - if self.is_online: self.close() + if self.is_online: self.close("closed") return if not data: - if self.is_online: self.close() + if self.is_online: self.close("closed") return buffer += data @@ -205,15 +216,17 @@ self.__parser(self.__uid, simplejson.loads(msg)) - def close(self): + def close(self, reason = "manual"): """ Closes the connection for this client and kills the socket. """ - + + try: self.__sock.shutdown(0); + except: pass self.__sock.close() self.is_online = False - self.__call.connection_closed(self.__uid) + self.__call.connection_closed(self.__uid, reason) del self.__clients[self.__uid] @@ -231,3 +244,5 @@ self.__sock.send(data + chr(1)) except: pass +class ConnectionError(Exception): + pass This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-11-15 16:19:27
|
Revision: 309 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=309&view=rev Author: BlueWolf_ Date: 2009-11-15 16:19:20 +0000 (Sun, 15 Nov 2009) Log Message: ----------- Added reason in callback.disconnected and the core can now properly reconnect Modified Paths: -------------- trunk/client/core/callback.py trunk/client/core/client.py Modified: trunk/client/core/callback.py =================================================================== --- trunk/client/core/callback.py 2009-11-14 23:08:44 UTC (rev 308) +++ trunk/client/core/callback.py 2009-11-15 16:19:20 UTC (rev 309) @@ -23,18 +23,29 @@ send stuff. This is placeholder. If you want to catch this event, - overwrite this in your own placeholder + overwrite this in your own callback """ pass - def disconnected(self): + 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 only has two options: + * "server" - Server dropped the connection + * "manual" - Client (you) closed the connection + with .close() + + + Return True if you want it to reconnect. Be warned that this + event also will be raised when you do .close()! + This is placeholder. If you want to catch this event, - overwrite this in your own placeholder + overwrite this in your own callback """ pass @@ -48,7 +59,7 @@ This is placeholder. If you want to catch this event, - overwrite this in your own placeholder + overwrite this in your own callback """ pass @@ -62,7 +73,7 @@ This is placeholder. If you want to catch this event, - overwrite this in your own placeholder + overwrite this in your own callback """ pass Modified: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py 2009-11-14 23:08:44 UTC (rev 308) +++ trunk/client/core/client.py 2009-11-15 16:19:20 UTC (rev 309) @@ -18,7 +18,6 @@ import simplejson, socket, threading, time from parser import Parser - class Client(threading.Thread): """ This is the client-core for Virtual Playground. This will handle the @@ -55,12 +54,18 @@ # Create all default settings self.__config_default(config) self.__config = config - self.__parse = Parser(self.__call, self) - self.is_online = True + self.__is_online = False + self.__disconnect_reason = None + self.__do_connect = threading.Event() + self.__do_connect.clear() + threading.Thread.__init__(self) + + self.setDaemon(True) + self.start() def __config_default(self, config): @@ -81,51 +86,65 @@ if self.__sock: raise ConnectionError("You are already connected!") - self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.__do_connect.set() # Release the hounds - self.start() def run(self): """ Used by threading, not for external usage. """ - - #TODO: reconnect loop thingy here - while 1: - try: - self.__sock.connect((self.__host, self.__port)) - break - except: - time.sleep(1) + self.__do_connect.wait() # Wait to connect + + self.__is_online = True + self.__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.__call.connected() - self.__pinger = self.__Pinger(self.send) + self.__pinger = self.__Pinger(self.send) - #Infinite loop that receives data - buffer = '' - while 1: - try: - data = self.__sock.recv(1024) - except: - if self.is_online: self.close() - return - if not data: - if self.is_online: self.close() - return + #Infinite loop that receives data + buffer = '' + while 1: + try: + data = self.__sock.recv(1024) + except: + print 'except' + self.__disconnect_reason = "close" + break + if not data: + self.__disconnect_reason = "close" + break - buffer += data - #Each dataset must end with a delimiter: chr(1) - if chr(1) in buffer: + 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.__is_online: + self.close() + + + def send(self, data_header, data_body = {}): """ Sends `data_body` of type `data_header` to the server. It will @@ -149,16 +168,32 @@ callback. If not, you can reuse this class by calling `connect`. """ - if not self.is_online: - raise ConnectionError("The connection is already \ - closed!") + if not self.__is_online: + raise ConnectionError("The connection is already " \ + "closed!") + # What's the reason, the meaning of this? + if self.__disconnect_reason == "close": # 42 + reason = "server" + else: + reason = "manual" + + + self.__do_connect.clear() # Block the thread-loop + + self.__is_online = False + self.__pinger.cancel() + self.__pinger = None + + self.__sock.shutdown(0) self.__sock.close() - self.is_online = False - if self.__call.disconnected(): - self.__sock = None - self.connect(self.__host, self.__port) + self.__sock = None + + if self.__call.disconnected(reason): + # Reconnect + self.__do_connect.set() + class __Pinger(): def __init__(self, send): """ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-11-14 23:08:56
|
Revision: 308 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=308&view=rev Author: BlueWolf_ Date: 2009-11-14 23:08:44 +0000 (Sat, 14 Nov 2009) Log Message: ----------- Core now uses his own exception(s) Modified Paths: -------------- trunk/client/core/client.py Modified: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py 2009-10-24 19:35:13 UTC (rev 307) +++ trunk/client/core/client.py 2009-11-14 23:08:44 UTC (rev 308) @@ -79,7 +79,7 @@ self.__port = port if self.__sock: - raise Exception, "You are already connected!" + raise ConnectionError("You are already connected!") self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -150,7 +150,8 @@ """ if not self.is_online: - raise Exception, "The connection is already closed!" + raise ConnectionError("The connection is already \ + closed!") self.__sock.close() self.is_online = False @@ -188,3 +189,5 @@ self.running = False +class ConnectionError(Exception): + pass This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-10-24 20:27:42
|
Revision: 306 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=306&view=rev Author: BlueWolf_ Date: 2009-10-24 18:56:45 +0000 (Sat, 24 Oct 2009) Log Message: ----------- * Will now uses the defaults in the config * Send will not crash when the connection is dead * connection_close renamed to connection_closed * Some changes in the callback Modified Paths: -------------- trunk/server/core/__init__.py trunk/server/core/callback.py trunk/server/core/server.py Modified: trunk/server/core/__init__.py =================================================================== --- trunk/server/core/__init__.py 2009-10-21 22:34:25 UTC (rev 305) +++ trunk/server/core/__init__.py 2009-10-24 18:56:45 UTC (rev 306) @@ -1,3 +1,7 @@ +""" +This is the server core for Virtual Playground. +You can use this by importing Server and Callback +""" ## This file is part of Virtual Playground ## Copyright (c) 2009 Jos Ratsma + Koen Koning @@ -19,3 +23,4 @@ Server = server.Server Callback = callback.Callback +__all__ = ['Server', 'Callback'] Modified: trunk/server/core/callback.py =================================================================== --- trunk/server/core/callback.py 2009-10-21 22:34:25 UTC (rev 305) +++ trunk/server/core/callback.py 2009-10-24 18:56:45 UTC (rev 306) @@ -16,40 +16,54 @@ ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. class Callback: - def server_online(self, clients): + def server_online(self): """ - server_online(self, clients) Called when the server is online and ready to accept incoming connections. This means it has successfully bounded itself to a port. Most of the times this will be called immediately after calling Server.start() - This is a placeholder. - If you want to catch this event, overwrite it. + + This is placeholder. If you want to catch this event, + overwrite this in your own callback. """ pass def connection_opened(self, uid, client, host, port): """ - connection_opened(self, uid, client, host, port) - Called when a new client connects, and we accepted the + Called when a new client connects and we accepted the connection. You can, however, still kill the connection by returning True in this function. - This is a placeholder. - If you want to catch this event, overwrite it. + uid: + The unique ID for this connection. This is usually + 'ip:port'. + client: + The client class. Normally, you don't need this. + host: + The IP adress for this user + port: + The current port this connection uses. + + + This is placeholder. If you want to catch this event, + overwrite this in your own callback. """ pass def connection_closed(self, uid): """ - connection_closed(self, uid) Called when a connection with a client is closed. This can be when they closed their connection themselves, or when we disconnect someone. - This is a placeholder. - If you want to catch this event, overwrite it. + uid: + The unique ID for this connection. This is usually + 'ip:port'. + + + This is placeholder. If you want to catch this event, + overwrite this in your own callback. """ #TODO: Reason? pass @@ -57,34 +71,53 @@ def connection_limit_exceeded(self, ip, current_connections, max_connections): """ - connection_limit_exceeded(self, ip, current_connections, - max_connections) Called when a new client connects, but the maximum number of connections is exceeded. You can, however, still accept the connection by returning True in this function. - This is a placeholder. - If you want to catch this event, overwrite it. + ip: + The IP-adress for this connection + current_connections: + Amount of current open connections + max_connections: + This is the same as in the config + 'max_connections'. + + + This is placeholder. If you want to catch this event, + overwrite this in your own callback. """ pass def data_received(self, uid, data): """ - data_received(self, uid, data) Called when the server received data from one of the clients. + Normally, you don't need this. - This is a placeholder. - If you want to catch this event, overwrite it. + uid: + The unique ID for this connection. This is usually + 'ip:port'. + + + This is placeholder. If you want to catch this event, + overwrite this in your own callback. """ pass def data_send(self, uid, data): """ - data_send(self, uid, data) Called when the server send data to one of the clients. + Normally, you don't need this. - This is a placeholder. - If you want to catch this event, overwrite it. + uid: + The unique ID for this connection. This is usually + 'ip:port'. + data: + Dict with the data that will be send. + + + This is placeholder. If you want to catch this event, + overwrite this in your own callback. """ pass Modified: trunk/server/core/server.py =================================================================== --- trunk/server/core/server.py 2009-10-21 22:34:25 UTC (rev 305) +++ trunk/server/core/server.py 2009-10-24 18:56:45 UTC (rev 306) @@ -19,46 +19,76 @@ from parser import Parser class Server(threading.Thread): - def __init__(self, config, callback_class): - """ - Will handle all connections from clients. It has one main - socket, and creates all (client)sockets. + """ + This is the server-core for Virtual Playground. This will handle all + connections from clients. It has one main socket, and it will create + all (client)sockets. + + + config: + This should be a dict with settings for the server. 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: - Config: (maybe this explanation should be moved? maybe provide - example config with the core? maybe this function - should check the given config for error, raise - exceptions, and fill in standard values for some - missing keys) - Should be dict with settings for the server. Below a list of all - posible keys and an explanation. + class Callback(core.Callback): + ... - -host: Host to which the server binds itself(am i saying this - correctly?) standard value is '', an empty string, which - means everyone can connect to the server. - -port: Port the server should listen on. Should be int, and can - be anything. - -max_connections: Maximum ammount of clients that can be - connected simultaneously. If this number is exceeded, - the client will dropped, unless specified otherwise (see - callback `connection_limit_exceeded`). Should be int. If - this value is either None or 0, there will be no limit. - """ + See the doc in core.Callback for more information about this. + + -------- + + The settings: + -host: + Host to which the server binds itself. The default is an + empty string, an empty string, which means everyone can + connect to the server. + -port: + The port the server should listen on. Should be int + between 1 and 65535. Note that everything lower than 100 + usually needs to be run as root under Unix/Linux. + Default is 5162. + + -max_connections: + Maximum amount of clients that can be connected + simultaneously. If this number is exceeded, the new + connection will dropped, unless specified otherwise + (see callback `connection_limit_exceeded`). Should be + int. If this value is either None or 0, there will be no + limit. Default is 0. But it is wise to specify a limit. + """ + + + def __init__(self, config, callback_class): self.__sock = None - self.__call = callback_class() + self.__call = callback_class + + # Create all default settings + self.__config_default(config) self.__config = config - self.__clients = {} - self.__parse = Parser(self.__call, self.__clients) + self.clients = {} + self.__parse = Parser(self.__call, self.clients) + threading.Thread.__init__(self) + + def __config_default(self, config): + """ + Create all the config-defaults + """ + config.setdefault('host', '') + config.setdefault('port', 5162) + config.setdefault('max_connections', 0) + def start_server(self): """ - start_server() => None - - This will start the server. It will listen on the port - specified in the config. + This will start the server. It will listen on the port specified + in the config. """ #Isn't the server running already? @@ -90,19 +120,19 @@ time.sleep(1) self.__sock.listen(20) - self.__call.server_online(self.__clients) + self.__call.server_online(self.clients) #Infinite loop that will wait for incomming connections while 1: sock, addr = self.__sock.accept() - if self.__config['max_connections'] != None and \ - len(self.__clients) >= \ + if self.__config['max_connections'] and \ + len(self.clients) >= \ self.__config['max_connections']: #We exceeded our connection limit, but maybe #this is a special occasion? Send callback! if not self.__call.connection_limit_exceeded( - addr[0], len(self.__clients), + addr[0], len(self.clients), self.__config['max_connections']): #We're full, kick him out @@ -111,24 +141,25 @@ continue uid = addr[0] + ':' + str(addr[1]) - self.__clients[uid] = Client(uid, sock, self.__clients, + self.clients[uid] = Client(uid, sock, self.clients, self.__call, self.__parse) - self.__clients[uid].start() + self.clients[uid].start() if self.__call.connection_opened(uid, - self.__clients[uid], *addr): + self.clients[uid], *addr): #User returned True -> drop user time.sleep(0.1) #Let the `run` start - self.__clients[uid].close() + self.clients[uid].close() class Client(threading.Thread): + """ + This class manages the socket for the connection to clients. + Each client has it's own class. + """ + def __init__(self, uid, sock, clients, callback, parser): - """ - This class manages the socket for the connection to clients. - Each client has it's own class. - """ self.__uid = uid self.__sock = sock @@ -176,26 +207,27 @@ def close(self): """ - close() => None - Closes this connection, and kills the socket. + Closes the connection for this client and kills the socket. """ self.__sock.close() self.is_online = False - self.__call.connection_close(self.__uid) + self.__call.connection_closed(self.__uid) del self.__clients[self.__uid] def send(self, data_header, data_body = {}): """ - send(data_header, data_body = {}) => None Sends `data_body` of type `data_header` to the client. 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. + `data_header` is a string, `data_body` a dict. """ self.__call.data_send(self.__uid, {data_header:data_body}) data = simplejson.dumps({data_header:data_body}) - self.__sock.send(data + chr(1)) + + try: + self.__sock.send(data + chr(1)) + except: pass This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-10-24 19:35:20
|
Revision: 307 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=307&view=rev Author: BlueWolf_ Date: 2009-10-24 19:35:13 +0000 (Sat, 24 Oct 2009) Log Message: ----------- * Some changes in de Callback * Added config in the core * Callback is now outside the try, in send Modified Paths: -------------- trunk/client/core/__init__.py trunk/client/core/callback.py trunk/client/core/client.py Modified: trunk/client/core/__init__.py =================================================================== --- trunk/client/core/__init__.py 2009-10-24 18:56:45 UTC (rev 306) +++ trunk/client/core/__init__.py 2009-10-24 19:35:13 UTC (rev 307) @@ -1,3 +1,8 @@ +""" +This is the client core for Virtual Playground. +You can use this by importing Client and Callback +""" + ## This file is part of Virtual Playground ## Copyright (c) 2009 Jos Ratsma + Koen Koning @@ -19,3 +24,4 @@ Client = client.Client Callback = callback.Callback +__all__ = ['Client', 'Callback'] Modified: trunk/client/core/callback.py =================================================================== --- trunk/client/core/callback.py 2009-10-24 18:56:45 UTC (rev 306) +++ trunk/client/core/callback.py 2009-10-24 19:35:13 UTC (rev 307) @@ -16,47 +16,53 @@ ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. class Callback: - def connected(self, con): + def connected(self): """ - connected(self, con) This will be called when a connection with the server is made. `con` contains the core's `Client` class, so you can use it to send stuff. - This is a placeholder. - If you want to catch this event, overwrite it. + This is placeholder. If you want to catch this event, + overwrite this in your own placeholder """ pass def disconnected(self): """ - connected(self) 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. - This is a placeholder. - If you want to catch this event, overwrite it. + This is placeholder. If you want to catch this event, + overwrite this in your own placeholder """ pass def data_received(self, data): """ - data_received(self, data) - Called when we received data from the server. + Called when we received data from the server. Normally, you + don't need this. - This is a placeholder. - If you want to catch this event, overwrite it. + data: + Dict with the data that has been received + + + This is placeholder. If you want to catch this event, + overwrite this in your own placeholder """ pass def data_send(self, data): """ - data_send(self, data) - Called when we send data to the server. + Called when we send data to the server. Normally, you + don't need this. - This is a placeholder. - If you want to catch this event, overwrite it. + data: + Dict with the data that will be send. + + + This is placeholder. If you want to catch this event, + overwrite this in your own placeholder """ pass Modified: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py 2009-10-24 18:56:45 UTC (rev 306) +++ trunk/client/core/client.py 2009-10-24 19:35:13 UTC (rev 307) @@ -20,19 +20,54 @@ class Client(threading.Thread): - def __init__(self, callback_class): - """ - This class will handle all of the connection to the server. - """ + """ + 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: + Currently, the config is a bit lonely and quiet. Do you want to + fill it? :-( - self.__call = callback_class() + """ + + def __init__(self, config, callback_class): + + self.__call = callback_class self.__sock = None self.__pinger = None + + # Create all default settings + self.__config_default(config) + self.__config = config + + self.__parse = Parser(self.__call, self) self.is_online = True threading.Thread.__init__(self) - + + + def __config_default(self, config): + #config.setdefault('whatever', 'duh') + pass + + def connect(self, host, port): """ Will (try to) connect to the server on `host`:`port`. @@ -64,7 +99,7 @@ except: time.sleep(1) - self.__call.connected(self) + self.__call.connected() self.__pinger = self.__Pinger(self.send) @@ -93,22 +128,21 @@ def send(self, data_header, data_body = {}): """ - send(data_header, data_body = {}) => None 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.__call.data_send({data_header:data_body}) - data = simplejson.dumps({data_header:data_body}) self.__sock.send(data + chr(1)) except: pass def close(self): """ - close(self) => None Will close the connection to the server. If the connection in already down, it will raise an exception. This will trigger the callback `disconnected`. It may reconnect, depending on the This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ch...@us...> - 2009-10-21 22:34:34
|
Revision: 305 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=305&view=rev Author: chozone Date: 2009-10-21 22:34:25 +0000 (Wed, 21 Oct 2009) Log Message: ----------- Begin of both client and server, core and app. -Server core: -Callback system -Accept incoming connections -Send/receive data -Client core: -Callback system -Connect to server -Send/receive data Modified Paths: -------------- trunk/client/VP.py Added Paths: ----------- trunk/client/callback.py trunk/client/core/__init__.py trunk/client/core/callback.py trunk/client/core/client.py trunk/client/core/parser.py trunk/server/VPS.py trunk/server/callback.py trunk/server/core/__init__.py trunk/server/core/callback.py trunk/server/core/parser.py trunk/server/core/server.py Removed Paths: ------------- trunk/server/VP.py Modified: trunk/client/VP.py =================================================================== --- trunk/client/VP.py 2009-10-18 19:17:08 UTC (rev 304) +++ trunk/client/VP.py 2009-10-21 22:34:25 UTC (rev 305) @@ -16,3 +16,22 @@ ## 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 time +import core +from callback import Callback + +def main(): + client = core.Client(Callback) + client.connect('localhost', 5162) + + while 1: + #Pygame event loop should go here later. + try: + time.sleep(5000) + except KeyboardInterrupt: + print + exit() + +if __name__ == '__main__': main() + Added: trunk/client/callback.py =================================================================== --- trunk/client/callback.py (rev 0) +++ trunk/client/callback.py 2009-10-21 22:34:25 UTC (rev 305) @@ -0,0 +1,35 @@ +## 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 core + +class Callback(core.Callback): + def connected(self, con): + print 'Connected!' + self.con = con + con.send('HI') + + def disconnected(self): + print 'CONNECTION DEAD' + #return True #reconnect + + def data_received(self, data): + print '<', repr(data) + + def data_send(self, data): + print '>', repr(data) + Added: trunk/client/core/__init__.py =================================================================== --- trunk/client/core/__init__.py (rev 0) +++ trunk/client/core/__init__.py 2009-10-21 22:34:25 UTC (rev 305) @@ -0,0 +1,21 @@ +## 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 client, callback +Client = client.Client +Callback = callback.Callback + Added: trunk/client/core/callback.py =================================================================== --- trunk/client/core/callback.py (rev 0) +++ trunk/client/core/callback.py 2009-10-21 22:34:25 UTC (rev 305) @@ -0,0 +1,62 @@ +## 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. + +class Callback: + def connected(self, con): + """ + connected(self, con) + This will be called when a connection with the server is made. + `con` contains the core's `Client` class, so you can use it to + send stuff. + + This is a placeholder. + If you want to catch this event, overwrite it. + """ + pass + + def disconnected(self): + """ + connected(self) + 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. + + This is a placeholder. + If you want to catch this event, overwrite it. + """ + pass + + def data_received(self, data): + """ + data_received(self, data) + Called when we received data from the server. + + This is a placeholder. + If you want to catch this event, overwrite it. + """ + pass + + def data_send(self, data): + """ + data_send(self, data) + Called when we send data to the server. + + This is a placeholder. + If you want to catch this event, overwrite it. + """ + pass + Added: trunk/client/core/client.py =================================================================== --- trunk/client/core/client.py (rev 0) +++ trunk/client/core/client.py 2009-10-21 22:34:25 UTC (rev 305) @@ -0,0 +1,156 @@ +## 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 simplejson, socket, threading, time +from parser import Parser + + +class Client(threading.Thread): + def __init__(self, callback_class): + """ + This class will handle all of the connection to the server. + """ + + self.__call = callback_class() + self.__sock = None + self.__pinger = None + self.__parse = Parser(self.__call, self) + self.is_online = True + + threading.Thread.__init__(self) + + 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. + """ + + self.__host = host + self.__port = port + + if self.__sock: + raise Exception, "You are already connected!" + + self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + self.start() + + def run(self): + """ + Used by threading, not for external usage. + """ + + #TODO: reconnect loop thingy here + + while 1: + try: + self.__sock.connect((self.__host, self.__port)) + break + except: + time.sleep(1) + + self.__call.connected(self) + + self.__pinger = self.__Pinger(self.send) + + + #Infinite loop that receives data + buffer = '' + while 1: + try: + data = self.__sock.recv(1024) + except: + if self.is_online: self.close() + return + if not data: + if self.is_online: self.close() + return + + buffer += data + #Each dataset must end with a delimiter: chr(1) + if chr(1) in buffer: + data = buffer.split(chr(1)) + buffer = data[-1] + data = data[:-1] + + for msg in data: + self.__parse(simplejson.loads(msg)) + + def send(self, data_header, data_body = {}): + """ + send(data_header, data_body = {}) => None + 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. + """ + try: + self.__call.data_send({data_header:data_body}) + data = simplejson.dumps({data_header:data_body}) + self.__sock.send(data + chr(1)) + except: pass + + + def close(self): + """ + close(self) => None + Will close the connection to the server. If the connection in + 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.is_online: + raise Exception, "The connection is already closed!" + + self.__sock.close() + self.is_online = False + if self.__call.disconnected(): + self.__sock = None + self.connect(self.__host, self.__port) + + 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() + + def run(self): + if self.running == False: return + + #Ping! + self.send('PNG', {}) + + #Start again + self.timer = threading.Timer(30, self.run) + self.timer.start() + + def cancel(self): + if self.running: + self.timer.cancel() + self.running = False + + Added: trunk/client/core/parser.py =================================================================== --- trunk/client/core/parser.py (rev 0) +++ trunk/client/core/parser.py 2009-10-21 22:34:25 UTC (rev 305) @@ -0,0 +1,33 @@ +## 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. + +class Parser(): + def __init__(self, callback, client): + """ + This class parses all received messages from client. + It may need a better name... + """ + self.__call = callback + self.__client = client + + def __call__(self, msg): + self.__call.data_received(msg) + + head = msg.keys()[0] + body = msg[head] + + #handle data here later... Deleted: trunk/server/VP.py =================================================================== --- trunk/server/VP.py 2009-10-18 19:17:08 UTC (rev 304) +++ trunk/server/VP.py 2009-10-21 22:34:25 UTC (rev 305) @@ -1,18 +0,0 @@ -#!/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. Copied: trunk/server/VPS.py (from rev 304, trunk/server/VP.py) =================================================================== --- trunk/server/VPS.py (rev 0) +++ trunk/server/VPS.py 2009-10-21 22:34:25 UTC (rev 305) @@ -0,0 +1,40 @@ +#!/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. + +import time +import core +from callback import Callback + +def main(): + conf = {'host':'', + 'port':5162, + 'max_connections':0} + + server = core.Server(conf, Callback) + server.start_server() + + while 1: + try: + time.sleep(5000) + except KeyboardInterrupt: + print + exit() + +if __name__ == '__main__': main() + Property changes on: trunk/server/VPS.py ___________________________________________________________________ Added: svn:mergeinfo + Added: trunk/server/callback.py =================================================================== --- trunk/server/callback.py (rev 0) +++ trunk/server/callback.py 2009-10-21 22:34:25 UTC (rev 305) @@ -0,0 +1,49 @@ +## 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 core + +class Callback(core.Callback): + def server_online(self, clients): + print 'Server is online! :-)' + self.clients = clients + + def connection_opened(self, uid, client, host, port): + print 'New connection:', uid + + def connection_close(self, uid): + print 'Connection dead:', uid + + def connection_limit_exceeded(self, ip, current_connections, + max_connections): + print 'Connection limit exceeded: used %s/%s slots, auto '\ + 'accepted request from %s.' % (current_connections, + max_connections, ip) + return True + + def data_send(self, uid, data): + print '>', repr(data) + + def data_received(self, uid, data): + print '<', repr(data) + + head = data.keys()[0] + body = data[head] + + if head == 'HI': + self.clients[uid].send('LO') + Added: trunk/server/core/__init__.py =================================================================== --- trunk/server/core/__init__.py (rev 0) +++ trunk/server/core/__init__.py 2009-10-21 22:34:25 UTC (rev 305) @@ -0,0 +1,21 @@ +## 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 server, callback +Server = server.Server +Callback = callback.Callback + Added: trunk/server/core/callback.py =================================================================== --- trunk/server/core/callback.py (rev 0) +++ trunk/server/core/callback.py 2009-10-21 22:34:25 UTC (rev 305) @@ -0,0 +1,90 @@ +## 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. + +class Callback: + def server_online(self, clients): + """ + server_online(self, clients) + Called when the server is online and ready to accept incoming + connections. This means it has successfully bounded itself to a + port. Most of the times this will be called immediately after + calling Server.start() + + This is a placeholder. + If you want to catch this event, overwrite it. + """ + pass + + def connection_opened(self, uid, client, host, port): + """ + connection_opened(self, uid, client, host, port) + Called when a new client connects, and we accepted the + connection. You can, however, still kill the connection by + returning True in this function. + + This is a placeholder. + If you want to catch this event, overwrite it. + """ + pass + + def connection_closed(self, uid): + """ + connection_closed(self, uid) + Called when a connection with a client is closed. This can be + when they closed their connection themselves, or when we + disconnect someone. + + This is a placeholder. + If you want to catch this event, overwrite it. + """ + #TODO: Reason? + pass + + def connection_limit_exceeded(self, ip, current_connections, + max_connections): + """ + connection_limit_exceeded(self, ip, current_connections, + max_connections) + Called when a new client connects, but the maximum number of + connections is exceeded. You can, however, still accept the + connection by returning True in this function. + + This is a placeholder. + If you want to catch this event, overwrite it. + """ + pass + + def data_received(self, uid, data): + """ + data_received(self, uid, data) + Called when the server received data from one of the clients. + + This is a placeholder. + If you want to catch this event, overwrite it. + """ + pass + + def data_send(self, uid, data): + """ + data_send(self, uid, data) + Called when the server send data to one of the clients. + + This is a placeholder. + If you want to catch this event, overwrite it. + """ + pass + Added: trunk/server/core/parser.py =================================================================== --- trunk/server/core/parser.py (rev 0) +++ trunk/server/core/parser.py 2009-10-21 22:34:25 UTC (rev 305) @@ -0,0 +1,35 @@ +## 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. + +class Parser(): + def __init__(self, callback, clients): + """ + This class parses all received messages from client. + It may need a better name... + """ + self.__call = callback + self.__clients = clients + + def __call__(self, uid, msg): + self.__call.data_received(uid, msg) + + head = msg.keys()[0] + body = msg[head] + + if head == 'PNG': #Ping + pass #Should this have it's own callback/do anything? + Added: trunk/server/core/server.py =================================================================== --- trunk/server/core/server.py (rev 0) +++ trunk/server/core/server.py 2009-10-21 22:34:25 UTC (rev 305) @@ -0,0 +1,201 @@ +## 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 simplejson, socket, threading, time +from parser import Parser + +class Server(threading.Thread): + def __init__(self, config, callback_class): + """ + Will handle all connections from clients. It has one main + socket, and creates all (client)sockets. + + + Config: (maybe this explanation should be moved? maybe provide + example config with the core? maybe this function + should check the given config for error, raise + exceptions, and fill in standard values for some + missing keys) + Should be dict with settings for the server. Below a list of all + posible keys and an explanation. + + -host: Host to which the server binds itself(am i saying this + correctly?) standard value is '', an empty string, which + means everyone can connect to the server. + -port: Port the server should listen on. Should be int, and can + be anything. + -max_connections: Maximum ammount of clients that can be + connected simultaneously. If this number is exceeded, + the client will dropped, unless specified otherwise (see + callback `connection_limit_exceeded`). Should be int. If + this value is either None or 0, there will be no limit. + """ + + self.__sock = None + self.__call = callback_class() + self.__config = config + self.__clients = {} + self.__parse = Parser(self.__call, self.__clients) + + threading.Thread.__init__(self) + + def start_server(self): + """ + start_server() => None + + This will start the server. It will listen on the port + specified in the config. + """ + + #Isn't the server running already? + if self.__sock: + raise Exception, "The server is already online!" + + #Load our server socket + self.__sock = socket.socket(socket.AF_INET, + socket.SOCK_STREAM) + #Configure it to re-use the previous one + self.__sock.setsockopt(socket.SOL_SOCKET, + socket.SO_REUSEADDR, 1) + + self.start() #For more adventures of the socket, see `run` + + + def run(self): + """ + Used by threading, not for external usage. + """ + + #Try to claim the pre-specified port + while 1: + try: + self.__sock.bind((self.__config['host'], + self.__config['port'])) + break + except: + time.sleep(1) + + self.__sock.listen(20) + self.__call.server_online(self.__clients) + + #Infinite loop that will wait for incomming connections + while 1: + sock, addr = self.__sock.accept() + + if self.__config['max_connections'] != None and \ + len(self.__clients) >= \ + self.__config['max_connections']: + #We exceeded our connection limit, but maybe + #this is a special occasion? Send callback! + if not self.__call.connection_limit_exceeded( + addr[0], len(self.__clients), + self.__config['max_connections']): + + #We're full, kick him out + #TODO: Tell him we're full? + sock.close() + continue + + uid = addr[0] + ':' + str(addr[1]) + self.__clients[uid] = Client(uid, sock, self.__clients, + self.__call, self.__parse) + self.__clients[uid].start() + + if self.__call.connection_opened(uid, + self.__clients[uid], *addr): + #User returned True -> drop user + time.sleep(0.1) #Let the `run` start + self.__clients[uid].close() + + + +class Client(threading.Thread): + def __init__(self, uid, sock, clients, callback, parser): + """ + This class manages the socket for the connection to clients. + Each client has it's own class. + """ + + self.__uid = uid + self.__sock = sock + self.__clients = clients + self.__call = callback + self.__parser = parser + self.is_online = True + + threading.Thread.__init__(self) + + def __repr__(self): + return '<Client(%s)>'%self.__uid + + def run(self): + """ + Used by threading, not for external usage. + """ + #Client must ping (at least) every 30 seconds. So we set a + #timeout of 45 seconds. + self.__sock.settimeout(45) + + #Infinite loop that receives data + buffer = '' + while 1: + try: + data = self.__sock.recv(1024) + except: + #Ping timeout? + if self.is_online: self.close() + return + if not data: + if self.is_online: self.close() + return + + buffer += data + #Each dataset must end with a delimiter: chr(1) + if chr(1) in buffer: + data = buffer.split(chr(1)) + buffer = data[-1] + data = data[:-1] + + for msg in data: + self.__parser(self.__uid, + simplejson.loads(msg)) + + def close(self): + """ + close() => None + Closes this connection, and kills the socket. + """ + + self.__sock.close() + self.is_online = False + + self.__call.connection_close(self.__uid) + + del self.__clients[self.__uid] + + def send(self, data_header, data_body = {}): + """ + send(data_header, data_body = {}) => None + Sends `data_body` of type `data_header` to the client. 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(self.__uid, {data_header:data_body}) + data = simplejson.dumps({data_header:data_body}) + self.__sock.send(data + chr(1)) + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <blu...@us...> - 2009-10-18 19:17:20
|
Revision: 304 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=304&view=rev Author: bluewolf_ Date: 2009-10-18 19:17:08 +0000 (Sun, 18 Oct 2009) Log Message: ----------- Added a new diagram: callback Added Paths: ----------- res/code design/callback.png Added: res/code design/callback.png =================================================================== (Binary files differ) Property changes on: res/code design/callback.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <blu...@us...> - 2009-10-18 15:31:04
|
Revision: 303 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=303&view=rev Author: bluewolf_ Date: 2009-10-18 15:30:57 +0000 (Sun, 18 Oct 2009) Log Message: ----------- Added a new diagram: protocol Added Paths: ----------- res/code design/protocol.png Added: res/code design/protocol.png =================================================================== (Binary files differ) Property changes on: res/code design/protocol.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <blu...@us...> - 2009-10-18 13:17:22
|
Revision: 302 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=302&view=rev Author: bluewolf_ Date: 2009-10-18 13:17:14 +0000 (Sun, 18 Oct 2009) Log Message: ----------- First code design proposal: the cores Added Paths: ----------- res/code design/ res/code design/cores.png Added: res/code design/cores.png =================================================================== (Binary files differ) Property changes on: res/code design/cores.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-10-12 17:24:04
|
Revision: 301 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=301&view=rev Author: BlueWolf_ Date: 2009-10-12 17:23:56 +0000 (Mon, 12 Oct 2009) Log Message: ----------- And hello world! Added Paths: ----------- trunk/client/ trunk/client/COPYING trunk/client/VP.py trunk/client/core/ trunk/server/ trunk/server/COPYING trunk/server/VP.py trunk/server/core/ Added: trunk/client/COPYING =================================================================== --- trunk/client/COPYING (rev 0) +++ trunk/client/COPYING 2009-10-12 17:23:56 UTC (rev 301) @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS Added: trunk/client/VP.py =================================================================== --- trunk/client/VP.py (rev 0) +++ trunk/client/VP.py 2009-10-12 17:23:56 UTC (rev 301) @@ -0,0 +1,18 @@ +#!/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. Added: trunk/server/COPYING =================================================================== --- trunk/server/COPYING (rev 0) +++ trunk/server/COPYING 2009-10-12 17:23:56 UTC (rev 301) @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS Added: trunk/server/VP.py =================================================================== --- trunk/server/VP.py (rev 0) +++ trunk/server/VP.py 2009-10-12 17:23:56 UTC (rev 301) @@ -0,0 +1,18 @@ +#!/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. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-10-11 13:06:16
|
Revision: 300 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=300&view=rev Author: BlueWolf_ Date: 2009-10-11 13:06:07 +0000 (Sun, 11 Oct 2009) Log Message: ----------- Removing the previous code. Beginning with the new program Removed Paths: ------------- trunk/VP/ trunk/VPS/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-10-11 13:05:38
|
Revision: 299 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=299&view=rev Author: BlueWolf_ Date: 2009-10-11 13:05:23 +0000 (Sun, 11 Oct 2009) Log Message: ----------- Removing the previous code. Beginning with the new program Removed Paths: ------------- branches/VP-Grounds/ tags/VP-old_version/ tags/VPS-running_version/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ch...@us...> - 2009-05-09 15:25:05
|
Revision: 298 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=298&view=rev Author: chozone Date: 2009-05-09 15:25:00 +0000 (Sat, 09 May 2009) Log Message: ----------- Merging latest trunk changes in the grounds-branche. Now it works on windows, and with python 2.6+. Modified Paths: -------------- branches/VP-Grounds/TODO branches/VP-Grounds/VP.py branches/VP-Grounds/interface.py branches/VP-Grounds/lang/en.lang branches/VP-Grounds/lang/nl.lang branches/VP-Grounds/modules/input.py branches/VP-Grounds/modules/playground.py branches/VP-Grounds/modules/settings.py branches/VP-Grounds/notify.py Added Paths: ----------- branches/VP-Grounds/modules/__init__.py branches/VP-Grounds/modules/playgroundObj/ branches/VP-Grounds/modules/playgroundObj/__init__.py branches/VP-Grounds/modules/playgroundObj/avatar-multidir.py branches/VP-Grounds/modules/playgroundObj/avatar-multidir_parts.py branches/VP-Grounds/modules/playgroundObj/avatar-multipart.py branches/VP-Grounds/modules/playgroundObj/avatar-static.py branches/VP-Grounds/modules/playgroundObj/background.py branches/VP-Grounds/modules/playgroundObj/object.py Removed Paths: ------------- branches/VP-Grounds/modules/playground/ branches/VP-Grounds/modules/playgroundObj/__init__.py branches/VP-Grounds/modules/playgroundObj/background.py branches/VP-Grounds/modules/playgroundObj/object.py Property Changed: ---------------- branches/VP-Grounds/ Property changes on: branches/VP-Grounds ___________________________________________________________________ Modified: svn:mergeinfo - /trunk/VP:276-287 + /trunk/VP:276-297 Modified: branches/VP-Grounds/TODO =================================================================== --- branches/VP-Grounds/TODO 2009-05-02 15:19:34 UTC (rev 297) +++ branches/VP-Grounds/TODO 2009-05-09 15:25:00 UTC (rev 298) @@ -11,6 +11,9 @@ Chat * Making the scroll button (assigned to BlueWolf_) + Help +* Creating the help system (like http://dl.getdropbox.com/u/343509/help1.png) + Info(bar) * Creating the Info bar with information like: Current ground, user(?), money... @@ -20,16 +23,11 @@ * Connecting the items with functions (assigned to BlueWolf_) * Submenus (assigned to BlueWolf_) - Playground + Playground (see VP-Grounds branche) * Creating the avatars (the images) -* Finishing up Static avatar (Z coords) (assigned to chozone) -* Finishing up multidir avatar (Z coords) (assigned to chozone) -* Finishing up multiparts avatar (Z coords) (assigned to chozone) -* Finishing up multidir_parts avatar (Z coords) (assigned to chozone) -* Walls +* Walls (assigned to chozone) on hold, we need jumping, before we can create/test this any further * Smooth walking -* Jumping -* Running (assigned to chozone) +* Jumping (will be assigned to BlueWolf_, or someone else really wants to do this...?) * Walking/running bit slower when walking diagonally (assigned to chozone) * Chat balloons (assigned to K-4U) Modified: branches/VP-Grounds/VP.py =================================================================== --- branches/VP-Grounds/VP.py 2009-05-02 15:19:34 UTC (rev 297) +++ branches/VP-Grounds/VP.py 2009-05-09 15:25:00 UTC (rev 298) @@ -45,9 +45,9 @@ #chat auto-states if not 'chat' in conf: conf['chat'] = {} - conf['chat']['auto_states_enabled'] = conf['chat'].get('auto_states_enabled','False') #Later this True? + conf['chat']['auto_states_enabled'] = conf['chat'].get('auto_states_enabled','True') conf['chat']['auto_states_online'] = conf['chat'].get('auto_states_online','(b|back)\Z') - conf['chat']['auto_states_busy'] = conf['chat'].get('auto_states_busy','(phone|dnd)((\W.*)\Z|\Z)') + conf['chat']['auto_states_busy'] = conf['chat'].get('auto_states_busy','(dnd)((\W.*)\Z|\Z)') conf['chat']['auto_states_away'] = conf['chat'].get('auto_states_away','(brb|afk)((\W.*)\Z|\Z)') #animations @@ -61,27 +61,21 @@ conf['misc']['time_after_idle'] = int(conf['misc'].get('time_after_idle', 0)) #in mins, 0 = off, later this 5? -class Events(threading.Thread): +class ResponseLoop(threading.Thread): def __init__(self, share): self.sh = share threading.Thread.__init__(self) def run(self): while 1: - resp = pygame.event.wait() - if resp.type == QUIT: - self.sh['response'].put(('Exit',)) + #Some wacky workaround here. + #Without timeout, the Queue will not respond to KeyboardInterrupts. + #This is a timeout of year. Think that will be enough :-) + resp = share['response'].get(True, 31536000) + + if resp[0] == 'Exit': + pygame.event.post(pygame.event.Event(QUIT)) return - - elif resp.type == USEREVENT: #Pinger - self.sh['Connection'].ping() - - elif resp.type == ACTIVEEVENT: - if resp.state == 2: #focus - self.sh['focus'] = resp.gain - - else: - self.sh['Interface'].event(resp, lock=True) @@ -116,23 +110,29 @@ share['Sounds'].start() share['Brains'].start() +#Start Response-loop in thread +respLoop = ResponseLoop(share) +respLoop.start() -#Starting our event-catcher -events = Events(share) -events.start() - #Entering our main-loop. Yeah! try: while 1: - #Some wacky workaround here. - #Without timeout, the Queue will not response to KeyboardInterrupts. - #This is a timeout of year. Think that will be enough :-) - resp = response.get(True, 31536000) + resp = pygame.event.wait() - if resp[0] == 'Exit': - share['conf'].write() - exit() + if resp.type == QUIT: + share['conf'].write() + exit() + + elif resp.type == USEREVENT: #Pinger + share['Connection'].ping() + + elif resp.type == ACTIVEEVENT: + if resp.state == 2: #focus + share['focus'] = resp.gain + + else: + share['Interface'].event(resp, lock=True) except KeyboardInterrupt: print Modified: branches/VP-Grounds/interface.py =================================================================== --- branches/VP-Grounds/interface.py 2009-05-02 15:19:34 UTC (rev 297) +++ branches/VP-Grounds/interface.py 2009-05-09 15:25:00 UTC (rev 298) @@ -19,6 +19,7 @@ #4 - Menu/tooltips self.lock = threading.Lock() + self.updateLock = threading.Lock() #Lock for forceUpdate self.needUpdate = [] @@ -39,9 +40,9 @@ #Load all modules in our memory self.modules = {} for module in os.listdir(getRealDir('modules')): - if module[-3:] == '.py': - realName = os.path.join('modules', module[:-3]) - self.modules[module[:-3]] = __import__(realName).Module + if module[-3:] == '.py' and not module.startswith('__'): + realName = '.'.join(('modules', module[:-3])) + self.modules[module[:-3]] = __import__(realName, fromlist=module[:-3]).Module @@ -81,7 +82,7 @@ for i, module in enumerate(self.openModules[prio]): if type(name) == str: - if module.__module__ == 'modules/' + name: + if module.__module__ == 'modules.' + name: module.close() del self.openModules[prio][i] print 'Interface.closeModule: Close', name, 'at', prio, '-', i @@ -128,7 +129,7 @@ #Search within the given priorities for prio in prioList: for i, module in enumerate(self.openModules[prio]): - if module.__module__ == 'modules/' + name: + if module.__module__ == 'modules.' + name: return True return False @@ -147,7 +148,7 @@ for prio in prioList: for i, module in enumerate(self.openModules[prio]): if type(name) == str: - if module.__module__ == 'modules/' + name: + if module.__module__ == 'modules.' + name: if len(self.openModules[prio])-1 != i: self.openModules[prio].append(self.openModules[prio].pop(i)) self.update(blit = True) @@ -196,6 +197,8 @@ """This will the interface use to actually update the screen""" if self.needUpdate != []: + self.updateLock.acquire() + #print 'Interface.forceUpdate' + str(self.needUpdate) if self.needUpdate == [None]: #Fullscreen update, yeah! @@ -207,6 +210,8 @@ for module in self.openModules[prio]: module.update(self.screen, rect_list) pygame.display.update(rect_list) + + self.updateLock.release() #Change the cursor, if needed if self.cursor != self.cursorNew: @@ -265,7 +270,7 @@ self.lock.acquire() for prio in range(5): for module in self.openModules[prio]: - if name == '' or module.__module__ == 'modules/' + name: + if name == '' or module.__module__ == 'modules.' + name: module.call(*arg) self.forceUpdate() Modified: branches/VP-Grounds/lang/en.lang =================================================================== --- branches/VP-Grounds/lang/en.lang 2009-05-02 15:19:34 UTC (rev 297) +++ branches/VP-Grounds/lang/en.lang 2009-05-09 15:25:00 UTC (rev 298) @@ -50,7 +50,7 @@ [[autostatechangedefault]] online = (b|back)\Z -busy = (phone|dnd)((\W.*)\Z|\Z) +busy = (dnd)((\W.*)\Z|\Z) away = (brb|afk)((\W.*)\Z|\Z) Modified: branches/VP-Grounds/lang/nl.lang =================================================================== --- branches/VP-Grounds/lang/nl.lang 2009-05-02 15:19:34 UTC (rev 297) +++ branches/VP-Grounds/lang/nl.lang 2009-05-09 15:25:00 UTC (rev 298) @@ -50,7 +50,7 @@ [[autostatechangedefault]] online = (b|back|biw)\Z -busy = (phone|dnd)((\W.*)\Z|\Z) +busy = (dnd)((\W.*)\Z|\Z) away = (brb|afk|bzt)((\W.*)\Z|\Z) Copied: branches/VP-Grounds/modules/__init__.py (from rev 297, trunk/VP/modules/__init__.py) =================================================================== --- branches/VP-Grounds/modules/__init__.py (rev 0) +++ branches/VP-Grounds/modules/__init__.py 2009-05-09 15:25:00 UTC (rev 298) @@ -0,0 +1 @@ +# Dummy file, not a module. Do NOT remove this file! Modified: branches/VP-Grounds/modules/input.py =================================================================== --- branches/VP-Grounds/modules/input.py 2009-05-02 15:19:34 UTC (rev 297) +++ branches/VP-Grounds/modules/input.py 2009-05-09 15:25:00 UTC (rev 298) @@ -1,5 +1,5 @@ from functions import * -import time +import time, re class Module(): def __init__(self, share, *arg): @@ -39,9 +39,11 @@ else: #Just an enter if self.inputText != '': - text = self.inputText.encode('utf-8') - text = text.strip() - self.sh['Brains'].chatSend(text) + textToSend=self.checkChat() + if textToSend: + text = self.inputText.encode('utf-8') + text = text.strip() + self.sh['Brains'].chatSend(text) self.inputText = '' self.blit() @@ -56,9 +58,17 @@ else: #Control key pressed (and no backspace....) if ev.key == K_v: #Ctrl+V, paste clipboard - text = pygame.scrap.get('UTF8_STRING') - text = unicode(text) + if sys.platform == 'win32': + text = pygame.scrap.get('text/plain;charset=utf-8') + else: + text = pygame.scrap.get('UTF8_STRING') + + + if text: + text=text.replace(chr(0), '') + text = unicode(text) + #Check if we have to shorten, and maybe shorten #the text so it doesn't raise a 'too large' error. if self.fontObj.size(text)[0] > 16383: @@ -130,3 +140,51 @@ interface.update([179,471,370,29]) + + + def checkChat(self): + """ + Handles all commands that are in the chat. + Is called when user presses the enter key in the Input. + The message that will be send to the server is what this function returns. + """ + t=self.inputText + c=t[2:] if len(t)>=2 and t.startswith('//') else '' + + if c == 'exit' or c == 'quit': + self.sh['response'].put(('Exit',)) + elif c == 'time' or c == 'date' or c == 'datetime': + return time.ctime() + elif c.startswith('stat ') or c.startswith('status '): + t=t.replace('//status ', '') + t=t.replace('//stat ', '') + if t == 'online' or t == 'busy' or t == 'away': + user=self.sh['conf']['account']['user'] + curStatus=self.sh['users'][user]['State'] + + if t != curStatus: + self.sh['Brains'].setStatus(t) + else: + return self.inputText + elif c == 'online' or c == 'busy' or c == 'away': + user=self.sh['conf']['account']['user'] + curStatus=self.sh['users'][user]['State'] + if c != curStatus: + self.sh['Brains'].setStatus(c) + else: + #Maybe... it is part of that stupid auto chat status thingy? + conf=self.sh['conf']['chat'] + print conf + if conf['auto_states_enabled']=='True': + user=self.sh['conf']['account']['user'] + curStatus=self.sh['users'][user]['State'] + + stat=None + if re.match(conf['auto_states_online'], t): stat='online' + if re.match(conf['auto_states_busy'], t): stat='busy' + if re.match(conf['auto_states_away'], t): stat='away' + + if stat and stat != curStatus: + self.sh['Brains'].setStatus(stat) + + return self.inputText Modified: branches/VP-Grounds/modules/playground.py =================================================================== --- branches/VP-Grounds/modules/playground.py 2009-05-02 15:19:34 UTC (rev 297) +++ branches/VP-Grounds/modules/playground.py 2009-05-09 15:25:00 UTC (rev 298) @@ -26,10 +26,10 @@ #Loading all our objects-modules (kinda like interface.py) self.modObjects = {} - for object in os.listdir(getRealDir('modules','playground')): - if object[-3:] == '.py': - realName = os.path.join('modules', 'playground', object[:-3]) - self.modObjects[object[:-3]] = __import__(realName).Object + for object in os.listdir(getRealDir('modules','playgroundObj')): + if object[-3:] == '.py' and not object.startswith('__'): + realName = '.'.join(('modules', 'playgroundObj', object[:-3])) + self.modObjects[object[:-3]] = __import__(realName, fromlist=object[:-3]).Object self.surf = pygame.Surface((726, 402)) Deleted: branches/VP-Grounds/modules/playgroundObj/__init__.py =================================================================== --- trunk/VP/modules/playgroundObj/__init__.py 2009-05-02 15:19:34 UTC (rev 297) +++ branches/VP-Grounds/modules/playgroundObj/__init__.py 2009-05-09 15:25:00 UTC (rev 298) @@ -1 +0,0 @@ -# Dummy file, not a playground-module. Do NOT remove this file! Copied: branches/VP-Grounds/modules/playgroundObj/__init__.py (from rev 297, trunk/VP/modules/playgroundObj/__init__.py) =================================================================== --- branches/VP-Grounds/modules/playgroundObj/__init__.py (rev 0) +++ branches/VP-Grounds/modules/playgroundObj/__init__.py 2009-05-09 15:25:00 UTC (rev 298) @@ -0,0 +1 @@ +# Dummy file, not a playground-module. Do NOT remove this file! Added: branches/VP-Grounds/modules/playgroundObj/avatar-multidir.py =================================================================== --- branches/VP-Grounds/modules/playgroundObj/avatar-multidir.py (rev 0) +++ branches/VP-Grounds/modules/playgroundObj/avatar-multidir.py 2009-05-09 15:25:00 UTC (rev 298) @@ -0,0 +1,102 @@ +from functions import * + +class Object(): + def __init__(self, data, share): + self.sh = share + + self.currentDir=-1 #-1=none, 0=d, 1=l, 2=u, 3=r + + self.imageName=data['Avatar'][1] + self.image=None + self.fullImage=None + + self.rect = Rect(data['Pos'][1], data['Pos'][2]-data['Pos'][3], 0, 0) + self.zorder = self.rect.top + self.rect.height + self.blitRect = Rect(0,0,0,0) #Internal rect, inside fullImage + + def show(self): + """ + Start the whole process of: + checking whether avatar is downloaded, [download it], return avatar, and finally: blit ourselves. + This has to be a seperate def. If you put this right into __init__, we will make playground blit + ourself, before the initialisation is ready. And so, if that's not ready, we're not in the objects + list of the playground, and we will not be blitted. + """ + self.sh['Downloader'].getImage(self.imageName, self.imageUpdate) + + def imageUpdate(self, image, *arg): + """ + The downloader will call this when he's finished. + Will load in the image, and make playground blit our rect. + """ + + self.rect.size = image[1].size + self.rect.w = self.rect.w/4 + + self.blitRect.size=self.rect.size + + self.fullImage = image[0] + + self.setDir(0) + + self.zorder = self.rect.top + self.rect.height + + self.sh['Playground'].blit(self.rect) + + def update(self, screen, rect): + if not self.image: return + if self.rect.colliderect(rect): #Check if the rect collide with ours + rect = rect.move(-self.rect[0], -self.rect[1]) #Move rect to our position + myPos = (self.rect[0] + rect[0], self.rect[1] + rect[1]) #Calculate our position from the rect + screen.blit(self.image, myPos, rect) #Blit + + + def move(self, pos): + """ + Call this def to move this avatar to pos x=pos[1], y=pos[2]. + Will update rect, and make playground module update our old+new area. + Will also change our direction if needed. + """ + oldRect=self.rect.__copy__() + + #Change avatar direction + if self.rect.x < pos[1]: self.setDir('r') + elif self.rect.x > pos[1]: self.setDir('l') + elif self.rect.y < pos[2]: self.setDir('d') + elif self.rect.y > pos[2]: self.setDir('u') + + self.rect.x=pos[1] + self.rect.y=pos[2]-pos[3] + self.zorder = self.rect.top + self.rect.height + + updateRect=oldRect.union(self.rect) + + self.sh['Playground'].blit(updateRect) + + def setDir(self, dir, blit=False): + """ + Change avatar direction. + `dir` can be either int(0,1,2,3) or str('d','l','u','r'). + """ + + #Change to correct value, or exit + if type(dir)!=int: + if dir=='d': dir=0 + elif dir=='l': dir=1 + elif dir=='u': dir=2 + elif dir=='r': dir=3 + else: return + + if dir < 0 or dir > 3: return #Valid number? + if dir == self.currentDir: return #Not the same as old direction? + + if not self.fullImage: return #Do we have base image? + + self.currentDir=dir + + #Actually change image + self.blitRect.x = self.blitRect.w * dir + self.image=self.fullImage.subsurface(self.blitRect) + + if blit: + self.sh['Playground'].blit(self.rect) Added: branches/VP-Grounds/modules/playgroundObj/avatar-multidir_parts.py =================================================================== --- branches/VP-Grounds/modules/playgroundObj/avatar-multidir_parts.py (rev 0) +++ branches/VP-Grounds/modules/playgroundObj/avatar-multidir_parts.py 2009-05-09 15:25:00 UTC (rev 298) @@ -0,0 +1,123 @@ +from functions import * + +class Object(): + def __init__(self, data, share): + self.sh = share + + self.currentDir=0 # 0=d, 1=l, 2=u, 3=r + + self.imageList=data['Avatar'][1:] + self.imageNameList=data['Avatar'][1:] + self.rect = Rect(data['Pos'][1], data['Pos'][2]-data['Pos'][3], 0, 0) + self.zorder = self.rect.top + self.rect.height + + def show(self): + """ + Start the whole process of: + checking whether avatar is downloaded, [download it], return avatar, and finally: blit ourselves. + This has to be a seperate def. If you put this right into __init__, we will make playground blit + ourself, before the initialisation is ready. And so, if that's not ready, we're not in the objects + list of the playground, and we will not be blitted. + """ + + #We have multiple images, so loop through them, to download them all + for image in self.imageList: + self.sh['Downloader'].getImage(image, self.imageUpdate, image) + + def imageUpdate(self, image, *arg): + """ + The downloader will call this when he's finished. + Will load in the image, and when we have all our images, we wil build ourselved. + """ + imageName=arg[0] + image=image + + self.imageList[self.imageNameList.index(imageName)]=image + + #Does our list still contain strings? + #(wich indicates we are still awaiting some downloads) + for img in self.imageList: + if type(img)!=tuple: return + + self.buildAvatar(True) + + def update(self, screen, rect): + if self.rect.colliderect(rect): #Check if the rect collide with ours + rect = rect.move(-self.rect[0], -self.rect[1]) #Move rect to our position + myPos = (self.rect[0] + rect[0], self.rect[1] + rect[1]) #Calculate our position from the rect + screen.blit(self.image, myPos, rect) #Blit + + + def move(self, pos): + """ + Call this def to move this avatar to pos x=pos[1], y=pos[2]. + Will update rect, and make playground module update our old+new area. + Will also change our direction if needed. + """ + oldRect=self.rect.__copy__() + + #Change avatar direction + if self.rect.x < pos[1]: self.setDir('r') + elif self.rect.x > pos[1]: self.setDir('l') + elif self.rect.y < pos[2]: self.setDir('d') + elif self.rect.y > pos[2]: self.setDir('u') + + self.rect.x=pos[1] + self.rect.y=pos[2]-pos[3] + self.zorder = self.rect.top + self.rect.height + + updateRect=oldRect.union(self.rect) + + self.sh['Playground'].blit(updateRect) + + + def buildAvatar(self, blit=False): + oldRect=self.rect.__copy__() #So we can combine it later with our new rect, so we can also update te old area + + #Update Width(w) and height(h) + self.rect.w=max([rect.w/4 for img,rect in self.imageList]) + self.rect.h=0 + for img, rect in self.imageList: self.rect.h+=rect.h + + #And the zorder('cause we have new height) + self.zorder=self.rect.top+self.rect.height + + #Create clean surface for our avatar + self.image=pygame.Surface(self.rect.size, SRCALPHA, 32) + + #Blit all parts on this fresh surface + y=0 + for img,rect in self.imageList: + w=rect.w/4 #width of real image(there are 4 images in this one, for directions) + x=self.rect.w/2-w/2 + + self.image.blit(img, (x,y), (w*self.currentDir,0,w,rect.h)) + y+=rect.h + + if blit: + #Combine rects, and update area. It's time to show ourselves! :D + updateRect=self.rect.union(oldRect) + self.sh['Playground'].blit(updateRect) + + + def setDir(self, dir, blit=False): + """ + Change avatar direction. + `dir` can be either int(0,1,2,3) or str('d','l','u','r'). + """ + + #Change to correct value, or exit + if type(dir)!=int: + if dir=='d': dir=0 + elif dir=='l': dir=1 + elif dir=='u': dir=2 + elif dir=='r': dir=3 + else: return + + if dir < 0 or dir > 3: return #Valid number? + if dir == self.currentDir: return #Not the same as old direction? + + self.currentDir=dir + + #Actually change image + self.buildAvatar(blit) Added: branches/VP-Grounds/modules/playgroundObj/avatar-multipart.py =================================================================== --- branches/VP-Grounds/modules/playgroundObj/avatar-multipart.py (rev 0) +++ branches/VP-Grounds/modules/playgroundObj/avatar-multipart.py 2009-05-09 15:25:00 UTC (rev 298) @@ -0,0 +1,88 @@ +from functions import * + +class Object(): + def __init__(self, data, share): + self.sh = share + + self.imageList=data['Avatar'][1:] + self.imageNameList=data['Avatar'][1:] + self.rect = Rect(data['Pos'][1], data['Pos'][2]-data['Pos'][3], 0, 0) + self.zorder = self.rect.top + self.rect.height + + def show(self): + """ + Start the whole process of: + checking whether avatar is downloaded, [download it], return avatar, and finally: blit ourselves. + This has to be a seperate def. If you put this right into __init__, we will make playground blit + ourself, before the initialisation is ready. And so, if that's not ready, we're not in the objects + list of the playground, and we will not be blitted. + """ + + #We have multiple images, so loop through them, to download them all + for image in self.imageList: + self.sh['Downloader'].getImage(image, self.imageUpdate, image) + + def imageUpdate(self, image, *arg): + """ + The downloader will call this when he's finished. + Will load in the image, and when we have all our images, we wil build ourselved. + """ + imageName=arg[0] + image=image + + self.imageList[self.imageNameList.index(imageName)]=image + + #Does our list still contain strings? + #(wich indicates we are still awaiting some downloads) + for img in self.imageList: + if type(img)!=tuple: return + + self.buildAvatar() + + def update(self, screen, rect): + if self.rect.colliderect(rect): #Check if the rect collide with ours + rect = rect.move(-self.rect[0], -self.rect[1]) #Move rect to our position + myPos = (self.rect[0] + rect[0], self.rect[1] + rect[1]) #Calculate our position from the rect + screen.blit(self.image, myPos, rect) #Blit + + + def move(self, pos): + """ + Call this def to move this avatar to pos x=pos[1], y=pos[2]. + Will update rect, and make playground module update our old+new area + """ + oldRect=self.rect.__copy__() + + self.rect.x=pos[1] + self.rect.y=pos[2]-pos[3] + self.zorder = self.rect.top + self.rect.height + + updateRect=oldRect.union(self.rect) + + self.sh['Playground'].blit(updateRect) + + + def buildAvatar(self): + oldRect=self.rect.__copy__() #So we can combine it later with our new rect, so we can also update te old area + + #Update Width(w) and height(h) + self.rect.w=max([rect.w for img,rect in self.imageList]) + self.rect.h=0 + for img, rect in self.imageList: self.rect.h+=rect.h + + #And the zorder('cause we have new height) + self.zorder=self.rect.top+self.rect.height + + #Create clean surface for our avatar + self.image=pygame.Surface(self.rect.size, SRCALPHA, 32) + + #Blit all parts on this fresh surface + y=0 + for img,rect in self.imageList: + x=self.rect.w/2-rect.w/2 + self.image.blit(img, (x,y)) + y+=rect.h + + #Combine rects, and update area. It's time to show ourselves! :D + updateRect=self.rect.union(oldRect) + self.sh['Playground'].blit(updateRect) Added: branches/VP-Grounds/modules/playgroundObj/avatar-static.py =================================================================== --- branches/VP-Grounds/modules/playgroundObj/avatar-static.py (rev 0) +++ branches/VP-Grounds/modules/playgroundObj/avatar-static.py 2009-05-09 15:25:00 UTC (rev 298) @@ -0,0 +1,52 @@ +from functions import * + +class Object(): + def __init__(self, data, share): + self.sh = share + + self.imageName=data['Avatar'][1] + self.rect = Rect(data['Pos'][1], data['Pos'][2]-data['Pos'][3], 0, 0) + self.zorder = self.rect.top + self.rect.height + + def show(self): + """ + Start the whole process of: + checking whether avatar is downloaded, [download it], return avatar, and finally: blit ourselves. + This has to be a seperate def. If you put this right into __init__, we will make playground blit + ourself, before the initialisation is ready. And so, if that's not ready, we're not in the objects + list of the playground, and we will not be blitted. + """ + self.sh['Downloader'].getImage(self.imageName, self.imageUpdate) + + def imageUpdate(self, image, *arg): + """ + The downloader will call this when he's finished. + Will load in the image, and make playground blit our rect. + """ + self.image = image[0] + self.rect.size = image[1].size + self.zorder = self.rect.top + self.rect.height + + self.sh['Playground'].blit(self.rect) + + def update(self, screen, rect): + if self.rect.colliderect(rect): #Check if the rect collide with ours + rect = rect.move(-self.rect[0], -self.rect[1]) #Move rect to our position + myPos = (self.rect[0] + rect[0], self.rect[1] + rect[1]) #Calculate our position from the rect + screen.blit(self.image, myPos, rect) #Blit + + + def move(self, pos): + """ + Call this def to move this avatar to pos x=pos[1], y=pos[2]. + Will update rect, and make playground module update our old+new area + """ + oldRect=self.rect.__copy__() + + self.rect.x=pos[1] + self.rect.y=pos[2]-pos[3] + self.zorder = self.rect.top + self.rect.height + + updateRect=oldRect.union(self.rect) + + self.sh['Playground'].blit(updateRect) Deleted: branches/VP-Grounds/modules/playgroundObj/background.py =================================================================== --- trunk/VP/modules/playgroundObj/background.py 2009-05-02 15:19:34 UTC (rev 297) +++ branches/VP-Grounds/modules/playgroundObj/background.py 2009-05-09 15:25:00 UTC (rev 298) @@ -1,44 +0,0 @@ -from functions import * - -class Object(): - def __init__(self, data, share): - self.downloader = share['downloader'] - self.master = share['master'] - - #Settings defaults - data['background'] = data.get('background', None) - backgroundcolor = data.get('backgroundcolor', (0,0,0)) - data['backgroundcolor'] = [int(c) for c in backgroundcolor] - self.data = data - - self.rect = Rect(0,0,726,402) - self.zorder = -1000 - - if self.data['background'] != None: - self.background = None - - self.downloader.getImage(self.data['background'], self.imageChange) - else: - self.background = pygame.Surface((726,402)) - self.background.fill(self.data['backgroundcolor']) - - def imageChange(self, image, *arg): - #Creating a new surface - self.background = pygame.Surface((726,402)) - self.background.fill(self.data['backgroundcolor']) - - #Trying to tile the image - pos = [0,0] - while pos[1] < 402: - while pos[0] < 726: - self.background.blit(image[0], pos) - pos[0] += image[1].w - pos[1] += image[1].h - pos[0] = 0 - self.master.blit(self.rect) - - def update(self, screen, rect): - if self.rect.colliderect(rect): #Check if the rect collide with ours - rect = rect.move(-self.rect[0], -self.rect[1]) #Move rect to our position - myPos = (self.rect[0] + rect[0], self.rect[1] + rect[1]) #Calculate our position from the rect - screen.blit(self.background, myPos, rect) #Blit Copied: branches/VP-Grounds/modules/playgroundObj/background.py (from rev 297, trunk/VP/modules/playgroundObj/background.py) =================================================================== --- branches/VP-Grounds/modules/playgroundObj/background.py (rev 0) +++ branches/VP-Grounds/modules/playgroundObj/background.py 2009-05-09 15:25:00 UTC (rev 298) @@ -0,0 +1,43 @@ +from functions import * + +class Object(): + def __init__(self, data, share): + self.sh = share + + #Settings defaults + data['background'] = data.get('background', None) + backgroundcolor = data.get('backgroundcolor', (0,0,0)) + data['backgroundcolor'] = [int(c) for c in backgroundcolor] + self.data = data + + self.rect = Rect(0,0,726,402) + self.zorder = -1000 + + if self.data['background'] != None: + self.background = None + + self.sh['Downloader'].getImage(self.data['background'], self.imageChange) + else: + self.background = pygame.Surface((726,402)) + self.background.fill(self.data['backgroundcolor']) + + def imageChange(self, image, *arg): + #Creating a new surface + self.background = pygame.Surface((726,402)) + self.background.fill(self.data['backgroundcolor']) + + #Trying to tile the image + pos = [0,0] + while pos[1] < 402: + while pos[0] < 726: + self.background.blit(image[0], pos) + pos[0] += image[1].w + pos[1] += image[1].h + pos[0] = 0 + self.sh['Playground'].blit(self.rect) + + def update(self, screen, rect): + if self.rect.colliderect(rect): #Check if the rect collide with ours + rect = rect.move(-self.rect[0], -self.rect[1]) #Move rect to our position + myPos = (self.rect[0] + rect[0], self.rect[1] + rect[1]) #Calculate our position from the rect + screen.blit(self.background, myPos, rect) #Blit Deleted: branches/VP-Grounds/modules/playgroundObj/object.py =================================================================== --- trunk/VP/modules/playgroundObj/object.py 2009-05-02 15:19:34 UTC (rev 297) +++ branches/VP-Grounds/modules/playgroundObj/object.py 2009-05-09 15:25:00 UTC (rev 298) @@ -1,50 +0,0 @@ -from functions import * - -class Object(): - def __init__(self, data, share): - self.downloader = share['downloader'] - self.master = share['master'] - - obj = data['objecttype'] - - self.pos = [int(i) for i in data['pos']] - self.size = [int(i) for i in obj['size']] - self.objZorder = int(obj['zorder']) - - #self.image = None - #self.imageName = 'default' - self.imageD = obj['imageD'] - self.imageN = obj['imageN'] - self.imageStyle = 'D' - - self.rect = Rect(self.pos[0], self.pos[1]-self.pos[2], self.size[0], self.size[1]) - self.zorder = self.pos[1] + self.objZorder - - self.changeImage('default') - - - def changeImage(self, name): - self.imageName = name - if self.imageStyle == 'D': - name = self.imageD[name] - else: - name = self.imageN[name] - - self.downloader.getImage(name, self.imageUpdate) - - - def imageUpdate(self, image, *arg): - self.image = list(image) - if list(image[1].size) != self.size: - self.image[0] = pygame.transform.smoothscale(self.image[0], self.size) - - self.master.blit(self.rect) - - - def update(self, screen, rect): - #print rect, self.rect - if self.rect.colliderect(rect): #Check if the rect collide with ours - rect = rect.move(-self.rect[0], -self.rect[1]) #Move rect to our position - myPos = (self.rect[0] + rect[0], self.rect[1] + rect[1]) #Calculate our position from the rect - screen.blit(self.image[0], myPos, rect) #Blit - #screen.blit(self.image[0], (0,0)) Copied: branches/VP-Grounds/modules/playgroundObj/object.py (from rev 297, trunk/VP/modules/playgroundObj/object.py) =================================================================== --- branches/VP-Grounds/modules/playgroundObj/object.py (rev 0) +++ branches/VP-Grounds/modules/playgroundObj/object.py 2009-05-09 15:25:00 UTC (rev 298) @@ -0,0 +1,72 @@ +from functions import * + +class Object(): + def __init__(self, data, share): + self.sh = share + + obj = data['objecttype'] + + self.pos = [int(i) for i in data['pos']] + self.size = [int(i) for i in obj['size']] + self.objZorder = int(obj['zorder']) + + self.walls = data['objecttype']['walls'] + #Convert a dict of walls (in format 'name':['X1','X2','Y1','Y2','Z1','Z2']) + #to a simple list with all int values + self.walls = [[int(i) for i in w] for w in self.walls.values()] + + #Create a copy of our walls, and move these walls, so they + #are real position, instead of internal position + self.realWalls=[] + for wall in self.walls: + wall = wall[:] #Make a copy of this var, so we don't change it in our origional list + wall[0]+=self.pos[0] + wall[1]+=self.pos[0] + wall[2]+=self.pos[1] + wall[3]+=self.pos[1] + self.realWalls.append(wall) + + + + self.imageD = obj['imageD'] + self.imageN = obj['imageN'] + self.imageStyle = 'D' + + self.rect = Rect(self.pos[0], self.pos[1]-self.pos[2], self.size[0], self.size[1]) + self.zorder = self.pos[1] + self.objZorder + + self.changeImage('default') + + + def changeImage(self, name): + self.imageName = name + if self.imageStyle == 'D': + name = self.imageD[name] + else: + name = self.imageN[name] + + self.sh['Downloader'].getImage(name, self.imageUpdate) + + + def imageUpdate(self, image, *arg): + self.image = list(image) + if list(image[1].size) != self.size: + self.image[0] = pygame.transform.smoothscale(self.image[0], self.size) + + n=0 + for wall in self.walls: + rect=Rect(wall[0], wall[2], wall[1]-wall[0], wall[3]-wall[2]) + col=(50+20*n,50+20*n,50+20*n,200) + self.image[0].fill(col,rect) + + n+=1 + + self.sh['Playground'].blit(self.rect) + + + def update(self, screen, rect): + if self.rect.colliderect(rect): #Check if the rect collide with ours + rect = rect.move(-self.rect[0], -self.rect[1]) #Move rect to our position + myPos = (self.rect[0] + rect[0], self.rect[1] + rect[1]) #Calculate our position from the rect + screen.blit(self.image[0], myPos, rect) #Blit + #screen.blit(self.image[0], (0,0)) Modified: branches/VP-Grounds/modules/settings.py =================================================================== --- branches/VP-Grounds/modules/settings.py 2009-05-02 15:19:34 UTC (rev 297) +++ branches/VP-Grounds/modules/settings.py 2009-05-09 15:25:00 UTC (rev 298) @@ -117,8 +117,7 @@ gui.Label(position = (15,80), parent = self.tab_misc, text = self.lang('misc','autochangestatus'))#section caption #DISABLED self.as_time=gui.CheckBox(position = self.tab_misc.nextPosition(5), parent = self.tab_misc, text = self.lang('misc','afterxmin'), value=conf['misc']['time_after_idle'],enabled=False) - #DISABLED - self.as_chat=gui.CheckBox(position = self.tab_misc.nextPosition(2), parent = self.tab_misc, text = self.lang('misc','chat'), value=conf['chat']['auto_states_enabled'],enabled=False) + self.as_chat=gui.CheckBox(position = self.tab_misc.nextPosition(2), parent = self.tab_misc, text = self.lang('misc','chat'), value=conf['chat']['auto_states_enabled']) #Create a special font style for our button labelStyleCopy = gui.defaultLabelStyle.copy() @@ -280,12 +279,6 @@ when the user click the 'reset chat states' button. Updates all images""" - #standard regexes - #now in lang files - #sonline="(b|back)\Z" - #sbusy="(phone|dnd)((\W.*)\Z|\Z)" - #saway="(brb|afk)((\W.*)\Z|\Z)" - #save in the local dict conf = self.sh['conf'] conf['chat']['auto_states_online'] = self.lang('autostatechangedefault','online') Modified: branches/VP-Grounds/notify.py =================================================================== --- branches/VP-Grounds/notify.py 2009-05-02 15:19:34 UTC (rev 297) +++ branches/VP-Grounds/notify.py 2009-05-09 15:25:00 UTC (rev 298) @@ -1,9 +1,36 @@ -import pynotify, re from functions import getRealDir -pynotify.init("Virtual Playground") + +method = None +print 'Looking for notify program...' + +#pynotify +try: + import pynotify +except ImportError: + print 'Not found: pynotify' +else: + import re + pynotify.init("Virtual Playground") + + print 'Found pynotify!' + method = 'pynotify' + +if not method: + #snarl + try: + import PySnarl + except ImportError: + print 'Not found: snarl' + else: + print 'Found snarl!' + method = 'snarl' + +if not method: print 'No notify program found!' + + def popup(caption,msg, img="", timeout=5000, urgency="normal"): - """popup(caption, message, image="", timeout=5000, urgency="normal) + """popup(caption, message, image="", timeout=5000, urgency="normal") Show a popup on screen. @@ -14,28 +41,36 @@ Urgency: low, normal, high """ - #Don't make libnotify crash by alien characters - msg=msg.decode('utf-8') + if method=='snarl': + id = PySnarl.snShowMessage( title = caption, + text = msg, + timeout = timeout/1000, + iconPath = getRealDir('images','popup',img)) - #Clickable urls - msg=re.sub('([^:]+://[^.]+\.[^ ]+)', '<a href="\\1">\\1</a>', msg) + elif method=='pynotify': - #Create it - notif=pynotify.Notification(caption,\ - msg,\ - getRealDir('images','popup',img)) - - #How long should we keep it on the screen? - notif.set_timeout(timeout) - - #Urgency - if urgency=="low": - notif.set_urgency(pynotify.URGENCY_LOW) - elif urgency=="high" or urgency=="critical": - notif.set_urgency(pynotify.URGENCY_CRITICAL) - else: - notif.set_urgency(pynotify.URGENCY_NORMAL) - - #Show it(+error catcher thingy) - if not notif.show(): - print "Failed to show notification" + #Don't make libnotify crash by alien characters + msg=msg.decode('utf-8') + + #Clickable urls + msg=re.sub('([^:]+://[^.]+\.[^ ]+)', '<a href="\\1">\\1</a>', msg) + + #Create it + notif=pynotify.Notification(caption, + msg, + getRealDir('images','popup',img)) + + #How long should we keep it on the screen? + notif.set_timeout(timeout) + + #Urgency + if urgency=="low": + notif.set_urgency(pynotify.URGENCY_LOW) + elif urgency=="high" or urgency=="critical": + notif.set_urgency(pynotify.URGENCY_CRITICAL) + else: + notif.set_urgency(pynotify.URGENCY_NORMAL) + + #Show it(+error catcher thingy) + if not notif.show(): + print "Failed to show notification" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ch...@us...> - 2009-05-02 15:19:39
|
Revision: 297 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=297&view=rev Author: chozone Date: 2009-05-02 15:19:34 +0000 (Sat, 02 May 2009) Log Message: ----------- Made some basic commands for the input (like //exit). And now, the auto chat status thing works (like when you say 'brb', it will change your status to away). Modified Paths: -------------- trunk/VP/TODO trunk/VP/VP.py trunk/VP/lang/en.lang trunk/VP/lang/nl.lang trunk/VP/modules/input.py trunk/VP/modules/settings.py Modified: trunk/VP/TODO =================================================================== --- trunk/VP/TODO 2009-05-01 22:22:11 UTC (rev 296) +++ trunk/VP/TODO 2009-05-02 15:19:34 UTC (rev 297) @@ -17,10 +17,6 @@ Info(bar) * Creating the Info bar with information like: Current ground, user(?), money... - - Input -* Making special commands in chat -* Making that 'auto chat status' thingy (when you say something like 'brb', it will change your status to 'away') Menu * Creating checkitems (assigned to BlueWolf_) Modified: trunk/VP/VP.py =================================================================== --- trunk/VP/VP.py 2009-05-01 22:22:11 UTC (rev 296) +++ trunk/VP/VP.py 2009-05-02 15:19:34 UTC (rev 297) @@ -45,9 +45,9 @@ #chat auto-states if not 'chat' in conf: conf['chat'] = {} - conf['chat']['auto_states_enabled'] = conf['chat'].get('auto_states_enabled','False') #Later this True? + conf['chat']['auto_states_enabled'] = conf['chat'].get('auto_states_enabled','True') conf['chat']['auto_states_online'] = conf['chat'].get('auto_states_online','(b|back)\Z') - conf['chat']['auto_states_busy'] = conf['chat'].get('auto_states_busy','(phone|dnd)((\W.*)\Z|\Z)') + conf['chat']['auto_states_busy'] = conf['chat'].get('auto_states_busy','(dnd)((\W.*)\Z|\Z)') conf['chat']['auto_states_away'] = conf['chat'].get('auto_states_away','(brb|afk)((\W.*)\Z|\Z)') #animations @@ -72,7 +72,6 @@ #Without timeout, the Queue will not respond to KeyboardInterrupts. #This is a timeout of year. Think that will be enough :-) resp = share['response'].get(True, 31536000) - print resp if resp[0] == 'Exit': pygame.event.post(pygame.event.Event(QUIT)) Modified: trunk/VP/lang/en.lang =================================================================== --- trunk/VP/lang/en.lang 2009-05-01 22:22:11 UTC (rev 296) +++ trunk/VP/lang/en.lang 2009-05-02 15:19:34 UTC (rev 297) @@ -50,7 +50,7 @@ [[autostatechangedefault]] online = (b|back)\Z -busy = (phone|dnd)((\W.*)\Z|\Z) +busy = (dnd)((\W.*)\Z|\Z) away = (brb|afk)((\W.*)\Z|\Z) Modified: trunk/VP/lang/nl.lang =================================================================== --- trunk/VP/lang/nl.lang 2009-05-01 22:22:11 UTC (rev 296) +++ trunk/VP/lang/nl.lang 2009-05-02 15:19:34 UTC (rev 297) @@ -50,7 +50,7 @@ [[autostatechangedefault]] online = (b|back|biw)\Z -busy = (phone|dnd)((\W.*)\Z|\Z) +busy = (dnd)((\W.*)\Z|\Z) away = (brb|afk|bzt)((\W.*)\Z|\Z) Modified: trunk/VP/modules/input.py =================================================================== --- trunk/VP/modules/input.py 2009-05-01 22:22:11 UTC (rev 296) +++ trunk/VP/modules/input.py 2009-05-02 15:19:34 UTC (rev 297) @@ -1,5 +1,5 @@ from functions import * -import time +import time, re class Module(): def __init__(self, share, *arg): @@ -39,9 +39,8 @@ else: #Just an enter if self.inputText != '': - if self.inputText == '//exit': - self.sh['response'].put(('Exit',)) - else: + textToSend=self.checkChat() + if textToSend: text = self.inputText.encode('utf-8') text = text.strip() self.sh['Brains'].chatSend(text) @@ -141,3 +140,51 @@ interface.update([179,471,370,29]) + + + def checkChat(self): + """ + Handles all commands that are in the chat. + Is called when user presses the enter key in the Input. + The message that will be send to the server is what this function returns. + """ + t=self.inputText + c=t[2:] if len(t)>=2 and t.startswith('//') else '' + + if c == 'exit' or c == 'quit': + self.sh['response'].put(('Exit',)) + elif c == 'time' or c == 'date' or c == 'datetime': + return time.ctime() + elif c.startswith('stat ') or c.startswith('status '): + t=t.replace('//status ', '') + t=t.replace('//stat ', '') + if t == 'online' or t == 'busy' or t == 'away': + user=self.sh['conf']['account']['user'] + curStatus=self.sh['users'][user]['State'] + + if t != curStatus: + self.sh['Brains'].setStatus(t) + else: + return self.inputText + elif c == 'online' or c == 'busy' or c == 'away': + user=self.sh['conf']['account']['user'] + curStatus=self.sh['users'][user]['State'] + if c != curStatus: + self.sh['Brains'].setStatus(c) + else: + #Maybe... it is part of that stupid auto chat status thingy? + conf=self.sh['conf']['chat'] + print conf + if conf['auto_states_enabled']=='True': + user=self.sh['conf']['account']['user'] + curStatus=self.sh['users'][user]['State'] + + stat=None + if re.match(conf['auto_states_online'], t): stat='online' + if re.match(conf['auto_states_busy'], t): stat='busy' + if re.match(conf['auto_states_away'], t): stat='away' + + if stat and stat != curStatus: + self.sh['Brains'].setStatus(stat) + + return self.inputText Modified: trunk/VP/modules/settings.py =================================================================== --- trunk/VP/modules/settings.py 2009-05-01 22:22:11 UTC (rev 296) +++ trunk/VP/modules/settings.py 2009-05-02 15:19:34 UTC (rev 297) @@ -117,8 +117,7 @@ gui.Label(position = (15,80), parent = self.tab_misc, text = self.lang('misc','autochangestatus'))#section caption #DISABLED self.as_time=gui.CheckBox(position = self.tab_misc.nextPosition(5), parent = self.tab_misc, text = self.lang('misc','afterxmin'), value=conf['misc']['time_after_idle'],enabled=False) - #DISABLED - self.as_chat=gui.CheckBox(position = self.tab_misc.nextPosition(2), parent = self.tab_misc, text = self.lang('misc','chat'), value=conf['chat']['auto_states_enabled'],enabled=False) + self.as_chat=gui.CheckBox(position = self.tab_misc.nextPosition(2), parent = self.tab_misc, text = self.lang('misc','chat'), value=conf['chat']['auto_states_enabled']) #Create a special font style for our button labelStyleCopy = gui.defaultLabelStyle.copy() @@ -280,12 +279,6 @@ when the user click the 'reset chat states' button. Updates all images""" - #standard regexes - #now in lang files - #sonline="(b|back)\Z" - #sbusy="(phone|dnd)((\W.*)\Z|\Z)" - #saway="(brb|afk)((\W.*)\Z|\Z)" - #save in the local dict conf = self.sh['conf'] conf['chat']['auto_states_online'] = self.lang('autostatechangedefault','online') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ch...@us...> - 2009-05-01 22:22:13
|
Revision: 296 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=296&view=rev Author: chozone Date: 2009-05-01 22:22:11 +0000 (Fri, 01 May 2009) Log Message: ----------- With the following modifications, VP now works on windows: -event handler had to be in main thread, so swapped event loop, and Reponse loop. (is the Response loop still needed?) -notify.py now works with more than one program(not platform-dependent!). Also added support for Snarl. -on windows, clipboard now works, and had to replace all chr(0)'s with '', because... well, it's windows... Modified Paths: -------------- trunk/VP/TODO trunk/VP/VP.py trunk/VP/modules/input.py trunk/VP/notify.py Modified: trunk/VP/TODO =================================================================== --- trunk/VP/TODO 2009-05-01 15:27:26 UTC (rev 295) +++ trunk/VP/TODO 2009-05-01 22:22:11 UTC (rev 296) @@ -11,9 +11,16 @@ Chat * Making the scroll button (assigned to BlueWolf_) + Help +* Creating the help system (like http://dl.getdropbox.com/u/343509/help1.png) + Info(bar) * Creating the Info bar with information like: Current ground, user(?), money... + + Input +* Making special commands in chat +* Making that 'auto chat status' thingy (when you say something like 'brb', it will change your status to 'away') Menu * Creating checkitems (assigned to BlueWolf_) @@ -22,7 +29,7 @@ Playground (see VP-Grounds branche) * Creating the avatars (the images) -* Walls (assigned to chozone) +* Walls (assigned to chozone) on hold, we need jumping, before we can create/test this any further * Smooth walking * Jumping (will be assigned to BlueWolf_, or someone else really wants to do this...?) * Walking/running bit slower when walking diagonally (assigned to chozone) Modified: trunk/VP/VP.py =================================================================== --- trunk/VP/VP.py 2009-05-01 15:27:26 UTC (rev 295) +++ trunk/VP/VP.py 2009-05-01 22:22:11 UTC (rev 296) @@ -61,27 +61,22 @@ conf['misc']['time_after_idle'] = int(conf['misc'].get('time_after_idle', 0)) #in mins, 0 = off, later this 5? -class Events(threading.Thread): +class ResponseLoop(threading.Thread): def __init__(self, share): self.sh = share threading.Thread.__init__(self) def run(self): while 1: - resp = pygame.event.wait() - if resp.type == QUIT: - self.sh['response'].put(('Exit',)) + #Some wacky workaround here. + #Without timeout, the Queue will not respond to KeyboardInterrupts. + #This is a timeout of year. Think that will be enough :-) + resp = share['response'].get(True, 31536000) + print resp + + if resp[0] == 'Exit': + pygame.event.post(pygame.event.Event(QUIT)) return - - elif resp.type == USEREVENT: #Pinger - self.sh['Connection'].ping() - - elif resp.type == ACTIVEEVENT: - if resp.state == 2: #focus - self.sh['focus'] = resp.gain - - else: - self.sh['Interface'].event(resp, lock=True) @@ -116,23 +111,29 @@ share['Sounds'].start() share['Brains'].start() +#Start Response-loop in thread +respLoop = ResponseLoop(share) +respLoop.start() -#Starting our event-catcher -events = Events(share) -events.start() - #Entering our main-loop. Yeah! try: while 1: - #Some wacky workaround here. - #Without timeout, the Queue will not response to KeyboardInterrupts. - #This is a timeout of year. Think that will be enough :-) - resp = response.get(True, 31536000) + resp = pygame.event.wait() - if resp[0] == 'Exit': - share['conf'].write() - exit() + if resp.type == QUIT: + share['conf'].write() + exit() + + elif resp.type == USEREVENT: #Pinger + share['Connection'].ping() + + elif resp.type == ACTIVEEVENT: + if resp.state == 2: #focus + share['focus'] = resp.gain + + else: + share['Interface'].event(resp, lock=True) except KeyboardInterrupt: print Modified: trunk/VP/modules/input.py =================================================================== --- trunk/VP/modules/input.py 2009-05-01 15:27:26 UTC (rev 295) +++ trunk/VP/modules/input.py 2009-05-01 22:22:11 UTC (rev 296) @@ -39,9 +39,12 @@ else: #Just an enter if self.inputText != '': - text = self.inputText.encode('utf-8') - text = text.strip() - self.sh['Brains'].chatSend(text) + if self.inputText == '//exit': + self.sh['response'].put(('Exit',)) + else: + text = self.inputText.encode('utf-8') + text = text.strip() + self.sh['Brains'].chatSend(text) self.inputText = '' self.blit() @@ -56,9 +59,17 @@ else: #Control key pressed (and no backspace....) if ev.key == K_v: #Ctrl+V, paste clipboard - text = pygame.scrap.get('UTF8_STRING') - text = unicode(text) + if sys.platform == 'win32': + text = pygame.scrap.get('text/plain;charset=utf-8') + else: + text = pygame.scrap.get('UTF8_STRING') + + + if text: + text=text.replace(chr(0), '') + text = unicode(text) + #Check if we have to shorten, and maybe shorten #the text so it doesn't raise a 'too large' error. if self.fontObj.size(text)[0] > 16383: Modified: trunk/VP/notify.py =================================================================== --- trunk/VP/notify.py 2009-05-01 15:27:26 UTC (rev 295) +++ trunk/VP/notify.py 2009-05-01 22:22:11 UTC (rev 296) @@ -1,9 +1,36 @@ -import pynotify, re from functions import getRealDir -pynotify.init("Virtual Playground") + +method = None +print 'Looking for notify program...' + +#pynotify +try: + import pynotify +except ImportError: + print 'Not found: pynotify' +else: + import re + pynotify.init("Virtual Playground") + + print 'Found pynotify!' + method = 'pynotify' + +if not method: + #snarl + try: + import PySnarl + except ImportError: + print 'Not found: snarl' + else: + print 'Found snarl!' + method = 'snarl' + +if not method: print 'No notify program found!' + + def popup(caption,msg, img="", timeout=5000, urgency="normal"): - """popup(caption, message, image="", timeout=5000, urgency="normal) + """popup(caption, message, image="", timeout=5000, urgency="normal") Show a popup on screen. @@ -14,28 +41,36 @@ Urgency: low, normal, high """ - #Don't make libnotify crash by alien characters - msg=msg.decode('utf-8') + if method=='snarl': + id = PySnarl.snShowMessage( title = caption, + text = msg, + timeout = timeout/1000, + iconPath = getRealDir('images','popup',img)) - #Clickable urls - msg=re.sub('([^:]+://[^.]+\.[^ ]+)', '<a href="\\1">\\1</a>', msg) + elif method=='pynotify': - #Create it - notif=pynotify.Notification(caption,\ - msg,\ - getRealDir('images','popup',img)) - - #How long should we keep it on the screen? - notif.set_timeout(timeout) - - #Urgency - if urgency=="low": - notif.set_urgency(pynotify.URGENCY_LOW) - elif urgency=="high" or urgency=="critical": - notif.set_urgency(pynotify.URGENCY_CRITICAL) - else: - notif.set_urgency(pynotify.URGENCY_NORMAL) - - #Show it(+error catcher thingy) - if not notif.show(): - print "Failed to show notification" + #Don't make libnotify crash by alien characters + msg=msg.decode('utf-8') + + #Clickable urls + msg=re.sub('([^:]+://[^.]+\.[^ ]+)', '<a href="\\1">\\1</a>', msg) + + #Create it + notif=pynotify.Notification(caption, + msg, + getRealDir('images','popup',img)) + + #How long should we keep it on the screen? + notif.set_timeout(timeout) + + #Urgency + if urgency=="low": + notif.set_urgency(pynotify.URGENCY_LOW) + elif urgency=="high" or urgency=="critical": + notif.set_urgency(pynotify.URGENCY_CRITICAL) + else: + notif.set_urgency(pynotify.URGENCY_NORMAL) + + #Show it(+error catcher thingy) + if not notif.show(): + print "Failed to show notification" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ch...@us...> - 2009-05-01 15:27:32
|
Revision: 295 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=295&view=rev Author: chozone Date: 2009-05-01 15:27:26 +0000 (Fri, 01 May 2009) Log Message: ----------- Changed module system, now it works in python 2.6+. Had to rename the VP/modules/playground dir to VP/modules/playgroundObj, because there was a conflict between that dir and VP/modules/playground.py. Modified Paths: -------------- trunk/VP/interface.py trunk/VP/modules/playground.py Added Paths: ----------- trunk/VP/modules/__init__.py trunk/VP/modules/playgroundObj/ trunk/VP/modules/playgroundObj/__init__.py Removed Paths: ------------- trunk/VP/modules/playground/ Modified: trunk/VP/interface.py =================================================================== --- trunk/VP/interface.py 2009-03-31 20:46:57 UTC (rev 294) +++ trunk/VP/interface.py 2009-05-01 15:27:26 UTC (rev 295) @@ -40,9 +40,9 @@ #Load all modules in our memory self.modules = {} for module in os.listdir(getRealDir('modules')): - if module[-3:] == '.py': - realName = os.path.join('modules', module[:-3]) - self.modules[module[:-3]] = __import__(realName).Module + if module[-3:] == '.py' and not module.startswith('__'): + realName = '.'.join(('modules', module[:-3])) + self.modules[module[:-3]] = __import__(realName, fromlist=module[:-3]).Module @@ -82,7 +82,7 @@ for i, module in enumerate(self.openModules[prio]): if type(name) == str: - if module.__module__ == 'modules/' + name: + if module.__module__ == 'modules.' + name: module.close() del self.openModules[prio][i] print 'Interface.closeModule: Close', name, 'at', prio, '-', i @@ -129,7 +129,7 @@ #Search within the given priorities for prio in prioList: for i, module in enumerate(self.openModules[prio]): - if module.__module__ == 'modules/' + name: + if module.__module__ == 'modules.' + name: return True return False @@ -148,7 +148,7 @@ for prio in prioList: for i, module in enumerate(self.openModules[prio]): if type(name) == str: - if module.__module__ == 'modules/' + name: + if module.__module__ == 'modules.' + name: if len(self.openModules[prio])-1 != i: self.openModules[prio].append(self.openModules[prio].pop(i)) self.update(blit = True) @@ -270,7 +270,7 @@ self.lock.acquire() for prio in range(5): for module in self.openModules[prio]: - if name == '' or module.__module__ == 'modules/' + name: + if name == '' or module.__module__ == 'modules.' + name: module.call(*arg) self.forceUpdate() Added: trunk/VP/modules/__init__.py =================================================================== --- trunk/VP/modules/__init__.py (rev 0) +++ trunk/VP/modules/__init__.py 2009-05-01 15:27:26 UTC (rev 295) @@ -0,0 +1 @@ +# Dummy file, not a module. Do NOT remove this file! Modified: trunk/VP/modules/playground.py =================================================================== --- trunk/VP/modules/playground.py 2009-03-31 20:46:57 UTC (rev 294) +++ trunk/VP/modules/playground.py 2009-05-01 15:27:26 UTC (rev 295) @@ -25,10 +25,10 @@ #Loading all our objects-modules (kinda like interface.py) self.modObjects = {} - for object in os.listdir(getRealDir('modules','playground')): - if object[-3:] == '.py': - realName = os.path.join('modules', 'playground', object[:-3]) - self.modObjects[object[:-3]] = __import__(realName).Object + for object in os.listdir(getRealDir('modules','playgroundObj')): + if object[-3:] == '.py' and not object.startswith('__'): + realName = '.'.join(('modules', 'playgroundObj', object[:-3])) + self.modObjects[object[:-3]] = __import__(realName, fromlist=object[:-3]).Object self.surf = pygame.Surface((726, 402)) Property changes on: trunk/VP/modules/playgroundObj ___________________________________________________________________ Added: svn:mergeinfo + Added: trunk/VP/modules/playgroundObj/__init__.py =================================================================== --- trunk/VP/modules/playgroundObj/__init__.py (rev 0) +++ trunk/VP/modules/playgroundObj/__init__.py 2009-05-01 15:27:26 UTC (rev 295) @@ -0,0 +1 @@ +# Dummy file, not a playground-module. Do NOT remove this file! This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ch...@us...> - 2009-03-31 20:47:03
|
Revision: 294 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=294&view=rev Author: chozone Date: 2009-03-31 20:46:57 +0000 (Tue, 31 Mar 2009) Log Message: ----------- NOTE: NOT finished, some (visual) debugging still active! After a lot of debugging, the first parts of walls are here! Still need to work on walls+Z/height, and walls of other users. For debugging: the grey transparant blocks in objects are their walls, the red line under the user is the rect of the user. (note that you can't see the Z/height in these debug-walls) Modified Paths: -------------- branches/VP-Grounds/brains.py branches/VP-Grounds/modules/playground/object.py branches/VP-Grounds/modules/playground.py Modified: branches/VP-Grounds/brains.py =================================================================== --- branches/VP-Grounds/brains.py 2009-03-29 21:11:28 UTC (rev 293) +++ branches/VP-Grounds/brains.py 2009-03-31 20:46:57 UTC (rev 294) @@ -1,6 +1,7 @@ from language import * import notify from connection import Connection +from pygame import Rect class Brains(): """ @@ -102,28 +103,48 @@ def doWalk(self): """ - This will be started from walkTimer + This will be started from walkTimer. + This will update our position wit each step, so we can blit it. + But it will NOT send our position to the server, that would cause + waaay to much traffic. For this we have the walkUpdateTimer. """ - #Update our position + ##Update our position #Get our name first name = self.sh['conf']['account']['user'] users = self.sh['users'] if name in users: - users[name]['Pos'][2] -= self.walkingDir[0] - users[name]['Pos'][1] -= self.walkingDir[1] - users[name]['Pos'][2] += self.walkingDir[2] - users[name]['Pos'][1] += self.walkingDir[3] + tPos=users[name]['Pos'][:] - self.sh['Interface'].call('playground', 'UserUpdate', users[name]) + tPos[1] -= self.walkingDir[1] + tPos[1] += self.walkingDir[3] - #print users[name]['Pos'] + #Are there any walls in the way? + if not self.checkWall(tPos): + updated=True + users[name]['Pos'][:]=tPos + else: + updated=False + tPos=users[name]['Pos'][:] + + tPos[2] -= self.walkingDir[0] + tPos[2] += self.walkingDir[2] + + #Are there any walls in the way, for y now? + if self.checkWall(tPos): tPos=users[name]['Pos'][:] + + if users[name]['Pos']!=tPos or updated: + users[name]['Pos']=tPos + + self.sh['Interface'].call('playground', 'UserUpdate', users[name]) def doWalkUpdate(self): """ - This will be started each 0.5 seconds from walkTimerUpdate + This will be started from walkTimerUpdate. + It sends our current position to the server. + Has to be on a slower interval than walkTimer. """ #Update our position to the server! @@ -135,3 +156,37 @@ if self.walkTimer.isRunning == False: #Stop ourself since nothing has to be updated return False + + def checkWall(self, pos): + """ + CheckWall(pos) ==> True if there is a wall on pos. + """ + + walls = self.sh['Ground-walls'] #[0]=lists, [1]=pygame rects + + #Is our rect-wallist already build? + if walls[1]==[]: + if walls[0]==[]: return #No walls at all: user can move :) + + for wall in walls[0]: + rect=Rect(wall[0], wall[2], wall[1]-wall[0], wall[3]-wall[2]) + walls[1].append(rect) + + #Do we have a rect for ourselves? + #TODO: later loop through all users(in our ground), and check/create + #rects for them all, and see if another user is in the way + #Creating rects for other users in getData, or somewhere where their pos update is processed + ownName=self.sh['conf']['account']['user'] + ownSh=self.sh['users'][ownName] + ownSh['collRect'].x=pos[1] + ownSh['collRect'].y=pos[2]+ownSh['size'][2]-1 + + collides = ownSh['collRect'].collidelistall(walls[1]) + + #No collides with walls, user can move :) + if collides == []: return + + #Well, we're on a wall, but are we IN it, or is + #it floating above us/are we floating above it? + #TODO: making this... (Z positions) + return True Modified: branches/VP-Grounds/modules/playground/object.py =================================================================== --- branches/VP-Grounds/modules/playground/object.py 2009-03-29 21:11:28 UTC (rev 293) +++ branches/VP-Grounds/modules/playground/object.py 2009-03-31 20:46:57 UTC (rev 294) @@ -10,6 +10,24 @@ self.size = [int(i) for i in obj['size']] self.objZorder = int(obj['zorder']) + self.walls = data['objecttype']['walls'] + #Convert a dict of walls (in format 'name':['X1','X2','Y1','Y2','Z1','Z2']) + #to a simple list with all int values + self.walls = [[int(i) for i in w] for w in self.walls.values()] + + #Create a copy of our walls, and move these walls, so they + #are real position, instead of internal position + self.realWalls=[] + for wall in self.walls: + wall = wall[:] #Make a copy of this var, so we don't change it in our origional list + wall[0]+=self.pos[0] + wall[1]+=self.pos[0] + wall[2]+=self.pos[1] + wall[3]+=self.pos[1] + self.realWalls.append(wall) + + + self.imageD = obj['imageD'] self.imageN = obj['imageN'] self.imageStyle = 'D' @@ -35,11 +53,18 @@ if list(image[1].size) != self.size: self.image[0] = pygame.transform.smoothscale(self.image[0], self.size) + n=0 + for wall in self.walls: + rect=Rect(wall[0], wall[2], wall[1]-wall[0], wall[3]-wall[2]) + col=(50+20*n,50+20*n,50+20*n,200) + self.image[0].fill(col,rect) + + n+=1 + self.sh['Playground'].blit(self.rect) def update(self, screen, rect): - #print rect, self.rect if self.rect.colliderect(rect): #Check if the rect collide with ours rect = rect.move(-self.rect[0], -self.rect[1]) #Move rect to our position myPos = (self.rect[0] + rect[0], self.rect[1] + rect[1]) #Calculate our position from the rect Modified: branches/VP-Grounds/modules/playground.py =================================================================== --- branches/VP-Grounds/modules/playground.py 2009-03-29 21:11:28 UTC (rev 293) +++ branches/VP-Grounds/modules/playground.py 2009-03-31 20:46:57 UTC (rev 294) @@ -20,8 +20,8 @@ self.timer = None - self.walkingStep=10 #Size(px) of each step. - self.runningStep=20 #Size(px) of each step while running. + self.walkingStep=5 #Size(px) of each step. + self.runningStep=15 #Size(px) of each step while running. #Loading all our objects-modules (kinda like interface.py) @@ -106,6 +106,7 @@ #Wait with updating until all data has arrived self.dontUpdate = True self.objects = {} + self.sh['Ground-walls']=[[],[]] #Purge all walls, while all objects are gone, and with them, all walls elif msg['state'] == 'free': #We're free to update! @@ -137,6 +138,14 @@ self.openObject('avatar-' + user['Avatar'][0], 'av-' + user['Name'], user) if not 'avatar-' + user['Avatar'][0] in self.modObjects.keys(): return self.objects['av-%s'%user['Name']].show() #Will start downloading, see modules/playground/avatar-static.py for full explanation + + #Create a 'coll(ide)Rect, the rect that will be used when checking for walls + rRect=self.objects['av-%s'%user['Name']].rect + shUsr=self.sh['users'][user['Name']] + shUsr['collRect']=Rect((rRect.x, rRect.y+rRect.h-1), (rRect.w, 1)) + shUsr['size']=(rRect.w, 1, rRect.h) + + else: #Not in ground, but do we still have the avatar-object? @@ -156,6 +165,12 @@ rect = rect.move(-myRect[0], -myRect[1]) #Move rect to our position myPos = (myRect[0] + rect[0], myRect[1] + rect[1]) #Calculate our position from the rect screen.blit(self.surf, myPos, rect) #Blit + + + ownName=self.sh['conf']['account']['user'] + if ownName in self.sh['users'].keys(): + ownRect=self.sh['users'][ownName]['collRect'] + screen.fill((220,20,20), ownRect) def close(self): del self.sh['Playground'] @@ -201,6 +216,9 @@ #What is this? if info['object'] == 'object': self.openObject('object', name, info) + + #Add walls to our wall-list thingy + for wall in self.objects[name].realWalls: self.sh['Ground-walls'][0].append(wall) def openObject(self, objname, name, data): """ @@ -211,7 +229,7 @@ print 'ERROR @Playground: Object type', objname,'not found, cannot open', name return - #print '## Open Object', name, 'as', objname #DEBUG + print '## Open object', name, 'as', objname#, '==', data #DEBUG obj = self.modObjects[objname] obj = obj(data, self.sh) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ch...@us...> - 2009-03-29 21:11:40
|
Revision: 293 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=293&view=rev Author: chozone Date: 2009-03-29 21:11:28 +0000 (Sun, 29 Mar 2009) Log Message: ----------- TODO update, forgot to commit it yesterday... Modified Paths: -------------- trunk/VP/TODO Modified: trunk/VP/TODO =================================================================== --- trunk/VP/TODO 2009-03-26 15:50:09 UTC (rev 292) +++ trunk/VP/TODO 2009-03-29 21:11:28 UTC (rev 293) @@ -20,11 +20,11 @@ * Connecting the items with functions (assigned to BlueWolf_) * Submenus (assigned to BlueWolf_) - Playground + Playground (see VP-Grounds branche) * Creating the avatars (the images) -* Walls +* Walls (assigned to chozone) * Smooth walking -* Jumping +* Jumping (will be assigned to BlueWolf_, or someone else really wants to do this...?) * Walking/running bit slower when walking diagonally (assigned to chozone) * Chat balloons (assigned to K-4U) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <K-...@us...> - 2009-03-26 15:50:19
|
Revision: 292 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=292&view=rev Author: K-4U Date: 2009-03-26 15:50:09 +0000 (Thu, 26 Mar 2009) Log Message: ----------- Now we have unix sockets! They are only fetched in the connection file, but will be implemented into a getData function later on. Everything send trough this function should be send in XML. There is a minor bug, that you should manually chmod the unixSocket file Modified Paths: -------------- trunk/VPS/TODO trunk/VPS/connection.py trunk/VPS/dataConvert.py trunk/VPS/dataConvert_xml.py Added Paths: ----------- trunk/VPS/object_dict.py trunk/VPS/xml2dict.py Modified: trunk/VPS/TODO =================================================================== --- trunk/VPS/TODO 2009-03-25 19:11:24 UTC (rev 291) +++ trunk/VPS/TODO 2009-03-26 15:50:09 UTC (rev 292) @@ -1,2 +1,2 @@ =General= -* Create an communicator (for the website/UNIX socket) (assigned to K-4U) +* Create an communicator (for the website/UNIX socket) (assigned to K-4U) On Hold Modified: trunk/VPS/connection.py =================================================================== --- trunk/VPS/connection.py 2009-03-25 19:11:24 UTC (rev 291) +++ trunk/VPS/connection.py 2009-03-26 15:50:09 UTC (rev 292) @@ -13,6 +13,8 @@ def closeAll(self): log(1, 'SRV', 'Closing server socket') self.socket.close() + #Remove unix socket: + os.remove("../unixSocket") for i, data in enumerate(self.sh['Data']): if data != None: @@ -21,9 +23,13 @@ data.socket.close() def run(self): + #Create our tcp-socket self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + #Create our unix-socket: + #log(2,"UNIX","Setting up") + self.unixSocket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) #Trying to get hold of the port while 1: @@ -33,9 +39,32 @@ except: time.sleep(1) + #And, bind unix socket: + while 1: + try: + #log(2,"UNIX","Binding") + self.unixSocket.bind("../unixSocket") + break + except socket.error, msg: + if msg[0] == 98: #File already exists + #log(2,"UNIX","File exists") + os.remove("../unixSocket") #Remove our existing socket + else: + log(3, 'SRV', msg) + break + log(2,"UNIX","Binding succeeded") + #Try to chmod our socket: + os.chmod("../unixSocket",777) + + self.unixSocket.listen(20) self.socket.listen(20) log(2, 'SRV', "I'm online!") + + #Create a new thread for the unix: + self.unixSocket = unixHandler(self.sh,self.unixSocket) + self.unixSocket.start() + #Now we just wait for some lone souls... while 1: sock = self.socket.accept() @@ -45,10 +74,40 @@ self.sh['Data'][i] = Data(self.sh, i, sock) self.sh['Data'][i].start() else: - log(3, 'SRV', 'To much connections!') - + log(3, 'SRV', 'Too much connections!') + +class unixHandler(threading.Thread): + def __init__(self, share, unixSock): + self.sh = share + self.unixSock = unixSock + + threading.Thread.__init__(self) + + def run(self): + while 1: + #Get our connection: + conn, addr = self.unixSock.accept() + buffer = "" + while 1: + #Get our data: + data = conn.recv(1024) + buffer = buffer + data + if data[-1] == chr(1): + part = buffer.split(chr(1)) + buffer = "" + for message in part: + if message != '': + #And here, we handle our stuff: + print message + message = dataConvert.UNIXXML2Data(message) + #log(0,"UNIX","<", message) + break + + #And close the socket after receiving + conn.close() + class Data(threading.Thread): def __init__(self, share, id, sock): self.id = id @@ -114,7 +173,6 @@ except: log(3, self.id, 'Connection closed before sending protocol') return - if D == 'bPickle': self.sh['user'][self.id]['con']['style'] = 'bPickle' self.socket.send('OK') @@ -122,7 +180,7 @@ self.sh['user'][self.id]['con']['style'] = 'XML' self.socket.send('OK') else: - log(3, self.id, 'Unknow protocol') + log(3, self.id, 'Unknown protocol') return self.sh['user'][self.id]['con']['state'] = 1 Modified: trunk/VPS/dataConvert.py =================================================================== --- trunk/VPS/dataConvert.py 2009-03-25 19:11:24 UTC (rev 291) +++ trunk/VPS/dataConvert.py 2009-03-26 15:50:09 UTC (rev 292) @@ -9,6 +9,11 @@ elif style == 'XML': return xml.Data2XML({title: msg}) + +def UNIXXML2Data(msg): + msg = xml.XML2Data(msg) + return msg + def MSG2Data(msg, style): if style == 'bPickle': msg = bPickle.String2Data(msg) Modified: trunk/VPS/dataConvert_xml.py =================================================================== --- trunk/VPS/dataConvert_xml.py 2009-03-25 19:11:24 UTC (rev 291) +++ trunk/VPS/dataConvert_xml.py 2009-03-26 15:50:09 UTC (rev 292) @@ -1,16 +1,24 @@ +from xml2dict import XML2Dict + + +dTypes = {type({}):"array",type([]):"array",type(0):"integer",type(""):"string",type(False):"boolean"} + def Data2XML(msg): data = '' - if msg == None: pass #Add nothing elif msg.__class__().__str__() == '{}': for D in msg.keys(): - data = data + '<' + D + '>' + Data2XML(msg[D]) + '</' + D + '>' + if msg[D].__class__().__str__() == '[]': + for listItem in msg[D]: + data = data + '<' + D + ' type="' + dTypes[type(listItem)] + '">' + Data2XML(listItem) + '</' + D + '>' + else: + data = data + '<' + D + ' type="' + dTypes[type(msg[D])] + '">' + Data2XML(msg[D]) + '</' + D + '>' elif msg.__class__().__str__() == '[]': for D in msg: - data = data + '<[list]>' + Data2XML(D) + '</[list]>' + data = data + '<Item type="' + dTypes[type(D)] + '">' + Data2XML(D) + '</Item>' elif msg.__class__().__str__() == '' or msg.__class__().__str__() == '0': data = str(msg) @@ -21,9 +29,38 @@ return data + + def XML2Data(msg): + xml = XML2Dict() + r = xml.fromstring(msg) + return r + from pprint import pprint + #return handle(r) + +def handle(dict): + endDict = {} + if dict.__class__().__str__() == '{}': + for key in dict: + if key != "type": + if key == "value": + endDict = dict[key] + else: + endDict[key] = handle(dict[key]) + elif dict.__class__().__str__() == "[]": + endDict = [] + for item in dict: + endDict.append(handle(item)) + else: + #endDict = dict + pass + return endDict + + + + +def OLD_XML2Data(msg,depth=[]): data = {} - while 1: pos1 = msg.find('<') if pos1 == -1: @@ -35,9 +72,26 @@ pos2 = msg.find('>',pos1) if pos2 == -1: break name = msg[pos1+1:pos2] + #Check for spaces, wich could indicate for attributes: + attributes = "" + if name.find(" ") != -1: + attributes = name[name.find(" ") +1:] + name=name[:name.find(" ")] - posend = msg.find('</' + name + '>') - if posend == -1: raise Exception('XML geen eind-tag') + newMsg = msg + tagCount = 0 + #posend = msg.find("</" + name + ">") + while 1: + if newMsg.find("<" + name) != -1: + tagCount+=1 + newMsg = newMsg[newMsg.find("<" + name) + len("<" + name):] + else: + tagCount-=1 + if tagCount <= 0: + posend = newMsg.find('</' + name + '>') + break + print "Handling XML-tag: '" + name + "', Attributes: '" + attributes + "'" + if posend == -1: raise Exception('XML geen eind-tag. Verwacht: "' + name + '"') databetween = msg[pos2+1:posend] if name == '[list]': Added: trunk/VPS/object_dict.py =================================================================== --- trunk/VPS/object_dict.py (rev 0) +++ trunk/VPS/object_dict.py 2009-03-26 15:50:09 UTC (rev 292) @@ -0,0 +1,45 @@ +""" +object_dict + +nk...@gm... 2007 + +Provided as-is; use at your own risk; no warranty; no promises; enjoy! +""" + +class object_dict(dict): + """object view of dict, you can + >>> a = object_dict() + >>> a.fish = 'fish' + >>> a['fish'] + 'fish' + >>> a['water'] = 'water' + >>> a.water + 'water' + >>> a.test = {'value': 1} + >>> a.test2 = object_dict({'name': 'test2', 'value': 2}) + >>> a.test, a.test2.name, a.test2.value + (1, 'test2', 2) + """ + def __init__(self, initd=None): + if initd is None: + initd = {} + dict.__init__(self, initd) + + def __getattr__(self, item): + d = self.__getitem__(item) + # if value is the only key in object, you can omit it + if isinstance(d, dict) and 'value' in d and len(d) == 1: + return d['value'] + else: + return d + + def __setattr__(self, item, value): + self.__setitem__(item, value) + + +def _test(): + import doctest + doctest.testmod() + +if __name__ == "__main__": + _test() Added: trunk/VPS/xml2dict.py =================================================================== --- trunk/VPS/xml2dict.py (rev 0) +++ trunk/VPS/xml2dict.py 2009-03-26 15:50:09 UTC (rev 292) @@ -0,0 +1,61 @@ +""" +Thunder Chen<nk...@gm...> 2007.9.1 +""" +try: + import xml.etree.ElementTree as ET +except: + import cElementTree as ET # for 2.4 + +from object_dict import object_dict +import re + +class XML2Dict(object): + + def __init__(self): + pass + + def _parse_node(self, node): + node_tree = object_dict() + # Save attrs and text, hope there will not be a child with same name + if node.text: + node_tree.value = node.text + for (k,v) in node.attrib.items(): + k,v = self._namespace_split(k, object_dict({'value':v})) + node_tree[k] = v + #Save childrens + for child in node.getchildren(): + tag, tree = self._namespace_split(child.tag, self._parse_node(child)) + if tag not in node_tree: # the first time, so store it in dict + node_tree[tag] = tree + continue + old = node_tree[tag] + if not isinstance(old, list): + node_tree.pop(tag) + node_tree[tag] = [old] # multi times, so change old dict to a list + node_tree[tag].append(tree) # add the new one + + return node_tree + + + def _namespace_split(self, tag, value): + """ + Split the tag '{http://cs.sfsu.edu/csc867/myscheduler}patients' + ns = http://cs.sfsu.edu/csc867/myscheduler + name = patients + """ + result = re.compile("\{(.*)\}(.*)").search(tag) + if result: + print tag + value.namespace, tag = result.groups() + return (tag, value) + + def parse(self, file): + """parse a xml file to a dict""" + f = open(file, 'r') + return self.fromstring(f.read()) + + def fromstring(self, s): + """parse a string""" + t = ET.fromstring(s) + root_tag, root_tree = self._namespace_split(t.tag, self._parse_node(t)) + return object_dict({root_tag: root_tree}) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <K-...@us...> - 2009-03-25 19:11:40
|
Revision: 291 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=291&view=rev Author: K-4U Date: 2009-03-25 19:11:24 +0000 (Wed, 25 Mar 2009) Log Message: ----------- Updated the todo, had to set the correct guy Modified Paths: -------------- trunk/VPS/TODO Modified: trunk/VPS/TODO =================================================================== --- trunk/VPS/TODO 2009-03-23 21:54:44 UTC (rev 290) +++ trunk/VPS/TODO 2009-03-25 19:11:24 UTC (rev 291) @@ -1,2 +1,2 @@ =General= -* Create an communicator (for the website/UNIX socket) (assigned to BlueWolf_) +* Create an communicator (for the website/UNIX socket) (assigned to K-4U) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-03-23 21:54:47
|
Revision: 290 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=290&view=rev Author: BlueWolf_ Date: 2009-03-23 21:54:44 +0000 (Mon, 23 Mar 2009) Log Message: ----------- Updated todo and fixed a bug in forceUpdate with threading Modified Paths: -------------- trunk/VP/TODO trunk/VP/interface.py Modified: trunk/VP/TODO =================================================================== --- trunk/VP/TODO 2009-03-23 21:50:06 UTC (rev 289) +++ trunk/VP/TODO 2009-03-23 21:54:44 UTC (rev 290) @@ -22,14 +22,9 @@ Playground * Creating the avatars (the images) -* Finishing up Static avatar (Z coords) (assigned to chozone) -* Finishing up multidir avatar (Z coords) (assigned to chozone) -* Finishing up multiparts avatar (Z coords) (assigned to chozone) -* Finishing up multidir_parts avatar (Z coords) (assigned to chozone) * Walls * Smooth walking * Jumping -* Running (assigned to chozone) * Walking/running bit slower when walking diagonally (assigned to chozone) * Chat balloons (assigned to K-4U) Modified: trunk/VP/interface.py =================================================================== --- trunk/VP/interface.py 2009-03-23 21:50:06 UTC (rev 289) +++ trunk/VP/interface.py 2009-03-23 21:54:44 UTC (rev 290) @@ -19,6 +19,7 @@ #4 - Menu/tooltips self.lock = threading.Lock() + self.updateLock = threading.Lock() #Lock for forceUpdate self.needUpdate = [] @@ -196,6 +197,8 @@ """This will the interface use to actually update the screen""" if self.needUpdate != []: + self.updateLock.acquire() + #print 'Interface.forceUpdate' + str(self.needUpdate) if self.needUpdate == [None]: #Fullscreen update, yeah! @@ -207,6 +210,8 @@ for module in self.openModules[prio]: module.update(self.screen, rect_list) pygame.display.update(rect_list) + + self.updateLock.release() #Change the cursor, if needed if self.cursor != self.cursorNew: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <Blu...@us...> - 2009-03-23 21:50:19
|
Revision: 289 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=289&view=rev Author: BlueWolf_ Date: 2009-03-23 21:50:06 +0000 (Mon, 23 Mar 2009) Log Message: ----------- Rects should not be saved Modified Paths: -------------- branches/VP-Grounds/modules/playground.py Modified: branches/VP-Grounds/modules/playground.py =================================================================== --- branches/VP-Grounds/modules/playground.py 2009-03-23 15:00:53 UTC (rev 288) +++ branches/VP-Grounds/modules/playground.py 2009-03-23 21:50:06 UTC (rev 289) @@ -15,9 +15,6 @@ #Objects will have all the object-classes. #the key is the name of the object. self.objects = {} - #rects is an dict where the keys are the rects - #and the values are the names of the object. - self.rects = {} self.walkingDir = [False] * 4 #up, left, right, down @@ -120,8 +117,6 @@ self.loadGround(msg['data']) elif arg[0] == 'UserUpdate': - updateRects = [] #What's this?? - user = arg[1] #Is this on our ground? Do we need to update it? if user.has_key('Pos') and user['Pos'] != None: @@ -172,12 +167,19 @@ """ if self.dontUpdate == False: self.lock.acquire() - self.createRects() - collidelist = rect.collidedictall(self.rects) + #Create our rect-dict + rects = {} + for name, obj in self.objects.items(): + rects[tuple(obj.rect)] = name + #Get the name of which rects collides + collidelist = rect.collidedictall(rects) + + #Sort it with zorder collidelist = self.sortObjectList(collidelist) + #Update the one which collide for name in collidelist: obj = self.objects[name] obj.update(self.surf, rect) @@ -199,9 +201,6 @@ #What is this? if info['object'] == 'object': self.openObject('object', name, info) - - - self.createRects() def openObject(self, objname, name, data): """ @@ -217,13 +216,6 @@ obj = self.modObjects[objname] obj = obj(data, self.sh) self.objects[name] = obj - - - def createRects(self): - #Generate self.rects - self.rects = {} - for name, obj in self.objects.items(): - self.rects[tuple(obj.rect)] = name def sortObjectList(self, objectList): #Get the list of all zorders and names This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |