/usr/share/pyshared/tofu/client.py is in python-tofu 0.5-5.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | # TOFU
# Copyright (C) 2005 Jean-Baptiste LAMY
#
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""tofu.client
This module implements a Tofu client.
To lauch a server, create a GameInterface instance, import this module,
and then call serve_forever().
"""
from twisted.internet.protocol import DatagramProtocol, Protocol, Factory, ClientFactory
from twisted.protocols.basic import LineReceiver, NetstringReceiver
from twisted.python.failure import Failure
#from twisted.internet import reactor
import twisted.internet.selectreactor
#reactor = twisted.internet.selectreactor.SelectReactor()
import sys, struct
import tofu
try: set
except: from sets import Set as set
class ClientServerError(StandardError): pass
class UDP(DatagramProtocol):
def startProtocol(self):
a = "hello"
self.transport.write(a, ("127.0.0.1", 9999))
def datagramReceived(self, data, (host, port)):
print "UDP received %r from %s:%d" % (data, host, port)
PLANNED_ARRIVAL_UIDS = set()
WAITERS = {}
class Waiter(object):
def __init__(self, callback = lambda *args: None):
self.callback = callback
self.uniques = set([])
self.nb_waited_unique = 0
def wait_for(self, uid, ask_for_it = 1):
if tofu.Unique.hasuid(uid): # Already available
self.uniques.add(tofu.Unique.getbyuid(uid))
else:
#if ask_for_it:
# if not uid in tofu.NOTIFIER.uids_arrival_planned:
# tofu.NOTIFIER.ask_unique(uid)
self.nb_waited_unique += 1
waiters = WAITERS.get(uid)
if not waiters: waiters = WAITERS[uid] = []
waiters.append(self)
def arrived(self, unique):
self.uniques.add(unique)
self.nb_waited_unique -= 1
if self.nb_waited_unique == 0: self.callback(*self.uniques)
def start(self):
if self.nb_waited_unique == 0: self.callback(*self.uniques)
MAX_LENGTH = 99999
class Notifier(NetstringReceiver, tofu.Notifier):
def __init__(self):
tofu.Notifier.__init__(self)
self.errors = []
self.MAX_LENGTH = MAX_LENGTH
self.uids_arrival_planned = set()
def connectionMade(self):
self.sendString(tofu.CODE_CHECK_VERSION + tofu.VERSION)
tofu.GAME_INTERFACE.ready(self)
def login_player(self, filename, password, client_side_data = ""):
self.sendString("%s%s\n%s\n%s" % (tofu.CODE_LOGIN_PLAYER, filename, password, client_side_data))
def logout_player(self):
self.sendString(tofu.CODE_LOGOUT_PLAYER)
def stringReceived(self, data):
#print "TCP receive:", repr(data)
#print len(data)
code = data[0]
#print "* Tofu * receiving code %s..." % code
if code == tofu.CODE_DATA_STATE:
state = tofu.YourState.undump(data[5:])
uid = struct.unpack("!i", data[1:5])[0]
if tofu.Unique.hasuid(uid): tofu.Unique.getbyuid(uid).doer.push(state)
elif state.is_crucial():
pass
# XXX
# waiter = Waiter(lambda mobile: mobile.doer.push(state))
# waiter.wait_for(uid)
# waiter.start()
elif code == tofu.CODE_OWN_CONTROL:
uid = struct.unpack("!i", data[1:])[0]
print "* Tofu * Owning mobile %s..." % uid
#def own_control(mobile):
# print "own_control", mobile.level
# tofu.IDLER.next_round_tasks.append(mobile.control_owned)
#waiter = Waiter(own_control)
waiter = Waiter(lambda mobile: mobile.control_owned())
waiter.wait_for(uid, 0)
waiter.start()
elif code == tofu.CODE_REMOVE_MOBILE:
uid = struct.unpack("!i", data[1:])[0]
print "* Tofu * Removing mobile %s..." % uid
def remove_mobile(mobile):
mobile.level.remove_mobile(mobile)
mobile.discard()
#def remove_mobile(mobile):
# def remove_mobile2():
# print "* Tofu * Mobile %s removed !" % mobile.uid
# mobile.level.remove_mobile(mobile)
# mobile.discard()
# tofu.IDLER.next_round_tasks.append(remove_mobile2)
waiter = Waiter(remove_mobile)
waiter.wait_for(uid, 0)
waiter.start()
elif code == tofu.CODE_ADD_MOBILE:
mobile_uid = struct.unpack("!i", data[1:5])[0]
level_uid = struct.unpack("!i", data[5:9])[0]
print "* Tofu * Adding mobile %s in level %s..." % (mobile_uid, level_uid)
def add_mobile(*args):
mobile = tofu.Unique.getbyuid(mobile_uid)
level = tofu.Unique.getbyuid(level_uid )
if not mobile in level.mobiles: mobile.level.add_mobile(mobile)
waiter = Waiter(add_mobile)
waiter.wait_for(mobile_uid)
waiter.wait_for(level_uid)
waiter.start()
elif code == tofu.CODE_DATA_UNIQUE:
print "* Tofu * Receiving unique..."
unique = tofu.Unique.undump(data[1:])
unique.received()
assert (not hasattr(unique, "level")) or (not unique.level) or (unique.level in unique.level._alls2.values()), "Level sent with non-level unique !"
self.arrived(unique)
elif code == tofu.CODE_ENTER_LEVEL:
uid = struct.unpack("!i", data[1:])[0]
print "* Tofu * Entering level %s..." % uid
#self.uids_arrival_planned.add(uid) # The server will send it
# Previous level is outdated => drop it
if tofu.Unique.hasuid(uid): tofu.Unique.getbyuid(uid).set_active(0)
waiter = Waiter(lambda *uniques: None)
waiter.wait_for(uid)
waiter.start()
elif code == tofu.CODE_ERROR:
print "* Tofu * Server error: %s" % data[1:]
#self.errors.append(data[1:])
raise ClientServerError(data[1:])
def arrived(self, unique):
print "* Tofu * Received unique %s %s." % (unique.uid, unique)
waiters = WAITERS.get(unique.uid)
if waiters:
for waiter in waiters: waiter.arrived(unique)
del WAITERS[unique.uid]
if hasattr(unique, "mobiles"):
for mobile in unique.mobiles: self.arrived(mobile)
self.uids_arrival_planned.discard(unique.uid)
def ask_unique(self, uid):
print "* Tofu * Ask for UID %s..." % uid
self.uids_arrival_planned.add(uid)
self.sendString(tofu.CODE_ASK_UNIQUE + struct.pack("!i", uid))
def notify_action(self, mobile, action):
self.sendString(tofu.CODE_DATA_ACTION + "%s%s" % (mobile.dumpuid(), action.dump()))
def notify_add_mobile (self, mobile): pass
def notify_remove_mobile(self, mobile): pass
def check_level_activity(self, level):
for mobile in level.mobiles:
if not mobile.controller.remote:
level.set_active(1)
return
# No local user for this level => we can inactive it
level.set_active(0)
def notify_discard(self, unique):
# The client NEVER saves data
pass
class TCPFactory(ClientFactory):
protocol = Notifier
def clientConnectionFailed(self, connector, reason):
m = reason.getErrorMessage()
print "* Tofu * Connection failed:", m
tofu.GAME_INTERFACE.network_error(m)
def clientConnectionLost(self, connector, reason):
m = reason.getErrorMessage()
print "* Tofu * Connection lost:", m
tofu.GAME_INTERFACE.network_error(m)
def serve_forever(host = "localhost", port = 6900, *args, **kargs):
"""serve_forever(host = "localhost", port = 6900, *ARGS, **KARGS)
Starts a game client, and connect to HOST on port PORT.
ARGS and KARGS are passed to GameInterface.__init__()."""
#reactor.listenUDP(0, UDP())
#twisted.internet.selectreactor.install()
reactor = twisted.internet.reactor
tofu.YourGameInterface(*args, **kargs)
factory = TCPFactory()
twisted.internet.reactor.connectTCP(host, port, factory)
try:
return tofu.IDLER.idle()
finally:
tofu.NOTIFIER.transport.loseConnection()
tofu.IDLER.reactor.iterate()
tofu.IDLER.reactor.runUntilCurrent()
tofu.IDLER.reactor.removeAll()
tofu.IDLER.reactor.disconnectAll()
# We need to start the reactor in order to be able to stop it !!!
# Else the program cannot ends normally.
tofu.IDLER.reactor.callLater(0.0, reactor.stop); reactor.run()
|