Module serverController
[hide private]
[frames] | no frames]

Source Code for Module serverController

  1  import math 
  2  import utils 
  3  import cocos 
  4   
  5  from cocos.actions.instant_actions import CallFuncS 
  6  from cocos.actions.interval_actions import MoveTo, Delay 
  7  from cocos.director import director 
  8  from twisted.internet.endpoints import TCP4ClientEndpoint, TCP4ServerEndpoint 
  9  from twisted.python.log import err 
 10   
 11  from clientController import ClientController, EndMenu 
 12  from commands import * 
 13  import constants 
 14  from constants import UNIT_STARTING_OPACITY, TIMER_Z 
 15  from maps import Vertex 
 16  from game_layers import InfoLayer, ActionButton,TransTimer, MenuButton 
 17  from models import * 
 18  from utils import get_action_button_clicked 
 19  from research import RESEARCH 
 20  from client import ServerNoteFactory 
 21  import music 
 22  from twisted.internet import reactor 
 23   
 24   
 25  # this deals with all the game logic, sorta replaces our old controller.py and some of player.py 
 26   
 27   
28 -class ServerController(ClientController):
29
30 - def __init__(self,mapName):
31 super(ServerController, self).__init__(mapName) 32 33 self.pid = self.map.players.pop(0) 34 35 self.connectedClients = {} # k:pid, v:IP of connected clients 36 37 self.connectedClientsIP = {} # k:IP, v:pid 38 39 self.gameStarted = False 40 # start the AI players, todo later 41 42 self.curLevel = 1
43 44 45 ''' 46 Local methods 47 ''' 48
49 - def on_enter(self):
50 # self.gameStarted = True 51 self._init_players() 52 super(ServerController, self).on_enter() 53 self.schedule_interval(self.update_build_status, 0.5)
54 55 56 # updates the buildings' health and build status 57 # called every 0.1 second
58 - def update_build_status(self, dt):
59 for p in self.players.values(): 60 for uid in p.underConstruction.keys(): 61 unit = p.underConstruction[uid] 62 unit.health += unit.maxHealth * (dt / unit.buildTime) 63 self._complete_build(unit, p, uid) 64 if type(unit) != CPU: 65 self.client_update_health(uid, unit.health, p.pid)
66
67 - def execute_action(self, actionName, unit):
68 if actionName[0] == "B": 69 if actionName[1:] == "CPU": #build CPU 70 for a in self.visibleASes: 71 if self.map.AS[a].cores: 72 k, core = self.map.AS[a].cores.popitem() 73 self.map.AS[a].usedCores[k] = core 74 self.build_unit(actionName[1:],self.player,core.vid, unit) 75 break 76 else: 77 self.build_unit(actionName[1:], self.player, unit.curVertex.vid, unit) 78 elif actionName[0] == "T": 79 self.build_unit(actionName[1:], self.player, unit.curVertex.vid) 80 elif actionName == "DEL": 81 self.remove_unit(unit) 82 elif actionName[0] == "R": 83 self.perform_research(actionName,self.player,unit) 84 elif actionName == "Ping": 85 unit.ping(self.remove_unit) 86 elif actionName == "UPingOfDeath": 87 self.upgrade_unit(unit,actionName[1:]) 88 elif actionName == "UNMap": 89 self.upgrade_unit(unit,actionName[1:]) 90 elif actionName == "USinkhole": 91 self.upgrade_unit(unit,actionName[1:]) 92 elif actionName == "Shake": 93 self.curAction = "Shake" 94 self.selectedUnits = [unit] 95 elif actionName == "Attack": 96 self.curAction = "Attack" 97 self.selectedUnits = [unit] 98 elif actionName == "Decrypt": 99 self.upgrade_unit(unit,unit.originalType) 100 self.dispatch_event("click_on_action", actionName)
101 102 ''' 103 Local/Network triggered methods 104 ''' 105
106 - def hand_shake(self,h1,h2):
107 h1.shake(h2)
108
109 - def attack_unit(self,target,attacker=None):
110 if attacker == None: 111 if self.selectedUnits: 112 attacker = self.selectedUnits.pop() 113 if type(attacker) == BufferOverflow: 114 # A bufferoverflow is attacking - attack all enemy troops and enemy building! 115 if type(target) == Vertex: 116 targetVertex = target 117 else: 118 targetVertex = target.curVertex 119 120 attacker.should_attack = 0 121 122 for troopSlot in targetVertex.troopSlots.values(): 123 troop = troopSlot.troop 124 if troop.pid != attacker.pid: # Not sure we need this? 125 attacker.should_attack += 1 126 attacker.attack(troop,self.map) 127 if targetVertex.building != None and targetVertex.building.pid != attacker.pid: 128 attacker.should_attack += 1 129 attacker.attack(targetVertex.building,self.map) 130 131 if attacker.should_attack == 0: 132 attacker.should_attack = 1 133 134 else: 135 # Generic attack 136 attacker.attack(target,self.map)
137 138
139 - def build_unit(self, tid, owner, vid, builder=None,onInit=False):
140 curVertex = self.map.get_vertex(vid) 141 newUnit = self.build_unit_common(tid, owner, curVertex, builder=builder,onInit=onInit) 142 143 if newUnit and not onInit: 144 145 for pid in self.connectedClients.keys(): 146 d = self.connect_end_point(self.connectedClients[pid]) 147 def c(ampProto): 148 return ampProto.callRemote(BuildUnit, pid=owner.pid, tid=tid, vid=vid, uid=newUnit.uid,buid=-1)
149 d.addCallback(c) 150 d.addErrback(err) 151 152 if newUnit.buildTime != 0: 153 owner.underConstruction[newUnit.uid] = newUnit 154 newUnit.update_opacity(math.floor(curVertex.visibilityState) * UNIT_STARTING_OPACITY) 155 156 return newUnit
157
158 - def upgrade_unit(self,oldUnit,newType):
159 160 curVertex = oldUnit.curVertex 161 owner = self.players[oldUnit.pid] 162 self.remove_unit(oldUnit) 163 newUnit = self.build_unit(newType,owner,curVertex.vid) 164 if newType == "EncryptedTroop": 165 newUnit.originalType = oldUnit.__class__.__name__ #get string of name 166 return newUnit
167 168
169 - def remove_unit(self, unit):
170 if unit.isRemoved: 171 # DEBUG 172 # print "already removed" 173 return 174 unit.do(CallFuncS(self.remove_unit_common)) 175 176 for p in self.connectedClients.keys(): 177 d = self.connect_end_point(self.connectedClients[p]) 178 179 def c(ampProto): 180 return ampProto.callRemote(RemoveUnit, pid=unit.pid, uid=unit.uid)
181 d.addCallback(c) 182 d.addErrback(err) 183 reactor.callLater(10, d.cancel) 184 185 186
187 - def start_cpu(self,newUnit,owner,builder=None,researchF=None,upgradeFrom=None):
188 #CPU related logic 189 cpu = owner.idleCPUs.pop() 190 191 timer = TransTimer(newUnit.buildTime, pos=cpu.position) 192 193 if owner.pid == self.pid: 194 action = timer.get_move_action() 195 self.map.add(timer, z=TIMER_Z) 196 else: 197 action = Delay(newUnit.buildTime) 198 cpu.action = action 199 action += CallFunc(self.stop_cpu, cpu,owner) 200 if builder: #building a building 201 action += CallFunc(self.remove_unit,builder) 202 elif researchF: #research 203 action += CallFunc(self.finish_research, newUnit,owner,researchF) 204 if owner.pid == self.pid: 205 timer.do(action) 206 else: 207 self.do(action)
208
209 - def stop_cpu(self, cpu, owner):
210 if owner.pid == self.pid: 211 utils.play_sound("Clock_end.wav") 212 owner.idleCPUs.append(cpu)
213
214 - def move_unit(self, dest, unit, pid):
215 if issubclass(type(unit), Troop) and dest != unit.curVertex and dest.emptyTroopSlots and unit.isSelectable: 216 217 path = self.map.get_path(unit.curVertex, dest, pid, unit) 218 219 #check for firewall 220 if not path: 221 utils.play_sound("firewall.wav") 222 return 223 224 #check for sinkhole 225 sinkHoleIndex = -1 226 for i in range(1,len(path)): 227 vertID = path[i] 228 vert = self.map.vertices[vertID] 229 if vert.building != None and type(vert.building) == Sinkhole and type(unit) != EncryptedTroop and vert.building.pid != pid: 230 sinkHoleIndex = i 231 if sinkHoleIndex != -1: 232 dest = unit.curVertex 233 t = path[:sinkHoleIndex] 234 t.reverse() 235 path = path[:sinkHoleIndex + 1] + t 236 237 #set unit logical position 238 unit.isSelectable = False 239 unit.curVertex.remove_troop(unit) 240 slot = dest.add_trans_troop(unit) 241 unit.destVertex = dest 242 if unit.pid == self.pid: 243 self.dispatch_event("click_on_move", unit.__class__.__name__, dest.vid) 244 245 #dispatch to client 246 for p in self.connectedClients.keys(): 247 d = self.connect_end_point(self.connectedClients[p]) 248 249 def c(ampProto): 250 return ampProto.callRemote(MoveTroop, pid=pid, uid=unit.uid, vid=-1, path=path)
251 d.addCallback(c) 252 d.addErrback(err) 253 reactor.callLater(10, d.cancel) 254 255 # first vertex 256 if pid == self.pid: 257 utils.play_sound("Move.wav") 258 action = CallFuncS(self.cm.remove_tricky) 259 action += MoveTo(unit.curVertex.position, 0.2) 260 else: 261 action = MoveTo(unit.curVertex.position, 0.2) 262 263 # intermediate vertices 264 for i in range(1, len(path)): 265 vertex = self.map.vertices[path[i]] 266 action += MoveTo(vertex.position, 1 / unit.speed) 267 action += CallFuncS(self.update_location, vertex.position, pid, vertex) 268 if i == sinkHoleIndex: 269 action += CallFunc(utils.play_sound, "Sinkhole.wav") 270 action += CallFunc(unit.on_attack,math.ceil(unit.health/3.0),vertex.building) 271 action += Delay(1) 272 273 # final position 274 if type(dest.building) != RSA or type(unit) == EncryptedTroop or dest.building.pid != unit.pid: 275 action += MoveTo(slot.position, 0.2) 276 action += CallFuncS(self.update_location, slot.position, pid) 277 else: 278 action += CallFuncS(self.upgrade_unit,"EncryptedTroop") 279 action += CallFuncS(self.cm.add) 280 unit.do(action) 281 return path 282 return [] 283
284 - def update_location(self, unit, position, pid, vertex=None):
285 if vertex: # no vertex if moving into slot 286 unit.curVertex = vertex 287 if vertex.vid == unit.destVertex.vid: # if same, use set_trans_troop instead 288 vertex.set_trans_troop(unit) 289 self.client_update_location(unit.uid, vertex.vid, pid) 290 else: 291 unit.position = position 292 unit.cshape.center = position 293 unit.isSelectable = True
294
295 - def perform_research(self,researchName,owner,researchFactory):
296 if owner.idleCPUs: 297 if owner.pid == self.pid: 298 utils.play_sound("Clock.wav") 299 researchType = RESEARCH[researchName] 300 researchType.on_start(owner) 301 self.start_cpu(researchType, owner, researchF=researchFactory) 302 return True 303 return False
304 305 306 307 ''' 308 Twisted client methods 309 ''' 310 311 # connect to client
312 - def connect_end_point(self, ip):
313 from twisted.internet import reactor 314 endpoint = TCP4ClientEndpoint(reactor, ip, 8750) 315 factory = ServerNoteFactory() 316 return endpoint.connect(factory)
317
318 - def client_attack(self,tpid,tuid,val):
319 for client_pid in self.connectedClients.keys(): 320 d = self.connect_end_point(self.connectedClients[client_pid]) 321 322 def c(ampProto): 323 return ampProto.callRemote(Attack, tpid=tpid, tuid=tuid, val=val)
324 d.addCallback(c) 325 d.addErrback(err) 326 reactor.callLater(10, d.cancel) 327
328 - def client_attack_animation(self,pid,uid,tpid,tuid,path):
329 for client_pid in self.connectedClients.keys(): 330 d = self.connect_end_point(self.connectedClients[client_pid]) 331 332 def c(ampProto): 333 return ampProto.callRemote(AttackAnimation, pid=pid, uid=uid, tpid=tpid,tuid=tuid,path=path)
334 d.addCallback(c) 335 d.addErrback(err) 336 reactor.callLater(10, d.cancel) 337
338 - def client_update_health(self, uid, health, pid):
339 for client_pid in self.connectedClients.keys(): 340 d = self.connect_end_point(self.connectedClients[client_pid]) 341 342 def c(ampProto): 343 if uid in self.players[pid].underConstruction.keys(): 344 u = self.players[pid].underConstruction[uid] 345 else: 346 u = self.players[pid].units[uid] 347 return ampProto.callRemote(UpdateHealth, pid=pid, uid=uid, h=health,tid=u.tid,vid=u.curVertex.vid)
348 d.addCallback(c) 349 d.addErrback(err) 350 reactor.callLater(10, d.cancel) 351
352 - def client_update_location(self, uid, vid, pid):
353 for p in self.connectedClients.keys(): 354 d = self.connect_end_point(self.connectedClients[p]) 355 356 def c(ampProto): 357 return ampProto.callRemote(UpdateLocation, pid=pid, uid=uid, vid=vid)
358 d.addCallback(c) 359 d.addErrback(err) 360 reactor.callLater(10, d.cancel) 361
362 - def client_add_player(self, newpid):
363 for pid in self.connectedClients.keys(): 364 d = self.connect_end_point(self.connectedClients[pid]) 365 366 def c(ampProto): 367 return ampProto.callRemote(AddPlayer, pid=newpid)
368 d.addCallback(c) 369 d.addErrback(err) 370 reactor.callLater(10, d.cancel) 371
372 - def client_start_game(self):
373 for pid in self.connectedClients.keys(): 374 d = self.connect_end_point(self.connectedClients[pid]) 375 def c(ampProto): 376 return ampProto.callRemote(StartGame)
377 d.addCallback(c) 378 d.addErrback(err) 379 reactor.callLater(10, d.cancel) 380 381 ''' 382 helper methods 383 ''' 384
385 - def _move_selected_units(self, dest):
386 for unit in self.selectedUnits: 387 self.move_unit(dest, unit, self.pid) 388 self._deselect_all_units()
389