// Copyright (c) 2017 PSForever package objects import java.util.concurrent.atomic.AtomicInteger import akka.actor.ActorContext import base.ActorTest import net.psforever.objects.entity.IdentifiableEntity import net.psforever.objects.equipment.Equipment import net.psforever.objects.guid.NumberPoolHub import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.serverobject.terminals.Terminal import net.psforever.objects.serverobject.tube.SpawnTube import net.psforever.objects._ import net.psforever.types._ import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder, StructureType} import net.psforever.objects.zones.{Zone, ZoneMap} import net.psforever.objects.Vehicle import org.specs2.mutable.Specification import akka.actor.typed.scaladsl.adapter._ import net.psforever.actors.zone.ZoneActor import net.psforever.objects.avatar.Avatar import net.psforever.services.ServiceManager import scala.concurrent.duration._ class ZoneTest extends Specification { def test(a: String, b: Int, c: Int, d: Zone, e: ActorContext): Building = { Building.NoBuilding } "ZoneMap" should { "construct" in { new ZoneMap("map13") ok } "references bases by a positive building id (defaults to 0)" in { val map = new ZoneMap("map13") map.localBuildings mustEqual Map.empty map.addLocalBuilding("Building", buildingGuid = 10, mapId = 0, FoundationBuilder(test)) map.localBuildings.keySet.contains(("Building", 10, 0)) mustEqual true map.addLocalBuilding("Building", buildingGuid = -1, mapId = 0, FoundationBuilder(test)) map.localBuildings.keySet.contains(("Building", 10, 0)) mustEqual true map.localBuildings.keySet.contains(("Building", -1, 0)) mustEqual false } "associates objects to bases (doesn't check numbers)" in { val map = new ZoneMap("map13") map.objectToBuilding mustEqual Map.empty map.linkObjectToBuilding(1, 2) map.objectToBuilding mustEqual Map(1 -> 2) map.linkObjectToBuilding(3, 4) map.objectToBuilding mustEqual Map(1 -> 2, 3 -> 4) } "associates doors to door locks (doesn't check numbers)" in { val map = new ZoneMap("map13") map.doorToLock mustEqual Map.empty map.linkDoorToLock(1, 2) map.doorToLock mustEqual Map(1 -> 2) map.linkDoorToLock(3, 4) map.doorToLock mustEqual Map(1 -> 2, 3 -> 4) } "associates terminals to spawn pads (doesn't check numbers)" in { val map = new ZoneMap("map13") map.terminalToSpawnPad mustEqual Map.empty map.linkTerminalToSpawnPad(1, 2) map.terminalToSpawnPad mustEqual Map(1 -> 2) map.linkTerminalToSpawnPad(3, 4) map.terminalToSpawnPad mustEqual Map(1 -> 2, 3 -> 4) } "associates mechanical components to implant terminals (doesn't check numbers)" in { val map = new ZoneMap("map13") map.terminalToInterface mustEqual Map.empty map.linkTerminalToInterface(1, 2) map.terminalToInterface mustEqual Map(1 -> 2) map.linkTerminalToInterface(3, 4) map.terminalToInterface mustEqual Map(1 -> 2, 3 -> 4) } "associate turrets to weapons" in { val map = new ZoneMap("map13") map.turretToWeapon mustEqual Map.empty map.linkTurretToWeapon(1, 2) map.turretToWeapon mustEqual Map(1 -> 2) map.linkTurretToWeapon(3, 4) map.turretToWeapon mustEqual Map(1 -> 2, 3 -> 4) } } val map13 = new ZoneMap("map13") map13.addLocalBuilding("Building", buildingGuid = 0, mapId = 10, FoundationBuilder(test)) class TestObject extends IdentifiableEntity "Zone" should { "construct" in { val zone = new Zone("home3", map13, 13) zone.EquipmentOnGround mustEqual List.empty[Equipment] zone.Vehicles mustEqual List.empty[Vehicle] zone.Players mustEqual List.empty[Player] zone.Corpses mustEqual List.empty[Player] } "can have its unique identifier system changed if no objects were added to it" in { val zone = new Zone("home3", map13, 13) val guid1: NumberPoolHub = new NumberPoolHub(new MaxNumberSource(100)) zone.GUID(guid1) mustEqual true zone.AddPool("pool1", (0 to 50).toList) zone.AddPool("pool2", (51 to 75).toList) val obj = new TestObject() val registration = guid1.register(obj, "pool2") registration.isSuccess mustEqual true guid1.WhichPool(obj).contains("pool2") mustEqual true zone.GUID(new NumberPoolHub(new MaxNumberSource(150))) mustEqual false } } } class ZoneActorTest extends ActorTest { ServiceManager.boot "Zone" should { "refuse new number pools after the Actor is started" in { val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = {} } zone.GUID(new NumberPoolHub(new MaxNumberSource(40150))) zone.actor = system.spawn(ZoneActor(zone), "test-add-pool-actor-init") expectNoMessage(Duration.create(500, "ms")) assert(!zone.AddPool("test1", 1 to 2)) } "refuse to remove number pools after the Actor is started" in { val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = {} } zone.GUID(new NumberPoolHub(new MaxNumberSource(10))) zone.AddPool("test", 1 to 2) zone.actor = system.spawn(ZoneActor(zone), "test-remove-pool-actor-init") expectNoMessage(Duration.create(300, "ms")) assert(!zone.RemovePool("test")) } "set up spawn groups based on buildings" in { val map6 = new ZoneMap("map6") { addLocalBuilding( "Building", buildingGuid = 1, mapId = 1, FoundationBuilder(Building.Structure(StructureType.Building, Vector3(1, 1, 1))) ) addLocalObject(2, SpawnTube.Constructor(Vector3(1, 0, 0), Vector3.Zero)) addLocalObject(3, Terminal.Constructor(Vector3.Zero, GlobalDefinitions.dropship_vehicle_terminal)) addLocalObject(4, SpawnTube.Constructor(Vector3(1, 0, 0), Vector3.Zero)) linkObjectToBuilding(2, 1) linkObjectToBuilding(3, 1) linkObjectToBuilding(4, 1) addLocalBuilding( "Building", buildingGuid = 5, mapId = 2, FoundationBuilder(Building.Structure(StructureType.Building)) ) addLocalObject(6, SpawnTube.Constructor(Vector3.Zero, Vector3.Zero)) linkObjectToBuilding(6, 5) addLocalBuilding( "Building", buildingGuid = 7, mapId = 3, FoundationBuilder(Building.Structure(StructureType.Building, Vector3(1, 1, 1))) ) addLocalObject(8, Terminal.Constructor(Vector3.Zero, GlobalDefinitions.dropship_vehicle_terminal)) addLocalObject(9, SpawnTube.Constructor(Vector3(1, 0, 0), Vector3.Zero)) addLocalObject(10, Terminal.Constructor(Vector3.Zero, GlobalDefinitions.dropship_vehicle_terminal)) linkObjectToBuilding(8, 7) linkObjectToBuilding(9, 7) linkObjectToBuilding(10, 7) } val zone = new Zone("test", map6, 1) { override def SetupNumberPools() = {} } zone.actor = system.spawn(ZoneActor(zone), "test-init") expectNoMessage(Duration.create(1, "seconds")) val groups = zone.SpawnGroups() assert(groups.size == 2) zone .SpawnGroups() .foreach({ case (building, tubes) => if (building.MapId == 1) { val building1 = zone.SpawnGroups(building) assert(tubes.length == 2) assert(tubes.head == building1.head) assert(tubes.head.GUID == PlanetSideGUID(2)) assert(tubes(1) == building1(1)) assert(tubes(1).GUID == PlanetSideGUID(4)) } else if (building.MapId == 3) { val building2 = zone.SpawnGroups(building) assert(tubes.length == 1) assert(tubes.head == building2.head) assert(tubes.head.GUID == PlanetSideGUID(9)) } else { assert(false) } }) } } } class ZonePopulationTest extends ActorTest { "ZonePopulationActor" should { "add new user to zones" in { val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} } val avatar = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) val player = Player(avatar) player.GUID = PlanetSideGUID(1) zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) assert(zone.Players.isEmpty) assert(zone.LivePlayers.isEmpty) zone.Population ! Zone.Population.Join(avatar) zone.Population ! Zone.Population.Spawn(avatar, player, null) expectNoMessage(Duration.create(200, "ms")) assert(zone.Players.size == 1) assert(zone.Players.head == avatar) // assert(zone.LivePlayers.isEmpty) } "remove user from zones" in { val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} } val avatar = Avatar(1, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) val player = Player(avatar) player.GUID = PlanetSideGUID(1) zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) receiveOne(Duration.create(200, "ms")) //consume zone.Population ! Zone.Population.Join(avatar) zone.Population ! Zone.Population.Spawn(avatar, player, null) expectNoMessage(Duration.create(100, "ms")) assert(zone.Players.size == 1) assert(zone.Players.head == avatar) zone.Population ! Zone.Population.Leave(avatar) val reply = receiveOne(Duration.create(100, "ms")) assert(reply.isInstanceOf[Zone.Population.PlayerHasLeft]) assert(zone.Players.isEmpty) } /* TODO they need AvatarActor, which has further dependencies "associate user with a character" in { val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} } val avatar = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) val player = Player(avatar) player.GUID = PlanetSideGUID(1) zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) zone.Population ! Zone.Population.Join(avatar) expectNoMessage(Duration.create(100, "ms")) assert(zone.Players.size == 1) assert(zone.Players.head == avatar) assert(zone.LivePlayers.isEmpty) zone.Population ! Zone.Population.Spawn(avatar, player) expectNoMessage(Duration.create(100, "ms")) assert(zone.Players.size == 1) assert(zone.Players.head == avatar) assert(zone.LivePlayers.size == 1) assert(zone.LivePlayers.head == player) } "disassociate character from a user" in { val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} } val avatar = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) val player = Player(avatar) player.GUID = PlanetSideGUID(1) zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) zone.Population ! Zone.Population.Join(avatar) expectNoMessage(Duration.create(100, "ms")) zone.Population ! Zone.Population.Spawn(avatar, player) expectNoMessage(Duration.create(100, "ms")) assert(zone.Players.size == 1) assert(zone.Players.head == avatar) assert(zone.LivePlayers.size == 1) assert(zone.LivePlayers.head == player) zone.Population ! Zone.Population.Release(avatar) expectNoMessage(Duration.create(100, "ms")) assert(zone.Players.size == 1) assert(zone.Players.head == avatar) assert(zone.LivePlayers.isEmpty) } "user tries to Leave, but still has an associated character" in { val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} } val avatar = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) val player = Player(avatar) player.GUID = PlanetSideGUID(1) zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) zone.Population ! Zone.Population.Join(avatar) expectNoMessage(Duration.create(100, "ms")) zone.Population ! Zone.Population.Spawn(avatar, player) expectNoMessage(Duration.create(100, "ms")) assert(zone.Players.size == 1) assert(zone.Players.head == avatar) assert(zone.LivePlayers.size == 1) assert(zone.LivePlayers.head == player) zone.Population ! Zone.Population.Leave(avatar) val reply = receiveOne(Duration.create(500, "ms")) assert(zone.Players.isEmpty) assert(zone.LivePlayers.isEmpty) assert(reply.isInstanceOf[Zone.Population.PlayerHasLeft]) assert(reply.asInstanceOf[Zone.Population.PlayerHasLeft].zone == zone) assert(reply.asInstanceOf[Zone.Population.PlayerHasLeft].player.contains(player)) } "user tries to Spawn a character, but an associated character already exists" in { val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} } val avatar = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) val player1 = Player(avatar) player1.GUID = PlanetSideGUID(1) val player2 = Player(avatar) player2.GUID = PlanetSideGUID(2) zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) zone.Population ! Zone.Population.Join(avatar) expectNoMessage(Duration.create(100, "ms")) zone.Population ! Zone.Population.Spawn(avatar, player1) expectNoMessage(Duration.create(100, "ms")) assert(zone.Players.size == 1) assert(zone.Players.head == avatar) assert(zone.LivePlayers.size == 1) assert(zone.LivePlayers.head == player1) zone.Population ! Zone.Population.Spawn(avatar, player2) val reply = receiveOne(Duration.create(100, "ms")) assert(zone.Players.size == 1) assert(zone.Players.head == avatar) assert(zone.LivePlayers.size == 1) assert(zone.LivePlayers.head == player1) assert(reply.isInstanceOf[Zone.Population.PlayerAlreadySpawned]) assert(reply.asInstanceOf[Zone.Population.PlayerAlreadySpawned].player == player1) } "user tries to Spawn a character, but did not Join first" in { val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} } val avatar = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) val player = Player(avatar) player.GUID = PlanetSideGUID(1) zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) assert(zone.Players.isEmpty) assert(zone.LivePlayers.isEmpty) zone.Population ! Zone.Population.Spawn(avatar, player) val reply = receiveOne(Duration.create(100, "ms")) assert(zone.Players.isEmpty) assert(zone.LivePlayers.isEmpty) assert(reply.isInstanceOf[Zone.Population.PlayerCanNotSpawn]) assert(reply.asInstanceOf[Zone.Population.PlayerCanNotSpawn].zone == zone) assert(reply.asInstanceOf[Zone.Population.PlayerCanNotSpawn].player == player) } */ "user tries to Release a character, but did not Spawn a character first" in { val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} } val avatar = Avatar(2, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5) val player = Player(avatar) player.GUID = PlanetSideGUID(1) zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) zone.Population ! Zone.Population.Join(avatar) zone.Population ! Zone.Population.Spawn(avatar, player, null) expectNoMessage(Duration.create(100, "ms")) assert(zone.Players.size == 1) assert(zone.Players.head == avatar) // assert(zone.LivePlayers.isEmpty) zone.Population ! Zone.Population.Release(avatar) val reply = receiveOne(Duration.create(100, "ms")) // assert(zone.Players.size == 1) // assert(zone.Players.head == avatar) // assert(zone.LivePlayers.isEmpty) assert(reply.isInstanceOf[Zone.Population.PlayerHasLeft]) assert(reply.asInstanceOf[Zone.Population.PlayerHasLeft].zone == zone) // assert(reply.asInstanceOf[Zone.Population.PlayerHasLeft].player.isEmpty) } "user adds character to list of retired characters" in { val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} } val player = Player(Avatar(3, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)) player.GUID = PlanetSideGUID(1) player.Release zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) assert(zone.Corpses.isEmpty) zone.Population ! Zone.Corpse.Add(player) expectNoMessage(Duration.create(500, "ms")) assert(zone.Corpses.size == 1) assert(zone.Corpses.head == player) } "user removes character from the list of retired characters" in { val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} } val player = Player(Avatar(4, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)) player.GUID = PlanetSideGUID(1) player.Release zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) zone.Population ! Zone.Corpse.Add(player) expectNoMessage(Duration.create(500, "ms")) assert(zone.Corpses.size == 1) assert(zone.Corpses.head == player) zone.Population ! Zone.Corpse.Remove(player) expectNoMessage(Duration.create(200, "ms")) assert(zone.Corpses.isEmpty) } "user removes THE CORRECT character from the list of retired characters" in { val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} } val player1 = Player(Avatar(5, "Chord1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)) player1.GUID = PlanetSideGUID(1) player1.Release val player2 = Player(Avatar(6, "Chord2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)) player2.GUID = PlanetSideGUID(2) player2.Release val player3 = Player(Avatar(7, "Chord3", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)) player3.GUID = PlanetSideGUID(3) player3.Release zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) zone.Population ! Zone.Corpse.Add(player1) zone.Population ! Zone.Corpse.Add(player2) zone.Population ! Zone.Corpse.Add(player3) expectNoMessage(Duration.create(500, "ms")) assert(zone.Corpses.size == 3) assert(zone.Corpses.head == player1) assert(zone.Corpses(1) == player2) assert(zone.Corpses(2) == player3) zone.Population ! Zone.Corpse.Remove(player2) expectNoMessage(Duration.create(200, "ms")) assert(zone.Corpses.size == 2) assert(zone.Corpses.head == player1) assert(zone.Corpses(1) == player3) } "user tries to add character to list of retired characters, but is not in correct state" in { val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} } val player = Player(Avatar(8, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)) player.GUID = PlanetSideGUID(1) //player.Release !!important zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) assert(zone.Corpses.isEmpty) zone.Population ! Zone.Corpse.Add(player) expectNoMessage(Duration.create(200, "ms")) assert(zone.Corpses.isEmpty) } } } class ZoneGroundDropItemTest extends ActorTest { val item = AmmoBox(GlobalDefinitions.bullet_9mm) val hub = new NumberPoolHub(new MaxNumberSource(20)) hub.register(item, 10) val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} } zone.GUID(hub) zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) "DropItem" should { "drop item on ground" in { receiveOne(1 second) //consume assert(!zone.EquipmentOnGround.contains(item)) zone.Ground ! Zone.Ground.DropItem(item, Vector3(1.1f, 2.2f, 3.3f), Vector3(4.4f, 5.5f, 6.6f)) val reply = receiveOne(200 milliseconds) assert(reply.isInstanceOf[Zone.Ground.ItemOnGround]) assert(reply.asInstanceOf[Zone.Ground.ItemOnGround].item == item) assert(reply.asInstanceOf[Zone.Ground.ItemOnGround].pos == Vector3(1.1f, 2.2f, 3.3f)) assert(reply.asInstanceOf[Zone.Ground.ItemOnGround].orient == Vector3(4.4f, 5.5f, 6.6f)) assert(zone.EquipmentOnGround.contains(item)) } } } class ZoneGroundCanNotDropItem1Test extends ActorTest { val item = AmmoBox(GlobalDefinitions.bullet_9mm) val hub = new NumberPoolHub(new MaxNumberSource(20)) //hub.register(item, 10) //!important val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} } zone.GUID(hub) zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) "DropItem" should { "not drop an item that is not registered" in { receiveOne(1 second) //consume assert(!zone.EquipmentOnGround.contains(item)) zone.Ground ! Zone.Ground.DropItem(item, Vector3.Zero, Vector3.Zero) val reply = receiveOne(300 milliseconds) assert(reply.isInstanceOf[Zone.Ground.CanNotDropItem]) assert(reply.asInstanceOf[Zone.Ground.CanNotDropItem].item == item) assert(reply.asInstanceOf[Zone.Ground.CanNotDropItem].zone == zone) assert(reply.asInstanceOf[Zone.Ground.CanNotDropItem].reason == "not registered yet") assert(!zone.EquipmentOnGround.contains(item)) } } } class ZoneGroundCanNotDropItem2Test extends ActorTest { val item = AmmoBox(GlobalDefinitions.bullet_9mm) val hub = new NumberPoolHub(new MaxNumberSource(20)) hub.register(item, 10) //!important val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} } //zone.GUID(hub) //!important zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) "DropItem" should { "not drop an item that is not registered to the zone" in { receiveOne(1 second) //consume assert(!zone.EquipmentOnGround.contains(item)) zone.Ground ! Zone.Ground.DropItem(item, Vector3.Zero, Vector3.Zero) val reply = receiveOne(300 milliseconds) assert(reply.isInstanceOf[Zone.Ground.CanNotDropItem]) assert(reply.asInstanceOf[Zone.Ground.CanNotDropItem].item == item) assert(reply.asInstanceOf[Zone.Ground.CanNotDropItem].zone == zone) assert(reply.asInstanceOf[Zone.Ground.CanNotDropItem].reason == "registered to some other zone") assert(!zone.EquipmentOnGround.contains(item)) } } } class ZoneGroundCanNotDropItem3Test extends ActorTest { val item = AmmoBox(GlobalDefinitions.bullet_9mm) val hub = new NumberPoolHub(new MaxNumberSource(20)) hub.register(item, 10) //!important val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} } zone.GUID(hub) //!important zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) "DropItem" should { "not drop an item that has already been dropped" in { receiveOne(1 second) //consume assert(!zone.EquipmentOnGround.contains(item)) assert(zone.EquipmentOnGround.isEmpty) zone.Ground ! Zone.Ground.DropItem(item, Vector3.Zero, Vector3.Zero) val reply1 = receiveOne(300 milliseconds) assert(reply1.isInstanceOf[Zone.Ground.ItemOnGround]) assert(reply1.asInstanceOf[Zone.Ground.ItemOnGround].item == item) assert(zone.EquipmentOnGround.contains(item)) assert(zone.EquipmentOnGround.size == 1) zone.Ground ! Zone.Ground.DropItem(item, Vector3.Zero, Vector3.Zero) val reply2 = receiveOne(300 milliseconds) assert(reply2.isInstanceOf[Zone.Ground.CanNotDropItem]) assert(reply2.asInstanceOf[Zone.Ground.CanNotDropItem].item == item) assert(reply2.asInstanceOf[Zone.Ground.CanNotDropItem].zone == zone) assert(reply2.asInstanceOf[Zone.Ground.CanNotDropItem].reason == "already dropped") assert(zone.EquipmentOnGround.size == 1) } } } class ZoneGroundPickupItemTest extends ActorTest { val item = AmmoBox(GlobalDefinitions.bullet_9mm) val hub = new NumberPoolHub(new MaxNumberSource(20)) hub.register(item, 10) val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} } zone.GUID(hub) zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) "PickupItem" should { "pickup an item from ground" in { receiveOne(1 second) //consume assert(!zone.EquipmentOnGround.contains(item)) zone.Ground ! Zone.Ground.DropItem(item, Vector3.Zero, Vector3.Zero) val reply1 = receiveOne(200 milliseconds) assert(reply1.isInstanceOf[Zone.Ground.ItemOnGround]) assert(zone.EquipmentOnGround.contains(item)) zone.Ground ! Zone.Ground.PickupItem(item.GUID) val reply2 = receiveOne(200 milliseconds) assert(reply2.isInstanceOf[Zone.Ground.ItemInHand]) assert(reply2.asInstanceOf[Zone.Ground.ItemInHand].item == item) assert(!zone.EquipmentOnGround.contains(item)) } } } class ZoneGroundCanNotPickupItemTest extends ActorTest { val item = AmmoBox(GlobalDefinitions.bullet_9mm) val hub = new NumberPoolHub(new MaxNumberSource(20)) hub.register(item, 10) val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} } zone.GUID(hub) //still registered to this zone zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) "PickupItem" should { "not pickup an item if it can not be found" in { receiveOne(1 second) //consume assert(!zone.EquipmentOnGround.contains(item)) zone.Ground ! Zone.Ground.PickupItem(item.GUID) val reply2 = receiveOne(200 milliseconds) assert(reply2.isInstanceOf[Zone.Ground.CanNotPickupItem]) assert(reply2.asInstanceOf[Zone.Ground.CanNotPickupItem].item_guid == item.GUID) assert(reply2.asInstanceOf[Zone.Ground.CanNotPickupItem].zone == zone) assert(reply2.asInstanceOf[Zone.Ground.CanNotPickupItem].reason == "can not find") } } } class ZoneGroundRemoveItemTest extends ActorTest { val item = AmmoBox(GlobalDefinitions.bullet_9mm) val hub = new NumberPoolHub(new MaxNumberSource(20)) hub.register(item, 10) val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} } zone.GUID(hub) //still registered to this zone zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName) expectNoMessage(200 milliseconds) "RemoveItem" should { "remove an item from the ground without callback (even if the item is not found)" in { receiveOne(1 second) assert(!zone.EquipmentOnGround.contains(item)) zone.Ground ! Zone.Ground.DropItem(item, Vector3.Zero, Vector3.Zero) receiveOne(200 milliseconds) assert(zone.EquipmentOnGround.contains(item)) //dropped zone.Ground ! Zone.Ground.RemoveItem(item.GUID) expectNoMessage(500 milliseconds) assert(!zone.EquipmentOnGround.contains(item)) zone.Ground ! Zone.Ground.RemoveItem(item.GUID) //repeat expectNoMessage(500 milliseconds) assert(!zone.EquipmentOnGround.contains(item)) } } } object ZoneTest { val testNum = new AtomicInteger(1) def TestName: String = s"test${testNum.getAndIncrement()}" }