diff --git a/server/src/test/scala/actor/objects/VehicleSpawnPadTest.scala b/server/src/test/scala/actor/objects/VehicleSpawnPadTest.scala index c2ab882a..391fbc04 100644 --- a/server/src/test/scala/actor/objects/VehicleSpawnPadTest.scala +++ b/server/src/test/scala/actor/objects/VehicleSpawnPadTest.scala @@ -213,7 +213,7 @@ object VehicleSpawnPadControlTest { faction: PlanetSideEmpire.Value )(implicit system: ActorSystem): (Vehicle, Player, VehicleSpawnPad, Zone) = { import net.psforever.objects.guid.NumberPoolHub - import net.psforever.objects.guid.source.LimitedNumberSource + import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.serverobject.structures.Building import net.psforever.objects.vehicles.VehicleControl import net.psforever.objects.Tool @@ -221,7 +221,7 @@ object VehicleSpawnPadControlTest { val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy) val weapon = vehicle.WeaponControlledFromSeat(1).get.asInstanceOf[Tool] - val guid: NumberPoolHub = new NumberPoolHub(LimitedNumberSource(5)) + val guid: NumberPoolHub = new NumberPoolHub(MaxNumberSource(5)) guid.AddPool("test-pool", (0 to 5).toList) guid.register(vehicle, "test-pool") guid.register(weapon, "test-pool") diff --git a/server/src/test/scala/actor/service/AvatarServiceTest.scala b/server/src/test/scala/actor/service/AvatarServiceTest.scala index 4f9d2365..94e4ea3b 100644 --- a/server/src/test/scala/actor/service/AvatarServiceTest.scala +++ b/server/src/test/scala/actor/service/AvatarServiceTest.scala @@ -17,7 +17,7 @@ import scala.concurrent.duration._ import akka.actor.typed.scaladsl.adapter._ import net.psforever.actors.zone.ZoneActor import net.psforever.objects.avatar.Avatar -import net.psforever.objects.guid.source.LimitedNumberSource +import net.psforever.objects.guid.source.MaxNumberSource class AvatarService1Test extends ActorTest { "AvatarService" should { @@ -512,7 +512,7 @@ class AvatarReleaseTest extends ActorTest { val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } } - val guid1: NumberPoolHub = new NumberPoolHub(new LimitedNumberSource(100)) + val guid1: NumberPoolHub = new NumberPoolHub(new MaxNumberSource(100)) zone.GUID(guid1) val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service") zone.actor = system.spawn(ZoneActor(zone), "release-test-zone") @@ -564,7 +564,7 @@ class AvatarReleaseEarly1Test extends ActorTest { val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } } - val guid1: NumberPoolHub = new NumberPoolHub(new LimitedNumberSource(100)) + val guid1: NumberPoolHub = new NumberPoolHub(new MaxNumberSource(100)) zone.GUID(guid1) val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service") zone.actor = system.spawn(ZoneActor(zone), "release-test-zone") @@ -617,7 +617,7 @@ class AvatarReleaseEarly2Test extends ActorTest { val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } } - val guid1: NumberPoolHub = new NumberPoolHub(new LimitedNumberSource(100)) + val guid1: NumberPoolHub = new NumberPoolHub(new MaxNumberSource(100)) zone.GUID(guid1) val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service") zone.actor = system.spawn(ZoneActor(zone), "release-test-zone") diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala index 88e7aaef..7180c8ed 100644 --- a/src/main/scala/net/psforever/actors/session/SessionActor.scala +++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala @@ -8,8 +8,11 @@ import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware} import akka.pattern.ask import akka.util.Timeout import java.util.concurrent.TimeUnit + import MDCContextAware.Implicits._ +import net.psforever.objects.locker.LockerContainer import org.log4s.MDC + import scala.collection.mutable import scala.concurrent.{Await, Future} import scala.concurrent.duration._ @@ -359,13 +362,29 @@ class SessionActor extends Actor with MDCContextAware { def ValidObject(id: Option[PlanetSideGUID]): Option[PlanetSideGameObject] = continent.GUID(id) match { + case Some(obj: LocalProjectile) => + FindProjectileEntry(id.get) + + case Some(_: LocalLockerItem) => + player.avatar.locker.Inventory.hasItem(id.get) match { + case out @ Some(_) => + out + case None => + //delete stale entity reference from client + log.warn(s"${player.Name} has an invalid reference to GUID ${id.get} in zone ${continent.id}") + sendResponse(ObjectDeleteMessage(id.get, 0)) + None + } + case out @ Some(obj) if obj.HasGUID => out + case None if id.nonEmpty && id.get != PlanetSideGUID(0) => //delete stale entity reference from client - log.warn(s"Player ${player.Name} has an invalid reference to GUID ${id.get} in zone ${continent.id}.") + log.warn(s"${player.Name} has an invalid reference to GUID ${id.get} in zone ${continent.id}") sendResponse(ObjectDeleteMessage(id.get, 0)) None + case _ => None } @@ -1893,7 +1912,7 @@ class SessionActor extends Actor with MDCContextAware { continent.GUID(mount) match { case Some(obj: Vehicle) => TotalDriverVehicleControl(obj) - UnAccessContents(obj) + UnaccessContainer(obj) case _ => ; } PlayerActionsToCancel() @@ -2480,7 +2499,7 @@ class SessionActor extends Actor with MDCContextAware { // the player will receive no messages consistently except the KeepAliveMessage echo keepAliveFunc = KeepAlivePersistence } - AccessContents(obj) + AccessContainer(obj) UpdateWeaponAtSeatPosition(obj, seat_num) MountingAction(tplayer, obj, seat_num) @@ -2516,7 +2535,7 @@ class SessionActor extends Actor with MDCContextAware { DismountAction(tplayer, obj, seat_num) case Mountable.CanDismount(obj: Vehicle, seat_num) if obj.Definition == GlobalDefinitions.droppod => - UnAccessContents(obj) + UnaccessContainer(obj) DismountAction(tplayer, obj, seat_num) case Mountable.CanDismount(obj: Vehicle, seat_num) => @@ -2524,7 +2543,7 @@ class SessionActor extends Actor with MDCContextAware { if (player_guid == player.GUID) { //disembarking self TotalDriverVehicleControl(obj) - UnAccessContents(obj) + UnaccessContainer(obj) DismountAction(tplayer, obj, seat_num) } else { continent.VehicleEvents ! VehicleServiceMessage( @@ -2735,7 +2754,7 @@ class SessionActor extends Actor with MDCContextAware { if (tplayer_guid == guid) { continent.GUID(vehicle_guid) match { case Some(obj: Vehicle) => - UnAccessContents(obj) + UnaccessContainer(obj) case _ => ; } } @@ -3779,9 +3798,7 @@ class SessionActor extends Actor with MDCContextAware { val guid = player.GUID sendResponse(UnuseItemMessage(guid, veh.GUID)) sendResponse(UnuseItemMessage(guid, guid)) - veh.AccessingTrunk = None - UnAccessContents(veh) - accessedContainer = None + UnaccessContainer(veh) } case Some(container) => //just in case if (isMovingPlus) { @@ -3791,7 +3808,7 @@ class SessionActor extends Actor with MDCContextAware { sendResponse(UnuseItemMessage(guid, container.GUID)) } sendResponse(UnuseItemMessage(guid, guid)) - accessedContainer = None + UnaccessContainer(container) } case None => ; } @@ -4384,25 +4401,20 @@ class SessionActor extends Actor with MDCContextAware { case Some(obj: Equipment) => FindEquipmentToDelete(object_guid, obj) - case Some(_: LocalProjectile) => - FindProjectileEntry(object_guid) match { - case Some(projectile) => - if (projectile.isResolved) { - log.warn( - s"RequestDestroy: tried to clean up projectile ${object_guid.guid} but it was already resolved" - ) - } else { - projectile.Miss() - if (projectile.profile.ExistsOnRemoteClients && projectile.HasGUID) { - continent.AvatarEvents ! AvatarServiceMessage( - continent.id, - AvatarAction.ProjectileExplodes(player.GUID, projectile.GUID, projectile) - ) - taskResolver ! UnregisterProjectile(projectile) - } - } - case None => - log.warn(s"RequestDestroy: projectile ${object_guid.guid} has never been fired") + case Some(obj: Projectile) => + if (obj.isResolved) { + log.warn( + s"RequestDestroy: tried to clean up projectile ${object_guid.guid} but it was already resolved" + ) + } else { + obj.Miss() + if (obj.profile.ExistsOnRemoteClients && obj.HasGUID) { + continent.AvatarEvents ! AvatarServiceMessage( + continent.id, + AvatarAction.ProjectileExplodes(player.GUID, obj.GUID, obj) + ) + taskResolver ! UnregisterProjectile(obj) + } } case Some(obj: BoomerDeployable) => @@ -4463,7 +4475,7 @@ class SessionActor extends Actor with MDCContextAware { Some(destination: PlanetSideServerObject with Container), Some(item: Equipment) ) => - source.Actor ! Containable.MoveItem(destination, item, dest) + ContainableMoveItem(taskResolver, player.Name, source, destination, item, dest) case (None, _, _) => log.error(s"MoveItem: wanted to move $item_guid from $source_guid, but could not find source object") case (_, None, _) => @@ -4500,7 +4512,7 @@ class SessionActor extends Actor with MDCContextAware { destination.Fit(item) ) match { case (Some((source, Some(_))), Some(dest)) => - source.Actor ! Containable.MoveItem(destination, item, dest) + ContainableMoveItem(taskResolver, player.Name, source, destination, item, dest) case (None, _) => log.error(s"LootItem: can not find where $item is put currently") case (_, None) => @@ -4610,7 +4622,7 @@ class SessionActor extends Actor with MDCContextAware { itemType ) ) - accessedContainer = Some(obj) + AccessContainer(obj) } } else if (!unk3 && player.isAlive) { //potential kit use ValidObject(item_used_guid) match { @@ -4759,13 +4771,12 @@ class SessionActor extends Actor with MDCContextAware { case None if locker.Faction == player.Faction || !locker.HackedBy.isEmpty => log.trace(s"UseItem: ${player.Name} accessing a locker") CancelZoningProcessWithDescriptiveReason("cancel_use") - val container = player.avatar.locker - accessedContainer = Some(container) + val playerLocker = player.avatar.locker sendResponse( UseItemMessage( avatar_guid, item_used_guid, - container.GUID, + playerLocker.GUID, unk2, unk3, unk4, @@ -4776,6 +4787,7 @@ class SessionActor extends Actor with MDCContextAware { 456 ) ) + AccessContainer(playerLocker) case _ => ; } @@ -4827,8 +4839,7 @@ class SessionActor extends Actor with MDCContextAware { ) { CancelZoningProcessWithDescriptiveReason("cancel_use") obj.AccessingTrunk = player.GUID - accessedContainer = Some(obj) - AccessContents(obj) + AccessContainer(obj) sendResponse( UseItemMessage( avatar_guid, @@ -5044,19 +5055,16 @@ class SessionActor extends Actor with MDCContextAware { case msg @ UnuseItemMessage(player_guid, object_guid) => log.info(s"UnuseItem: $msg") - //TODO check for existing accessedContainer value? ValidObject(object_guid) match { - case Some(obj: Vehicle) => - if (obj.AccessingTrunk.contains(player.GUID)) { - obj.AccessingTrunk = None - UnAccessContents(obj) - } case Some(obj: Player) => + UnaccessContainer(obj) TryDisposeOfLootedCorpse(obj) + case Some(obj: Container) => + UnaccessContainer(obj) + case _ => ; } - accessedContainer = None case msg @ DeployObjectMessage(guid, unk1, pos, orient, unk2) => log.info(s"DeployObject: $msg") @@ -5757,7 +5765,8 @@ class SessionActor extends Actor with MDCContextAware { } /** - * Construct tasking that registers all aspects of a `Player` avatar. + * Construct tasking that registers all aspects of a `Player` avatar + * as if that player is only just being introduced. * `Players` are complex objects that contain a variety of other register-able objects and each of these objects much be handled. * @param tplayer the avatar `Player` * @return a `TaskResolver.GiveTask` message @@ -5785,7 +5794,7 @@ class SessionActor extends Actor with MDCContextAware { } override def onFailure(ex: Throwable): Unit = { - localAnnounce ! PlayerFailedToLoad(localPlayer) //alerts WorldSessionActor + localAnnounce ! PlayerFailedToLoad(localPlayer) //alerts SessionActor } }, List(GUIDTask.RegisterAvatar(tplayer)(continent.GUID)) @@ -5793,7 +5802,8 @@ class SessionActor extends Actor with MDCContextAware { } /** - * Construct tasking that registers all aspects of a `Player` avatar. + * Construct tasking that registers all aspects of a `Player` avatar + * as if that player was already introduced and is just being renewed. * `Players` are complex objects that contain a variety of other register-able objects and each of these objects much be handled. * @param tplayer the avatar `Player` * @return a `TaskResolver.GiveTask` message @@ -5872,7 +5882,7 @@ class SessionActor extends Actor with MDCContextAware { * Additionally, the driver is only partially associated with the vehicle at this time. * `interstellarFerry` is properly keeping track of the vehicle during the transition * and the user who is the driver (second param) is properly seated - * but the said driver does not know about the vehicle through his usual convention - VehicleSeated` - yet. + * but the said driver does not know about the vehicle through his usual convention - `VehicleSeated` - yet. * @see `GlobalDefinitions.droppod` * @see `GUIDTask.RegisterObjectTask` * @see `interstellarFerry` @@ -5975,10 +5985,10 @@ class SessionActor extends Actor with MDCContextAware { } override def onFailure(ex: Throwable): Unit = { - localAnnounce ! PlayerFailedToLoad(localDriver) //alerts WorldSessionActor + localAnnounce ! PlayerFailedToLoad(localDriver) //alerts SessionActor } }, - List(GUIDTask.RegisterAvatar(driver)(continent.GUID), GUIDTask.RegisterVehicle(obj)(continent.GUID)) + List(RegisterNewAvatar(driver), GUIDTask.RegisterVehicle(obj)(continent.GUID)) ) } @@ -6115,50 +6125,106 @@ class SessionActor extends Actor with MDCContextAware { ) } + def AccessContainer(container: Container): Unit = { + container match { + case v: Vehicle => + AccessVehicleContents(v) + case o: LockerContainer => + AccessGenericContainer(o) + case p: PlanetSideServerObject with Container => + accessedContainer = Some(p) + case _ => ; + } + } + + def AccessGenericContainer(container: PlanetSideServerObject with Container): Unit = { + accessedContainer = Some(container) + DisplayContainerContents(container.GUID, container) + } + /** * Common preparation for interfacing with a vehicle. * Join a vehicle-specific group for shared updates. * Construct every object in the vehicle's inventory for shared manipulation updates. * @param vehicle the vehicle */ - def AccessContents(vehicle: Vehicle): Unit = { - AccessContentsChannel(vehicle) - val parent_guid = vehicle.GUID - vehicle.Trunk.Items.foreach(entry => { - val obj = entry.obj - val objDef = obj.Definition - sendResponse( - ObjectCreateDetailedMessage( - objDef.ObjectId, - obj.GUID, - ObjectCreateMessageParent(parent_guid, entry.start), - objDef.Packet.DetailedConstructorData(obj).get - ) - ) - }) + def AccessVehicleContents(vehicle: Vehicle): Unit = { + accessedContainer = Some(vehicle) + if(vehicle.AccessingTrunk.isEmpty) { + vehicle.AccessingTrunk = Some(player.GUID) + } + AccessVehicleContainerChannel(vehicle) + DisplayContainerContents(vehicle.GUID, vehicle) } - def AccessContentsChannel(container: PlanetSideServerObject): Unit = { + def AccessVehicleContainerChannel(container: PlanetSideServerObject): Unit = { continent.VehicleEvents ! Service.Join(s"${container.Actor}") } + def DisplayContainerContents(containerId: PlanetSideGUID, container: Container): Unit = { + container.Inventory.Items.foreach(entry => { + val obj = entry.obj + val objDef = obj.Definition + sendResponse( + ObjectCreateDetailedMessage( + objDef.ObjectId, + obj.GUID, + ObjectCreateMessageParent(containerId, entry.start), + objDef.Packet.DetailedConstructorData(obj).get + ) + ) + }) + } + + def UnaccessContainer(): Unit = { + accessedContainer match { + case Some(container) => UnaccessContainer(container) + case _ => ; + } + } + + def UnaccessContainer(container: Container): Unit = { + container match { + case v: Vehicle => + UnaccessVehicleContainer(v) + case o: LockerContainer => + UnaccessGenericContainer(o) + case _: PlanetSideServerObject with Container => + accessedContainer = None + case _ => ; + } + } + + def UnaccessGenericContainer(container: Container): Unit = { + accessedContainer = None + HideContainerContents(container) + } + /** * Common preparation for disengaging from a vehicle. * Leave the vehicle-specific group that was used for shared updates. * Deconstruct every object in the vehicle's inventory. * @param vehicle the vehicle */ - def UnAccessContents(vehicle: Vehicle): Unit = { - continent.VehicleEvents ! Service.Leave(Some(s"${vehicle.Actor}")) - vehicle.Trunk.Items.foreach(entry => { - sendResponse(ObjectDeleteMessage(entry.obj.GUID, 0)) - }) + def UnaccessVehicleContainer(vehicle: Vehicle): Unit = { + accessedContainer = None + if(vehicle.AccessingTrunk.contains(player.GUID)) { + vehicle.AccessingTrunk = None + } + UnaccessVehicleContainerChannel(vehicle) + HideContainerContents(vehicle) } - def UnAccessContentsChannel(container: PlanetSideServerObject): Unit = { + def UnaccessVehicleContainerChannel(container: PlanetSideServerObject): Unit = { continent.VehicleEvents ! Service.Leave(Some(s"${container.Actor}")) } + def HideContainerContents(container: Container): Unit = { + container.Inventory.Items.foreach(entry => { + sendResponse(ObjectDeleteMessage(entry.obj.GUID, 0)) + }) + } + /** * Check two locations for a controlled piece of equipment that is associated with the `player`.
*
@@ -6813,19 +6879,7 @@ class SessionActor extends Actor with MDCContextAware { progressBarUpdate.cancel() progressBarValue = None lastTerminalOrderFulfillment = true - accessedContainer match { - case Some(obj: Vehicle) => - if (obj.AccessingTrunk.contains(player.GUID)) { - obj.AccessingTrunk = None - UnAccessContents(obj) - } - accessedContainer = None - - case Some(_) => - accessedContainer = None - - case None => ; - } + UnaccessContainer() prefire.orElse(shooting) match { case Some(guid) => sendResponse(ChangeFireStateMessage_Stop(guid)) @@ -7030,7 +7084,7 @@ class SessionActor extends Actor with MDCContextAware { * and is permitted to introduce the avatar to the vehicle's internal settings in a similar way. * Neither the player avatar nor the vehicle should be reconstructed before the next zone load operation * to avoid damaging the critical setup of this function. - * @see `AccessContents` + * @see `AccessContainer` * @see `UpdateWeaponAtSeatPosition` * @param tplayer the player avatar seated in the vehicle's seat * @param vehicle the vehicle the player is riding @@ -7046,7 +7100,7 @@ class SessionActor extends Actor with MDCContextAware { sendResponse(ObjectCreateDetailedMessage(pdef.ObjectId, pguid, pdata)) if (seat == 0 || vehicle.Seats(seat).ControlledWeapon.nonEmpty) { sendResponse(ObjectAttachMessage(vguid, pguid, seat)) - AccessContents(vehicle) + AccessContainer(vehicle) UpdateWeaponAtSeatPosition(vehicle, seat) } else { interimUngunnedVehicle = Some(vguid) @@ -7120,7 +7174,7 @@ class SessionActor extends Actor with MDCContextAware { //log.info(s"AvatarRejoin: $vguid -> $vdata") if (seat == 0 || vehicle.Seats(seat).ControlledWeapon.nonEmpty) { sendResponse(ObjectAttachMessage(vguid, pguid, seat)) - AccessContents(vehicle) + AccessContainer(vehicle) UpdateWeaponAtSeatPosition(vehicle, seat) } else { interimUngunnedVehicle = Some(vguid) @@ -8203,6 +8257,7 @@ class SessionActor extends Actor with MDCContextAware { /** * A simple object searching algorithm that is limited to containers currently known and accessible by the player. * If all relatively local containers are checked and the object is not found, + * the player's locker inventory will be checked, and then * the game environment (items on the ground) will be checked too. * If the target object is discovered, it is removed from its current location and is completely destroyed. * @see `RequestDestroyMessage`
@@ -8218,8 +8273,7 @@ class SessionActor extends Actor with MDCContextAware { : PlanetSideServerObject with Container => Option[(PlanetSideServerObject with Container, Option[Int])] = FindInLocalContainer(object_guid) - findFunc(player.avatar.locker) - .orElse(findFunc(player)) + findFunc(player) .orElse(accessedContainer match { case Some(parent: PlanetSideServerObject) => findFunc(parent) @@ -8239,7 +8293,11 @@ class SessionActor extends Actor with MDCContextAware { true case _ => - if (continent.EquipmentOnGround.contains(obj)) { + if (player.avatar.locker.Inventory.Remove(object_guid)) { + sendResponse(ObjectDeleteMessage(object_guid, 0)) + log.info(s"RequestDestroy: equipment $obj") + true + } else if (continent.EquipmentOnGround.contains(obj)) { obj.Position = Vector3.Zero continent.Ground ! Zone.Ground.RemoveItem(object_guid) continent.AvatarEvents ! AvatarServiceMessage.Ground(RemoverActor.ClearSpecific(List(obj), continent)) @@ -8440,7 +8498,7 @@ class SessionActor extends Actor with MDCContextAware { if (player.isBackpack) { session = session.copy(player = targetPlayer) taskThenZoneChange( - GUIDTask.UnregisterLocker(original.avatar.locker)(continent.GUID), + GUIDTask.UnregisterObjectTask(original.avatar.locker)(continent.GUID), InterstellarClusterService.FindZone(_.id == zoneId, context.self) ) } else if (player.HasGUID) { @@ -8545,12 +8603,12 @@ class SessionActor extends Actor with MDCContextAware { InterstellarClusterService.FindZone(_.id == zoneId, context.self) ) } else { - UnAccessContents(vehicle) + UnaccessContainer(vehicle) LoadZoneCommonTransferActivity() player.VehicleSeated = vehicle.GUID player.Continent = zoneId //forward-set the continent id to perform a test interstellarFerryTopLevelGUID = - (if ( + if ( manifest.passengers.isEmpty && manifest.cargo.count { case (name, _) => !name.equals("MISSING_DRIVER") } == 0 ) { //do not delete if vehicle has passengers or cargo @@ -8561,7 +8619,7 @@ class SessionActor extends Actor with MDCContextAware { None } else { Some(topLevel) - }) + } //unregister vehicle and driver whole + GiveWorld continent.Transport ! Zone.Vehicle.Despawn(vehicle) taskThenZoneChange( @@ -8586,12 +8644,12 @@ class SessionActor extends Actor with MDCContextAware { * A reference to the top-level ferrying vehicle's former globally unique identifier has been retained for this purpose. * This vehicle can be deleted for everyone if no more work can be detected. * - * @see `GUIDTask.UnregisterAvatar` + * @see `GUIDTask.UnregisterPlayer` * @see `LoadZoneCommonTransferActivity` * @see `Vehicles.AllGatedOccupantsInSameZone` * @see `PlayerLoaded` * @see `TaskBeforeZoneChange` - * @see `UnAccessContents` + * @see `UnaccessContainer` * @param vehicle the target vehicle being moved around * @param zoneId the zone in which the vehicle and driver will be placed * @return a tuple composed of an `ActorRef` destination and a message to send to that destination @@ -9209,7 +9267,7 @@ class SessionActor extends Actor with MDCContextAware { } /** - * The upstream counter accumulates when the server receives sp[ecific messages from the client. + * The upstream counter accumulates when the server receives specific messages from the client. * It counts upwards until it reach maximum value, and then starts over. * When it starts over, which should take an exceptionally long time to achieve, * it starts counting at one rather than zero. @@ -9265,7 +9323,7 @@ class SessionActor extends Actor with MDCContextAware { case (Some(vehicle: Vehicle), Some(vguid), Some(seat)) => //sit down sendResponse(ObjectAttachMessage(vguid, pguid, seat)) - AccessContents(vehicle) + AccessContainer(vehicle) keepAliveFunc = KeepAlivePersistence case _ => ; //we can't find a vehicle? and we're still here? that's bad diff --git a/src/main/scala/net/psforever/login/WorldSession.scala b/src/main/scala/net/psforever/login/WorldSession.scala index 7ba59e80..4154646e 100644 --- a/src/main/scala/net/psforever/login/WorldSession.scala +++ b/src/main/scala/net/psforever/login/WorldSession.scala @@ -6,6 +6,7 @@ import akka.util.Timeout import net.psforever.objects.equipment.{Ammo, Equipment} import net.psforever.objects.guid.{GUIDTask, Task, TaskResolver} import net.psforever.objects.inventory.{Container, InventoryItem} +import net.psforever.objects.locker.LockerContainer import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.containable.Containable import net.psforever.objects.zones.Zone @@ -504,6 +505,215 @@ object WorldSession { result } + /** + * Move an item from one container to another. + * If the source or if the destination is a kind of container called a `LockerContainer`, + * then a special procedure for the movement of the item must be respected. + * If the source and the destination are both `LockerContainer` objects, however, + * the normal operations for moving an item may be executed. + * @see `ActorRef` + * @see `Containable.MoveItem` + * @see `Container` + * @see `Equipment` + * @see `LockerContainer` + * @see `RemoveEquipmentFromLockerContainer` + * @see `StowEquipmentInLockerContainer` + * @see `TaskResolver` + * @param taskResolver na + * @param toChannel broadcast channel name for a manual packet callback + * @param source the container in which the item is to be removed + * @param destination the container into which the item is to be placed + * @param item the item + * @param dest where in the destination container the item is being placed + */ + def ContainableMoveItem( + taskResolver: ActorRef, + toChannel: String, + source: PlanetSideServerObject with Container, + destination: PlanetSideServerObject with Container, + item: Equipment, + dest: Int + ) : Unit = { + (source, destination) match { + case (locker: LockerContainer, _) if !destination.isInstanceOf[LockerContainer] => + RemoveEquipmentFromLockerContainer(taskResolver, toChannel, locker, destination, item, dest) + case (_, locker: LockerContainer) => + StowEquipmentInLockerContainer(taskResolver, toChannel, source, locker, item, dest) + case _ => + source.Actor ! Containable.MoveItem(destination, item, dest) + } + } + + /** + * Move an item into a player's locker inventory. + * Handle any swap item that might become involved in the transfer. + * Failure of this process is not supported and may lead to irregular behavior. + * @see `ActorRef` + * @see `AvatarAction.ObjectDelete` + * @see `AvatarServiceMessage` + * @see `Containable.MoveItem` + * @see `Container` + * @see `Equipment` + * @see `GridInventory.CheckCollisionsVar` + * @see `GUIDTask.RegisterEquipment` + * @see `GUIDTask.UnregisterEquipment` + * @see `IdentifiableEntity.Invalidate` + * @see `LockerContainer` + * @see `Service` + * @see `Task` + * @see `TaskResolver` + * @see `TaskResolver.GiveTask` + * @see `Zone.AvatarEvents` + * @param taskResolver na + * @param toChannel broadcast channel name for a manual packet callback + * @param source the container in which the item is to be removed + * @param destination the container into which the item is to be placed + * @param item the item + * @param dest where in the destination container the item is being placed + */ + def StowEquipmentInLockerContainer( + taskResolver: ActorRef, + toChannel: String, + source: PlanetSideServerObject with Container, + destination: PlanetSideServerObject with Container, + item: Equipment, + dest: Int + ): Unit = { + val registrationTask = GUIDTask.UnregisterEquipment(item)(source.Zone.GUID) + //check for the existence of a swap item - account for that in advance + val (subtasks, swapItemGUID): (List[TaskResolver.GiveTask], Option[PlanetSideGUID]) = { + val tile = item.Definition.Tile + destination.Inventory.CheckCollisionsVar(dest, tile.Width, tile.Height) + } match { + case Success(Nil) => + //no swap item + (List(registrationTask), None) + case Success(List(swapEntry: InventoryItem)) => + //the swap item is to be registered to the source's zone + /* + destination is a locker container that has its own internal unique number system + the swap item is currently registered to this system + the swap item will be moved into the system in which the source operates + to facilitate the transfer, the item needs to be partially unregistered from the destination's system + to facilitate the transfer, the item needs to be preemptively registered to the source's system + invalidating the current unique number is sufficient for both of these steps + */ + val swapItem = swapEntry.obj + swapItem.Invalidate() + (List(GUIDTask.RegisterEquipment(swapItem)(source.Zone.GUID), registrationTask), Some(swapItem.GUID)) + case _ => + //too many swap items or other error; this attempt will probably fail + (Nil, None) + } + taskResolver ! TaskResolver.GiveTask( + new Task() { + val localGUID = swapItemGUID //the swap item's original GUID, if any swap item + val localChannel = toChannel + val localSource = source + val localDestination = destination + val localItem = item + val localSlot = dest + + override def Description: String = s"unregistering $localItem before stowing in $localDestination" + + override def isComplete: Task.Resolution.Value = { + if (localItem.HasGUID && localDestination.Find(localItem).contains(localSlot)) { + Task.Resolution.Success + } else { + Task.Resolution.Incomplete + } + } + + def Execute(resolver: ActorRef): Unit = { + localGUID match { + case Some(guid) => + //see LockerContainerControl.RemoveItemFromSlotCallback + val zone = localSource.Zone + zone.AvatarEvents ! AvatarServiceMessage(localChannel, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid)) + case None => ; + } + localSource.Actor ! Containable.MoveItem(localDestination, localItem, localSlot) + resolver ! Success(this) + } + }, + subtasks + ) + } + + /** + * Remove an item from a player's locker inventory. + * Failure of this process is not supported and may lead to irregular behavior. + * @see `ActorRef` + * @see `AvatarAction.ObjectDelete` + * @see `AvatarServiceMessage` + * @see `Containable.MoveItem` + * @see `Container` + * @see `Equipment` + * @see `GridInventory.CheckCollisionsVar` + * @see `GUIDTask.RegisterEquipment` + * @see `GUIDTask.UnregisterEquipment` + * @see `IdentifiableEntity.Invalidate` + * @see `LockerContainer` + * @see `Service` + * @see `Task` + * @see `TaskResolver` + * @see `TaskResolver.GiveTask` + * @see `Zone.AvatarEvents` + * @param taskResolver na + * @param toChannel broadcast channel name for a manual packet callback + * @param source the container in which the item is to be removed + * @param destination the container into which the item is to be placed + * @param item the item + * @param dest where in the destination container the item is being placed + */ + def RemoveEquipmentFromLockerContainer( + taskResolver: ActorRef, + toChannel: String, + source: PlanetSideServerObject with Container, + destination: PlanetSideServerObject with Container, + item: Equipment, + dest: Int + ): Unit = { + taskResolver ! TaskResolver.GiveTask( + new Task() { + val localGUID = item.GUID //original GUID + val localChannel = toChannel + val localSource = source + val localDestination = destination + val localItem = item + val localSlot = dest + /* + source is a locker container that has its own internal unique number system + the item is currently registered to this system + the item will be moved into the system in which the destination operates + to facilitate the transfer, the item needs to be partially unregistered from the source's system + to facilitate the transfer, the item needs to be preemptively registered to the destination's system + invalidating the current unique number is sufficient for both of these steps + */ + localItem.Invalidate() + + override def Description: String = s"registering $localItem in ${localDestination.Zone.id} before removing from $localSource" + + override def isComplete: Task.Resolution.Value = { + if (localItem.HasGUID && localDestination.Find(localItem).isEmpty) { + Task.Resolution.Success + } else { + Task.Resolution.Incomplete + } + } + + def Execute(resolver: ActorRef): Unit = { + val zone = localSource.Zone + //see LockerContainerControl.RemoveItemFromSlotCallback + zone.AvatarEvents ! AvatarServiceMessage(localChannel, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, localGUID)) + localSource.Actor ! Containable.MoveItem(localDestination, localItem, localSlot) + resolver ! Success(this) + } + }, + List(GUIDTask.RegisterEquipment(item)(destination.Zone.GUID)) + ) + } + /** * If a timeout occurs on the manipulation, declare a terminal transaction failure. * @see `AskTimeoutException` diff --git a/src/main/scala/net/psforever/objects/LocalLockerItem.scala b/src/main/scala/net/psforever/objects/LocalLockerItem.scala new file mode 100644 index 00000000..c60ba9c2 --- /dev/null +++ b/src/main/scala/net/psforever/objects/LocalLockerItem.scala @@ -0,0 +1,37 @@ +// Copyright (c) 2020 PSForever +package net.psforever.objects + +import akka.actor.ActorContext +import net.psforever.objects.serverobject.PlanetSideServerObject +import net.psforever.types.PlanetSideEmpire + +/** + * A `LocalLockerItem` is a server-side object designed to populate a fake unshared space within a shared space. + * It is a placeholder intended to block out the existence of locker objects that may or may not exist. + * All clients reserve the same internal range of user-generated GUID's from 40150 to 40449, inclusive. + * All clients recognize this same range independent of each other as "equipment in their own locker." + * The GUID's in this locker-space can be reflected onto the zone GUID. + * The item of that GUID may exist to the client. + * The item of that GUID does not formally exist to the server, but it can be searched. + * @see `Zone.MakeReservedObjects` + */ +class LocalLockerItem extends PlanetSideServerObject { + def Faction = PlanetSideEmpire.NEUTRAL + + def Definition = LocalLockerItem.local +} + +object LocalLockerItem { + import net.psforever.objects.definition.ObjectDefinition + def local = new ObjectDefinition(0) { Name = "locker-equipment" } + + /** + * Instantiate and configure a `LocalProjectile` object. + * @param id the unique id that will be assigned to this entity + * @param context a context to allow the object to properly set up `ActorSystem` functionality + * @return the `LocalProjectile` object + */ + def Constructor(id: Int, context: ActorContext): LocalLockerItem = { + new LocalLockerItem() + } +} diff --git a/src/main/scala/net/psforever/objects/avatar/Avatar.scala b/src/main/scala/net/psforever/objects/avatar/Avatar.scala index aa3cdc43..c823e4fe 100644 --- a/src/main/scala/net/psforever/objects/avatar/Avatar.scala +++ b/src/main/scala/net/psforever/objects/avatar/Avatar.scala @@ -2,8 +2,10 @@ package net.psforever.objects.avatar import net.psforever.objects.definition.{AvatarDefinition, BasicDefinition} import net.psforever.objects.equipment.{EquipmentSize, EquipmentSlot} +import net.psforever.objects.inventory.LocallyRegisteredInventory import net.psforever.objects.loadouts.{Loadout, SquadLoadout} -import net.psforever.objects.{GlobalDefinitions, LockerContainer, LockerEquipment, OffhandEquipmentSlot} +import net.psforever.objects.locker.{LockerContainer, LockerEquipment} +import net.psforever.objects.{GlobalDefinitions, OffhandEquipmentSlot} import net.psforever.types._ import org.joda.time.{Duration, LocalDateTime, Seconds} @@ -82,7 +84,11 @@ case class Avatar( loadouts: Seq[Option[Loadout]] = Seq.fill(15)(None), squadLoadouts: Seq[Option[SquadLoadout]] = Seq.fill(10)(None), implants: Seq[Option[Implant]] = Seq(None, None, None), - locker: LockerContainer = new LockerContainer(), // TODO var bad + locker: LockerContainer = new LockerContainer({ + val inv = new LocallyRegisteredInventory(numbers = 40150 until 40450) // TODO var bad + inv.Resize(30,20) + inv + }), deployables: DeployableToolbox = new DeployableToolbox(), // TODO var bad lookingForSquad: Boolean = false, var vehicle: Option[PlanetSideGUID] = None, // TODO var bad diff --git a/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala b/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala index b47f3338..0943d808 100644 --- a/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala +++ b/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala @@ -27,6 +27,8 @@ import net.psforever.services.{RemoverActor, Service} import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.local.{LocalAction, LocalServiceMessage} import akka.actor.typed +import net.psforever.objects.locker.LockerContainerControl + import scala.concurrent.duration._ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Command]) diff --git a/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala b/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala index ed3ce3a3..48bb92e3 100644 --- a/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala +++ b/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala @@ -4,7 +4,7 @@ package net.psforever.objects.definition.converter import net.psforever.objects.Player import net.psforever.objects.equipment.{Equipment, EquipmentSlot} import net.psforever.packet.game.objectcreate._ -import net.psforever.types.{ExoSuitType, GrenadeState, PlanetSideGUID} +import net.psforever.types.{ExoSuitType, GrenadeState, PlanetSideEmpire, PlanetSideGUID} import scala.annotation.tailrec import scala.util.{Success, Try} @@ -175,7 +175,9 @@ object AvatarConverter { def MakeDetailedInventoryData(obj: Player): InventoryData = { InventoryData( - (MakeHolsters(obj, BuildDetailedEquipment) ++ MakeFifthSlot(obj) ++ MakeInventory(obj)).sortBy(_.parentSlot) + (MakeHolsters(obj, BuildDetailedEquipment) ++ + MakeFifthSlot(obj) ++ + MakeInventory(obj)).sortBy(_.parentSlot) ) } @@ -222,7 +224,16 @@ object AvatarConverter { private def MakeFifthSlot(obj: Player): List[InternalSlot] = { obj.Slot(5).Equipment match { case Some(equip) => - BuildDetailedEquipment(5, equip) :: Nil + //List(BuildDetailedEquipment(5, equip)) + List(InternalSlot( + equip.Definition.ObjectId, + equip.GUID, + 5, + DetailedLockerContainerData( + CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)), + None + ) + )) case _ => Nil } diff --git a/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala b/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala index ee8a2d33..ff8e3bc4 100644 --- a/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala +++ b/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala @@ -1,9 +1,9 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.definition.converter -import net.psforever.objects.LockerEquipment import net.psforever.objects.equipment.Equipment import net.psforever.objects.inventory.GridInventory +import net.psforever.objects.locker.LockerEquipment import net.psforever.packet.game.objectcreate._ import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID} diff --git a/src/main/scala/net/psforever/objects/guid/GUIDTask.scala b/src/main/scala/net/psforever/objects/guid/GUIDTask.scala index c603714e..b8143a91 100644 --- a/src/main/scala/net/psforever/objects/guid/GUIDTask.scala +++ b/src/main/scala/net/psforever/objects/guid/GUIDTask.scala @@ -6,6 +6,7 @@ import net.psforever.objects.entity.IdentifiableEntity import net.psforever.objects.equipment.{Equipment, EquipmentSlot} import net.psforever.objects._ import net.psforever.objects.inventory.Container +import net.psforever.objects.locker.{LockerContainer, LockerEquipment} import net.psforever.objects.serverobject.turret.WeaponTurret import scala.annotation.tailrec @@ -153,7 +154,7 @@ object GUIDTask { */ def RegisterAvatar(tplayer: Player)(implicit guid: ActorRef): TaskResolver.GiveTask = { val holsterTasks = VisibleSlotTaskBuilding(tplayer.Holsters(), RegisterEquipment) - val lockerTask = List(RegisterLocker(tplayer.avatar.locker)) + val lockerTask = List(RegisterObjectTask(tplayer.avatar.locker)) val inventoryTasks = RegisterInventory(tplayer) TaskResolver.GiveTask(RegisterObjectTask(tplayer).task, holsterTasks ++ lockerTask ++ inventoryTasks) } @@ -311,7 +312,7 @@ object GUIDTask { */ def UnregisterAvatar(tplayer: Player)(implicit guid: ActorRef): TaskResolver.GiveTask = { val holsterTasks = VisibleSlotTaskBuilding(tplayer.Holsters(), UnregisterEquipment) - val lockerTask = List(UnregisterLocker(tplayer.avatar.locker)) + val lockerTask = List(UnregisterObjectTask(tplayer.avatar.locker)) val inventoryTasks = UnregisterInventory(tplayer) TaskResolver.GiveTask(UnregisterObjectTask(tplayer).task, holsterTasks ++ lockerTask ++ inventoryTasks) } @@ -368,7 +369,7 @@ object GUIDTask { * @param guid implicit reference to a unique number system * @return a list of `TaskResolver.GiveTask` messages */ - def VisibleSlotTaskBuilding(list: Iterable[EquipmentSlot], func: ((Equipment) => TaskResolver.GiveTask))(implicit + def VisibleSlotTaskBuilding(list: Iterable[EquipmentSlot], func: Equipment => TaskResolver.GiveTask)(implicit guid: ActorRef ): List[TaskResolver.GiveTask] = { recursiveVisibleSlotTaskBuilding(list.iterator, func) @@ -386,7 +387,7 @@ object GUIDTask { */ @tailrec private def recursiveVisibleSlotTaskBuilding( iter: Iterator[EquipmentSlot], - func: ((Equipment) => TaskResolver.GiveTask), + func: Equipment => TaskResolver.GiveTask, list: List[TaskResolver.GiveTask] = Nil )(implicit guid: ActorRef): List[TaskResolver.GiveTask] = { if (!iter.hasNext) { diff --git a/src/main/scala/net/psforever/objects/guid/NumberPoolHub.scala b/src/main/scala/net/psforever/objects/guid/NumberPoolHub.scala index aae4824d..fff77a2a 100644 --- a/src/main/scala/net/psforever/objects/guid/NumberPoolHub.scala +++ b/src/main/scala/net/psforever/objects/guid/NumberPoolHub.scala @@ -24,8 +24,8 @@ class NumberPoolHub(private val source: NumberSource) { import scala.collection.mutable private val hash: mutable.HashMap[String, NumberPool] = mutable.HashMap[String, NumberPool]() private val bigpool: mutable.LongMap[String] = mutable.LongMap[String]() - hash += "generic" -> new GenericPool(bigpool, source.Size) - source.FinalizeRestrictions.foreach(i => + hash += "generic" -> new GenericPool(bigpool, source.size) + source.finalizeRestrictions.foreach(i => bigpool += i.toLong -> "" ) //these numbers can never be pooled; the source can no longer restrict numbers @@ -47,7 +47,7 @@ class NumberPoolHub(private val source: NumberSource) { * @param number the unique number to attempt to retrieve from the `source` * @return the object that is assigned to the number */ - def apply(number: Int): Option[IdentifiableEntity] = source.Get(number).orElse(return None).get.Object + def apply(number: Int): Option[IdentifiableEntity] = source.get(number).orElse(return None).get.Object def Numbers: List[Int] = bigpool.keys.map(key => key.toInt).toList @@ -74,14 +74,15 @@ class NumberPoolHub(private val source: NumberSource) { if (pool.isEmpty) { throw new IllegalArgumentException(s"can not add empty pool $name") } - if (source.Size <= pool.max) { - throw new IllegalArgumentException(s"can not add pool $name - max(pool) is greater than source.size") + if (source.max < pool.max) { + throw new IllegalArgumentException(s"can not add pool $name - pool.max is greater than source.max") } - val collision = bigpool.keys.map(n => n.toInt).toSet.intersect(pool.toSet) - if (collision.nonEmpty) { - throw new IllegalArgumentException( - s"can not add pool $name - it contains the following redundant numbers: ${collision.toString}" - ) + bigpool.keys.map(n => n.toInt).toSet.intersect(pool.toSet).toSeq match { + case Nil => ; + case collisions => + throw new IllegalArgumentException( + s"can not add pool $name - it contains the following redundant numbers: ${collisions.mkString(",")}" + ) } pool.foreach(i => bigpool += i.toLong -> name) hash += name -> new ExclusivePool(pool) @@ -162,7 +163,7 @@ class NumberPoolHub(private val source: NumberSource) { def WhichPool(obj: IdentifiableEntity): Option[String] = { try { val number: Int = obj.GUID.guid - val entry = source.Get(number) + val entry = source.get(number) if (entry.isDefined && entry.get.Object.contains(obj)) { WhichPool(number) } else { None } } catch { @@ -228,7 +229,7 @@ class NumberPoolHub(private val source: NumberSource) { } private def register_GetAvailableNumberFromSource(number: Int): Try[LoanedKey] = { - source.Available(number) match { + source.getAvailable(number) match { case Some(key) => Success(key) case None => @@ -243,22 +244,21 @@ class NumberPoolHub(private val source: NumberSource) { * @return the number the was given to the object */ def register(obj: IdentifiableEntity, name: String): Try[Int] = { - try { + if (obj.HasGUID) { register_CheckNumberAgainstDesiredPool(obj, name, obj.GUID.guid) - } catch { - case _: Exception => - register_GetPool(name) match { - case Success(key) => - key.Object = obj - Success(obj.GUID.guid) - case Failure(ex) => - Failure(new Exception(s"trying to register an object but, ${ex.getMessage}")) - } + } else { + register_GetPool(name) match { + case Success(key) => + key.Object = obj + Success(obj.GUID.guid) + case Failure(ex) => + Failure(new Exception(s"trying to register an object but, ${ex.getMessage}")) + } } } private def register_CheckNumberAgainstDesiredPool(obj: IdentifiableEntity, name: String, number: Int): Try[Int] = { - val directKey = source.Get(number) + val directKey = source.get(number) if (directKey.isEmpty || !directKey.get.Object.contains(obj)) { Failure(new Exception("object already registered, but not to this source")) } else if (!WhichPool(number).contains(name)) { @@ -347,11 +347,34 @@ class NumberPoolHub(private val source: NumberSource) { case Success(pool) => val number = obj.GUID.guid pool.Return(number) - source.Return(number) + source.returnNumber(number) obj.Invalidate() Success(number) case Failure(ex) => - Failure(new Exception(s"can not unregister this object: ${ex.getMessage}")) + unregister_GetMonitorFromObject(obj, ex.getMessage) + } + } + + /** + * Unregister a specific object + * by actually finding the object itself, if it exists. + * @param obj an object being unregistered + * @param msg custom error message; + * has a vague default + * @return the number associated with this object + */ + def unregister_GetMonitorFromObject( + obj: IdentifiableEntity, + msg: String = "can not find this object" + ): Try[Int] = { + source.get(obj) match { + case Some(key) => + val number = key.GUID + GetPool(WhichPool(number).get).get.Return(number) + source.returnNumber(number) + Success(number) + case _ => + Failure(new Exception(s"can not unregister this $obj - $msg")) } } @@ -360,7 +383,7 @@ class NumberPoolHub(private val source: NumberSource) { case Some(name) => unregister_GetPool(name) case None => - Failure(throw new Exception("can not find a pool for this object")) + Failure(new Exception(s"can not find a pool for this $obj")) } } @@ -379,7 +402,7 @@ class NumberPoolHub(private val source: NumberSource) { * @return the object, if any, previous associated with the number */ def unregister(number: Int): Try[Option[IdentifiableEntity]] = { - if (source.Test(number)) { + if (source.test(number)) { unregister_GetObjectFromSource(number) } else { Failure(new Exception(s"can not unregister a number $number that this source does not own")) @@ -387,7 +410,7 @@ class NumberPoolHub(private val source: NumberSource) { } private def unregister_GetObjectFromSource(number: Int): Try[Option[IdentifiableEntity]] = { - source.Return(number) match { + source.returnNumber(number) match { case Some(obj) => unregister_ReturnObjectToPool(obj) case None => @@ -403,7 +426,7 @@ class NumberPoolHub(private val source: NumberSource) { obj.Invalidate() Success(Some(obj)) case Failure(ex) => - source.Available(number) //undo + source.getAvailable(number) //undo Failure(new Exception(s"started unregistering, but ${ex.getMessage}")) } } @@ -432,11 +455,11 @@ class NumberPoolHub(private val source: NumberSource) { } /** - * For accessing the `Return` function of the contained `NumberSource` directly. + * For accessing the `returnNumber` function of the contained `NumberSource` directly. * @param number the number to return. * @return any object previously using this number */ - def latterPartUnregister(number: Int): Option[IdentifiableEntity] = source.Return(number) + def latterPartUnregister(number: Int): Option[IdentifiableEntity] = source.returnNumber(number) /** * Determines if the object is registered.
@@ -451,7 +474,7 @@ class NumberPoolHub(private val source: NumberSource) { */ def isRegistered(obj: IdentifiableEntity): Boolean = { try { - source.Get(obj.GUID.guid) match { + source.get(obj.GUID.guid) match { case Some(monitor) => monitor.Object.contains(obj) case None => @@ -474,7 +497,7 @@ class NumberPoolHub(private val source: NumberSource) { * @see `isRegistered(IdentifiableEntity)` */ def isRegistered(number: Int): Boolean = { - source.Get(number) match { + source.get(number) match { case Some(monitor) => monitor.Policy == AvailabilityPolicy.Leased case None => diff --git a/src/main/scala/net/psforever/objects/guid/actor/NumberPoolActor.scala b/src/main/scala/net/psforever/objects/guid/actor/NumberPoolActor.scala index e1f3182a..0f759226 100644 --- a/src/main/scala/net/psforever/objects/guid/actor/NumberPoolActor.scala +++ b/src/main/scala/net/psforever/objects/guid/actor/NumberPoolActor.scala @@ -73,7 +73,7 @@ object NumberPoolActor { final case class NoNumber(ex: Throwable, id: Option[Any] = None) /** - * A message to invoke the `Return` functionality of the current `NumberSelector`. + * A message to invoke the `returnNumber` functionality of the current `NumberSelector`. * @param number the number */ final case class ReturnNumber(number: Int, id: Option[Any] = None) diff --git a/src/main/scala/net/psforever/objects/guid/key/LoanedKey.scala b/src/main/scala/net/psforever/objects/guid/key/LoanedKey.scala index 96a1f582..7af04d9c 100644 --- a/src/main/scala/net/psforever/objects/guid/key/LoanedKey.scala +++ b/src/main/scala/net/psforever/objects/guid/key/LoanedKey.scala @@ -12,9 +12,9 @@ import net.psforever.objects.guid.AvailabilityPolicy class LoanedKey(private val guid: Int, private val key: Monitor) { def GUID: Int = guid - def Policy: AvailabilityPolicy.Value = key.Policy + def Policy: AvailabilityPolicy.Value = key.policy - def Object: Option[IdentifiableEntity] = key.Object + def Object: Option[IdentifiableEntity] = key.obj /** * na @@ -30,18 +30,18 @@ class LoanedKey(private val guid: Int, private val key: Monitor) { */ def Object_=(obj: Option[IdentifiableEntity]): Option[IdentifiableEntity] = { if ( - key.Policy == AvailabilityPolicy.Leased || (key.Policy == AvailabilityPolicy.Restricted && key.Object.isEmpty) + key.policy == AvailabilityPolicy.Leased || (key.policy == AvailabilityPolicy.Restricted && key.obj.isEmpty) ) { - if (key.Object.isDefined) { - key.Object.get.Invalidate() - key.Object = None + if (key.obj.isDefined) { + key.obj.get.Invalidate() + key.obj = None } - key.Object = obj + key.obj = obj if (obj.isDefined) { import net.psforever.types.PlanetSideGUID obj.get.GUID = PlanetSideGUID(guid) } } - key.Object + key.obj } } diff --git a/src/main/scala/net/psforever/objects/guid/key/Monitor.scala b/src/main/scala/net/psforever/objects/guid/key/Monitor.scala index bf232857..e7cc1506 100644 --- a/src/main/scala/net/psforever/objects/guid/key/Monitor.scala +++ b/src/main/scala/net/psforever/objects/guid/key/Monitor.scala @@ -5,9 +5,7 @@ import net.psforever.objects.entity.IdentifiableEntity import net.psforever.objects.guid.AvailabilityPolicy trait Monitor { - def Policy: AvailabilityPolicy.Value + var policy: AvailabilityPolicy.Value - def Object: Option[IdentifiableEntity] - - def Object_=(objct: Option[IdentifiableEntity]): Option[IdentifiableEntity] + var obj: Option[IdentifiableEntity] } diff --git a/src/main/scala/net/psforever/objects/guid/key/SecureKey.scala b/src/main/scala/net/psforever/objects/guid/key/SecureKey.scala index e3aecf7d..8c333e2e 100644 --- a/src/main/scala/net/psforever/objects/guid/key/SecureKey.scala +++ b/src/main/scala/net/psforever/objects/guid/key/SecureKey.scala @@ -11,8 +11,8 @@ import net.psforever.objects.guid.AvailabilityPolicy final class SecureKey(private val guid: Int, private val key: Monitor) { def GUID: Int = guid - def Policy: AvailabilityPolicy.Value = key.Policy + def Policy: AvailabilityPolicy.Value = key.policy import net.psforever.objects.entity.IdentifiableEntity - def Object: Option[IdentifiableEntity] = key.Object + def Object: Option[IdentifiableEntity] = key.obj } diff --git a/src/main/scala/net/psforever/objects/guid/selector/NumberSelector.scala b/src/main/scala/net/psforever/objects/guid/selector/NumberSelector.scala index 8c75d2f5..2d116113 100644 --- a/src/main/scala/net/psforever/objects/guid/selector/NumberSelector.scala +++ b/src/main/scala/net/psforever/objects/guid/selector/NumberSelector.scala @@ -46,7 +46,7 @@ abstract class NumberSelector { * By default, a simple policy for returning numbers has been provided. * This will not be sufficient for all selection actions that can be implemented so `override` where necessary. *
- * `Return` is under no obligation to leave its parameter `Array` unmodified. + * `returnNumber` is under no obligation to leave its parameter `Array` unmodified. * In fact, it should modify it by default to provide additional feedback of its process. * Pass a copy if data mutation is a concern. * @param number the number to be returned diff --git a/src/main/scala/net/psforever/objects/guid/source/Key.scala b/src/main/scala/net/psforever/objects/guid/source/Key.scala index 97ac04b1..ae6be828 100644 --- a/src/main/scala/net/psforever/objects/guid/source/Key.scala +++ b/src/main/scala/net/psforever/objects/guid/source/Key.scala @@ -6,20 +6,7 @@ import net.psforever.objects.guid.AvailabilityPolicy import net.psforever.objects.guid.key.Monitor private class Key extends Monitor { - private var policy: AvailabilityPolicy.Value = AvailabilityPolicy.Available - private var obj: Option[IdentifiableEntity] = None + var policy: AvailabilityPolicy.Value = AvailabilityPolicy.Available - def Policy: AvailabilityPolicy.Value = policy - - def Policy_=(pol: AvailabilityPolicy.Value): AvailabilityPolicy.Value = { - policy = pol - Policy - } - - def Object: Option[IdentifiableEntity] = obj - - def Object_=(objct: Option[IdentifiableEntity]): Option[IdentifiableEntity] = { - obj = objct - Object - } + var obj: Option[IdentifiableEntity] = None } diff --git a/src/main/scala/net/psforever/objects/guid/source/LimitedNumberSource.scala b/src/main/scala/net/psforever/objects/guid/source/LimitedNumberSource.scala deleted file mode 100644 index 197ac17d..00000000 --- a/src/main/scala/net/psforever/objects/guid/source/LimitedNumberSource.scala +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.objects.guid.source - -import net.psforever.objects.entity.IdentifiableEntity -import net.psforever.objects.guid.key.{LoanedKey, SecureKey} -import net.psforever.objects.guid.AvailabilityPolicy - -import scala.collection.mutable - -/** - * A `NumberSource` is considered a master "pool" of numbers from which all numbers are available to be drawn. - * The numbers are considered to be exclusive.
- *
- * Produce a series of numbers from 0 to a maximum number (inclusive) to be used as globally unique identifiers (GUIDs). - * @param max the highest number to be generated by this source; - * must be a positive integer or zero - * @throws IllegalArgumentException if `max` is less than zero (therefore the count of generated numbers is at most zero) - * @throws java.lang.NegativeArraySizeException if the count of numbers generated due to max is negative - */ -class LimitedNumberSource(max: Int) extends NumberSource { - if (max < 0) { - throw new IllegalArgumentException(s"non-negative integers only, not $max") - } - private val ary: Array[Key] = Array.ofDim[Key](max + 1) - (0 to max).foreach(x => { ary(x) = new Key }) - private var allowRestrictions: Boolean = true - - def Size: Int = ary.length - - def CountAvailable: Int = ary.count(key => key.Policy == AvailabilityPolicy.Available) - - def CountUsed: Int = ary.count(key => key.Policy != AvailabilityPolicy.Available) - - def Get(number: Int): Option[SecureKey] = { - if (Test(number)) { - Some(new SecureKey(number, ary(number))) - } else { - None - } - } - - def Available(number: Int): Option[LoanedKey] = { - var out: Option[LoanedKey] = None - if (Test(number)) { - val key: Key = ary(number) - if (key.Policy == AvailabilityPolicy.Available) { - key.Policy = AvailabilityPolicy.Leased - out = Some(new LoanedKey(number, key)) - } - } - out - } - - /** - * Consume the number of a `Monitor` and release that number from its previous assignment/use. - * @param number the number - * @return any object previously using this number - */ - def Return(number: Int): Option[IdentifiableEntity] = { - var out: Option[IdentifiableEntity] = None - if (Test(number)) { - val existing: Key = ary(number) - if (existing.Policy == AvailabilityPolicy.Leased) { - out = existing.Object - existing.Policy = AvailabilityPolicy.Available - existing.Object = None - } - } - out - } - - /** - * Produce a modifiable wrapper for the `Monitor` for this number, only if the number has not been used. - * This wrapped `Monitor` can only be assigned once and the number may not be `Return`ed to this source. - * @param number the number - * @return the wrapped `Monitor` - * @throws ArrayIndexOutOfBoundsException if the requested number is above or below the range - */ - def Restrict(number: Int): Option[LoanedKey] = { - if (allowRestrictions && Test(number)) { - val key: Key = ary(number) - key.Policy = AvailabilityPolicy.Restricted - Some(new LoanedKey(number, key)) - } else { - None - } - } - - def FinalizeRestrictions: List[Int] = { - allowRestrictions = false - ary.zipWithIndex.filter(entry => entry._1.Policy == AvailabilityPolicy.Restricted).map(entry => entry._2).toList - } - - def Clear(): List[IdentifiableEntity] = { - val outList: mutable.ListBuffer[IdentifiableEntity] = mutable.ListBuffer[IdentifiableEntity]() - for (x <- ary.indices) { - ary(x).Policy = AvailabilityPolicy.Available - if (ary(x).Object.isDefined) { - outList += ary(x).Object.get - ary(x).Object = None - } - } - outList.toList - } -} - -object LimitedNumberSource { - def apply(max: Int): LimitedNumberSource = { - new LimitedNumberSource(max) - } -} diff --git a/src/main/scala/net/psforever/objects/guid/source/MaxNumberSource.scala b/src/main/scala/net/psforever/objects/guid/source/MaxNumberSource.scala new file mode 100644 index 00000000..222c942d --- /dev/null +++ b/src/main/scala/net/psforever/objects/guid/source/MaxNumberSource.scala @@ -0,0 +1,121 @@ +// Copyright (c) 2017 PSForever +package net.psforever.objects.guid.source + +import net.psforever.objects.entity.IdentifiableEntity +import net.psforever.objects.guid.key.{LoanedKey, SecureKey} +import net.psforever.objects.guid.AvailabilityPolicy + +/** + * A `NumberSource` is considered a master "pool" of numbers from which all numbers are available to be drawn. + * Produce a series of numbers from 0 to a maximum number (inclusive) to be used as globally unique identifiers (GUID's). + * @param max the highest number to be generated by this source; + * must be a positive integer or zero + * @throws IllegalArgumentException if `max` is less than zero (therefore the count of generated numbers is at most zero) + */ +class MaxNumberSource(val max: Int) extends NumberSource { + if (max < 0) { + throw new IllegalArgumentException(s"non-negative integers only, not $max") + } + private val ary: Array[Key] = Array.ofDim[Key](max + 1) + (0 to max).foreach(x => { ary(x) = new Key }) + private var allowRestrictions: Boolean = true + + def size: Int = ary.length + + def countAvailable: Int = ary.count(key => key.policy == AvailabilityPolicy.Available) + + def countUsed: Int = ary.count(_.policy != AvailabilityPolicy.Available) + + def test(number: Int): Boolean = -1 < number && number < size + + def get(number: Int): Option[SecureKey] = { + if (test(number)) { + Some(new SecureKey(number, ary(number))) + } else { + None + } + } + + def get(obj: IdentifiableEntity) : Option[SecureKey] = { + ary.zipWithIndex.find { case (key, _) => + key.obj match { + case Some(o) => o eq obj + case _ => false + } + } match { + case Some((key, number)) => Some(new SecureKey(number, key)) + case _=> None + } + } + + def getAvailable(number: Int): Option[LoanedKey] = { + var out: Option[LoanedKey] = None + if (test(number)) { + val key: Key = ary(number) + if (key.policy == AvailabilityPolicy.Available) { + key.policy = AvailabilityPolicy.Leased + out = Some(new LoanedKey(number, key)) + } + } + out + } + + /** + * Consume the number of a `Monitor` and release that number from its previous assignment/use. + * @param number the number + * @return any object previously using this number + */ + def returnNumber(number: Int): Option[IdentifiableEntity] = { + var out: Option[IdentifiableEntity] = None + if (test(number)) { + val existing: Key = ary(number) + if (existing.policy == AvailabilityPolicy.Leased) { + out = existing.obj + existing.policy = AvailabilityPolicy.Available + existing.obj = None + } + } + out + } + + /** + * Produce a modifiable wrapper for the `Monitor` for this number, only if the number has not been used. + * This wrapped `Monitor` can only be assigned once and the number may not be `returnNumber`ed to this source. + * @param number the number + * @return the wrapped `Monitor` + * @throws ArrayIndexOutOfBoundsException if the requested number is above or below the range + */ + def restrictNumber(number: Int): Option[LoanedKey] = { + ary.lift(number) match { + case Some(key: Key) if allowRestrictions && key.policy != AvailabilityPolicy.Restricted => + key.policy = AvailabilityPolicy.Restricted + Some(new LoanedKey(number, key)) + case None => + None + } + } + + def finalizeRestrictions: List[Int] = { + allowRestrictions = false + ary.zipWithIndex.filter(entry => entry._1.policy == AvailabilityPolicy.Restricted).map(entry => entry._2).toList + } + + def clear(): List[IdentifiableEntity] = { + val leased = ary.filter(_.policy != AvailabilityPolicy.Available) + leased collect { case key if key.obj.isEmpty => + key.policy = AvailabilityPolicy.Available + } + leased.toList collect { case key if key.obj.nonEmpty => + key.policy = AvailabilityPolicy.Available + val out = key.obj.get + key.obj = None + out + } + } +} + +object MaxNumberSource { + def apply(max: Int): MaxNumberSource = { + new MaxNumberSource(max) + } +} diff --git a/src/main/scala/net/psforever/objects/guid/source/NumberSource.scala b/src/main/scala/net/psforever/objects/guid/source/NumberSource.scala index 4c37a6e5..d2e342da 100644 --- a/src/main/scala/net/psforever/objects/guid/source/NumberSource.scala +++ b/src/main/scala/net/psforever/objects/guid/source/NumberSource.scala @@ -18,42 +18,51 @@ import net.psforever.objects.guid.key.{LoanedKey, SecureKey} * The purpose of a `NumberSource` is to help facilitate globally unique identifiers (GUID, pl. GUIDs). */ trait NumberSource { + /** + * The maximum number that can be produced by this source. + * @return the max + */ + def max: Int /** * The count of numbers allocated to this source. * @return the count */ - def Size: Int + def size: Int /** * The count of numbers that can still be drawn. * @return the count */ - def CountAvailable: Int + def countAvailable: Int /** * The count of numbers that can not be drawn. * @return the count */ - def CountUsed: Int + def countUsed: Int /** * Is this number a member of this number source? * @param number the number * @return `true`, if it is a member; `false`, otherwise */ - def Test(number: Int): Boolean = -1 < number && number < Size + def test(number: Int): Boolean /** * Produce an un-modifiable wrapper for the `Monitor` for this number. * @param number the number * @return the wrapped `Monitor` */ - def Get(number: Int): Option[SecureKey] + def get(number: Int): Option[SecureKey] - //def GetAll(list : List[Int]) : List[SecureKey] - - //def GetAll(p : Key => Boolean) : List[SecureKey] + /** + * Produce an un-modifiable wrapper for the `Monitor` for this entity, + * if the entity is discovered being represented in this source. + * @param obj the entity + * @return the wrapped `Monitor` + */ + def get(obj: IdentifiableEntity) : Option[SecureKey] /** * Produce a modifiable wrapper for the `Monitor` for this number, only if the number has not been used. @@ -61,15 +70,15 @@ trait NumberSource { * @param number the number * @return the wrapped `Monitor`, or `None` */ - def Available(number: Int): Option[LoanedKey] + def getAvailable(number: Int): Option[LoanedKey] /** * Consume a wrapped `Monitor` and release its number from its previous assignment/use. * @param monitor the `Monitor` * @return any object previously using this `Monitor` */ - def Return(monitor: SecureKey): Option[IdentifiableEntity] = { - Return(monitor.GUID) + def returnNumber(monitor: SecureKey): Option[IdentifiableEntity] = { + returnNumber(monitor.GUID) } /** @@ -77,8 +86,8 @@ trait NumberSource { * @param monitor the `Monitor` * @return any object previously using this `Monitor` */ - def Return(monitor: LoanedKey): Option[IdentifiableEntity] = { - Return(monitor.GUID) + def returnNumber(monitor: LoanedKey): Option[IdentifiableEntity] = { + returnNumber(monitor.GUID) } /** @@ -86,21 +95,21 @@ trait NumberSource { * @param number the number * @return any object previously using this number */ - def Return(number: Int): Option[IdentifiableEntity] + def returnNumber(number: Int): Option[IdentifiableEntity] /** * Produce a modifiable wrapper for the `Monitor` for this number, only if the number has not been used. - * This wrapped `Monitor` can only be assigned once and the number may not be `Return`ed to this source. + * This wrapped `Monitor` can only be assigned once and the number may not be `returnNumber`ed to this source. * @param number the number * @return the wrapped `Monitor` */ - def Restrict(number: Int): Option[LoanedKey] + def restrictNumber(number: Int): Option[LoanedKey] /** * Numbers from this source may not longer be marked as `Restricted`. * @return the `List` of all numbers that have been restricted */ - def FinalizeRestrictions: List[Int] + def finalizeRestrictions: List[Int] import net.psforever.objects.entity.IdentifiableEntity @@ -110,5 +119,5 @@ trait NumberSource { * This is the only way to free `Monitors` that are marked as `Restricted`. * @return a `List` of assignments maintained by all the currently-used number `Monitors` */ - def Clear(): List[IdentifiableEntity] + def clear(): List[IdentifiableEntity] } diff --git a/src/main/scala/net/psforever/objects/guid/source/SpecificNumberSource.scala b/src/main/scala/net/psforever/objects/guid/source/SpecificNumberSource.scala new file mode 100644 index 00000000..c0284b27 --- /dev/null +++ b/src/main/scala/net/psforever/objects/guid/source/SpecificNumberSource.scala @@ -0,0 +1,112 @@ +// Copyright (c) 2020 PSForever +package net.psforever.objects.guid.source + +import net.psforever.objects.entity.IdentifiableEntity +import net.psforever.objects.guid.AvailabilityPolicy +import net.psforever.objects.guid.key.{LoanedKey, SecureKey} + +/** + * A `NumberSource` is considered a master "pool" of numbers from which all numbers are available to be drawn. + * Produce a series of numbers from 0 to a maximum number (inclusive) to be used as globally unique identifiers (GUID's). + * @param values the domain of numbers to be used by this source; + * must only be positive integers or zero + * @throws IllegalArgumentException if no numbers are provided + * @throws IllegalArgumentException if any of the numbers provided are negative + */ +class SpecificNumberSource(values: Iterable[Int]) extends NumberSource { + if (values.isEmpty) { + throw new IllegalArgumentException(s"must provide one or more positive integers (or zero)") + } + values.filter(_ < 0) match { + case Nil => ; + case list => throw new IllegalArgumentException(s"non-negative integers only, not ${list.mkString(" ")}") + } + private val ary : Map[Int, Key] = values.map(index => (index, new Key)).toMap + + def max : Int = ary.keys.max + + def size : Int = ary.size + + def countAvailable : Int = ary.values.count(key => key.policy == AvailabilityPolicy.Available) + + def countUsed : Int = ary.values.count(_.policy != AvailabilityPolicy.Available) + + def test(number : Int) : Boolean = ary.get(number).nonEmpty + + def get(number : Int) : Option[SecureKey] = { + ary.get(number) match { + case Some(key) => Some(new SecureKey(number, key)) + case _ => None + } + } + + def get(obj : IdentifiableEntity) : Option[SecureKey] = { + ary.find { case (_, key) => + key.obj match { + case Some(o) => o eq obj + case _ => false + } + } match { + case Some((number, key)) => Some(new SecureKey(number, key)) + case _ => None + } + } + + def getAvailable(number : Int) : Option[LoanedKey] = { + ary.get(number) match { + case Some(key) if key.policy == AvailabilityPolicy.Available => + key.policy = AvailabilityPolicy.Leased + Some(new LoanedKey(number, key)) + case _ => + None + } + } + + def returnNumber(number : Int) : Option[IdentifiableEntity] = { + ary.get(number) match { + case Some(key) if key.policy == AvailabilityPolicy.Leased => + val out = key.obj + key.policy = AvailabilityPolicy.Available + key.obj = None + out + case _ => + None + } + } + + def restrictNumber(number : Int) : Option[LoanedKey] = { + ary.get(number) match { + case Some(key) if key.policy != AvailabilityPolicy.Restricted => + key.policy = AvailabilityPolicy.Restricted + Some(new LoanedKey(number, key)) + case _ => + None + } + } + + def finalizeRestrictions : List[Int] = { + ary + .filter { case (_, key : Key) => key.policy == AvailabilityPolicy.Restricted } + .keys + .toList + } + + def clear(): List[IdentifiableEntity] = { + val leased = ary.values.filter(_.policy != AvailabilityPolicy.Available) + leased collect { case key if key.obj.isEmpty => + key.policy = AvailabilityPolicy.Available + } + leased.toList collect { case key if key.obj.nonEmpty => + key.policy = AvailabilityPolicy.Available + val out = key.obj.get + key.obj = None + out + } + } +} + +object SpecificNumberSource { + def apply(values: Iterable[Int]): SpecificNumberSource = { + new SpecificNumberSource(values) + } +} diff --git a/src/main/scala/net/psforever/objects/inventory/Container.scala b/src/main/scala/net/psforever/objects/inventory/Container.scala index 16700c27..1dacfdeb 100644 --- a/src/main/scala/net/psforever/objects/inventory/Container.scala +++ b/src/main/scala/net/psforever/objects/inventory/Container.scala @@ -98,94 +98,3 @@ trait Container { def Collisions(index: Int, width: Int, height: Int): Try[List[InventoryItem]] = Inventory.CheckCollisionsVar(index, width, height) } - -//object Container { -// type ValidContainer = PlanetSideServerObject with Container -// -// final case class GetMoveItem(where_src : Int, other : ValidContainer, where_other : Int, other_item : Option[Equipment]) -// -// final case class GiveMoveItem(cont1 : ValidContainer, where_cont1 : Int, item : Option[Equipment], cont2 : ValidContainer, where_cont2 : Int, other_item : Option[Equipment]) -// -// -// final case class TakeMoveItem(source_index : Int, destination : ValidContainer, destination_index : Int) -// -// final case class TakeMoveItem2(item_guid : PlanetSideGUID, destination : ValidContainer, destination_index : Int) -// -// final case class GivingMoveItem(item : Equipment, source : ValidContainer, source_index : Int, destination : ValidContainer, destination_index : Int) -// -// final case class PutMoveItem(item : Equipment, target_index : Int, source : ValidContainer, source_index : Int) -// -// final case class DropMoveItem(item : Equipment, source : ValidContainer, source_index : Int) -// -// final case class ItemMoved(item : Equipment, location : ValidContainer, location_index : Int) -// -// final case class NoMoveItem(source : ValidContainer, source_index : Int) -//} -// -//trait ContainerBehavior { -// this : Actor => -// -// def ContainableObject : Container.ValidContainer -// -// val containerBehavior : Receive = { -// case Container.GetMoveItem(where_src, destination, where_dest, other_item) => -// val slot : EquipmentSlot = ContainableObject.Slot(where_src) -// val equipment = slot.Equipment -// slot.Equipment = None -// sender ! Container.GiveMoveItem(ContainableObject, where_src, equipment, destination, where_dest, other_item) -// -// case Container.TakeMoveItem(source_index, destination, destination_index) => -// val slot : EquipmentSlot = ContainableObject.Slot(source_index) -// val equipment : Option[Equipment] = slot.Equipment -// slot.Equipment = None -// sender ! (equipment match { -// case Some(item) => -// Container.GivingMoveItem(item, ContainableObject, source_index, destination, destination_index) -// case None => -// Container.NoMoveItem(ContainableObject, source_index) -// }) -// -// case Container.TakeMoveItem2(item_guid, destination, destination_index) => -// ContainableObject.Find(item_guid) match { -// case Some(source_index) => -// val slot : EquipmentSlot = ContainableObject.Slot(source_index) -// val equipment : Option[Equipment] = slot.Equipment -// slot.Equipment = None -// sender ! (equipment match { -// case Some(item) => -// Container.GivingMoveItem(item, ContainableObject, source_index, destination, destination_index) -// case None => ; -// }) -// -// case None => -// sender ! Container.NoMoveItem(ContainableObject, 65535) -// } -// -// case Container.PutMoveItem(item, target_index, source, source_index) => -// val slot : EquipmentSlot = ContainableObject.Slot(target_index) -// val equipment : Option[Equipment] = slot.Equipment -// if( { -// val tile = item.Definition.Tile -// ContainableObject.Collisions(target_index, tile.Width, tile.Height) match { -// case Success(Nil) => //no item swap -// true -// case Success(_ :: Nil) => //one item to swap -// true -// case Success(_) | Failure(_) => -// false //abort when too many items at destination or other failure case -// } -// }) { -// slot.Equipment = None -// slot.Equipment = item -// equipment match { -// case Some(swapItem) => -// sender ! Container.GivingMoveItem(swapItem, ContainableObject, target_index, source, source_index) -// case None => ; -// } -// sender ! Container.ItemMoved(item, ContainableObject, target_index) -// } -// else { -// sender ! Container.DropMoveItem(item, source, source_index) -// } -// } -//} diff --git a/src/main/scala/net/psforever/objects/inventory/GridInventory.scala b/src/main/scala/net/psforever/objects/inventory/GridInventory.scala index e8ad215f..e9ac30ea 100644 --- a/src/main/scala/net/psforever/objects/inventory/GridInventory.scala +++ b/src/main/scala/net/psforever/objects/inventory/GridInventory.scala @@ -191,8 +191,7 @@ class GridInventory extends Container { } else { val collisions: mutable.Set[InventoryItem] = mutable.Set[InventoryItem]() items - .map { case (_, item: InventoryItem) => item } - .foreach { item: InventoryItem => + .foreach { case (_, item: InventoryItem) => val actualItemStart: Int = item.start - offset val itemx: Int = actualItemStart % width val itemy: Int = actualItemStart / width @@ -542,8 +541,8 @@ class GridInventory extends Container { //lists with multiple entries represent a group of items that collide //perform a specific distinct on the list of lists of numeric id overlaps //THEN map each list of list's item id to an item - val out = testGrid.collect { - case (_, list) if list.size > 1 => list.sortWith(_ < _) + val out = testGrid.values.collect { + case list if list.size > 1 => list.sortWith(_ < _) } recursiveRelatedListCollisions(out.iterator, out.toList).map { list => list.map { items } } } diff --git a/src/main/scala/net/psforever/objects/inventory/LocallyRegisteredInventory.scala b/src/main/scala/net/psforever/objects/inventory/LocallyRegisteredInventory.scala new file mode 100644 index 00000000..452b8c63 --- /dev/null +++ b/src/main/scala/net/psforever/objects/inventory/LocallyRegisteredInventory.scala @@ -0,0 +1,132 @@ +// Copyright (c) 2020 PSForever +package net.psforever.objects.inventory + +import net.psforever.objects.Tool +import net.psforever.objects.equipment.Equipment +import net.psforever.objects.guid.NumberPoolHub +import net.psforever.objects.guid.selector.RandomSelector +import net.psforever.objects.guid.source.SpecificNumberSource +import net.psforever.types.PlanetSideGUID + +import scala.util.{Failure, Success} + +/** + * An inventory that contains its own internal unique number system bound by a domain of numbers. + * When equipment is inserted into this inventory, + * the equipment is registered to it, assigned one of its internal unique numbers. + * The equipment must not already be registered to another unique number system for that reason. + * Upon being removed, the removed equipment is unregistered. + * The registration system adds another unspoken layer to `Capacity` + * as it imposes a total object count to the inventory. + * @see `NumberSourceHub` + * @see `RandomSelector` + * @see `SpecificNumberSource` + * @param numbers the numbers used as unique identifiers + */ +class LocallyRegisteredInventory(numbers: Iterable[Int]) + extends GridInventory { + private val hub: NumberPoolHub = { + val numHub = new NumberPoolHub(SpecificNumberSource(numbers)) + //only one pool composed of all of the numbers; randomized selection + numHub.AddPool("internal", numbers.toList).Selector = new RandomSelector + numHub + } + + override def Insert(start : Int, obj : Equipment) : Boolean = { + if(!obj.HasGUID) { + registerEquipment(obj) match { + case true if super.Insert(start, obj) => + true + case true => + unregisterEquipment(obj) //the item failed to be inserted; undo the previous registration + false + case _ => + false + } + } + else { + false + } + } + + override def InsertQuickly(start : Int, obj : Equipment) : Boolean = { + if(!obj.HasGUID) { + registerEquipment(obj) match { + case true if super.InsertQuickly(start, obj) => + true + case true => + unregisterEquipment(obj) //the item failed to be inserted; undo the previous registration + false + case _ => + false + } + } + else { + false + } + } + + override def Remove(guid : PlanetSideGUID) : Boolean = { + hub(guid) match { + case Some(obj: Equipment) if super.Remove(guid) => + unregisterEquipment(obj) + case _ => + false + } + } + + override def Remove(index : Int) : Boolean = { + Slot(index).Equipment match { + case Some(obj: Equipment) if super.Remove(obj.GUID) => + unregisterEquipment(obj) + case _ => + false + } + } + + override def Clear() : List[InventoryItem] = { + val items = super.Clear() + items.foreach { item => unregisterEquipment(item.obj) } + items + } + + private def registerEquipment(obj: Equipment): Boolean = { + obj match { + case tool: Tool => registerTool(tool) + case _ => registerObject(obj) + } + } + + private def registerTool(obj: Tool): Boolean = { + val parts = obj +: obj.AmmoSlots.map { _.Box } + val tasks = parts.map { part => hub.register(part, "internal") } + if(tasks.exists(o => o.isInstanceOf[Failure[Int]])) { + tasks.zipWithIndex.collect { case (Success(_), index) => + unregisterEquipment(parts(index)) + } + false + } else { + true + } + } + + private def registerObject(obj: Equipment): Boolean = { + hub.register(obj, "internal").isSuccess + } + + private def unregisterEquipment(obj: Equipment): Boolean = { + obj match { + case tool: Tool => unregisterTool(tool) + case _ => unregisterObject(obj) + } + } + + private def unregisterTool(obj: Tool): Boolean = { + val parts = obj +: obj.AmmoSlots.map { _.Box } + parts.map { part => hub.unregister(part) }.forall(o => o.isInstanceOf[Success[Int]]) + } + + private def unregisterObject(obj: Equipment): Boolean = { + hub.unregister(obj).isSuccess + } +} diff --git a/src/main/scala/net/psforever/objects/locker/LockerContainer.scala b/src/main/scala/net/psforever/objects/locker/LockerContainer.scala new file mode 100644 index 00000000..ae40858a --- /dev/null +++ b/src/main/scala/net/psforever/objects/locker/LockerContainer.scala @@ -0,0 +1,44 @@ +// Copyright (c) 2017 PSForever +package net.psforever.objects.locker + +import net.psforever.objects.GlobalDefinitions +import net.psforever.objects.definition.EquipmentDefinition +import net.psforever.objects.inventory.{Container, GridInventory} +import net.psforever.objects.serverobject.PlanetSideServerObject +import net.psforever.types.PlanetSideEmpire + +/** + * The companion of a `Locker` that is carried with a player + * masquerading as their sixth `EquipmentSlot` object and a sub-inventory item. + * The inventory of this object is accessed indirectly using a game world `Locker` object (`mb_locker`) as a proxy. + * The `Player` class refers to it as the "fifth slot". + */ +class LockerContainer(inventory: GridInventory) + extends PlanetSideServerObject + with Container { + private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL + private val inv: GridInventory = inventory + + def Faction: PlanetSideEmpire.Value = faction + + override def Faction_=(fact: PlanetSideEmpire.Value): PlanetSideEmpire.Value = { + faction = fact + Faction + } + + def Inventory: GridInventory = inv + + def VisibleSlots: Set[Int] = Set.empty[Int] + + def Definition: EquipmentDefinition = GlobalDefinitions.locker_container +} + +object LockerContainer { + /** + * Overloaded constructor for the standard Infantry locker container of size 30x20. + * @return a `LockerContainer` object + */ + def apply(): LockerContainer = { + new LockerContainer(GridInventory(30, 20)) + } +} diff --git a/src/main/scala/net/psforever/objects/LockerContainer.scala b/src/main/scala/net/psforever/objects/locker/LockerContainerControl.scala similarity index 54% rename from src/main/scala/net/psforever/objects/LockerContainer.scala rename to src/main/scala/net/psforever/objects/locker/LockerContainerControl.scala index c3652596..c3a5c187 100644 --- a/src/main/scala/net/psforever/objects/LockerContainer.scala +++ b/src/main/scala/net/psforever/objects/locker/LockerContainerControl.scala @@ -1,69 +1,24 @@ -// Copyright (c) 2017 PSForever -package net.psforever.objects +// Copyright (c) 2020 PSForever +package net.psforever.objects.locker import akka.actor.Actor -import net.psforever.objects.definition.EquipmentDefinition import net.psforever.objects.equipment.Equipment -import net.psforever.objects.inventory.{Container, GridInventory} -import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.containable.{Containable, ContainableBehavior} -import net.psforever.packet.game.{ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectDetachMessage} import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent -import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3} +import net.psforever.packet.game.{ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectDetachMessage} import net.psforever.services.Service import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} +import net.psforever.types.{PlanetSideEmpire, Vector3} /** - * The companion of a `Locker` that is carried with a player - * masquerading as their sixth `EquipmentSlot` object and a sub-inventory item. - * The `Player` class refers to it as the "fifth slot" as its permanent slot number is encoded as `0x85`. - * The inventory of this object is accessed using a game world `Locker` object (`mb_locker`). + * A control agency mainly for manipulating the equipment stowed by a player in a `LockerContainer` + * and reporting back to a specific xchannel in the event system about these changes. + * @param locker the governed player-facing locker component + * @param toChannel the channel to which to publish events, typically the owning player's name */ -class LockerContainer extends PlanetSideServerObject with Container { - private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL - private val inventory = GridInventory(30, 20) - - def Faction: PlanetSideEmpire.Value = faction - - override def Faction_=(fact: PlanetSideEmpire.Value): PlanetSideEmpire.Value = { - faction = fact - Faction - } - - def Inventory: GridInventory = inventory - - def VisibleSlots: Set[Int] = Set.empty[Int] - - def Definition: EquipmentDefinition = GlobalDefinitions.locker_container -} - -object LockerContainer { - def apply(): LockerContainer = { - new LockerContainer() - } -} - -class LockerEquipment(locker: LockerContainer) extends Equipment with Container { - private val obj = locker - - override def GUID: PlanetSideGUID = obj.GUID - - override def GUID_=(guid: PlanetSideGUID): PlanetSideGUID = obj.GUID_=(guid) - - override def HasGUID: Boolean = obj.HasGUID - - override def Invalidate(): Unit = obj.Invalidate() - - override def Faction: PlanetSideEmpire.Value = obj.Faction - - def Inventory: GridInventory = obj.Inventory - - def VisibleSlots: Set[Int] = Set.empty[Int] - - def Definition: EquipmentDefinition = obj.Definition -} - -class LockerContainerControl(locker: LockerContainer, toChannel: String) extends Actor with ContainableBehavior { +class LockerContainerControl(locker: LockerContainer, toChannel: String) + extends Actor + with ContainableBehavior { def ContainerObject = locker def receive: Receive = diff --git a/src/main/scala/net/psforever/objects/locker/LockerEquipment.scala b/src/main/scala/net/psforever/objects/locker/LockerEquipment.scala new file mode 100644 index 00000000..cded00c9 --- /dev/null +++ b/src/main/scala/net/psforever/objects/locker/LockerEquipment.scala @@ -0,0 +1,41 @@ +// Copyright (c) 2020 PSForever +package net.psforever.objects.locker + +import net.psforever.objects.definition.EquipmentDefinition +import net.psforever.objects.equipment.Equipment +import net.psforever.objects.inventory.{Container, GridInventory} +import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID} + +/** + * A wrapper class that allows a player-facing locker component + * to be treated standard `Equipment` object in the player's fifth (sixth) slot. + * (The opposite is not true - the equipment does not get treated as a locker component.) + * During packet conversion and registration and general access in terms of holsters or "equipment slots", + * the component may be be treated the same as other existing objects at the same level. + * The entity's ability to be utilized like an inventory-stowable entity is not compromised. + * @see `EquipmentSlot` + * @see `IdentifiableEntity` + * @see `LockerContainer` + * @param locker the player-facing locker + */ +class LockerEquipment(locker: LockerContainer) + extends Equipment + with Container { + private val obj = locker + + override def GUID: PlanetSideGUID = obj.GUID + + override def GUID_=(guid: PlanetSideGUID): PlanetSideGUID = obj.GUID_=(guid) + + override def HasGUID: Boolean = obj.HasGUID + + override def Invalidate(): Unit = obj.Invalidate() + + override def Faction: PlanetSideEmpire.Value = obj.Faction + + def Inventory: GridInventory = obj.Inventory + + def VisibleSlots: Set[Int] = Set.empty[Int] + + def Definition: EquipmentDefinition = obj.Definition +} diff --git a/src/main/scala/net/psforever/objects/zones/Zone.scala b/src/main/scala/net/psforever/objects/zones/Zone.scala index debbf627..4c8c4312 100644 --- a/src/main/scala/net/psforever/objects/zones/Zone.scala +++ b/src/main/scala/net/psforever/objects/zones/Zone.scala @@ -12,7 +12,7 @@ import net.psforever.objects.guid.NumberPoolHub import net.psforever.objects.guid.actor.UniqueNumberSystem import net.psforever.objects.guid.key.LoanedKey import net.psforever.objects.guid.selector.RandomSelector -import net.psforever.objects.guid.source.LimitedNumberSource +import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.inventory.Container import net.psforever.objects.serverobject.painbox.{Painbox, PainboxDefinition} import net.psforever.objects.serverobject.resourcesilo.ResourceSilo @@ -73,7 +73,7 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) { private var accessor: ActorRef = ActorRef.noSender /** The basic support structure for the globally unique number system used by this `Zone`. */ - private var guid: NumberPoolHub = new NumberPoolHub(new LimitedNumberSource(65536)) + private var guid: NumberPoolHub = new NumberPoolHub(new MaxNumberSource(65536)) /** A synchronized `List` of items (`Equipment`) dropped by players on the ground and can be collected again. */ private val equipmentOnGround: ListBuffer[Equipment] = ListBuffer[Equipment]() @@ -322,6 +322,7 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) { guid.AddPool("f", (30001 to 35000).toList).Selector = new RandomSelector guid.AddPool("g", (35001 until 40100).toList).Selector = new RandomSelector guid.AddPool("projectiles", (Projectile.baseUID until Projectile.rangeUID).toList) + guid.AddPool("locker-contents", (40150 until 40450).toList).Selector = new RandomSelector //TODO disabled temporarily to lighten load times //guid.AddPool("h", (40150 to 45000).toList).Selector = new RandomSelector //guid.AddPool("i", (45001 to 50000).toList).Selector = new RandomSelector @@ -358,12 +359,12 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) { building match { case warpGate: WarpGate => warpGate.Faction == faction || warpGate.Faction == PlanetSideEmpire.NEUTRAL || warpGate.Broadcast - case building => + case _ => building.Faction == faction } } .map { - case (building, spawns) => + case (building, spawns: List[SpawnPoint]) => (building, spawns.filter(!_.Offline)) } .concat( diff --git a/src/main/scala/net/psforever/services/account/AccountPersistenceService.scala b/src/main/scala/net/psforever/services/account/AccountPersistenceService.scala index 8244da1f..cf65bcc1 100644 --- a/src/main/scala/net/psforever/services/account/AccountPersistenceService.scala +++ b/src/main/scala/net/psforever/services/account/AccountPersistenceService.scala @@ -364,13 +364,12 @@ class PersistenceMonitor(name: String, squadService: ActorRef, taskResolver: Act //player has released //our last body was turned into a corpse; just the avatar remains //TODO perform any last minute saving now ... - AvatarLogout(avatar) inZone.GUID(avatar.vehicle) match { case Some(obj: Vehicle) if obj.OwnerName.contains(avatar.name) => obj.Actor ! Vehicle.Ownership(None) case _ => ; } - taskResolver.tell(GUIDTask.UnregisterLocker(avatar.locker)(inZone.GUID), context.parent) + AvatarLogout(avatar) case _ => //user stalled during initial session, or was caught in between zone transfer @@ -386,7 +385,7 @@ class PersistenceMonitor(name: String, squadService: ActorRef, taskResolver: Act * @see `Avatar` * @see `AvatarAction.ObjectDelete` * @see `AvatarServiceMessage` - * @see `GUIDTask.UnregisterAvatar` + * @see `GUIDTask.UnregisterPlayer` * @see `Player` * @see `Zone.AvatarEvents` * @see `Zone.Population.Release` @@ -405,8 +404,8 @@ class PersistenceMonitor(name: String, squadService: ActorRef, taskResolver: Act } inZone.Population.tell(Zone.Population.Release(avatar), parent) inZone.AvatarEvents.tell(AvatarServiceMessage(inZone.id, AvatarAction.ObjectDelete(pguid, pguid)), parent) + taskResolver.tell(GUIDTask.UnregisterPlayer(player)(inZone.GUID), parent) AvatarLogout(avatar) - taskResolver.tell(GUIDTask.UnregisterAvatar(player)(inZone.GUID), parent) } /** @@ -424,6 +423,7 @@ class PersistenceMonitor(name: String, squadService: ActorRef, taskResolver: Act squadService.tell(Service.Leave(Some(avatar.id.toString)), context.parent) Deployables.Disown(inZone, avatar, context.parent) inZone.Population.tell(Zone.Population.Leave(avatar), context.parent) + taskResolver.tell(GUIDTask.UnregisterObjectTask(avatar.locker)(inZone.GUID), context.parent) log.info(s"logout of ${avatar.name}") } } diff --git a/src/main/scala/net/psforever/zones/Zones.scala b/src/main/scala/net/psforever/zones/Zones.scala index 5822f2a7..b2b2350e 100644 --- a/src/main/scala/net/psforever/zones/Zones.scala +++ b/src/main/scala/net/psforever/zones/Zones.scala @@ -2,21 +2,14 @@ package net.psforever.zones import java.io.FileNotFoundException -import net.psforever.objects.serverobject.terminals.{ - CaptureTerminal, - CaptureTerminalDefinition, - ProximityTerminal, - ProximityTerminalDefinition, - Terminal, - TerminalDefinition -} +import net.psforever.objects.serverobject.terminals.{CaptureTerminal, CaptureTerminalDefinition, ProximityTerminal, ProximityTerminalDefinition, Terminal, TerminalDefinition} import net.psforever.objects.serverobject.mblocker.Locker import java.util.concurrent.atomic.AtomicInteger import akka.actor.ActorContext import io.circe._ import io.circe.parser._ -import net.psforever.objects.{GlobalDefinitions, LocalProjectile} +import net.psforever.objects.{GlobalDefinitions, LocalLockerItem, LocalProjectile} import net.psforever.objects.ballistics.Projectile import net.psforever.objects.definition.BasicDefinition import net.psforever.objects.serverobject.doors.Door @@ -25,18 +18,13 @@ import net.psforever.objects.serverobject.locks.IFFLock import net.psforever.objects.serverobject.pad.{VehicleSpawnPad, VehicleSpawnPadDefinition} import net.psforever.objects.serverobject.painbox.{Painbox, PainboxDefinition} import net.psforever.objects.serverobject.resourcesilo.ResourceSilo -import net.psforever.objects.serverobject.structures.{ - Building, - BuildingDefinition, - FoundationBuilder, - StructureType, - WarpGate -} +import net.psforever.objects.serverobject.structures.{Building, BuildingDefinition, FoundationBuilder, StructureType, WarpGate} import net.psforever.objects.serverobject.tube.SpawnTube import net.psforever.objects.serverobject.turret.{FacilityTurret, FacilityTurretDefinition} import net.psforever.objects.zones.{MapInfo, Zone, ZoneInfo, ZoneMap} import net.psforever.types.{PlanetSideEmpire, Vector3} import net.psforever.util.DefinitionUtil + import scala.io.Source import scala.collection.parallel.CollectionConverters._ @@ -281,6 +269,9 @@ object Zones { (Projectile.baseUID until Projectile.rangeUID) foreach { zoneMap.addLocalObject(_, LocalProjectile.Constructor) } + 40150 until 40450 foreach { + zoneMap.addLocalObject(_, LocalLockerItem.Constructor) + } lattice.asObject.get(info.value).foreach { obj => obj.asArray.get.foreach { entry => diff --git a/src/test/scala/objects/AvatarTest.scala b/src/test/scala/objects/AvatarTest.scala index 3b155ec5..a5a4c47d 100644 --- a/src/test/scala/objects/AvatarTest.scala +++ b/src/test/scala/objects/AvatarTest.scala @@ -5,6 +5,7 @@ import net.psforever.objects.GlobalDefinitions._ import net.psforever.objects._ import net.psforever.objects.avatar.{Avatar, BattleRank, Implant} import net.psforever.objects.definition.ImplantDefinition +import net.psforever.objects.locker.LockerEquipment import net.psforever.types.{CharacterGender, CharacterVoice, ImplantType, PlanetSideEmpire} import org.specs2.mutable._ diff --git a/src/test/scala/objects/ConverterTest.scala b/src/test/scala/objects/ConverterTest.scala index 06f292e2..3f26716c 100644 --- a/src/test/scala/objects/ConverterTest.scala +++ b/src/test/scala/objects/ConverterTest.scala @@ -7,6 +7,7 @@ import net.psforever.objects.avatar.Avatar import net.psforever.objects.definition._ import net.psforever.objects.equipment._ import net.psforever.objects.inventory.InventoryTile +import net.psforever.objects.locker.{LockerContainer, LockerEquipment} import net.psforever.objects.serverobject.terminals.Terminal import net.psforever.objects.serverobject.tube.SpawnTube import net.psforever.objects.vehicles.UtilityType diff --git a/src/test/scala/objects/DamageableTest.scala b/src/test/scala/objects/DamageableTest.scala index d5973874..b8073036 100644 --- a/src/test/scala/objects/DamageableTest.scala +++ b/src/test/scala/objects/DamageableTest.scala @@ -8,7 +8,7 @@ import net.psforever.objects._ import net.psforever.objects.ballistics._ import net.psforever.objects.equipment.JammableUnit import net.psforever.objects.guid.NumberPoolHub -import net.psforever.objects.guid.source.LimitedNumberSource +import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.serverobject.damage.Damageable import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl} import net.psforever.objects.serverobject.implantmech.{ImplantTerminalMech, ImplantTerminalMechControl} @@ -242,7 +242,7 @@ essentially, treat them more as generic entities whose object types are damageab see specific object type tests in relation to what those object types does above and beyond that during damage */ class DamageableEntityDamageTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(5)) + val guid = new NumberPoolHub(new MaxNumberSource(5)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} @@ -313,7 +313,7 @@ class DamageableEntityDamageTest extends ActorTest { } class DamageableEntityDestroyedTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(5)) + val guid = new NumberPoolHub(new MaxNumberSource(5)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} @@ -387,7 +387,7 @@ class DamageableEntityDestroyedTest extends ActorTest { } class DamageableEntityNotDestroyTwice extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} @@ -458,7 +458,7 @@ class DamageableEntityNotDestroyTwice extends ActorTest { } class DamageableAmenityTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} @@ -546,7 +546,7 @@ class DamageableAmenityTest extends ActorTest { class DamageableMountableDamageTest extends ActorTest { //TODO this test with not send HitHint packets because LivePlayers is not being allocated for the players in the zone - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} @@ -638,7 +638,7 @@ class DamageableMountableDamageTest extends ActorTest { class DamageableMountableDestroyTest extends ActorTest { //TODO this test with not send HitHint packets because LivePlayers is not being allocated for the players in the zone - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} @@ -730,7 +730,7 @@ class DamageableMountableDestroyTest extends ActorTest { } class DamageableWeaponTurretDamageTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -823,7 +823,7 @@ class DamageableWeaponTurretDamageTest extends ActorTest { } class DamageableWeaponTurretJammerTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -918,7 +918,7 @@ class DamageableWeaponTurretJammerTest extends ActorTest { } class DamageableWeaponTurretDestructionTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -1069,7 +1069,7 @@ class DamageableWeaponTurretDestructionTest extends ActorTest { } class DamageableVehicleDamageTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -1174,7 +1174,7 @@ class DamageableVehicleDamageTest extends ActorTest { } class DamageableVehicleDamageMountedTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(15)) + val guid = new NumberPoolHub(new MaxNumberSource(15)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -1315,7 +1315,7 @@ class DamageableVehicleDamageMountedTest extends ActorTest { } class DamageableVehicleJammeringMountedTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(15)) + val guid = new NumberPoolHub(new MaxNumberSource(15)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -1428,7 +1428,7 @@ class DamageableVehicleJammeringMountedTest extends ActorTest { } class DamageableVehicleDestroyTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -1531,7 +1531,7 @@ class DamageableVehicleDestroyTest extends ActorTest { } class DamageableVehicleDestroyMountedTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(15)) + val guid = new NumberPoolHub(new MaxNumberSource(15)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) diff --git a/src/test/scala/objects/DeployableTest.scala b/src/test/scala/objects/DeployableTest.scala index 39ab6107..c734efea 100644 --- a/src/test/scala/objects/DeployableTest.scala +++ b/src/test/scala/objects/DeployableTest.scala @@ -7,7 +7,7 @@ import base.ActorTest import net.psforever.objects.ballistics._ import net.psforever.objects.ce.DeployedItem import net.psforever.objects.guid.NumberPoolHub -import net.psforever.objects.guid.source.LimitedNumberSource +import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.vital.Vitality import net.psforever.objects.zones.{Zone, ZoneMap} @@ -300,7 +300,7 @@ class ShieldGeneratorDeployableTest extends Specification { } class ExplosiveDeployableJammerTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -398,7 +398,7 @@ class ExplosiveDeployableJammerTest extends ActorTest { } class ExplosiveDeployableJammerExplodeTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -508,7 +508,7 @@ class ExplosiveDeployableJammerExplodeTest extends ActorTest { } class ExplosiveDeployableDestructionTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) diff --git a/src/test/scala/objects/FacilityTurretTest.scala b/src/test/scala/objects/FacilityTurretTest.scala index 78972419..45330390 100644 --- a/src/test/scala/objects/FacilityTurretTest.scala +++ b/src/test/scala/objects/FacilityTurretTest.scala @@ -8,7 +8,7 @@ import net.psforever.objects.avatar.Avatar import net.psforever.objects.{Default, GlobalDefinitions, Player, Tool} import net.psforever.objects.definition.ToolDefinition import net.psforever.objects.guid.NumberPoolHub -import net.psforever.objects.guid.source.LimitedNumberSource +import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.serverobject.structures.{Building, StructureType} @@ -182,7 +182,7 @@ class FacilityTurretControl4Test extends ActorTest { } class FacilityTurretControlRestorationTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) diff --git a/src/test/scala/objects/GeneratorTest.scala b/src/test/scala/objects/GeneratorTest.scala index 4d53ae41..d05b6620 100644 --- a/src/test/scala/objects/GeneratorTest.scala +++ b/src/test/scala/objects/GeneratorTest.scala @@ -8,7 +8,7 @@ import net.psforever.objects.avatar.Avatar import net.psforever.objects.ballistics._ import net.psforever.objects.{GlobalDefinitions, Player, Tool} import net.psforever.objects.guid.NumberPoolHub -import net.psforever.objects.guid.source.LimitedNumberSource +import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl} import net.psforever.objects.serverobject.structures.{Building, StructureType} @@ -46,7 +46,7 @@ class GeneratorControlConstructTest extends ActorTest { } class GeneratorControlDamageTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(5)) + val guid = new NumberPoolHub(new MaxNumberSource(5)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -128,7 +128,7 @@ class GeneratorControlDamageTest extends ActorTest { } class GeneratorControlCriticalTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(5)) + val guid = new NumberPoolHub(new MaxNumberSource(5)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -218,7 +218,7 @@ class GeneratorControlCriticalTest extends ActorTest { } class GeneratorControlDestroyedTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(5)) + val guid = new NumberPoolHub(new MaxNumberSource(5)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -341,7 +341,7 @@ class GeneratorControlKillsTest extends ActorTest { but its SOI information can be loaded with the players manually the players need something to catch the die message */ - val guid = new NumberPoolHub(new LimitedNumberSource(5)) + val guid = new NumberPoolHub(new MaxNumberSource(5)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -478,7 +478,7 @@ class GeneratorControlKillsTest extends ActorTest { } class GeneratorControlNotDestroyTwice extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} @@ -561,7 +561,7 @@ class GeneratorControlNotDestroyTwice extends ActorTest { } class GeneratorControlNotDamageIfExplodingTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(5)) + val guid = new NumberPoolHub(new MaxNumberSource(5)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -655,7 +655,7 @@ class GeneratorControlNotDamageIfExplodingTest extends ActorTest { } class GeneratorControlNotRepairIfExplodingTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(5)) + val guid = new NumberPoolHub(new MaxNumberSource(5)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -753,7 +753,7 @@ class GeneratorControlNotRepairIfExplodingTest extends ActorTest { } class GeneratorControlRepairPastRestorePoint extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(5)) + val guid = new NumberPoolHub(new MaxNumberSource(5)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) diff --git a/src/test/scala/objects/InventoryTest.scala b/src/test/scala/objects/InventoryTest.scala index 534dee6f..a8c15dec 100644 --- a/src/test/scala/objects/InventoryTest.scala +++ b/src/test/scala/objects/InventoryTest.scala @@ -3,13 +3,13 @@ package objects import net.psforever.objects.{AmmoBox, SimpleItem, Tool} import net.psforever.objects.definition.SimpleItemDefinition -import net.psforever.objects.inventory.{GridInventory, InventoryDisarrayException, InventoryItem, InventoryTile} +import net.psforever.objects.inventory._ import net.psforever.objects.GlobalDefinitions.{bullet_9mm, suppressor} import net.psforever.types.PlanetSideGUID import org.specs2.mutable._ import scala.collection.mutable.ListBuffer -import scala.util.{Success, Failure} +import scala.util.{Failure, Success} class InventoryTest extends Specification { val bullet9mmBox1 = AmmoBox(bullet_9mm) @@ -522,6 +522,168 @@ class InventoryTest extends Specification { } } + "LocallyRegisteredInventory" should { + "construct" in { + val obj: LocallyRegisteredInventory = new LocallyRegisteredInventory(List(15)) + obj.TotalCapacity mustEqual 1 + obj.Capacity mustEqual 1 + } + + "insert (and register) item" in { + val obj: LocallyRegisteredInventory = new LocallyRegisteredInventory(List(15)) + obj.Resize(9, 6) + obj.Size mustEqual 0 + val item = AmmoBox(bullet_9mm) + item.HasGUID mustEqual false + obj.CheckCollisions(2, item) mustEqual Success(Nil) + obj += 2 -> item + obj.Size mustEqual 1 + obj.hasItem(PlanetSideGUID(15)).contains(item) mustEqual true + item.HasGUID mustEqual true + item.GUID mustEqual PlanetSideGUID(15) + } + + "insert (and register) complex item" in { + val obj: LocallyRegisteredInventory = new LocallyRegisteredInventory(List(15, 16)) + obj.Resize(9, 6) + obj.Size mustEqual 0 + val item = Tool(suppressor) + item.HasGUID mustEqual false + item.AmmoSlot.Box.HasGUID mustEqual false + obj.CheckCollisions(2, item) mustEqual Success(Nil) + obj += 2 -> item + obj.Size mustEqual 1 + item.HasGUID mustEqual true + item.AmmoSlot.Box.HasGUID mustEqual true + } + + "not insert item if already registered" in { + val obj: LocallyRegisteredInventory = new LocallyRegisteredInventory(List(15)) + obj.Resize(9, 6) + obj.Size mustEqual 0 + val item = AmmoBox(bullet_9mm) + item.GUID = PlanetSideGUID(10) //artificially register + item.HasGUID mustEqual true + + obj.CheckCollisions(2, item) mustEqual Success(Nil) //insert should be possible + obj += 2 -> item + obj.Size mustEqual 0 + obj.hasItem(PlanetSideGUID(15)).isEmpty mustEqual true + } + + "not insert (or register) item if no (more) GUID's are available" in { + val obj: LocallyRegisteredInventory = new LocallyRegisteredInventory(List(15)) + obj.Resize(9, 6) + val item1 = AmmoBox(bullet_9mm) + val item2 = AmmoBox(bullet_9mm) + item1.HasGUID mustEqual false + item2.HasGUID mustEqual false + + obj.CheckCollisions(2, item1) mustEqual Success(Nil) //insert should be possible + obj += 2 -> item1 + obj.Size mustEqual 1 + obj.hasItem(PlanetSideGUID(15)).contains(item1) mustEqual true + item1.HasGUID mustEqual true + item1.GUID mustEqual PlanetSideGUID(15) + + obj.CheckCollisions(5, item2) mustEqual Success(Nil) //insert should be possible + obj += 5 -> item2 + obj.Size mustEqual 1 + item2.HasGUID mustEqual false + } + + "not insert (or register) complex item if no (more) GUID's are available" in { + val item = Tool(suppressor) + val obj: LocallyRegisteredInventory = new LocallyRegisteredInventory(List(15)) + obj.Resize(9, 6) + obj.Size mustEqual 0 + item.HasGUID mustEqual false + item.AmmoSlot.Box.HasGUID mustEqual false + + obj.CheckCollisions(2, item) mustEqual Success(Nil) //insert should be possible + obj += 2 -> item + obj.Size mustEqual 0 + item.HasGUID mustEqual false + item.AmmoSlot.Box.HasGUID mustEqual false + } + + "insert (and register) multiple items" in { + val obj: LocallyRegisteredInventory = new LocallyRegisteredInventory(List(15, 17)) + obj.Resize(9, 6) + val item1 = AmmoBox(bullet_9mm) + val item2 = AmmoBox(bullet_9mm) + item1.HasGUID mustEqual false + item2.HasGUID mustEqual false + + obj.CheckCollisions(2, item1) mustEqual Success(Nil) //insert should be possible + obj += 2 -> item1 + obj.Size mustEqual 1 + item1.HasGUID mustEqual true + + obj.CheckCollisions(5, item2) mustEqual Success(Nil) //insert should be possible + obj += 5 -> item2 + obj.Size mustEqual 2 + item2.HasGUID mustEqual true + } + + "clear (and unregister) all items" in { + val obj: LocallyRegisteredInventory = new LocallyRegisteredInventory(List(15, 17)) + obj.Resize(9, 6) + val item1 = AmmoBox(bullet_9mm) + val item2 = AmmoBox(bullet_9mm) + obj += 2 -> item1 + obj += 5 -> item2 + obj.Size mustEqual 2 + item1.HasGUID mustEqual true + item2.HasGUID mustEqual true + + obj.Clear() + obj.Size mustEqual 0 + item1.HasGUID mustEqual false + item2.HasGUID mustEqual false + } + + "remove (and unregister) item" in { + val obj: LocallyRegisteredInventory = new LocallyRegisteredInventory(List(15, 17)) + obj.Resize(9, 6) + val item1 = AmmoBox(bullet_9mm) + val item2 = AmmoBox(bullet_9mm) + obj += 2 -> item1 + obj += 5 -> item2 + obj.Size mustEqual 2 + item1.HasGUID mustEqual true + item2.HasGUID mustEqual true + + obj -= 2 + obj.Size mustEqual 1 + item1.HasGUID mustEqual false + item2.HasGUID mustEqual true + + obj -= 5 + obj.Size mustEqual 0 + item1.HasGUID mustEqual false + item2.HasGUID mustEqual false + } + } + + "remove (and unregister) complex item" in { + val obj: LocallyRegisteredInventory = new LocallyRegisteredInventory(List(15, 17)) + obj.Resize(9, 6) + val item = Tool(suppressor) + item.HasGUID mustEqual false + item.AmmoSlot.Box.HasGUID mustEqual false + obj.CheckCollisions(2, item) mustEqual Success(Nil) + obj += 2 -> item + obj.Size mustEqual 1 + item.HasGUID mustEqual true + item.AmmoSlot.Box.HasGUID mustEqual true + + obj -= 2 + obj.Size mustEqual 0 + item.HasGUID mustEqual false + item.AmmoSlot.Box.HasGUID mustEqual false + } + "InventoryEquiupmentSlot" should { "insert, collide, insert" in { val obj: GridInventory = GridInventory(7, 7) diff --git a/src/test/scala/objects/LocalTest.scala b/src/test/scala/objects/LocalTest.scala new file mode 100644 index 00000000..2fc8b016 --- /dev/null +++ b/src/test/scala/objects/LocalTest.scala @@ -0,0 +1,24 @@ +package objects + +import net.psforever.objects.{LocalLockerItem, LocalProjectile} +import net.psforever.types.PlanetSideEmpire +import org.specs2.mutable.Specification + +class LocalTest extends Specification { + "LocalProjectile" should { + "construct" in { + val obj = new LocalProjectile() //since they're just placeholders, they only need to construct + obj.Definition.ObjectId mustEqual 0 + obj.Definition.Name mustEqual "projectile" + } + } + + "LocalLockerItem" should { + "construct" in { + val obj = new LocalLockerItem() //since they're just placeholders, they only need to construct + obj.Faction mustEqual PlanetSideEmpire.NEUTRAL + obj.Definition.ObjectId mustEqual 0 + obj.Definition.Name mustEqual "locker-equipment" + } + } +} \ No newline at end of file diff --git a/src/test/scala/objects/PlayerControlTest.scala b/src/test/scala/objects/PlayerControlTest.scala index 9b261bdf..45a48d5a 100644 --- a/src/test/scala/objects/PlayerControlTest.scala +++ b/src/test/scala/objects/PlayerControlTest.scala @@ -7,7 +7,7 @@ import base.ActorTest import net.psforever.objects.avatar.{Avatar, PlayerControl} import net.psforever.objects.ballistics._ import net.psforever.objects.guid.NumberPoolHub -import net.psforever.objects.guid.source.LimitedNumberSource +import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.vital.Vitality import net.psforever.objects.zones.{Zone, ZoneMap} import net.psforever.objects._ @@ -20,7 +20,7 @@ import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import scala.concurrent.duration._ class PlayerControlHealTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(15)) + val guid = new NumberPoolHub(new MaxNumberSource(15)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -106,7 +106,7 @@ class PlayerControlHealTest extends ActorTest { } class PlayerControlHealSelfTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(15)) + val guid = new NumberPoolHub(new MaxNumberSource(15)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -181,7 +181,7 @@ class PlayerControlHealSelfTest extends ActorTest { } class PlayerControlRepairTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(15)) + val guid = new NumberPoolHub(new MaxNumberSource(15)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -277,7 +277,7 @@ class PlayerControlRepairTest extends ActorTest { } class PlayerControlRepairSelfTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(15)) + val guid = new NumberPoolHub(new MaxNumberSource(15)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -352,7 +352,7 @@ class PlayerControlRepairSelfTest extends ActorTest { } class PlayerControlDamageTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(15)) + val guid = new NumberPoolHub(new MaxNumberSource(15)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -449,7 +449,7 @@ class PlayerControlDamageTest extends ActorTest { } class PlayerControlDeathStandingTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(15)) + val guid = new NumberPoolHub(new MaxNumberSource(15)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -575,7 +575,7 @@ class PlayerControlDeathStandingTest extends ActorTest { } class PlayerControlDeathSeatedTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(15)) + val guid = new NumberPoolHub(new MaxNumberSource(15)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) diff --git a/src/test/scala/objects/PlayerTest.scala b/src/test/scala/objects/PlayerTest.scala index fd1034c5..d8f91da8 100644 --- a/src/test/scala/objects/PlayerTest.scala +++ b/src/test/scala/objects/PlayerTest.scala @@ -6,6 +6,7 @@ import net.psforever.objects._ import net.psforever.objects.avatar.Avatar import net.psforever.objects.definition.{SimpleItemDefinition, SpecialExoSuitDefinition} import net.psforever.objects.equipment.EquipmentSize +import net.psforever.objects.locker.LockerEquipment import net.psforever.types.{PlanetSideGUID, _} import org.specs2.mutable._ diff --git a/src/test/scala/objects/ProjectileTest.scala b/src/test/scala/objects/ProjectileTest.scala index 17f81493..8689c77b 100644 --- a/src/test/scala/objects/ProjectileTest.scala +++ b/src/test/scala/objects/ProjectileTest.scala @@ -14,13 +14,7 @@ class ProjectileTest extends Specification { val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) val fury = Vehicle(GlobalDefinitions.fury) - "LocalProjectile" should { - "construct" in { - val obj = new LocalProjectile() //since they're just placeholders, they only need to construct - obj.Definition.ObjectId mustEqual 0 - obj.Definition.Name mustEqual "projectile" - } - + "Range" should { "local projectile range" in { Projectile.baseUID < Projectile.rangeUID mustEqual true } diff --git a/src/test/scala/objects/RepairableTest.scala b/src/test/scala/objects/RepairableTest.scala index da89a9c1..70750d44 100644 --- a/src/test/scala/objects/RepairableTest.scala +++ b/src/test/scala/objects/RepairableTest.scala @@ -7,7 +7,7 @@ import base.ActorTest import net.psforever.objects._ import net.psforever.objects.avatar.Avatar import net.psforever.objects.guid.NumberPoolHub -import net.psforever.objects.guid.source.LimitedNumberSource +import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl} import net.psforever.objects.serverobject.structures.{Building, StructureType} @@ -28,7 +28,7 @@ essentially, treat it more as a generic entity whose object type is repairable see GeneratorTest in relation to what the generator does above and beyond that during repair */ class RepairableEntityRepairTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} @@ -100,7 +100,7 @@ class RepairableEntityRepairTest extends ActorTest { } class RepairableEntityNotRepairTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} @@ -141,7 +141,7 @@ class RepairableEntityNotRepairTest extends ActorTest { } class RepairableAmenityTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} @@ -229,7 +229,7 @@ class RepairableAmenityTest extends ActorTest { } class RepairableTurretWeapon extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -323,7 +323,7 @@ class RepairableTurretWeapon extends ActorTest { } class RepairableVehicleRepair extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) @@ -396,7 +396,7 @@ class RepairableVehicleRestoration extends ActorTest { /* no messages are dispatched, in this case, because most vehicles are flagged to not be repairable if destroyed */ - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { override def SetupNumberPools() = {} GUID(guid) diff --git a/src/test/scala/objects/ResourceSiloTest.scala b/src/test/scala/objects/ResourceSiloTest.scala index f7a3a9d0..ab7424cd 100644 --- a/src/test/scala/objects/ResourceSiloTest.scala +++ b/src/test/scala/objects/ResourceSiloTest.scala @@ -7,7 +7,7 @@ import akka.testkit.TestProbe import base.ActorTest import net.psforever.actors.zone.{BuildingActor, ZoneActor} import net.psforever.objects.guid.{NumberPoolHub, TaskResolver} -import net.psforever.objects.guid.source.LimitedNumberSource +import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.{GlobalDefinitions, Ntu, Player, Vehicle} import net.psforever.objects.serverobject.resourcesilo.{ResourceSilo, ResourceSiloControl, ResourceSiloDefinition} @@ -94,7 +94,7 @@ class ResourceSiloControlStartupTest extends ActorTest { } class ResourceSiloControlUseTest extends ActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val map = new ZoneMap("test") val zone = new Zone("test", map, 0) { override def SetupNumberPools() = {} diff --git a/src/test/scala/objects/ServerObjectBuilderTest.scala b/src/test/scala/objects/ServerObjectBuilderTest.scala index 718a63a3..674b85a6 100644 --- a/src/test/scala/objects/ServerObjectBuilderTest.scala +++ b/src/test/scala/objects/ServerObjectBuilderTest.scala @@ -1,8 +1,8 @@ // Copyright (c) 2017 PSForever package objects -import akka.actor.{Actor, ActorContext, Props} -import base.ActorTest +import akka.actor.ActorContext +import base.FreedContextActorTest import net.psforever.objects.GlobalDefinitions import net.psforever.objects.guid.NumberPoolHub import net.psforever.objects.serverobject.ServerObjectBuilder @@ -11,361 +11,223 @@ import net.psforever.objects.serverobject.terminals.ProximityTerminal import net.psforever.objects.zones.Zone import net.psforever.types.{PlanetSideGUID, Vector3} -import scala.concurrent.duration.Duration - -class BuildingBuilderTest extends ActorTest { +class BuildingBuilderTest extends FreedContextActorTest { "Building object" should { "build" in { val structure: (String, Int, Int, Zone, ActorContext) => Building = Building.Structure(StructureType.Building) - val actor = system.actorOf( - Props(classOf[ServerObjectBuilderTest.BuildingTestActor], structure, "Building", 10, 10, Zone.Nowhere), - "building" - ) - actor ! "!" - - val reply = receiveOne(Duration.create(1000, "ms")) - assert(reply.isInstanceOf[Building]) - assert(reply.asInstanceOf[Building].MapId == 10) - assert(reply.asInstanceOf[Building].Zone == Zone.Nowhere) + val building = FoundationBuilder(structure).Build("building", 10, 10, Zone.Nowhere)(context) + assert(building ne null) + assert(building.isInstanceOf[Building]) + assert(building.MapId == 10) + assert(building.Zone == Zone.Nowhere) } } } -class WarpGateBuilderTest extends ActorTest { +class WarpGateBuilderTest extends FreedContextActorTest { "WarpGate object" should { "build" in { val structure: (String, Int, Int, Zone, ActorContext) => Building = WarpGate.Structure - val actor = system.actorOf( - Props(classOf[ServerObjectBuilderTest.BuildingTestActor], structure, "wgate", 10, 10, Zone.Nowhere), - "wgate" - ) - actor ! "!" - - val reply = receiveOne(Duration.create(1000, "ms")) - assert(reply.isInstanceOf[Building]) - assert(reply.asInstanceOf[Building].MapId == 10) - assert(reply.asInstanceOf[Building].Zone == Zone.Nowhere) + val building = FoundationBuilder(structure).Build("wgate", 10, 10, Zone.Nowhere)(context) + assert(building ne null) + assert(building.isInstanceOf[WarpGate]) + assert(building.MapId == 10) + assert(building.Zone == Zone.Nowhere) } } } -class DoorObjectBuilderTest1 extends ActorTest { +class DoorObjectBuilderTest1 extends FreedContextActorTest { import net.psforever.objects.serverobject.doors.Door "Door object" should { "build" in { val hub = ServerObjectBuilderTest.NumberPoolHub - val actor = system.actorOf( - Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1, Door.Constructor), hub), - "door" - ) - actor ! "!" - - val reply = receiveOne(Duration.create(1000, "ms")) - assert(reply.isInstanceOf[Door]) - assert(reply.asInstanceOf[Door].HasGUID) - assert(reply.asInstanceOf[Door].GUID == PlanetSideGUID(1)) - assert(reply == hub(1).get) + val obj = ServerObjectBuilder(1, Door.Constructor).Build(context, hub) + assert(obj.isInstanceOf[Door]) + assert(obj.HasGUID) + assert(obj.GUID == PlanetSideGUID(1)) + assert(obj == hub(1).get) } } } -class DoorObjectBuilderTest2 extends ActorTest { +class DoorObjectBuilderTest2 extends FreedContextActorTest { import net.psforever.objects.serverobject.doors.Door "Door object" should { "build" in { val hub = ServerObjectBuilderTest.NumberPoolHub - val actor = system.actorOf( - Props( - classOf[ServerObjectBuilderTest.BuilderTestActor], - ServerObjectBuilder(1, Door.Constructor(Vector3(1, 2, 3))), - hub - ), - "door" - ) - actor ! "!" - - val reply = receiveOne(Duration.create(1000, "ms")) - assert(reply.isInstanceOf[Door]) - assert(reply.asInstanceOf[Door].Position == Vector3(1, 2, 3)) - assert(reply.asInstanceOf[Door].HasGUID) - assert(reply.asInstanceOf[Door].GUID == PlanetSideGUID(1)) - assert(reply == hub(1).get) + val obj = ServerObjectBuilder(1, Door.Constructor(Vector3(1, 2, 3))).Build(context, hub) + assert(obj.isInstanceOf[Door]) + assert(obj.HasGUID) + assert(obj.GUID == PlanetSideGUID(1)) + assert(obj == hub(1).get) + assert(obj.Position == Vector3(1, 2, 3)) } } } -class IFFLockObjectBuilderTest extends ActorTest { +class IFFLockObjectBuilderTest extends FreedContextActorTest { import net.psforever.objects.serverobject.locks.IFFLock "IFFLock object" should { "build" in { val hub = ServerObjectBuilderTest.NumberPoolHub - val actor = system.actorOf( - Props( - classOf[ServerObjectBuilderTest.BuilderTestActor], - ServerObjectBuilder(1, IFFLock.Constructor(Vector3(0f, 0f, 0f), Vector3(0f, 0f, 0f))), - hub - ), - "lock" - ) - actor ! "!" - - val reply = receiveOne(Duration.create(1000, "ms")) - assert(reply.isInstanceOf[IFFLock]) - assert(reply.asInstanceOf[IFFLock].HasGUID) - assert(reply.asInstanceOf[IFFLock].GUID == PlanetSideGUID(1)) - assert(reply == hub(1).get) + val obj = ServerObjectBuilder(1, IFFLock.Constructor(Vector3(1f, 1f, 1f), Vector3(2f, 2f, 2f))).Build(context, hub) + assert(obj.isInstanceOf[IFFLock]) + assert(obj.HasGUID) + assert(obj.GUID == PlanetSideGUID(1)) + assert(obj.Position == Vector3(1,1,1)) + assert(obj.Outwards == Vector3(0.034899496f, 0.99939084f, 0.0f)) + assert(obj == hub(1).get) } } } -class ImplantTerminalMechObjectBuilderTest extends ActorTest { +class ImplantTerminalMechObjectBuilderTest extends FreedContextActorTest { import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech "Implant terminal mech object" should { "build" in { val hub = ServerObjectBuilderTest.NumberPoolHub - val actor = system.actorOf( - Props( - classOf[ServerObjectBuilderTest.BuilderTestActor], - ServerObjectBuilder(1, ImplantTerminalMech.Constructor(Vector3.Zero)), - hub - ), - "mech" - ) - actor ! "!" - - val reply = receiveOne(Duration.create(1000, "ms")) - assert(reply.isInstanceOf[ImplantTerminalMech]) - assert(reply.asInstanceOf[ImplantTerminalMech].HasGUID) - assert(reply.asInstanceOf[ImplantTerminalMech].GUID == PlanetSideGUID(1)) - assert(reply == hub(1).get) + val obj = ServerObjectBuilder(1, ImplantTerminalMech.Constructor(Vector3.Zero)).Build(context, hub) + assert(obj.isInstanceOf[ImplantTerminalMech]) + assert(obj.HasGUID) + assert(obj.GUID == PlanetSideGUID(1)) + assert(obj == hub(1).get) } } } -class TerminalObjectBuilderTest extends ActorTest { +class TerminalObjectBuilderTest extends FreedContextActorTest { import net.psforever.objects.GlobalDefinitions.order_terminal import net.psforever.objects.serverobject.terminals.Terminal "Terminal object" should { "build" in { val hub = ServerObjectBuilderTest.NumberPoolHub - val actor = system.actorOf( - Props( - classOf[ServerObjectBuilderTest.BuilderTestActor], - ServerObjectBuilder(1, Terminal.Constructor(Vector3(1.1f, 2.2f, 3.3f), order_terminal)), - hub - ), - "term" - ) - actor ! "!" - - val reply = receiveOne(Duration.create(1000, "ms")) - assert(reply.isInstanceOf[Terminal]) - assert(reply.asInstanceOf[Terminal].HasGUID) - assert(reply.asInstanceOf[Terminal].GUID == PlanetSideGUID(1)) - assert(reply.asInstanceOf[Terminal].Position == Vector3(1.1f, 2.2f, 3.3f)) - assert(reply == hub(1).get) + val obj = ServerObjectBuilder(1, Terminal.Constructor(Vector3(1.1f, 2.2f, 3.3f), order_terminal)).Build(context, hub) + assert(obj.isInstanceOf[Terminal]) + assert(obj.HasGUID) + assert(obj.GUID == PlanetSideGUID(1)) + assert(obj.Position == Vector3(1.1f, 2.2f, 3.3f)) + assert(obj == hub(1).get) } } } -class ProximityTerminalObjectBuilderTest extends ActorTest { +class ProximityTerminalObjectBuilderTest extends FreedContextActorTest { import net.psforever.objects.GlobalDefinitions.medical_terminal import net.psforever.objects.serverobject.terminals.Terminal "Terminal object" should { "build" in { val hub = ServerObjectBuilderTest.NumberPoolHub - val actor = system.actorOf( - Props( - classOf[ServerObjectBuilderTest.BuilderTestActor], - ServerObjectBuilder(1, ProximityTerminal.Constructor(medical_terminal)), - hub - ), - "term" - ) - actor ! "!" - - val reply = receiveOne(Duration.create(1000, "ms")) - assert(reply.isInstanceOf[Terminal]) - assert(reply.asInstanceOf[Terminal].HasGUID) - assert(reply.asInstanceOf[Terminal].GUID == PlanetSideGUID(1)) - assert(reply == hub(1).get) + val obj = ServerObjectBuilder(1, ProximityTerminal.Constructor(medical_terminal)).Build(context, hub) + assert(obj.isInstanceOf[Terminal]) + assert(obj.HasGUID) + assert(obj.GUID == PlanetSideGUID(1)) + assert(obj == hub(1).get) } } } -class VehicleSpawnPadObjectBuilderTest extends ActorTest { +class VehicleSpawnPadObjectBuilderTest extends FreedContextActorTest { import net.psforever.objects.serverobject.pad.VehicleSpawnPad "Vehicle spawn pad object" should { "build" in { val hub = ServerObjectBuilderTest.NumberPoolHub - val actor = system.actorOf( - Props( - classOf[ServerObjectBuilderTest.BuilderTestActor], - ServerObjectBuilder( - 1, - VehicleSpawnPad - .Constructor(Vector3(1.1f, 2.2f, 3.3f), GlobalDefinitions.mb_pad_creation, Vector3(4.4f, 5.5f, 6.6f)) - ), - hub - ), - "pad" - ) - actor ! "!" - - val reply = receiveOne(Duration.create(1000, "ms")) - assert(reply.isInstanceOf[VehicleSpawnPad]) - assert(reply.asInstanceOf[VehicleSpawnPad].HasGUID) - assert(reply.asInstanceOf[VehicleSpawnPad].GUID == PlanetSideGUID(1)) - assert(reply.asInstanceOf[VehicleSpawnPad].Position == Vector3(1.1f, 2.2f, 3.3f)) - assert(reply.asInstanceOf[VehicleSpawnPad].Orientation == Vector3(4.4f, 5.5f, 6.6f)) - assert(reply == hub(1).get) + val obj = ServerObjectBuilder(1, + VehicleSpawnPad.Constructor( + Vector3(1.1f, 2.2f, 3.3f), GlobalDefinitions.mb_pad_creation, Vector3(4.4f, 5.5f, 6.6f) + ) + ).Build(context, hub) + assert(obj.isInstanceOf[VehicleSpawnPad]) + assert(obj.HasGUID) + assert(obj.GUID == PlanetSideGUID(1)) + assert(obj.Position == Vector3(1.1f, 2.2f, 3.3f)) + assert(obj.Orientation == Vector3(4.4f, 5.5f, 6.6f)) + assert(obj == hub(1).get) } } } -class LocalProjectileBuilderTest extends ActorTest { +class LocalProjectileBuilderTest extends FreedContextActorTest { import net.psforever.objects.LocalProjectile "Local projectile object" should { "build" in { val hub = ServerObjectBuilderTest.NumberPoolHub - val actor = system.actorOf( - Props( - classOf[ServerObjectBuilderTest.BuilderTestActor], - ServerObjectBuilder(1, LocalProjectile.Constructor), - hub - ), - "locker" - ) - actor ! "!" - - val reply = receiveOne(Duration.create(1000, "ms")) - assert(reply.isInstanceOf[LocalProjectile]) - assert(reply.asInstanceOf[LocalProjectile].HasGUID) - assert(reply.asInstanceOf[LocalProjectile].GUID == PlanetSideGUID(1)) - assert(reply == hub(1).get) + val obj = ServerObjectBuilder(1, LocalProjectile.Constructor).Build(context, hub) + assert(obj.isInstanceOf[LocalProjectile]) + assert(obj.HasGUID) + assert(obj.GUID == PlanetSideGUID(1)) + assert(obj == hub(1).get) } } } -class LockerObjectBuilderTest extends ActorTest { +class LockerObjectBuilderTest extends FreedContextActorTest { import net.psforever.objects.serverobject.mblocker.Locker "Locker object" should { "build" in { val hub = ServerObjectBuilderTest.NumberPoolHub - val actor = system.actorOf( - Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1, Locker.Constructor), hub), - "locker" - ) - actor ! "!" - - val reply = receiveOne(Duration.create(1000, "ms")) - assert(reply.isInstanceOf[Locker]) - assert(reply.asInstanceOf[Locker].HasGUID) - assert(reply.asInstanceOf[Locker].GUID == PlanetSideGUID(1)) - assert(reply == hub(1).get) + val obj = ServerObjectBuilder(1, Locker.Constructor).Build(context, hub) + assert(obj.isInstanceOf[Locker]) + assert(obj.HasGUID) + assert(obj.GUID == PlanetSideGUID(1)) + assert(obj == hub(1).get) } } } -class ResourceSiloObjectBuilderTest extends ActorTest { +class ResourceSiloObjectBuilderTest extends FreedContextActorTest { import net.psforever.objects.serverobject.resourcesilo.ResourceSilo "Resource silo object" should { "build" in { val hub = ServerObjectBuilderTest.NumberPoolHub - val actor = system.actorOf( - Props( - classOf[ServerObjectBuilderTest.BuilderTestActor], - ServerObjectBuilder(1, ResourceSilo.Constructor(Vector3(0f, 0f, 0f))), - hub - ), - "resource-silo" - ) - actor ! "startup" - - val reply = receiveOne(Duration.create(1000, "ms")) - assert(reply.isInstanceOf[ResourceSilo]) - assert(reply.asInstanceOf[ResourceSilo].HasGUID) - assert(reply.asInstanceOf[ResourceSilo].GUID == PlanetSideGUID(1)) - assert(reply == hub(1).get) + val obj = ServerObjectBuilder(1, ResourceSilo.Constructor(Vector3(1f, 1f, 1f))).Build(context, hub) + assert(obj.isInstanceOf[ResourceSilo]) + assert(obj.HasGUID) + assert(obj.GUID == PlanetSideGUID(1)) + assert(obj.Position == Vector3(1,1,1)) + assert(obj == hub(1).get) } } } -class SpawnTubeObjectBuilderTest extends ActorTest { +class SpawnTubeObjectBuilderTest extends FreedContextActorTest { import net.psforever.objects.serverobject.tube.SpawnTube "Spawn tube object" should { "build" in { val hub = ServerObjectBuilderTest.NumberPoolHub - val actor = system.actorOf( - Props( - classOf[ServerObjectBuilderTest.BuilderTestActor], - ServerObjectBuilder(1, SpawnTube.Constructor(Vector3(3980.4062f, 4267.3047f, 257.5625f), Vector3(0, 0, 90))), - hub - ), - "spawn-tube" - ) - actor ! "!" - - val reply = receiveOne(Duration.create(1000, "ms")) - assert(reply.isInstanceOf[SpawnTube]) - assert(reply.asInstanceOf[SpawnTube].HasGUID) - assert(reply.asInstanceOf[SpawnTube].GUID == PlanetSideGUID(1)) - assert(reply.asInstanceOf[SpawnTube].Position == Vector3(3980.4062f, 4267.3047f, 257.5625f)) - assert(reply.asInstanceOf[SpawnTube].Orientation == Vector3(0, 0, 90)) - assert(reply == hub(1).get) + val obj = ServerObjectBuilder( + 1, + SpawnTube.Constructor(Vector3(3980.4062f, 4267.3047f, 257.5625f), Vector3(0, 0, 90)) + ).Build(context, hub) + assert(obj.isInstanceOf[SpawnTube]) + assert(obj.HasGUID) + assert(obj.GUID == PlanetSideGUID(1)) + assert(obj.Position == Vector3(3980.4062f, 4267.3047f, 257.5625f)) + assert(obj.Orientation == Vector3(0, 0, 90)) + assert(obj == hub(1).get) } } } -class FacilityTurretObjectBuilderTest extends ActorTest { +class FacilityTurretObjectBuilderTest extends FreedContextActorTest { import net.psforever.objects.GlobalDefinitions.manned_turret import net.psforever.objects.serverobject.turret.FacilityTurret "FacilityTurretObjectBuilder" should { "build" in { val hub = ServerObjectBuilderTest.NumberPoolHub - val actor = system.actorOf( - Props( - classOf[ServerObjectBuilderTest.BuilderTestActor], - ServerObjectBuilder(1, FacilityTurret.Constructor(manned_turret)), - hub - ), - "manned-turret" - ) - actor ! "!" - - val reply = receiveOne(Duration.create(1000, "ms")) - assert(reply.isInstanceOf[FacilityTurret]) - assert(reply.asInstanceOf[FacilityTurret].HasGUID) - assert(reply.asInstanceOf[FacilityTurret].GUID == PlanetSideGUID(1)) - assert(reply == hub(1).get) + val obj = ServerObjectBuilder(1, FacilityTurret.Constructor(manned_turret)).Build(context, hub) + assert(obj.isInstanceOf[FacilityTurret]) + assert(obj.HasGUID) + assert(obj.GUID == PlanetSideGUID(1)) + assert(obj == hub(1).get) } } } object ServerObjectBuilderTest { - import net.psforever.objects.guid.source.LimitedNumberSource + import net.psforever.objects.guid.source.MaxNumberSource def NumberPoolHub: NumberPoolHub = { - val obj = new NumberPoolHub(new LimitedNumberSource(2)) + val obj = new NumberPoolHub(new MaxNumberSource(2)) obj } - - class BuilderTestActor(builder: ServerObjectBuilder[_], hub: NumberPoolHub) extends Actor { - def receive: Receive = { - case _ => - sender() ! builder.Build(context, hub) - } - } - - class BuildingTestActor( - structure_con: (String, Int, Int, Zone, ActorContext) => Building, - name: String, - building_guid: Int, - map_id: Int, - zone: Zone - ) extends Actor { - def receive: Receive = { - case _ => - sender() ! FoundationBuilder(structure_con).Build(name, building_guid, map_id, zone)(context) - } - } } diff --git a/src/test/scala/objects/VehicleTest.scala b/src/test/scala/objects/VehicleTest.scala index 7bd0fbf7..a0de397a 100644 --- a/src/test/scala/objects/VehicleTest.scala +++ b/src/test/scala/objects/VehicleTest.scala @@ -7,7 +7,7 @@ import base.{ActorTest, FreedContextActorTest} import net.psforever.objects._ import net.psforever.objects.definition.{SeatDefinition, VehicleDefinition} import net.psforever.objects.guid.NumberPoolHub -import net.psforever.objects.guid.source.LimitedNumberSource +import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.vehicles._ import net.psforever.objects.vital.VehicleShieldCharge @@ -408,7 +408,7 @@ class VehicleControlPrepareForDeletionPassengerTest extends ActorTest { class VehicleControlPrepareForDeletionMountedInTest extends FreedContextActorTest { ServiceManager.boot - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val zone = new Zone("test", new ZoneMap("test"), 0) { GUID(guid) @@ -534,7 +534,7 @@ class VehicleControlPrepareForDeletionMountedInTest extends FreedContextActorTes } class VehicleControlPrepareForDeletionMountedCargoTest extends FreedContextActorTest { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) ServiceManager.boot val zone = new Zone("test", new ZoneMap("test"), 0) { GUID(guid) diff --git a/src/test/scala/objects/ZoneTest.scala b/src/test/scala/objects/ZoneTest.scala index 7ac0988e..059a609d 100644 --- a/src/test/scala/objects/ZoneTest.scala +++ b/src/test/scala/objects/ZoneTest.scala @@ -7,7 +7,7 @@ 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.LimitedNumberSource +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._ @@ -104,7 +104,7 @@ class ZoneTest extends Specification { "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 LimitedNumberSource(100)) + 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) @@ -114,7 +114,7 @@ class ZoneTest extends Specification { registration.isSuccess mustEqual true guid1.WhichPool(obj).contains("pool2") mustEqual true - zone.GUID(new NumberPoolHub(new LimitedNumberSource(150))) mustEqual false + zone.GUID(new NumberPoolHub(new MaxNumberSource(150))) mustEqual false } } } @@ -123,7 +123,7 @@ class ZoneActorTest extends ActorTest { "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 LimitedNumberSource(40150))) + zone.GUID(new NumberPoolHub(new MaxNumberSource(40150))) zone.actor = system.spawn(ZoneActor(zone), "test-add-pool-actor-init") expectNoMessage(Duration.create(500, "ms")) @@ -133,7 +133,7 @@ class ZoneActorTest extends ActorTest { "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 LimitedNumberSource(10))) + 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")) @@ -482,7 +482,7 @@ class ZonePopulationTest extends ActorTest { class ZoneGroundDropItemTest extends ActorTest { val item = AmmoBox(GlobalDefinitions.bullet_9mm) - val hub = new NumberPoolHub(new LimitedNumberSource(20)) + 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) @@ -507,7 +507,7 @@ class ZoneGroundDropItemTest extends ActorTest { class ZoneGroundCanNotDropItem1Test extends ActorTest { val item = AmmoBox(GlobalDefinitions.bullet_9mm) - val hub = new NumberPoolHub(new LimitedNumberSource(20)) + 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) @@ -532,7 +532,7 @@ class ZoneGroundCanNotDropItem1Test extends ActorTest { class ZoneGroundCanNotDropItem2Test extends ActorTest { val item = AmmoBox(GlobalDefinitions.bullet_9mm) - val hub = new NumberPoolHub(new LimitedNumberSource(20)) + 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 @@ -557,7 +557,7 @@ class ZoneGroundCanNotDropItem2Test extends ActorTest { class ZoneGroundCanNotDropItem3Test extends ActorTest { val item = AmmoBox(GlobalDefinitions.bullet_9mm) - val hub = new NumberPoolHub(new LimitedNumberSource(20)) + 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 @@ -590,7 +590,7 @@ class ZoneGroundCanNotDropItem3Test extends ActorTest { class ZoneGroundPickupItemTest extends ActorTest { val item = AmmoBox(GlobalDefinitions.bullet_9mm) - val hub = new NumberPoolHub(new LimitedNumberSource(20)) + 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) @@ -618,7 +618,7 @@ class ZoneGroundPickupItemTest extends ActorTest { class ZoneGroundCanNotPickupItemTest extends ActorTest { val item = AmmoBox(GlobalDefinitions.bullet_9mm) - val hub = new NumberPoolHub(new LimitedNumberSource(20)) + 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 @@ -642,7 +642,7 @@ class ZoneGroundCanNotPickupItemTest extends ActorTest { class ZoneGroundRemoveItemTest extends ActorTest { val item = AmmoBox(GlobalDefinitions.bullet_9mm) - val hub = new NumberPoolHub(new LimitedNumberSource(20)) + 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 diff --git a/src/test/scala/objects/guidtask/GUIDTaskRegisterAvatarTest.scala b/src/test/scala/objects/guidtask/GUIDTaskRegisterAvatarTest.scala index a1142a88..d791a6b8 100644 --- a/src/test/scala/objects/guidtask/GUIDTaskRegisterAvatarTest.scala +++ b/src/test/scala/objects/guidtask/GUIDTaskRegisterAvatarTest.scala @@ -5,6 +5,7 @@ import base.ActorTest import net.psforever.objects._ import net.psforever.objects.avatar.Avatar import net.psforever.objects.guid.{GUIDTask, TaskResolver} +import net.psforever.objects.locker.LockerEquipment import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire} class GUIDTaskRegisterAvatarTest extends ActorTest { @@ -26,7 +27,7 @@ class GUIDTaskRegisterAvatarTest extends ActorTest { assert(!obj_wep_ammo.HasGUID) assert(!obj_inv_ammo.HasGUID) assert(!obj_locker.HasGUID) - assert(!obj_locker_ammo.HasGUID) + assert(obj_locker_ammo.HasGUID) taskResolver ! TaskResolver.GiveTask( new GUIDTaskTest.RegisterTestTask(probe.ref), List(GUIDTask.RegisterAvatar(obj)(uns)) diff --git a/src/test/scala/objects/guidtask/GUIDTaskRegisterPlayerTest.scala b/src/test/scala/objects/guidtask/GUIDTaskRegisterPlayerTest.scala index 2577b490..53ad4752 100644 --- a/src/test/scala/objects/guidtask/GUIDTaskRegisterPlayerTest.scala +++ b/src/test/scala/objects/guidtask/GUIDTaskRegisterPlayerTest.scala @@ -5,6 +5,7 @@ import base.ActorTest import net.psforever.objects._ import net.psforever.objects.avatar.Avatar import net.psforever.objects.guid.{GUIDTask, TaskResolver} +import net.psforever.objects.locker.LockerEquipment import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire} class GUIDTaskRegisterPlayerTest extends ActorTest { @@ -26,7 +27,7 @@ class GUIDTaskRegisterPlayerTest extends ActorTest { assert(!obj_wep_ammo.HasGUID) assert(!obj_inv_ammo.HasGUID) assert(!obj_locker.HasGUID) - assert(!obj_locker_ammo.HasGUID) + assert(obj_locker_ammo.HasGUID) taskResolver ! TaskResolver.GiveTask( new GUIDTaskTest.RegisterTestTask(probe.ref), List(GUIDTask.RegisterPlayer(obj)(uns)) @@ -37,6 +38,6 @@ class GUIDTaskRegisterPlayerTest extends ActorTest { assert(obj_wep_ammo.HasGUID) assert(obj_inv_ammo.HasGUID) assert(!obj_locker.HasGUID) - assert(!obj_locker_ammo.HasGUID) + assert(obj_locker_ammo.HasGUID) } } diff --git a/src/test/scala/objects/guidtask/GUIDTaskTest.scala b/src/test/scala/objects/guidtask/GUIDTaskTest.scala index bd1fc8c8..935f91cd 100644 --- a/src/test/scala/objects/guidtask/GUIDTaskTest.scala +++ b/src/test/scala/objects/guidtask/GUIDTaskTest.scala @@ -8,7 +8,7 @@ import akka.testkit.TestProbe import net.psforever.objects.entity.IdentifiableEntity import net.psforever.objects.guid.actor.{NumberPoolActor, UniqueNumberSystem} import net.psforever.objects.guid.selector.RandomSelector -import net.psforever.objects.guid.source.LimitedNumberSource +import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.guid.{NumberPoolHub, Task, TaskResolver} object GUIDTaskTest { @@ -26,7 +26,7 @@ object GUIDTaskTest { import akka.routing.RandomPool import akka.testkit.TestProbe - val guid: NumberPoolHub = new NumberPoolHub(new LimitedNumberSource(110)) + val guid: NumberPoolHub = new NumberPoolHub(new MaxNumberSource(110)) guid.AddPool("dynamic", (1 to 100).toList).Selector = new RandomSelector //TODO name is hardcoded for now val uns = system.actorOf( RandomPool(25).props(Props(classOf[UniqueNumberSystem], guid, GUIDTaskTest.AllocateNumberPoolActors(guid))), diff --git a/src/test/scala/objects/guidtask/GUIDTaskUnregisterAvatarTest.scala b/src/test/scala/objects/guidtask/GUIDTaskUnregisterAvatarTest.scala index e6ea5c1a..aff46a39 100644 --- a/src/test/scala/objects/guidtask/GUIDTaskUnregisterAvatarTest.scala +++ b/src/test/scala/objects/guidtask/GUIDTaskUnregisterAvatarTest.scala @@ -5,6 +5,7 @@ import base.ActorTest import net.psforever.objects._ import net.psforever.objects.avatar.Avatar import net.psforever.objects.guid.{GUIDTask, TaskResolver} +import net.psforever.objects.locker.LockerEquipment import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire} class GUIDTaskUnregisterAvatarTest extends ActorTest { @@ -43,6 +44,6 @@ class GUIDTaskUnregisterAvatarTest extends ActorTest { assert(!obj_wep_ammo.HasGUID) assert(!obj_inv_ammo.HasGUID) assert(!obj_locker.HasGUID) - assert(!obj_locker_ammo.HasGUID) + assert(obj_locker_ammo.HasGUID) } } diff --git a/src/test/scala/objects/guidtask/GUIDTaskUnregisterPlayerTest.scala b/src/test/scala/objects/guidtask/GUIDTaskUnregisterPlayerTest.scala index 6e1d2132..4c62dc0b 100644 --- a/src/test/scala/objects/guidtask/GUIDTaskUnregisterPlayerTest.scala +++ b/src/test/scala/objects/guidtask/GUIDTaskUnregisterPlayerTest.scala @@ -5,6 +5,7 @@ import base.ActorTest import net.psforever.objects._ import net.psforever.objects.avatar.Avatar import net.psforever.objects.guid.{GUIDTask, TaskResolver} +import net.psforever.objects.locker.LockerEquipment import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire} class GUIDTaskUnregisterPlayerTest extends ActorTest { diff --git a/src/test/scala/objects/number/NumberPoolHubTest.scala b/src/test/scala/objects/number/NumberPoolHubTest.scala index f2f38588..6266f214 100644 --- a/src/test/scala/objects/number/NumberPoolHubTest.scala +++ b/src/test/scala/objects/number/NumberPoolHubTest.scala @@ -4,7 +4,7 @@ package objects.number import net.psforever.objects.entity.IdentifiableEntity import net.psforever.objects.guid.NumberPoolHub import net.psforever.objects.guid.selector.RandomSelector -import net.psforever.objects.guid.source.LimitedNumberSource +import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.types.PlanetSideGUID import org.specs2.mutable.Specification @@ -20,17 +20,17 @@ class NumberPoolHubTest extends Specification { "NumberPoolHub" should { "construct" in { - new NumberPoolHub(new LimitedNumberSource(51)) + new NumberPoolHub(new MaxNumberSource(51)) ok } "get a pool" in { - val obj = new NumberPoolHub(new LimitedNumberSource(51)) + val obj = new NumberPoolHub(new MaxNumberSource(51)) obj.GetPool("generic").isDefined mustEqual true //default pool } "add a pool" in { - val obj = new NumberPoolHub(new LimitedNumberSource(51)) + val obj = new NumberPoolHub(new MaxNumberSource(51)) obj.Numbers.isEmpty mustEqual true obj.AddPool("fibonacci", numberList) obj.Numbers.toSet.equals(numberList.toSet) mustEqual true @@ -40,7 +40,7 @@ class NumberPoolHubTest extends Specification { } "enumerate the content of all pools" in { - val obj = new NumberPoolHub(new LimitedNumberSource(51)) + val obj = new NumberPoolHub(new MaxNumberSource(51)) obj.AddPool("fibonacci1", numberList1) obj.AddPool("fibonacci2", numberList2) numberSet1.intersect(obj.Numbers.toSet) mustEqual numberSet1 @@ -49,7 +49,7 @@ class NumberPoolHubTest extends Specification { } "remove a pool" in { - val obj = new NumberPoolHub(new LimitedNumberSource(51)) + val obj = new NumberPoolHub(new MaxNumberSource(51)) obj.Numbers.isEmpty mustEqual true obj.AddPool("fibonacci", numberList) obj.Numbers.toSet.equals(numberList.toSet) mustEqual true @@ -59,19 +59,19 @@ class NumberPoolHubTest extends Specification { } "block removing the default 'generic' pool" in { - val obj = new NumberPoolHub(new LimitedNumberSource(51)) + val obj = new NumberPoolHub(new MaxNumberSource(51)) obj.RemovePool("generic") must throwA[IllegalArgumentException] } "block adding pools that use already-included numbers" in { - val obj = new NumberPoolHub(new LimitedNumberSource(51)) + val obj = new NumberPoolHub(new MaxNumberSource(51)) obj.AddPool("fibonacci1", numberList) val numberList4 = 3 :: 7 :: 21 :: 34 :: 45 :: Nil obj.AddPool("fibonacci2", numberList4) must throwA[IllegalArgumentException] } "enumerate only the content of all current pools" in { - val obj = new NumberPoolHub(new LimitedNumberSource(51)) + val obj = new NumberPoolHub(new MaxNumberSource(51)) obj.AddPool("fibonacci1", numberList1) obj.AddPool("fibonacci2", numberList2) numberSet1.intersect(obj.Numbers.toSet) mustEqual numberSet1 @@ -82,7 +82,7 @@ class NumberPoolHubTest extends Specification { } "register an object to a pool" in { - val hub = new NumberPoolHub(new LimitedNumberSource(51)) + val hub = new NumberPoolHub(new MaxNumberSource(51)) hub.AddPool("fibonacci", numberList) val obj = new EntityTestClass() obj.GUID must throwA[Exception] @@ -95,7 +95,7 @@ class NumberPoolHubTest extends Specification { } "lookup a registered object" in { - val hub = new NumberPoolHub(new LimitedNumberSource(51)) + val hub = new NumberPoolHub(new MaxNumberSource(51)) hub.AddPool("fibonacci", numberList) val obj = new EntityTestClass() hub.register(obj, "fibonacci") match { @@ -108,14 +108,14 @@ class NumberPoolHubTest extends Specification { } "lookup the pool of a(n unassigned) number" in { - val hub = new NumberPoolHub(new LimitedNumberSource(51)) + val hub = new NumberPoolHub(new MaxNumberSource(51)) hub.AddPool("fibonacci1", numberList1) hub.AddPool("fibonacci2", numberList2) hub.WhichPool(13).contains("fibonacci2") mustEqual true } "lookup the pool of a registered object" in { - val hub = new NumberPoolHub(new LimitedNumberSource(51)) + val hub = new NumberPoolHub(new MaxNumberSource(51)) hub.AddPool("fibonacci", numberList1) val obj = new EntityTestClass() hub.register(obj, "fibonacci") @@ -123,7 +123,7 @@ class NumberPoolHubTest extends Specification { } "register an object to a specific, unused number; it is assigned to pool 'generic'" in { - val hub = new NumberPoolHub(new LimitedNumberSource(51)) + val hub = new NumberPoolHub(new MaxNumberSource(51)) hub.AddPool("fibonacci", numberList1) val obj = new EntityTestClass() obj.GUID must throwA[Exception] @@ -137,7 +137,7 @@ class NumberPoolHubTest extends Specification { } "register an object to a specific, pooled number (list 1)" in { - val src = new LimitedNumberSource(51) + val src = new MaxNumberSource(51) val hub = new NumberPoolHub(src) hub.AddPool("fibonacci", numberList) val obj = new EntityTestClass() @@ -146,14 +146,14 @@ class NumberPoolHubTest extends Specification { case Success(number) => obj.GUID mustEqual PlanetSideGUID(number) hub.WhichPool(obj).contains("fibonacci") mustEqual true - src.Available(5).isEmpty mustEqual true + src.getAvailable(5).isEmpty mustEqual true case _ => ko } } "register an object to a specific, pooled number (list 2)" in { - val src = new LimitedNumberSource(51) + val src = new MaxNumberSource(51) val hub = new NumberPoolHub(src) hub.AddPool("fibonacci", numberList2) val obj = new EntityTestClass() @@ -162,21 +162,21 @@ class NumberPoolHubTest extends Specification { case Success(number) => obj.GUID mustEqual PlanetSideGUID(number) hub.WhichPool(obj).contains("fibonacci") mustEqual true - src.Available(13).isEmpty mustEqual true + src.getAvailable(13).isEmpty mustEqual true case _ => ko } } "register an object without extra specifications; it is assigned to pool 'generic'" in { - val hub = new NumberPoolHub(new LimitedNumberSource(51)) + val hub = new NumberPoolHub(new MaxNumberSource(51)) val obj = new EntityTestClass() hub.register(obj) hub.WhichPool(obj).contains("generic") mustEqual true } "unregister an object" in { - val hub = new NumberPoolHub(new LimitedNumberSource(51)) + val hub = new NumberPoolHub(new MaxNumberSource(51)) hub.AddPool("fibonacci", numberList) val obj = new EntityTestClass() obj.HasGUID mustEqual false @@ -190,7 +190,7 @@ class NumberPoolHubTest extends Specification { } "not register an object to a different pool" in { - val hub = new NumberPoolHub(new LimitedNumberSource(51)) + val hub = new NumberPoolHub(new MaxNumberSource(51)) hub.AddPool("fibonacci1", numberList1) hub.AddPool("fibonacci2", numberList2) val obj = new EntityTestClass() @@ -200,17 +200,17 @@ class NumberPoolHubTest extends Specification { } "fail to unregister an object that is not registered to this hub" in { - val hub1 = new NumberPoolHub(new LimitedNumberSource(51)) - val hub2 = new NumberPoolHub(new LimitedNumberSource(51)) + val hub1 = new NumberPoolHub(new MaxNumberSource(51)) + val hub2 = new NumberPoolHub(new MaxNumberSource(51)) hub1.AddPool("fibonacci", numberList) hub2.AddPool("fibonacci", numberList) val obj = new EntityTestClass() hub1.register(obj, "fibonacci") - hub2.unregister(obj) must throwA[Exception] + hub2.unregister(obj).isFailure mustEqual true } "pre-register a specific, unused number" in { - val hub = new NumberPoolHub(new LimitedNumberSource(51)) + val hub = new NumberPoolHub(new MaxNumberSource(51)) hub.register(13) match { case Success(_) => ok @@ -220,7 +220,7 @@ class NumberPoolHubTest extends Specification { } "pre-register a specific, pooled number" in { - val hub = new NumberPoolHub(new LimitedNumberSource(51)) + val hub = new NumberPoolHub(new MaxNumberSource(51)) hub.AddPool("fibonacci", numberList) hub.register(13) match { case Success(key) => @@ -231,7 +231,7 @@ class NumberPoolHubTest extends Specification { } "pre-register a number from a known pool" in { - val hub = new NumberPoolHub(new LimitedNumberSource(51)) + val hub = new NumberPoolHub(new MaxNumberSource(51)) hub.AddPool("fibonacci", numberList).Selector = new RandomSelector hub.register("fibonacci") match { case Success(key) => @@ -242,7 +242,7 @@ class NumberPoolHubTest extends Specification { } "unregister a number" in { - val hub = new NumberPoolHub(new LimitedNumberSource(51)) + val hub = new NumberPoolHub(new MaxNumberSource(51)) hub.AddPool("fibonacci", numberList).Selector = new RandomSelector //leave this tagged on val obj = new EntityTestClass() hub.register(13) match { @@ -263,48 +263,48 @@ class NumberPoolHubTest extends Specification { } "not affect the hidden restricted pool by adding a new pool" in { - val src = new LimitedNumberSource(51) - src.Restrict(4) - src.Restrict(8) //in fibonacci - src.Restrict(10) - src.Restrict(12) + val src = new MaxNumberSource(51) + src.restrictNumber(4) + src.restrictNumber(8) //in fibonacci + src.restrictNumber(10) + src.restrictNumber(12) val hub = new NumberPoolHub(src) hub.AddPool("fibonacci", numberList) must throwA[IllegalArgumentException] } "not register an object to a number belonging to the restricted pool" in { - val src = new LimitedNumberSource(51) - src.Restrict(4) + val src = new MaxNumberSource(51) + src.restrictNumber(4) val hub = new NumberPoolHub(src) val obj = new EntityTestClass() hub.register(obj, 4).isFailure mustEqual true } "not register an object to the restricted pool directly" in { - val src = new LimitedNumberSource(51) -// src.Restrict(4) + val src = new MaxNumberSource(51) +// src.restrictNumber(4) val hub = new NumberPoolHub(src) val obj = new EntityTestClass() hub.register(obj, "").isFailure mustEqual true //the empty string represents the restricted pool } "not register a number belonging to the restricted pool" in { - val src = new LimitedNumberSource(51) - src.Restrict(4) + val src = new MaxNumberSource(51) + src.restrictNumber(4) val hub = new NumberPoolHub(src) hub.register(4).isFailure mustEqual true } "not unregister a number belonging to the restricted pool" in { - val src = new LimitedNumberSource(51) - src.Restrict(4) + val src = new MaxNumberSource(51) + src.restrictNumber(4) val hub = new NumberPoolHub(src) hub.unregister(4).isFailure mustEqual true } "identity an object that is registered to it" in { - val hub1 = new NumberPoolHub(new LimitedNumberSource(10)) - val hub2 = new NumberPoolHub(new LimitedNumberSource(10)) + val hub1 = new NumberPoolHub(new MaxNumberSource(10)) + val hub2 = new NumberPoolHub(new MaxNumberSource(10)) val obj1 = new EntityTestClass() val obj2 = new EntityTestClass() hub1.register(obj1) @@ -317,15 +317,15 @@ class NumberPoolHubTest extends Specification { } "identity a number that is registered to it" in { - val src1 = new LimitedNumberSource(5) + val src1 = new MaxNumberSource(5) val hub1 = new NumberPoolHub(src1) - val src2 = new LimitedNumberSource(10) - src2.Restrict(0) - src2.Restrict(1) - src2.Restrict(2) - src2.Restrict(3) - src2.Restrict(4) - src2.Restrict(5) + val src2 = new MaxNumberSource(10) + src2.restrictNumber(0) + src2.restrictNumber(1) + src2.restrictNumber(2) + src2.restrictNumber(3) + src2.restrictNumber(4) + src2.restrictNumber(5) val hub2 = new NumberPoolHub(src2) val obj1 = new EntityTestClass() val obj2 = new EntityTestClass() diff --git a/src/test/scala/objects/number/NumberSourceTest.scala b/src/test/scala/objects/number/NumberSourceTest.scala index 4601cfb7..e69f0442 100644 --- a/src/test/scala/objects/number/NumberSourceTest.scala +++ b/src/test/scala/objects/number/NumberSourceTest.scala @@ -10,62 +10,71 @@ class NumberSourceTest extends Specification { import net.psforever.objects.entity.IdentifiableEntity private class TestClass extends IdentifiableEntity - "LimitedNumberSource" should { - import net.psforever.objects.guid.source.LimitedNumberSource + "MaxNumberSource" should { + import net.psforever.objects.guid.source.MaxNumberSource "construct" in { - val obj = LimitedNumberSource(25) - obj.Size mustEqual 26 - obj.CountAvailable mustEqual 26 - obj.CountUsed mustEqual 0 + val obj = MaxNumberSource(25) + obj.size mustEqual 26 + obj.countAvailable mustEqual 26 + obj.countUsed mustEqual 0 } - "get a number" in { - val obj = LimitedNumberSource(25) - val result: Option[LoanedKey] = obj.Available(5) + "construct failure (negative max value)" in { + MaxNumberSource(-1) must throwA[IllegalArgumentException] + } + + "get any number (failure)" in { + val obj = MaxNumberSource(25) + obj.getAvailable(number = 50).isDefined mustEqual false + } + + "get a valid number" in { + val obj = MaxNumberSource(25) + val result: Option[LoanedKey] = obj.getAvailable(5) result.isDefined mustEqual true result.get.GUID mustEqual 5 result.get.Policy mustEqual AvailabilityPolicy.Leased result.get.Object.isEmpty mustEqual true - obj.Size mustEqual 26 - obj.CountAvailable mustEqual 25 - obj.CountUsed mustEqual 1 + obj.size mustEqual 26 + obj.countAvailable mustEqual 25 + obj.countUsed mustEqual 1 } "assign the number" in { - val obj = LimitedNumberSource(25) - val result: Option[LoanedKey] = obj.Available(5) + val obj = MaxNumberSource(25) + val result: Option[LoanedKey] = obj.getAvailable(5) result.isDefined mustEqual true result.get.Object = new TestClass() ok } "return a number (unused)" in { - val obj = LimitedNumberSource(25) - val result: Option[LoanedKey] = obj.Available(5) + val obj = MaxNumberSource(25) + val result: Option[LoanedKey] = obj.getAvailable(5) result.isDefined mustEqual true result.get.GUID mustEqual 5 - obj.CountUsed mustEqual 1 - val ret = obj.Return(result.get) + obj.countUsed mustEqual 1 + val ret = obj.returnNumber(result.get) ret.isEmpty mustEqual true - obj.CountUsed mustEqual 0 + obj.countUsed mustEqual 0 } "return a number (assigned)" in { - val obj = LimitedNumberSource(25) + val obj = MaxNumberSource(25) val test = new TestClass() - val result: Option[LoanedKey] = obj.Available(5) + val result: Option[LoanedKey] = obj.getAvailable(5) result.isDefined mustEqual true result.get.GUID mustEqual 5 result.get.Object = test - obj.CountUsed mustEqual 1 - val ret = obj.Return(result.get) + obj.countUsed mustEqual 1 + val ret = obj.returnNumber(result.get) ret.contains(test) mustEqual true - obj.CountUsed mustEqual 0 + obj.countUsed mustEqual 0 } "restrict a number (unassigned)" in { - val obj = LimitedNumberSource(25) - val result: Option[LoanedKey] = obj.Restrict(5) + val obj = MaxNumberSource(25) + val result: Option[LoanedKey] = obj.restrictNumber(5) result.isDefined mustEqual true result.get.GUID mustEqual 5 result.get.Policy mustEqual AvailabilityPolicy.Restricted @@ -73,10 +82,10 @@ class NumberSourceTest extends Specification { } "restrict a number (assigned + multiple assignments)" in { - val obj = LimitedNumberSource(25) + val obj = MaxNumberSource(25) val test1 = new TestClass() val test2 = new TestClass() - val result: Option[LoanedKey] = obj.Restrict(5) + val result: Option[LoanedKey] = obj.restrictNumber(5) result.get.GUID mustEqual 5 result.get.Policy mustEqual AvailabilityPolicy.Restricted result.get.Object.isEmpty mustEqual true @@ -89,108 +98,309 @@ class NumberSourceTest extends Specification { } "return a restricted number (correctly fail)" in { - val obj = LimitedNumberSource(25) + val obj = MaxNumberSource(25) val test = new TestClass() - val result: Option[LoanedKey] = obj.Restrict(5) + val result: Option[LoanedKey] = obj.restrictNumber(5) result.get.GUID mustEqual 5 result.get.Policy mustEqual AvailabilityPolicy.Restricted result.get.Object = test - obj.Return(5) - val result2: Option[SecureKey] = obj.Get(5) + obj.returnNumber(5) + val result2: Option[SecureKey] = obj.get(5) result2.get.GUID mustEqual 5 result2.get.Policy mustEqual AvailabilityPolicy.Restricted result2.get.Object.contains(test) mustEqual true } "return a secure key" in { - val obj = LimitedNumberSource(25) + val obj = MaxNumberSource(25) val test = new TestClass() - val result1: Option[LoanedKey] = obj.Available(5) + val result1: Option[LoanedKey] = obj.getAvailable(5) result1.get.Object = test test.GUID mustEqual PlanetSideGUID(5) - val result2: Option[SecureKey] = obj.Get(5) - obj.Return(result2.get).contains(test) mustEqual true + val result2: Option[SecureKey] = obj.get(5) + obj.returnNumber(result2.get).contains(test) mustEqual true } "restrict a previously-assigned number" in { - val obj = LimitedNumberSource(25) + val obj = MaxNumberSource(25) val test = new TestClass() - val result1: Option[LoanedKey] = obj.Available(5) + val result1: Option[LoanedKey] = obj.getAvailable(5) result1.isDefined mustEqual true result1.get.Policy mustEqual AvailabilityPolicy.Leased result1.get.Object = test - val result2: Option[LoanedKey] = obj.Restrict(5) + val result2: Option[LoanedKey] = obj.restrictNumber(5) result2.isDefined mustEqual true result2.get.Policy mustEqual AvailabilityPolicy.Restricted result2.get.Object.contains(test) mustEqual true } "check a number (not previously gotten)" in { - val obj = LimitedNumberSource(25) - val result2: Option[SecureKey] = obj.Get(5) + val obj = MaxNumberSource(25) + val result2: Option[SecureKey] = obj.get(5) result2.get.GUID mustEqual 5 result2.get.Policy mustEqual AvailabilityPolicy.Available result2.get.Object.isEmpty mustEqual true } "check a number (previously gotten)" in { - val obj = LimitedNumberSource(25) - val result: Option[LoanedKey] = obj.Available(5) + val obj = MaxNumberSource(25) + val result: Option[LoanedKey] = obj.getAvailable(5) result.isDefined mustEqual true result.get.GUID mustEqual 5 result.get.Policy mustEqual AvailabilityPolicy.Leased result.get.Object.isEmpty mustEqual true - val result2: Option[SecureKey] = obj.Get(5) + val result2: Option[SecureKey] = obj.get(5) result2.get.GUID mustEqual 5 result2.get.Policy mustEqual AvailabilityPolicy.Leased result2.get.Object.isEmpty mustEqual true } "check a number (assigned)" in { - val obj = LimitedNumberSource(25) - val result: Option[LoanedKey] = obj.Available(5) + val obj = MaxNumberSource(25) + val result: Option[LoanedKey] = obj.getAvailable(5) result.isDefined mustEqual true result.get.GUID mustEqual 5 result.get.Policy mustEqual AvailabilityPolicy.Leased result.get.Object = new TestClass() - val result2: Option[SecureKey] = obj.Get(5) + val result2: Option[SecureKey] = obj.get(5) result2.get.GUID mustEqual 5 result2.get.Policy mustEqual AvailabilityPolicy.Leased result2.get.Object mustEqual result.get.Object } "check a number (assigned and returned)" in { - val obj = LimitedNumberSource(25) + val obj = MaxNumberSource(25) val test = new TestClass() - val result: Option[LoanedKey] = obj.Available(5) + val result: Option[LoanedKey] = obj.getAvailable(5) result.get.Policy mustEqual AvailabilityPolicy.Leased result.get.Object = test - val result2: Option[SecureKey] = obj.Get(5) + val result2: Option[SecureKey] = obj.get(5) result2.get.Policy mustEqual AvailabilityPolicy.Leased result2.get.Object.get mustEqual test - obj.Return(5).contains(test) mustEqual true - val result3: Option[SecureKey] = obj.Get(5) + obj.returnNumber(5).contains(test) mustEqual true + val result3: Option[SecureKey] = obj.get(5) result3.get.Policy mustEqual AvailabilityPolicy.Available result3.get.Object.isEmpty mustEqual true } "clear" in { - val obj = LimitedNumberSource(25) + val obj = MaxNumberSource(25) val test1 = new TestClass() val test2 = new TestClass() val test3 = new TestClass() - obj.Available(5) //no assignment - obj.Available(10).get.Object = test1 - obj.Available(15).get.Object = test2 - obj.Restrict(15) - obj.Restrict(20).get.Object = test3 - obj.CountUsed mustEqual 4 + obj.getAvailable(5) //no assignment + obj.getAvailable(10).get.Object = test1 + obj.getAvailable(15).get.Object = test2 + obj.restrictNumber(15) + obj.restrictNumber(20).get.Object = test3 + obj.countUsed mustEqual 4 - val list: List[IdentifiableEntity] = obj.Clear() - obj.CountUsed mustEqual 0 + val list: List[IdentifiableEntity] = obj.clear() + obj.countUsed mustEqual 0 + list.size mustEqual 3 + list.count(obj => obj == test1) mustEqual 1 + list.count(obj => obj == test2) mustEqual 1 + list.count(obj => obj == test3) mustEqual 1 + } + } + + "SpecificNumberSource" should { + import net.psforever.objects.guid.source.SpecificNumberSource + "construct" in { + val obj = SpecificNumberSource(List(25)) + obj.size mustEqual 1 + obj.countAvailable mustEqual 1 + obj.countUsed mustEqual 0 + } + + "construct failure (no values)" in { + SpecificNumberSource(List()) must throwA[IllegalArgumentException] + } + + "construct failure (at least one value is negative)" in { + SpecificNumberSource(List(0, 1, -1, 2, 3)) must throwA[IllegalArgumentException] + } + + "get any number (failure)" in { + val obj = SpecificNumberSource(List(25)) + obj.getAvailable(number = 5).isDefined mustEqual false + } + + "get specific number (success)" in { + val obj = SpecificNumberSource(List(25)) + val result: Option[LoanedKey] = obj.getAvailable(25) + result.isDefined mustEqual true + result.get.GUID mustEqual 25 + result.get.Policy mustEqual AvailabilityPolicy.Leased + result.get.Object.isEmpty mustEqual true + obj.size mustEqual 1 + obj.countAvailable mustEqual 0 + obj.countUsed mustEqual 1 + } + + "assign the number" in { + val obj = SpecificNumberSource(List(25)) + val result: Option[LoanedKey] = obj.getAvailable(number = 25) + result.isDefined mustEqual true + result.get.Object = new TestClass() + ok + } + + "return a number (unused)" in { + val obj = SpecificNumberSource(List(25)) + val result: Option[LoanedKey] = obj.getAvailable(number = 25) + result.isDefined mustEqual true + result.get.GUID mustEqual 25 + obj.countUsed mustEqual 1 + val ret = obj.returnNumber(result.get) + ret.isEmpty mustEqual true + obj.countUsed mustEqual 0 + } + + "return a number (assigned)" in { + val obj = SpecificNumberSource(List(25)) + val test = new TestClass() + val result: Option[LoanedKey] = obj.getAvailable(number = 25) + result.isDefined mustEqual true + result.get.GUID mustEqual 25 + result.get.Object = test + obj.countUsed mustEqual 1 + val ret = obj.returnNumber(result.get) + ret.contains(test) mustEqual true + obj.countUsed mustEqual 0 + } + + "restrict a number (unassigned)" in { + val obj = SpecificNumberSource(List(25)) + val result: Option[LoanedKey] = obj.restrictNumber(number = 25) + result.isDefined mustEqual true + result.get.GUID mustEqual 25 + result.get.Policy mustEqual AvailabilityPolicy.Restricted + result.get.Object.isEmpty mustEqual true + } + + "restrict a number (assigned + multiple assignments)" in { + val obj = SpecificNumberSource(List(25, 26)) + val test1 = new TestClass() + val test2 = new TestClass() + val result: Option[LoanedKey] = obj.restrictNumber(number = 25) + result.get.GUID mustEqual 25 + result.get.Policy mustEqual AvailabilityPolicy.Restricted + result.get.Object.isEmpty mustEqual true + result.get.Object = None //assignment 1 + result.get.Object.isEmpty mustEqual true //still unassigned + result.get.Object = test1 //assignment 2 + result.get.Object.contains(test1) mustEqual true + result.get.Object = test2 //assignment 3 + result.get.Object.contains(test1) mustEqual true //same as above + } + + "return a restricted number (correctly fail)" in { + val obj = SpecificNumberSource(List(25)) + val test = new TestClass() + val result: Option[LoanedKey] = obj.restrictNumber(number = 25) + result.get.GUID mustEqual 25 + result.get.Policy mustEqual AvailabilityPolicy.Restricted + result.get.Object = test + + obj.returnNumber(number = 25) + val result2: Option[SecureKey] = obj.get(25) + result2.get.GUID mustEqual 25 + result2.get.Policy mustEqual AvailabilityPolicy.Restricted + result2.get.Object.contains(test) mustEqual true + } + + "return a secure key" in { + val obj = SpecificNumberSource(List(25)) + val test = new TestClass() + + val result1: Option[LoanedKey] = obj.getAvailable(number = 25) + result1.get.Object = test + test.GUID mustEqual PlanetSideGUID(25) + + val result2: Option[SecureKey] = obj.get(25) + obj.returnNumber(result2.get).contains(test) mustEqual true + } + + "restrict a previously-assigned number" in { + val obj = SpecificNumberSource(List(25)) + val test = new TestClass() + val result1: Option[LoanedKey] = obj.getAvailable(number = 25) + result1.isDefined mustEqual true + result1.get.Policy mustEqual AvailabilityPolicy.Leased + result1.get.Object = test + val result2: Option[LoanedKey] = obj.restrictNumber(number = 25) + result2.isDefined mustEqual true + result2.get.Policy mustEqual AvailabilityPolicy.Restricted + result2.get.Object.contains(test) mustEqual true + } + + "check a number (not previously gotten)" in { + val obj = SpecificNumberSource(List(25)) + val result2: Option[SecureKey] = obj.get(25) + result2.get.GUID mustEqual 25 + result2.get.Policy mustEqual AvailabilityPolicy.Available + result2.get.Object.isEmpty mustEqual true + } + + "check a number (previously gotten)" in { + val obj = SpecificNumberSource(List(25)) + val result: Option[LoanedKey] = obj.getAvailable(number = 25) + result.isDefined mustEqual true + result.get.GUID mustEqual 25 + result.get.Policy mustEqual AvailabilityPolicy.Leased + result.get.Object.isEmpty mustEqual true + val result2: Option[SecureKey] = obj.get(25) + result2.get.GUID mustEqual 25 + result2.get.Policy mustEqual AvailabilityPolicy.Leased + result2.get.Object.isEmpty mustEqual true + } + + "check a number (assigned)" in { + val obj = SpecificNumberSource(List(25)) + val result: Option[LoanedKey] = obj.getAvailable(number = 25) + result.isDefined mustEqual true + result.get.GUID mustEqual 25 + result.get.Policy mustEqual AvailabilityPolicy.Leased + result.get.Object = new TestClass() + val result2: Option[SecureKey] = obj.get(25) + result2.get.GUID mustEqual 25 + result2.get.Policy mustEqual AvailabilityPolicy.Leased + result2.get.Object mustEqual result.get.Object + } + + "check a number (assigned and returned)" in { + val obj = SpecificNumberSource(List(25)) + val test = new TestClass() + val result: Option[LoanedKey] = obj.getAvailable(number = 25) + result.get.Policy mustEqual AvailabilityPolicy.Leased + result.get.Object = test + val result2: Option[SecureKey] = obj.get(25) + result2.get.Policy mustEqual AvailabilityPolicy.Leased + result2.get.Object.get mustEqual test + obj.returnNumber(number = 25).contains(test) mustEqual true + val result3: Option[SecureKey] = obj.get(25) + result3.get.Policy mustEqual AvailabilityPolicy.Available + result3.get.Object.isEmpty mustEqual true + } + + "clear" in { + val obj = SpecificNumberSource(List(25, 26, 27, 28, 29, 30)) + val test1 = new TestClass() + val test2 = new TestClass() + val test3 = new TestClass() + obj.getAvailable(25) //no assignment + obj.getAvailable(26).get.Object = test1 + obj.getAvailable(28).get.Object = test2 + obj.restrictNumber(28) + obj.restrictNumber(30).get.Object = test3 + obj.countUsed mustEqual 4 + + val list: List[IdentifiableEntity] = obj.clear() + obj.countUsed mustEqual 0 list.size mustEqual 3 list.count(obj => obj == test1) mustEqual 1 list.count(obj => obj == test2) mustEqual 1 diff --git a/src/test/scala/objects/number/UniqueNumberSystemTest.scala b/src/test/scala/objects/number/UniqueNumberSystemTest.scala index bff5ab53..e26bc5a7 100644 --- a/src/test/scala/objects/number/UniqueNumberSystemTest.scala +++ b/src/test/scala/objects/number/UniqueNumberSystemTest.scala @@ -7,7 +7,7 @@ import net.psforever.objects.entity.IdentifiableEntity import net.psforever.objects.guid.NumberPoolHub import net.psforever.objects.guid.actor.{NumberPoolActor, Register, UniqueNumberSystem, Unregister} import net.psforever.objects.guid.selector.RandomSelector -import net.psforever.objects.guid.source.LimitedNumberSource +import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.types.PlanetSideGUID import scala.concurrent.duration._ @@ -15,7 +15,7 @@ import scala.util.{Failure, Success} class AllocateNumberPoolActors extends ActorTest { "AllocateNumberPoolActors" in { - val src: LimitedNumberSource = LimitedNumberSource(6000) + val src: MaxNumberSource = MaxNumberSource(6000) val guid: NumberPoolHub = new NumberPoolHub(src) guid.AddPool("pool1", (1001 to 2000).toList) guid.AddPool("pool2", (3001 to 4000).toList) @@ -32,7 +32,7 @@ class AllocateNumberPoolActors extends ActorTest { class UniqueNumberSystemTest extends ActorTest() { "UniqueNumberSystem" should { "constructor" in { - val src: LimitedNumberSource = LimitedNumberSource(6000) + val src: MaxNumberSource = MaxNumberSource(6000) val guid: NumberPoolHub = new NumberPoolHub(src) guid.AddPool("pool1", (1001 to 2000).toList) guid.AddPool("pool2", (3001 to 4000).toList) @@ -51,7 +51,7 @@ class UniqueNumberSystemTest1 extends ActorTest() { "UniqueNumberSystem" should { "Register (success)" in { - val src: LimitedNumberSource = LimitedNumberSource(6000) + val src: MaxNumberSource = MaxNumberSource(6000) val guid: NumberPoolHub = new NumberPoolHub(src) val pool1 = (1001 to 2000).toList val pool2 = (3001 to 4000).toList @@ -63,7 +63,7 @@ class UniqueNumberSystemTest1 extends ActorTest() { Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystemTest.AllocateNumberPoolActors(guid)), "uns" ) - assert(src.CountUsed == 0) + assert(src.countUsed == 0) //pool1 for (_ <- 1 to 100) { val testObj = new EntityTestClass() @@ -88,7 +88,7 @@ class UniqueNumberSystemTest1 extends ActorTest() { assert(msg.isInstanceOf[Success[_]]) assert(pool3.contains(testObj.GUID.guid)) } - assert(src.CountUsed == 300) + assert(src.countUsed == 300) } } } @@ -98,7 +98,7 @@ class UniqueNumberSystemTest2 extends ActorTest() { "UniqueNumberSystem" should { "Register (success; already registered)" in { - val src: LimitedNumberSource = LimitedNumberSource(6000) + val src: MaxNumberSource = MaxNumberSource(6000) val guid: NumberPoolHub = new NumberPoolHub(src) guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector @@ -109,20 +109,20 @@ class UniqueNumberSystemTest2 extends ActorTest() { ) val testObj = new EntityTestClass() assert(!testObj.HasGUID) - assert(src.CountUsed == 0) + assert(src.countUsed == 0) uns ! Register(testObj, "pool1") val msg1 = receiveOne(Duration.create(500, "ms")) assert(msg1.isInstanceOf[Success[_]]) assert(testObj.HasGUID) - assert(src.CountUsed == 1) + assert(src.countUsed == 1) val id = testObj.GUID.guid uns ! Register(testObj, "pool2") //different pool; makes no difference val msg2 = receiveOne(Duration.create(500, "ms")) assert(msg2.isInstanceOf[Success[_]]) assert(testObj.HasGUID) - assert(src.CountUsed == 1) + assert(src.countUsed == 1) assert(testObj.GUID.guid == id) //unchanged } } @@ -134,7 +134,7 @@ class UniqueNumberSystemTest3 extends ActorTest() { "UniqueNumberSystem" should { "Register (failure; no pool)" in { - val src: LimitedNumberSource = LimitedNumberSource(6000) + val src: MaxNumberSource = MaxNumberSource(6000) val guid: NumberPoolHub = new NumberPoolHub(src) guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector @@ -145,13 +145,13 @@ class UniqueNumberSystemTest3 extends ActorTest() { ) val testObj = new EntityTestClass() assert(!testObj.HasGUID) - assert(src.CountUsed == 0) + assert(src.countUsed == 0) uns ! Register(testObj, "pool4") val msg1 = receiveOne(Duration.create(500, "ms")) assert(msg1.isInstanceOf[Failure[_]]) assert(!testObj.HasGUID) - assert(src.CountUsed == 0) + assert(src.countUsed == 0) } } } @@ -161,7 +161,7 @@ class UniqueNumberSystemTest4 extends ActorTest() { "UniqueNumberSystem" should { "Register (failure; empty pool)" in { - val src: LimitedNumberSource = LimitedNumberSource(6000) + val src: MaxNumberSource = MaxNumberSource(6000) val guid: NumberPoolHub = new NumberPoolHub(src) guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector @@ -190,7 +190,7 @@ class UniqueNumberSystemTest5 extends ActorTest() { "UniqueNumberSystem" should { "Unregister (success)" in { - val src: LimitedNumberSource = LimitedNumberSource(6000) + val src: MaxNumberSource = MaxNumberSource(6000) val guid: NumberPoolHub = new NumberPoolHub(src) val pool2 = (3001 to 4000).toList guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector @@ -202,20 +202,20 @@ class UniqueNumberSystemTest5 extends ActorTest() { ) val testObj = new EntityTestClass() assert(!testObj.HasGUID) - assert(src.CountUsed == 0) + assert(src.countUsed == 0) uns ! Register(testObj, "pool2") val msg1 = receiveOne(Duration.create(2000, "ms")) assert(msg1.isInstanceOf[Success[_]]) assert(testObj.HasGUID) assert(pool2.contains(testObj.GUID.guid)) - assert(src.CountUsed == 1) + assert(src.countUsed == 1) uns ! Unregister(testObj) val msg2 = receiveOne(Duration.create(2000, "ms")) assert(msg2.isInstanceOf[Success[_]]) assert(!testObj.HasGUID) - assert(src.CountUsed == 0) + assert(src.countUsed == 0) } } } @@ -225,7 +225,7 @@ class UniqueNumberSystemTest6 extends ActorTest() { "UniqueNumberSystem" should { "Unregister (success; object not registered at all)" in { - val src: LimitedNumberSource = LimitedNumberSource(6000) + val src: MaxNumberSource = MaxNumberSource(6000) val guid: NumberPoolHub = new NumberPoolHub(src) guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector @@ -236,13 +236,13 @@ class UniqueNumberSystemTest6 extends ActorTest() { ) val testObj = new EntityTestClass() assert(!testObj.HasGUID) - assert(src.CountUsed == 0) + assert(src.countUsed == 0) uns ! Unregister(testObj) val msg1 = receiveOne(Duration.create(500, "ms")) assert(msg1.isInstanceOf[Success[_]]) assert(!testObj.HasGUID) - assert(src.CountUsed == 0) + assert(src.countUsed == 0) } } } @@ -252,7 +252,7 @@ class UniqueNumberSystemTest7 extends ActorTest() { "UniqueNumberSystem" should { "Unregister (failure; number not in system)" in { - val src: LimitedNumberSource = LimitedNumberSource(6000) + val src: MaxNumberSource = MaxNumberSource(6000) val guid: NumberPoolHub = new NumberPoolHub(src) guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector @@ -264,13 +264,13 @@ class UniqueNumberSystemTest7 extends ActorTest() { val testObj = new EntityTestClass() testObj.GUID = PlanetSideGUID(6001) //fake registering; number too high assert(testObj.HasGUID) - assert(src.CountUsed == 0) + assert(src.countUsed == 0) uns ! Unregister(testObj) val msg1 = receiveOne(Duration.create(500, "ms")) assert(msg1.isInstanceOf[Failure[_]]) assert(testObj.HasGUID) - assert(src.CountUsed == 0) + assert(src.countUsed == 0) } } } @@ -280,7 +280,7 @@ class UniqueNumberSystemTest8 extends ActorTest() { "UniqueNumberSystem" should { "Unregister (failure; object is not registered to that number)" in { - val src: LimitedNumberSource = LimitedNumberSource(6000) + val src: MaxNumberSource = MaxNumberSource(6000) val guid: NumberPoolHub = new NumberPoolHub(src) guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector @@ -292,13 +292,13 @@ class UniqueNumberSystemTest8 extends ActorTest() { val testObj = new EntityTestClass() testObj.GUID = PlanetSideGUID(3500) //fake registering assert(testObj.HasGUID) - assert(src.CountUsed == 0) + assert(src.countUsed == 0) uns ! Unregister(testObj) val msg1 = receiveOne(Duration.create(500, "ms")) assert(msg1.isInstanceOf[Failure[_]]) assert(testObj.HasGUID) - assert(src.CountUsed == 0) + assert(src.countUsed == 0) } } } @@ -308,7 +308,7 @@ class UniqueNumberSystemTest9 extends ActorTest() { "UniqueNumberSystem" should { "Failures (manually walking the failure cases)" in { - val src: LimitedNumberSource = LimitedNumberSource(6000) + val src: MaxNumberSource = MaxNumberSource(6000) val guid: NumberPoolHub = new NumberPoolHub(src) guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector @@ -345,7 +345,7 @@ class UniqueNumberSystemTestA extends ActorTest { "UniqueNumberSystem" should { "remain consistent between registrations" in { - val src: LimitedNumberSource = LimitedNumberSource(10) + val src: MaxNumberSource = MaxNumberSource(10) val guid: NumberPoolHub = new NumberPoolHub(src) guid.AddPool("pool1", (0 until 10).toList).Selector = new RandomSelector val uns = system.actorOf( @@ -354,9 +354,9 @@ class UniqueNumberSystemTestA extends ActorTest { ) expectNoMessage(Duration.create(200, "ms")) - assert(src.CountUsed == 0) + assert(src.countUsed == 0) (0 to 4).foreach(i => { assert(guid.register(new EntityTestClass(), i).isSuccess) }) - assert(src.CountUsed == 5) + assert(src.countUsed == 5) (0 to 5).foreach(_ => { uns ! Register(new EntityTestClass(), "pool1") }) assert(receiveOne(200 milliseconds).isInstanceOf[Success[_]]) //6th @@ -365,7 +365,7 @@ class UniqueNumberSystemTestA extends ActorTest { assert(receiveOne(200 milliseconds).isInstanceOf[Success[_]]) //9th assert(receiveOne(200 milliseconds).isInstanceOf[Success[_]]) //10th assert(receiveOne(200 milliseconds).isInstanceOf[Failure[_]]) //no more - assert(src.CountUsed == 10) + assert(src.countUsed == 10) } } } diff --git a/src/test/scala/objects/terminal/ImplantTerminalMechTest.scala b/src/test/scala/objects/terminal/ImplantTerminalMechTest.scala index 15c48ca2..0b39042f 100644 --- a/src/test/scala/objects/terminal/ImplantTerminalMechTest.scala +++ b/src/test/scala/objects/terminal/ImplantTerminalMechTest.scala @@ -7,7 +7,7 @@ import net.psforever.objects.avatar.Avatar import net.psforever.objects.{Default, GlobalDefinitions, Player} import net.psforever.objects.definition.SeatDefinition import net.psforever.objects.guid.NumberPoolHub -import net.psforever.objects.guid.source.LimitedNumberSource +import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.serverobject.implantmech.{ImplantTerminalMech, ImplantTerminalMechControl} import net.psforever.objects.serverobject.structures.{Building, StructureType} @@ -162,7 +162,7 @@ class ImplantTerminalMechControl5Test extends ActorTest { object ImplantTerminalMechTest { def SetUpAgents(faction: PlanetSideEmpire.Value)(implicit system: ActorSystem): (Player, ImplantTerminalMech) = { - val guid = new NumberPoolHub(new LimitedNumberSource(10)) + val guid = new NumberPoolHub(new MaxNumberSource(10)) val map = new ZoneMap("test") val zone = new Zone("test", map, 0) { override def SetupNumberPools() = {}