From: <Blu...@us...> - 2010-09-28 22:00:34
|
Revision: 414 http://virtplayground.svn.sourceforge.net/virtplayground/?rev=414&view=rev Author: BlueWolf_ Date: 2010-09-28 22:00:28 +0000 (Tue, 28 Sep 2010) Log Message: ----------- Added a tick-module for the core. It will check for the user's position but does not send them to other clients yet Modified Paths: -------------- trunk/server/core/functions.py trunk/server/core/parser.py trunk/server/core/server.py Added Paths: ----------- trunk/server/core/tick.py Modified: trunk/server/core/functions.py =================================================================== --- trunk/server/core/functions.py 2010-09-28 21:59:12 UTC (rev 413) +++ trunk/server/core/functions.py 2010-09-28 22:00:28 UTC (rev 414) @@ -15,6 +15,8 @@ ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +import threading, time, random, sys + def check_version(version, expr): """ Checks whether a version meets certain conditions. @@ -123,3 +125,141 @@ return False +def check_double_user(clients, isbot, screenname, data): + """ + Checks for an user or bot with the same name + """ + + # Check if there isn't already a bot online with this name + for i, client in clients.items(): + if client['status'] == "VP" and client['bot'] == True and \ + client['user'] == screenname: + # Our client cannot log in + return "duplicate user" + + if isbot == False: + # Check for the same user + for i, client in clients.items(): + if client['status'] == "VP" and client['bot'] == False and \ + client['user'] == screenname: + # Disconnect this user + client['con'].close_msg('duplicate') + + return True + +def get_visible_clients(viewport, client, clients): + """ + Get a list of all visible clients for this user + """ + + visible = [] + + margin = client['speed']*2 + view = ( + client['pos'][0] - (viewport[0]/2) - margin, + client['pos'][1] - (viewport[1]/2) - margin, + viewport[0] + margin, + viewport[1] + margin + ) + + for other in clients.values(): + if other['status'] != "VP": continue + if client['pos'][2] != other['pos'][2]: continue + + print client['user'], "->", other['user'] + + # Create his viewport + margin_other = other['speed']*2 + view_other = ( + other['pos'][0] - (viewport[0]/2) - margin, + other['pos'][1] - (viewport[1]/2) - margin, + viewport[0] + margin, + viewport[1] + margin + ) + + print view, view_other + # Is this without our viewport? + if (view[0]+view[2] >= view_other[0] and view[0] <= view_other[0]+view_other[2]) and \ + (view[1]+view[3] >= view_other[1] and view[1] <= view_other[1]+view_other[3]): + visible.append(other) + + + return visible + +def get_current_position(client): + """ + Returns the current position for this user + """ + + if client['moving']: + starttime, direction, speed = client['moving'] + pos = client['pos'][:] + timeline = time.time() - starttime + move = timeline*speed + + if direction == 0: + pos[1] = int(pos[1] - move) + elif direction == 1: + pos[1] = int(pos[1] - (move/1.7)) + pos[0] = int(pos[0] + (move/1.7)) + elif direction == 2: + pos[0] = int(pos[0] + move) + elif direction == 3: + pos[0] = int(pos[0] + (move/1.7)) + pos[1] = int(pos[1] + (move/1.7)) + elif direction == 4: + pos[1] = int(pos[1] + move) + elif direction == 5: + pos[1] = int(pos[1] + (move/1.7)) + pos[0] = int(pos[0] - (move/1.7)) + elif direction == 6: + pos[0] = int(pos[0] - move) + elif direction == 7: + pos[0] = int(pos[0] - (move/1.7)) + pos[1] = int(pos[1] - (move/1.7)) + + return pos + else: + return client['pos'] + +def position_check(sh, client, proposed_pos = None): + """ + Check the current position of the user for collisions or inaccurate data + """ + + # Check if newpos is valid + if client['moving'] == False: + # Just check if it's the same pos + if client['pos'] != proposed_pos: + client['con'].send("move", { + "cid": client['cid'], + "pos": client['pos'] + }) + + else: + current_pos = get_current_position(client) + + if proposed_pos != None: + # Compare current_pos with proposed_pos how much they differ + wrong = False + for p1, p2 in zip(current_pos[:2], proposed_pos[:2]): + diff = p2-p1 + if diff < 0: diff = -diff + if diff > sh['config']['position_error_margin']: + wrong = True + + if wrong: # Send correction + client['con'].send("move", { + "cid": client['cid'], + "pos": current_pos, + }) + else: + current_pos = proposed_pos + + + # Check for collisions between lastpos and current_pos + # [TODO] + print "Check", client['lastpos'], "->", current_pos + + client['lastpos'] = current_pos + Modified: trunk/server/core/parser.py =================================================================== --- trunk/server/core/parser.py 2010-09-28 21:59:12 UTC (rev 413) +++ trunk/server/core/parser.py 2010-09-28 22:00:28 UTC (rev 414) @@ -28,7 +28,7 @@ self.call = sh['call'] self.core = sh['core'] - # Shortkeys + # Shortcut self.clients = self.core.clients def __call__(self, cid, msg): @@ -41,57 +41,6 @@ if (func): return func(cid, body) - def _check_double_user(self, isbot, screenname, data): - """ - Checks for an user or bot with the same name - """ - - # Check if there isn't already a bot online with this name - for id, cl in self.clients.items(): - if cl['status'] == "VP" and cl['bot'] == True and \ - cl['user'] == screenname: - # Our client cannot log in - data.send("error", { - "reason": "duplicate user" - }) - return False - - if isbot == False: - # Check for the same user - for id, cl in self.clients.items(): - if cl['status'] == "VP" and cl['bot'] == False and \ - cl['user'] == screenname: - # Disconnect this user - cl['con'].close_msg('duplicate') - - return True - - def _is_client_visible(self, client1, client2): - """ - Checks if client1 can see client2 - """ - - client1 = client1['pos'] - client2 = client2['pos'] - - # Check height - if client1[2] != client2[2]: return False - - # Check horizontal - if client1[0]-client2[0] > self.sh['config']['viewport'][0]/2 \ - or client1[0]-client2[0] < -self.sh['config']['viewport'][0]/2: - return False - - # Check vertical - if client1[1]-client2[1] > self.sh['config']['viewport'][1]/2 \ - or client1[1]-client2[1] < -self.sh['config']['viewport'][1]/2: - return False - - # Clients see each other! - return True - - - def login(self, cid, msg): """ Send when the users wants to log in @@ -164,12 +113,18 @@ # Check for double logins if msg['bot'] == False: # Just an ordinary user - if self._check_double_user(False, username, data) == False: - return + resp = check_double_user(self.clients, False, username, data) + if resp != True: + data.send("error", { + "reason": resp + }) else: # Client is a bot - if self._check_double_user(True, screenname, data) == False: - return + resp = check_double_user(self.clients, True, screenname, data) + if resp != True: + data.send("error", { + "reason": resp + }) # Log the client in @@ -177,8 +132,14 @@ client['user'] = screenname client['app'] = tuple(msg['client']) client['version'] = str(msg['version']) - client['pos'] = [0, 0, 0] # XYZ + client['pos'] = [ + int(random.random()*500-250), # X + int(random.random()*500-250), # Y + 0] # Z + client['lastpos'] = client['pos'][:] # Last pos that is checked client['status'] = "VP" + client['speed'] = self.sh['config']['default_speed'] + client['moving'] = False if msg['bot'] == False: client['bot'] = False @@ -202,7 +163,6 @@ # TODO: Send world - user = {} # This will be send to others user['cid'] = cid user['user'] = client['user'] @@ -214,6 +174,9 @@ # Send online clients userlist = [] + visible = get_visible_clients(self.sh['config']['viewport'], client, + self.clients) + for cid_o, client_o in self.clients.items(): if client_o['status'] != "VP": continue @@ -239,7 +202,7 @@ # Positions # Is this user visible for this client? - if self._is_client_visible(client, client_o): + if client_o in visible: user_o['pos'] = client_o['pos'] user['pos'] = client['pos'] else: @@ -298,4 +261,28 @@ """ self.call.custom(cid, msg['header'], msg['body']) + + def move(self, cid, msg): + """ + An user is moving to a different position + * moving: + Boolean, if the user is walking or not + * pos: + Current position of the user + * direction + Current direction of this user (None when moving = False) + """ + + client = self.clients[cid] + + if msg['moving']: + position_check(self.sh, client, msg['pos']) + client['pos'] = msg['pos'] + client['moving'] = (time.time(), msg['direction'], client['speed']) + self.sh['tick'].start("moving") + else: + position_check(self.sh, client, msg['pos']) + client['pos'] = msg['pos'] + client['moving'] = False + Modified: trunk/server/core/server.py =================================================================== --- trunk/server/core/server.py 2010-09-28 21:59:12 UTC (rev 413) +++ trunk/server/core/server.py 2010-09-28 22:00:28 UTC (rev 414) @@ -15,10 +15,11 @@ ## 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, random, sys, hashlib, select +import simplejson, socket, hashlib, select from functions import * from parser import Parser +from tick import Tick import rsa @@ -78,11 +79,16 @@ because it's used to calculate which objects and people the client is able to see. By default this is (1000, 700). - -max_speed: - The amount of pixels a user may move in a certain time. - The default is (50, 1.0) which basically means 50px per 1 second. - When a user exceeds this, the server will just reset his position - to his last known location. + -default_speed: + How fast an user may walk by default. By default this is 175. You + can change this on the fly with client.change_speed (for example, + when the user starts running or uses a vehicle). The viewport for + this user will be changed based on the speed. Margin on all sides + will be speed*2 + + -position_error_margin + How much pixels is tolerated by the server before it starts + correcting user's positions. Default is 25 """ @@ -103,6 +109,8 @@ self.clients = {} self.__parse = Parser(self.__sh) + self.__sh['tick'] = Tick(self.__sh) + threading.Thread.__init__(self) def __config_default(self, config): @@ -115,7 +123,9 @@ config['rsa_bits'] = int(config.get('rsa_bits', 64)) config['bot_names'] = str(config.get('bot_names', "[%s]")) config['viewport'] = tuple(config.get('viewport', (1000,700))) - config['max_speed'] = tuple(config.get('max_speed', (50, 1.0))) + config['default_speed'] = int(config.get('max_speed', 175)) + config['position_error_margin'] = int(config.get( + "position_error_margin", 25)) def start_server(self): @@ -194,6 +204,7 @@ str(random.random())).hexdigest()[:8] self.clients[cid] = { + "cid": cid, "status": "", "con": Client(cid, sock, self.__sh, self.__parse) } Added: trunk/server/core/tick.py =================================================================== --- trunk/server/core/tick.py (rev 0) +++ trunk/server/core/tick.py 2010-09-28 22:00:28 UTC (rev 414) @@ -0,0 +1,83 @@ +#!/usr/bin/env python + +## This file is part of Virtual Playground +## Copyright (c) 2010 Jos Ratsma + Koen Koning + +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either +## version 2 of the License, or (at your option) any later version. + +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. + +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +from functions import * + +TICK_SPEED = 1 + +class Tick(): + """ + This will tick every second when needed + """ + def __init__(self, sh): + self.sh = sh + self.call = sh['call'] + self.core = sh['core'] + + # Shortcut + self.clients = self.core.clients + + self.callers = [] + self.timer = None + + def start(self, name, *extra): + # Start a timer for this call + + if name in self.callers: return + self.callers.append(name) + + if self.timer == None: # Start a timer + self.timer = threading.Timer(TICK_SPEED, self.update) + self.timer.start() + + def stop(self, name): + try: self.callers.remove(name) + except: pass + + if self.callers == [] and self.timer: + self.timer.cancel() + self.timer = None + + def update(self): + # Execute stuff + for name in self.callers: + if self.tick(name): + try: self.callers.remove(name) + except: pass # This can happen due to threading. It's not bad + + # Start the next timer + if self.callers != []: + self.timer = threading.Timer(TICK_SPEED, self.update) + self.timer.start() + else: + self.timer = None + + def tick(self, name): + if name == "moving": + # Find which users are moving + amount = 0 + for client in self.clients.values(): + if client['status'] != "VP" or client['moving'] == False: + continue + + amount += 1 + position_check(self.sh, client) + + if amount == 0: + return True This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |