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() = {}