Skip to content

Commit

Permalink
Expand #75 to include the list of active commands.
Browse files Browse the repository at this point in the history
Provide Command Name Enum on Client.
Add additional test cases for Radar.
Remove Self Destruct Command from Client.
  • Loading branch information
hawkerm committed May 9, 2016
1 parent 8104199 commit f10a9fe
Show file tree
Hide file tree
Showing 34 changed files with 493 additions and 83 deletions.
1 change: 1 addition & 0 deletions SBA_Serv/SBA_Serv.pyproj
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
<Compile Include="Tests\KingOfTheBubbleTestCases.py" />
<Compile Include="Tests\BaubleHuntTestCases.py" />
<Compile Include="Tests\HungryHungryBaublesTestCases.py" />
<Compile Include="Tests\RadarTestCases.py" />
<Compile Include="Tests\SurvivorTestCases.py" />
<Compile Include="Tests\CombatExerciseTestCases.py" />
<Compile Include="Tests\AsteroidMinerTestCases.py" />
Expand Down
2 changes: 1 addition & 1 deletion SBA_Serv/Server/MWNL2.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ def send(self, command, data = None, sendto = 0):
else:
# Broadcast Message
for conn in self.__connections.values():
logging.debug("Broadcasting to " + repr(conn))
logging.debug("Broadcasting to " + repr(conn.getAddress()))
conn.send(info, command, data)
#END FOR
#END IF
Expand Down
214 changes: 214 additions & 0 deletions SBA_Serv/Tests/RadarTestCases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
"""
Space Battle Arena is a Programming Game.
Copyright (C) 2012-2016 Michael A. Hawker and Brett Wortzman
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
The full text of the license is available online: http://opensource.org/licenses/GPL-2.0
"""

from TestCaseRigging import SBAServerTestCase, SBAGUIWithServerTestCase
import Server.MWNL2 as MWNL2
from World.AIShips import AIShip_Network_Harness
from World.WorldCommands import *

import time
import threading

class RadarClientServerTestCase(SBAGUIWithServerTestCase):

def get_config_filename(self):
return "test_server.cfg"

def test_add_two_ships_get_radar_results(self):
"""
Test adding two networked clients to a server and that one can radar the other
"""
self.__env_target = None
self.__env_radar = None

self.targetship = AIShip_Network_Harness("Target", self.__target_ship)
self.assertTrue(self.targetship.connect(self.cfg.getint("Server", "port")), "Target Didn't connect to server.")

self.radarship = AIShip_Network_Harness("Radar", self.__radar_ship)
self.assertTrue(self.radarship.connect(self.cfg.getint("Server", "port")), "Radar Didn't connect to server.")

time.sleep(0.5)

self.assertTrue(self.targetship.isconnected(), "Target Client not connected to server.")
self.assertTrue(self.radarship.isconnected(), "Radar Client not connected to server.")

self.assertIsNotNone(self.__env_target, "Target Never received environment.")
self.assertIsNotNone(self.__env_radar, "Radar Never received environment.")

tship = None
rship = None

for obj in self.game.world:
if "Target" in obj.player.name:
tship = obj
elif "Radar" in obj.player.name:
rship = obj

self.assertIsNotNone(tship, "Couldn't find Target Ship")
self.assertIsNotNone(rship, "Couldn't find Radar Ship")

tship.body.position = self.game.world.mid_point(-75, 0)
rship.body.position = self.game.world.mid_point(75, 0)

time.sleep(1)

self.assertEqual(len(self.__env_radar["RADARDATA"]), 1, "Radar Data Doesn't Contain 1 Item")
self.assertEqual(self.__env_radar["RADARDATA"][0]["ID"], tship.id, "Radar Doesn't Contain Target Ship")

self.assertIsNone(self.__env_target["RADARDATA"], "Target Radar Should Not Contain Data")

time.sleep(1)

self._endServer()

time.sleep(2)

self.assertFalse(self.targetship.isconnected(), "Target Client still connected to server after disconnect.")
self.assertFalse(self.radarship.isconnected(), "Radar Client still connected to server after disconnect.")

time.sleep(0.5)

def test_two_ships_no_radar_when_cloaked(self):
"""
Test adding two networked clients to a server and that one can't radar the other when it's cloaked
"""
self.__env_target = None
self.__env_radar = None

self.targetship = AIShip_Network_Harness("Cloak", self.__cloak_ship)
self.assertTrue(self.targetship.connect(self.cfg.getint("Server", "port")), "Target Didn't connect to server.")

self.radarship = AIShip_Network_Harness("Radar", self.__radar_ship)
self.assertTrue(self.radarship.connect(self.cfg.getint("Server", "port")), "Radar Didn't connect to server.")

time.sleep(0.5)

self.assertTrue(self.targetship.isconnected(), "Target Client not connected to server.")
self.assertTrue(self.radarship.isconnected(), "Radar Client not connected to server.")

self.assertIsNotNone(self.__env_target, "Target Never received environment.")
self.assertIsNotNone(self.__env_radar, "Radar Never received environment.")

tship = None
rship = None

for obj in self.game.world:
if "Cloak" in obj.player.name:
tship = obj
elif "Radar" in obj.player.name:
rship = obj

self.assertIsNotNone(tship, "Couldn't find Target Ship")
self.assertIsNotNone(rship, "Couldn't find Radar Ship")

tship.body.position = self.game.world.mid_point(-75, 0)
rship.body.position = self.game.world.mid_point(75, 0)

time.sleep(1)

self.assertEqual(len(self.__env_radar["RADARDATA"]), 0, "Radar Data Contains Cloaked Ship")
self.assertIsNone(self.__env_target["RADARDATA"], "Target Radar Should Not Contain Data")

time.sleep(1)

self._endServer()

time.sleep(2)

self.assertFalse(self.targetship.isconnected(), "Target Client still connected to server after disconnect.")
self.assertFalse(self.radarship.isconnected(), "Radar Client still connected to server after disconnect.")

time.sleep(0.5)

def test_two_ships_cant_read_command_queue_and_energy(self):
"""
Test adding two networked clients to a server and that one can't read the command queue of the other
"""
self.__env_target = None
self.__env_radar = None

self.targetship = AIShip_Network_Harness("Target", self.__target_ship)
self.assertTrue(self.targetship.connect(self.cfg.getint("Server", "port")), "Target Didn't connect to server.")

self.radarship = AIShip_Network_Harness("Radar", self.__radar_ship)
self.assertTrue(self.radarship.connect(self.cfg.getint("Server", "port")), "Radar Didn't connect to server.")

time.sleep(0.5)

self.assertTrue(self.targetship.isconnected(), "Target Client not connected to server.")
self.assertTrue(self.radarship.isconnected(), "Radar Client not connected to server.")

self.assertIsNotNone(self.__env_target, "Target Never received environment.")
self.assertIsNotNone(self.__env_radar, "Radar Never received environment.")

tship = None
rship = None

for obj in self.game.world:
if "Target" in obj.player.name:
tship = obj
elif "Radar" in obj.player.name:
rship = obj

self.assertIsNotNone(tship, "Couldn't find Target Ship")
self.assertIsNotNone(rship, "Couldn't find Radar Ship")

tship.body.position = self.game.world.mid_point(-75, 0)
rship.body.position = self.game.world.mid_point(75, 0)

time.sleep(1)

self.assertEqual(len(self.__env_radar["RADARDATA"]), 1, "Radar Data Doesn't Contain 1 Item")
self.assertEqual(self.__env_radar["RADARDATA"][0]["ID"], tship.id, "Radar Doesn't Contain Target Ship")
self.assertFalse(self.__env_radar["RADARDATA"][0].has_key("CURENERGY"), "Radar shouldn't contain Target's Energy Level")
self.assertFalse(self.__env_radar["RADARDATA"][0].has_key("CMDQ"), "Radar shouldn't contain Target's Command Queue")

self.assertIsNone(self.__env_target["RADARDATA"], "Target Radar Should Not Contain Data")
self.assertIsNotNone(self.__env_target["SHIPDATA"], "Target Should Contain Ship Data")
self.assertIsNotNone(self.__env_target["SHIPDATA"]["CURENERGY"], "Target Ship Should Know It's Energy Level.")
self.assertEqual(self.__env_target["SHIPDATA"]["CURENERGY"], self.__env_target["SHIPDATA"]["MAXENERGY"], "Target Ship Should have all its energy.")
self.assertIsNotNone(self.__env_target["SHIPDATA"]["CMDQ"], "Target Ship Should Know It's Command Queue.")

time.sleep(1)

self._endServer()

time.sleep(2)

self.assertFalse(self.targetship.isconnected(), "Target Client still connected to server after disconnect.")
self.assertFalse(self.radarship.isconnected(), "Radar Client still connected to server after disconnect.")

time.sleep(0.5)

def __target_ship(self, env):
logging.info("Test Case got Callback from Network for Target Ship")
self.__env_target = env
return RotateCommand(self.targetship, 6)

def __cloak_ship(self, env):
logging.info("Test Case got Callback from Network for Cloak Ship")
if self.__env_target == None:
self.__env_target = env
return CloakCommand(self.targetship, 8.0)

self.__env_target = env
return IdleCommand(self.targetship, 2.0)

def __radar_ship(self, env):
logging.info("Test Case got Callback from Network for Radar Ship")
self.__env_radar = env
return RadarCommand(self.radarship, 5)

if __name__ == '__main__':
unittest.main()
65 changes: 65 additions & 0 deletions SBA_Serv/Tests/ServerTestCases.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,5 +228,70 @@ def __error_ship(self, env):
# means we should be more prudent with testing for those cases with asserts to prevent bad tests.
raise Exception


class ServerGUITwoShipRemoteTestCase(SBAGUIWithServerTestCase):

def get_config_filename(self):
return "test_server.cfg"

# TODO: Expected Failure - Issue #112
def test_add_two_ships_and_disconnect(self):
"""
Tests adding two networked clients to a server and that they can disconnect
"""
self.__env_target = None
self.__env_radar = None

self.targetship = AIShip_Network_Harness("Target", self.__target_ship)
self.assertTrue(self.targetship.connect(self.cfg.getint("Server", "port")), "Target Didn't connect to server.")

self.radarship = AIShip_Network_Harness("Radar", self.__radar_ship)
self.assertTrue(self.radarship.connect(self.cfg.getint("Server", "port")), "Radar Didn't connect to server.")

time.sleep(0.25)

self.assertTrue(self.targetship.isconnected(), "Target Client not connected to server.")
self.assertTrue(self.radarship.isconnected(), "Radar Client not connected to server.")

self.assertIsNotNone(self.__env_target, "Target Never received environment.")
self.assertIsNotNone(self.__env_radar, "Radar Never received environment.")

self.assertEqual(len(self.game.world), 2, "Both Ships not in world.")

tship = None
rship = None

for obj in self.game.world:
if "Target" in obj.player.name:
tship = obj
elif "Radar" in obj.player.name:
rship = obj

self.assertIsNotNone(tship, "Couldn't find Target Ship")
self.assertIsNotNone(rship, "Couldn't find Radar Ship")

time.sleep(0.25)

self._endServer() # Note, Ship will still be visible as we're not removing it from world in this test.

time.sleep(0.5)

self.assertFalse(self.targetship.isconnected(), "Target Client still connected to server after disconnect.")
self.assertFalse(self.radarship.isconnected(), "Radar Client still connected to server after disconnect.")

self.assertEqual(len(self.game.world), 0, "Objects still in world.")

time.sleep(0.5)

def __target_ship(self, env):
logging.info("Test Case got Callback from Network for Target Ship")
self.__env_target = env
return RotateCommand(self.targetship, 240)

def __radar_ship(self, env):
logging.info("Test Case got Callback from Network for Radar Ship")
self.__env_radar = env
return RotateCommand(self.radarship, 240)

if __name__ == '__main__':
unittest.main()
9 changes: 9 additions & 0 deletions SBA_Serv/World/Commanding.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,5 +126,14 @@ def isBlockingCommandOnTop(self):
self.__queueSemaphore.release()
return x

def getRadarRepr(self):
# Returns a short form of list with just the command names
lst = []
self.__queueSemaphore.acquire()
for cmd in self.__queue:
lst.append(cmd.NAME)
self.__queueSemaphore.release()
return lst

def __repr__(self):
return "CommandSystem(" + repr(self.__queue) + ")"
9 changes: 8 additions & 1 deletion SBA_Serv/World/WorldCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,9 @@ def __init__(self, obj, level, target=-1):
def __repr__(self):
return super(RadarCommand, self).__repr__() + " LVL: " + repr(self.level) + " TAR: " + repr(self.target)

def net_repr(self):
return (RadarCommand.NAME, {"LVL": self.level, "TAR":self.target})

class DeployLaserBeaconCommand(OneTimeCommand):
NAME = SHIP_CMD_DEPLOY_LASER_BEACON

Expand Down Expand Up @@ -529,7 +532,8 @@ class CloakCommand(Command):
def __init__(self, obj, duration):
super(CloakCommand, self).__init__(obj, CloakCommand.NAME, duration, block=False, required=15)
self.energycost = 2
self._obj.player.sound = "CLOAK"
if hasattr(self._obj, "player") and self._obj.player != None:
self._obj.player.sound = "CLOAK"
self._done = False

def isComplete(self):
Expand All @@ -541,6 +545,9 @@ def execute(self, t):
if self._obj.commandQueue.containstype(FireTorpedoCommand, True) or self._obj.commandQueue.containstype(RaiseShieldsCommand, True):
self._done = True

def net_repr(self):
return (CloakCommand.NAME, {"DUR": self.timeToLive})

class RaiseShieldsCommand(Command):
NAME = SHIP_CMD_SHIELD

Expand Down
8 changes: 7 additions & 1 deletion SBA_Serv/World/WorldEntities.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,13 @@ def getExtraInfo(self, objData, player):
objData["ROTATIONSPEED"] = self.rotationSpeed
objData["CURSHIELD"] = self.shield.value
objData["MAXSHIELD"] = self.shield.maximum
objData["CMDLEN"] = len(self.commandQueue)

# Only show some properties to the owner of the ship
if player != None and hasattr(self, "player") and self.player != None and self.player.netid == player.netid:
objData["CMDQ"] = self.commandQueue.getRadarRepr()
else:
# Remove this property for other ships
del objData["CURENERGY"]

class CelestialBody:
"""
Expand Down
1 change: 1 addition & 0 deletions SBA_Serv/World/WorldMap.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ def get_count_of_objects(self, type):
return count

def getObjectData(self, obj, player):
#TODO: Move these properties to the 'getExtraInfo' of the base Entity and have child classes call super...
objData = {}
# Convert Type of Object to String
objData["TYPE"] = friendly_type(obj)
Expand Down
2 changes: 1 addition & 1 deletion SBA_Serv/buildnum
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1113
1114
3 changes: 3 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ v1.2 : Planned - May 2016 [Season 5]
* Added **getPointAt** for point projections based on angles and distance
* Added **isInEllipse** check method
* Added **getClosestMappedPoint** for world bounds assistance
* Added ability for client to get info on ship's running commands **getCommandQueue** in the environment *getShipStatus*.
* Command Queue and Current Energy Properties are now only available to its own ship (can't be seen with radar).
* **Removed SelfDestructCommand**
* Added option for Torpedoes to be effected by gravity
* Split 'explodable' from 'gravitable' for Entities, two separate object flags now.
* Separated option for 'showip' in Application settings to decouple from showing statistics, no longer always show IP in Debug mode.
Expand Down
Loading

0 comments on commit f10a9fe

Please sign in to comment.