Lightweight Locker (#578)

* object registration adjustments for players and avatars and lockers (especially lockers)

* refactored locker container

* modifications to fields and method names for guid-related files; SpecificNumberSource created

* locker item display; proper item insertion into locker-space and searchability of that locker-space

* proper item removal from locker-space, including swap-items on other insertion tasks

* comments and tests; adjusted avatar/player registrations; allowed for restriction in the SpecificNumberSource; renamed CataloguedInventory to LocallyRegisteredInventory, and made internal object registration work

* accommodations for RequestDestroy, to allow the locker's Clear button to work; modification of expectation for resolving projectiles through ValidObject
This commit is contained in:
Fate-JH 2020-09-15 19:46:56 -04:00 committed by GitHub
parent 8245d3ff1e
commit 7626c8e6c9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
55 changed files with 1743 additions and 948 deletions

View file

@ -213,7 +213,7 @@ object VehicleSpawnPadControlTest {
faction: PlanetSideEmpire.Value faction: PlanetSideEmpire.Value
)(implicit system: ActorSystem): (Vehicle, Player, VehicleSpawnPad, Zone) = { )(implicit system: ActorSystem): (Vehicle, Player, VehicleSpawnPad, Zone) = {
import net.psforever.objects.guid.NumberPoolHub 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.serverobject.structures.Building
import net.psforever.objects.vehicles.VehicleControl import net.psforever.objects.vehicles.VehicleControl
import net.psforever.objects.Tool import net.psforever.objects.Tool
@ -221,7 +221,7 @@ object VehicleSpawnPadControlTest {
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy) val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
val weapon = vehicle.WeaponControlledFromSeat(1).get.asInstanceOf[Tool] 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.AddPool("test-pool", (0 to 5).toList)
guid.register(vehicle, "test-pool") guid.register(vehicle, "test-pool")
guid.register(weapon, "test-pool") guid.register(weapon, "test-pool")

View file

@ -17,7 +17,7 @@ import scala.concurrent.duration._
import akka.actor.typed.scaladsl.adapter._ import akka.actor.typed.scaladsl.adapter._
import net.psforever.actors.zone.ZoneActor import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.avatar.Avatar import net.psforever.objects.avatar.Avatar
import net.psforever.objects.guid.source.LimitedNumberSource import net.psforever.objects.guid.source.MaxNumberSource
class AvatarService1Test extends ActorTest { class AvatarService1Test extends ActorTest {
"AvatarService" should { "AvatarService" should {
@ -512,7 +512,7 @@ class AvatarReleaseTest extends ActorTest {
val zone = new Zone("test", new ZoneMap("test-map"), 0) { val zone = new Zone("test", new ZoneMap("test-map"), 0) {
override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } 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) zone.GUID(guid1)
val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service") val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service")
zone.actor = system.spawn(ZoneActor(zone), "release-test-zone") 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) { val zone = new Zone("test", new ZoneMap("test-map"), 0) {
override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } 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) zone.GUID(guid1)
val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service") val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service")
zone.actor = system.spawn(ZoneActor(zone), "release-test-zone") 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) { val zone = new Zone("test", new ZoneMap("test-map"), 0) {
override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } 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) zone.GUID(guid1)
val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service") val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service")
zone.actor = system.spawn(ZoneActor(zone), "release-test-zone") zone.actor = system.spawn(ZoneActor(zone), "release-test-zone")

View file

@ -8,8 +8,11 @@ import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware}
import akka.pattern.ask import akka.pattern.ask
import akka.util.Timeout import akka.util.Timeout
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import MDCContextAware.Implicits._ import MDCContextAware.Implicits._
import net.psforever.objects.locker.LockerContainer
import org.log4s.MDC import org.log4s.MDC
import scala.collection.mutable import scala.collection.mutable
import scala.concurrent.{Await, Future} import scala.concurrent.{Await, Future}
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -359,13 +362,29 @@ class SessionActor extends Actor with MDCContextAware {
def ValidObject(id: Option[PlanetSideGUID]): Option[PlanetSideGameObject] = def ValidObject(id: Option[PlanetSideGUID]): Option[PlanetSideGameObject] =
continent.GUID(id) match { 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 => case out @ Some(obj) if obj.HasGUID =>
out out
case None if id.nonEmpty && id.get != PlanetSideGUID(0) => case None if id.nonEmpty && id.get != PlanetSideGUID(0) =>
//delete stale entity reference from client //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)) sendResponse(ObjectDeleteMessage(id.get, 0))
None None
case _ => case _ =>
None None
} }
@ -1893,7 +1912,7 @@ class SessionActor extends Actor with MDCContextAware {
continent.GUID(mount) match { continent.GUID(mount) match {
case Some(obj: Vehicle) => case Some(obj: Vehicle) =>
TotalDriverVehicleControl(obj) TotalDriverVehicleControl(obj)
UnAccessContents(obj) UnaccessContainer(obj)
case _ => ; case _ => ;
} }
PlayerActionsToCancel() PlayerActionsToCancel()
@ -2480,7 +2499,7 @@ class SessionActor extends Actor with MDCContextAware {
// the player will receive no messages consistently except the KeepAliveMessage echo // the player will receive no messages consistently except the KeepAliveMessage echo
keepAliveFunc = KeepAlivePersistence keepAliveFunc = KeepAlivePersistence
} }
AccessContents(obj) AccessContainer(obj)
UpdateWeaponAtSeatPosition(obj, seat_num) UpdateWeaponAtSeatPosition(obj, seat_num)
MountingAction(tplayer, obj, seat_num) MountingAction(tplayer, obj, seat_num)
@ -2516,7 +2535,7 @@ class SessionActor extends Actor with MDCContextAware {
DismountAction(tplayer, obj, seat_num) DismountAction(tplayer, obj, seat_num)
case Mountable.CanDismount(obj: Vehicle, seat_num) if obj.Definition == GlobalDefinitions.droppod => case Mountable.CanDismount(obj: Vehicle, seat_num) if obj.Definition == GlobalDefinitions.droppod =>
UnAccessContents(obj) UnaccessContainer(obj)
DismountAction(tplayer, obj, seat_num) DismountAction(tplayer, obj, seat_num)
case Mountable.CanDismount(obj: Vehicle, seat_num) => case Mountable.CanDismount(obj: Vehicle, seat_num) =>
@ -2524,7 +2543,7 @@ class SessionActor extends Actor with MDCContextAware {
if (player_guid == player.GUID) { if (player_guid == player.GUID) {
//disembarking self //disembarking self
TotalDriverVehicleControl(obj) TotalDriverVehicleControl(obj)
UnAccessContents(obj) UnaccessContainer(obj)
DismountAction(tplayer, obj, seat_num) DismountAction(tplayer, obj, seat_num)
} else { } else {
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! VehicleServiceMessage(
@ -2735,7 +2754,7 @@ class SessionActor extends Actor with MDCContextAware {
if (tplayer_guid == guid) { if (tplayer_guid == guid) {
continent.GUID(vehicle_guid) match { continent.GUID(vehicle_guid) match {
case Some(obj: Vehicle) => case Some(obj: Vehicle) =>
UnAccessContents(obj) UnaccessContainer(obj)
case _ => ; case _ => ;
} }
} }
@ -3779,9 +3798,7 @@ class SessionActor extends Actor with MDCContextAware {
val guid = player.GUID val guid = player.GUID
sendResponse(UnuseItemMessage(guid, veh.GUID)) sendResponse(UnuseItemMessage(guid, veh.GUID))
sendResponse(UnuseItemMessage(guid, guid)) sendResponse(UnuseItemMessage(guid, guid))
veh.AccessingTrunk = None UnaccessContainer(veh)
UnAccessContents(veh)
accessedContainer = None
} }
case Some(container) => //just in case case Some(container) => //just in case
if (isMovingPlus) { if (isMovingPlus) {
@ -3791,7 +3808,7 @@ class SessionActor extends Actor with MDCContextAware {
sendResponse(UnuseItemMessage(guid, container.GUID)) sendResponse(UnuseItemMessage(guid, container.GUID))
} }
sendResponse(UnuseItemMessage(guid, guid)) sendResponse(UnuseItemMessage(guid, guid))
accessedContainer = None UnaccessContainer(container)
} }
case None => ; case None => ;
} }
@ -4384,25 +4401,20 @@ class SessionActor extends Actor with MDCContextAware {
case Some(obj: Equipment) => case Some(obj: Equipment) =>
FindEquipmentToDelete(object_guid, obj) FindEquipmentToDelete(object_guid, obj)
case Some(_: LocalProjectile) => case Some(obj: Projectile) =>
FindProjectileEntry(object_guid) match { if (obj.isResolved) {
case Some(projectile) => log.warn(
if (projectile.isResolved) { s"RequestDestroy: tried to clean up projectile ${object_guid.guid} but it was already resolved"
log.warn( )
s"RequestDestroy: tried to clean up projectile ${object_guid.guid} but it was already resolved" } else {
) obj.Miss()
} else { if (obj.profile.ExistsOnRemoteClients && obj.HasGUID) {
projectile.Miss() continent.AvatarEvents ! AvatarServiceMessage(
if (projectile.profile.ExistsOnRemoteClients && projectile.HasGUID) { continent.id,
continent.AvatarEvents ! AvatarServiceMessage( AvatarAction.ProjectileExplodes(player.GUID, obj.GUID, obj)
continent.id, )
AvatarAction.ProjectileExplodes(player.GUID, projectile.GUID, projectile) taskResolver ! UnregisterProjectile(obj)
) }
taskResolver ! UnregisterProjectile(projectile)
}
}
case None =>
log.warn(s"RequestDestroy: projectile ${object_guid.guid} has never been fired")
} }
case Some(obj: BoomerDeployable) => case Some(obj: BoomerDeployable) =>
@ -4463,7 +4475,7 @@ class SessionActor extends Actor with MDCContextAware {
Some(destination: PlanetSideServerObject with Container), Some(destination: PlanetSideServerObject with Container),
Some(item: Equipment) Some(item: Equipment)
) => ) =>
source.Actor ! Containable.MoveItem(destination, item, dest) ContainableMoveItem(taskResolver, player.Name, source, destination, item, dest)
case (None, _, _) => case (None, _, _) =>
log.error(s"MoveItem: wanted to move $item_guid from $source_guid, but could not find source object") log.error(s"MoveItem: wanted to move $item_guid from $source_guid, but could not find source object")
case (_, None, _) => case (_, None, _) =>
@ -4500,7 +4512,7 @@ class SessionActor extends Actor with MDCContextAware {
destination.Fit(item) destination.Fit(item)
) match { ) match {
case (Some((source, Some(_))), Some(dest)) => case (Some((source, Some(_))), Some(dest)) =>
source.Actor ! Containable.MoveItem(destination, item, dest) ContainableMoveItem(taskResolver, player.Name, source, destination, item, dest)
case (None, _) => case (None, _) =>
log.error(s"LootItem: can not find where $item is put currently") log.error(s"LootItem: can not find where $item is put currently")
case (_, None) => case (_, None) =>
@ -4610,7 +4622,7 @@ class SessionActor extends Actor with MDCContextAware {
itemType itemType
) )
) )
accessedContainer = Some(obj) AccessContainer(obj)
} }
} else if (!unk3 && player.isAlive) { //potential kit use } else if (!unk3 && player.isAlive) { //potential kit use
ValidObject(item_used_guid) match { 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 => case None if locker.Faction == player.Faction || !locker.HackedBy.isEmpty =>
log.trace(s"UseItem: ${player.Name} accessing a locker") log.trace(s"UseItem: ${player.Name} accessing a locker")
CancelZoningProcessWithDescriptiveReason("cancel_use") CancelZoningProcessWithDescriptiveReason("cancel_use")
val container = player.avatar.locker val playerLocker = player.avatar.locker
accessedContainer = Some(container)
sendResponse( sendResponse(
UseItemMessage( UseItemMessage(
avatar_guid, avatar_guid,
item_used_guid, item_used_guid,
container.GUID, playerLocker.GUID,
unk2, unk2,
unk3, unk3,
unk4, unk4,
@ -4776,6 +4787,7 @@ class SessionActor extends Actor with MDCContextAware {
456 456
) )
) )
AccessContainer(playerLocker)
case _ => ; case _ => ;
} }
@ -4827,8 +4839,7 @@ class SessionActor extends Actor with MDCContextAware {
) { ) {
CancelZoningProcessWithDescriptiveReason("cancel_use") CancelZoningProcessWithDescriptiveReason("cancel_use")
obj.AccessingTrunk = player.GUID obj.AccessingTrunk = player.GUID
accessedContainer = Some(obj) AccessContainer(obj)
AccessContents(obj)
sendResponse( sendResponse(
UseItemMessage( UseItemMessage(
avatar_guid, avatar_guid,
@ -5044,19 +5055,16 @@ class SessionActor extends Actor with MDCContextAware {
case msg @ UnuseItemMessage(player_guid, object_guid) => case msg @ UnuseItemMessage(player_guid, object_guid) =>
log.info(s"UnuseItem: $msg") log.info(s"UnuseItem: $msg")
//TODO check for existing accessedContainer value?
ValidObject(object_guid) match { ValidObject(object_guid) match {
case Some(obj: Vehicle) =>
if (obj.AccessingTrunk.contains(player.GUID)) {
obj.AccessingTrunk = None
UnAccessContents(obj)
}
case Some(obj: Player) => case Some(obj: Player) =>
UnaccessContainer(obj)
TryDisposeOfLootedCorpse(obj) TryDisposeOfLootedCorpse(obj)
case Some(obj: Container) =>
UnaccessContainer(obj)
case _ => ; case _ => ;
} }
accessedContainer = None
case msg @ DeployObjectMessage(guid, unk1, pos, orient, unk2) => case msg @ DeployObjectMessage(guid, unk1, pos, orient, unk2) =>
log.info(s"DeployObject: $msg") 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. * `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` * @param tplayer the avatar `Player`
* @return a `TaskResolver.GiveTask` message * @return a `TaskResolver.GiveTask` message
@ -5785,7 +5794,7 @@ class SessionActor extends Actor with MDCContextAware {
} }
override def onFailure(ex: Throwable): Unit = { override def onFailure(ex: Throwable): Unit = {
localAnnounce ! PlayerFailedToLoad(localPlayer) //alerts WorldSessionActor localAnnounce ! PlayerFailedToLoad(localPlayer) //alerts SessionActor
} }
}, },
List(GUIDTask.RegisterAvatar(tplayer)(continent.GUID)) 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. * `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` * @param tplayer the avatar `Player`
* @return a `TaskResolver.GiveTask` message * @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. * Additionally, the driver is only partially associated with the vehicle at this time.
* `interstellarFerry` is properly keeping track of the vehicle during the transition * `interstellarFerry` is properly keeping track of the vehicle during the transition
* and the user who is the driver (second param) is properly seated * 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 `GlobalDefinitions.droppod`
* @see `GUIDTask.RegisterObjectTask` * @see `GUIDTask.RegisterObjectTask`
* @see `interstellarFerry` * @see `interstellarFerry`
@ -5975,10 +5985,10 @@ class SessionActor extends Actor with MDCContextAware {
} }
override def onFailure(ex: Throwable): Unit = { 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. * Common preparation for interfacing with a vehicle.
* Join a vehicle-specific group for shared updates. * Join a vehicle-specific group for shared updates.
* Construct every object in the vehicle's inventory for shared manipulation updates. * Construct every object in the vehicle's inventory for shared manipulation updates.
* @param vehicle the vehicle * @param vehicle the vehicle
*/ */
def AccessContents(vehicle: Vehicle): Unit = { def AccessVehicleContents(vehicle: Vehicle): Unit = {
AccessContentsChannel(vehicle) accessedContainer = Some(vehicle)
val parent_guid = vehicle.GUID if(vehicle.AccessingTrunk.isEmpty) {
vehicle.Trunk.Items.foreach(entry => { vehicle.AccessingTrunk = Some(player.GUID)
val obj = entry.obj }
val objDef = obj.Definition AccessVehicleContainerChannel(vehicle)
sendResponse( DisplayContainerContents(vehicle.GUID, vehicle)
ObjectCreateDetailedMessage(
objDef.ObjectId,
obj.GUID,
ObjectCreateMessageParent(parent_guid, entry.start),
objDef.Packet.DetailedConstructorData(obj).get
)
)
})
} }
def AccessContentsChannel(container: PlanetSideServerObject): Unit = { def AccessVehicleContainerChannel(container: PlanetSideServerObject): Unit = {
continent.VehicleEvents ! Service.Join(s"${container.Actor}") 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. * Common preparation for disengaging from a vehicle.
* Leave the vehicle-specific group that was used for shared updates. * Leave the vehicle-specific group that was used for shared updates.
* Deconstruct every object in the vehicle's inventory. * Deconstruct every object in the vehicle's inventory.
* @param vehicle the vehicle * @param vehicle the vehicle
*/ */
def UnAccessContents(vehicle: Vehicle): Unit = { def UnaccessVehicleContainer(vehicle: Vehicle): Unit = {
continent.VehicleEvents ! Service.Leave(Some(s"${vehicle.Actor}")) accessedContainer = None
vehicle.Trunk.Items.foreach(entry => { if(vehicle.AccessingTrunk.contains(player.GUID)) {
sendResponse(ObjectDeleteMessage(entry.obj.GUID, 0)) 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}")) 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`.<br> * Check two locations for a controlled piece of equipment that is associated with the `player`.<br>
* <br> * <br>
@ -6813,19 +6879,7 @@ class SessionActor extends Actor with MDCContextAware {
progressBarUpdate.cancel() progressBarUpdate.cancel()
progressBarValue = None progressBarValue = None
lastTerminalOrderFulfillment = true lastTerminalOrderFulfillment = true
accessedContainer match { UnaccessContainer()
case Some(obj: Vehicle) =>
if (obj.AccessingTrunk.contains(player.GUID)) {
obj.AccessingTrunk = None
UnAccessContents(obj)
}
accessedContainer = None
case Some(_) =>
accessedContainer = None
case None => ;
}
prefire.orElse(shooting) match { prefire.orElse(shooting) match {
case Some(guid) => case Some(guid) =>
sendResponse(ChangeFireStateMessage_Stop(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. * 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 * 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. * to avoid damaging the critical setup of this function.
* @see `AccessContents` * @see `AccessContainer`
* @see `UpdateWeaponAtSeatPosition` * @see `UpdateWeaponAtSeatPosition`
* @param tplayer the player avatar seated in the vehicle's seat * @param tplayer the player avatar seated in the vehicle's seat
* @param vehicle the vehicle the player is riding * @param vehicle the vehicle the player is riding
@ -7046,7 +7100,7 @@ class SessionActor extends Actor with MDCContextAware {
sendResponse(ObjectCreateDetailedMessage(pdef.ObjectId, pguid, pdata)) sendResponse(ObjectCreateDetailedMessage(pdef.ObjectId, pguid, pdata))
if (seat == 0 || vehicle.Seats(seat).ControlledWeapon.nonEmpty) { if (seat == 0 || vehicle.Seats(seat).ControlledWeapon.nonEmpty) {
sendResponse(ObjectAttachMessage(vguid, pguid, seat)) sendResponse(ObjectAttachMessage(vguid, pguid, seat))
AccessContents(vehicle) AccessContainer(vehicle)
UpdateWeaponAtSeatPosition(vehicle, seat) UpdateWeaponAtSeatPosition(vehicle, seat)
} else { } else {
interimUngunnedVehicle = Some(vguid) interimUngunnedVehicle = Some(vguid)
@ -7120,7 +7174,7 @@ class SessionActor extends Actor with MDCContextAware {
//log.info(s"AvatarRejoin: $vguid -> $vdata") //log.info(s"AvatarRejoin: $vguid -> $vdata")
if (seat == 0 || vehicle.Seats(seat).ControlledWeapon.nonEmpty) { if (seat == 0 || vehicle.Seats(seat).ControlledWeapon.nonEmpty) {
sendResponse(ObjectAttachMessage(vguid, pguid, seat)) sendResponse(ObjectAttachMessage(vguid, pguid, seat))
AccessContents(vehicle) AccessContainer(vehicle)
UpdateWeaponAtSeatPosition(vehicle, seat) UpdateWeaponAtSeatPosition(vehicle, seat)
} else { } else {
interimUngunnedVehicle = Some(vguid) 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. * 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, * 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. * 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. * If the target object is discovered, it is removed from its current location and is completely destroyed.
* @see `RequestDestroyMessage`<br> * @see `RequestDestroyMessage`<br>
@ -8218,8 +8273,7 @@ class SessionActor extends Actor with MDCContextAware {
: PlanetSideServerObject with Container => Option[(PlanetSideServerObject with Container, Option[Int])] = : PlanetSideServerObject with Container => Option[(PlanetSideServerObject with Container, Option[Int])] =
FindInLocalContainer(object_guid) FindInLocalContainer(object_guid)
findFunc(player.avatar.locker) findFunc(player)
.orElse(findFunc(player))
.orElse(accessedContainer match { .orElse(accessedContainer match {
case Some(parent: PlanetSideServerObject) => case Some(parent: PlanetSideServerObject) =>
findFunc(parent) findFunc(parent)
@ -8239,7 +8293,11 @@ class SessionActor extends Actor with MDCContextAware {
true true
case _ => 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 obj.Position = Vector3.Zero
continent.Ground ! Zone.Ground.RemoveItem(object_guid) continent.Ground ! Zone.Ground.RemoveItem(object_guid)
continent.AvatarEvents ! AvatarServiceMessage.Ground(RemoverActor.ClearSpecific(List(obj), continent)) continent.AvatarEvents ! AvatarServiceMessage.Ground(RemoverActor.ClearSpecific(List(obj), continent))
@ -8440,7 +8498,7 @@ class SessionActor extends Actor with MDCContextAware {
if (player.isBackpack) { if (player.isBackpack) {
session = session.copy(player = targetPlayer) session = session.copy(player = targetPlayer)
taskThenZoneChange( taskThenZoneChange(
GUIDTask.UnregisterLocker(original.avatar.locker)(continent.GUID), GUIDTask.UnregisterObjectTask(original.avatar.locker)(continent.GUID),
InterstellarClusterService.FindZone(_.id == zoneId, context.self) InterstellarClusterService.FindZone(_.id == zoneId, context.self)
) )
} else if (player.HasGUID) { } else if (player.HasGUID) {
@ -8545,12 +8603,12 @@ class SessionActor extends Actor with MDCContextAware {
InterstellarClusterService.FindZone(_.id == zoneId, context.self) InterstellarClusterService.FindZone(_.id == zoneId, context.self)
) )
} else { } else {
UnAccessContents(vehicle) UnaccessContainer(vehicle)
LoadZoneCommonTransferActivity() LoadZoneCommonTransferActivity()
player.VehicleSeated = vehicle.GUID player.VehicleSeated = vehicle.GUID
player.Continent = zoneId //forward-set the continent id to perform a test player.Continent = zoneId //forward-set the continent id to perform a test
interstellarFerryTopLevelGUID = interstellarFerryTopLevelGUID =
(if ( if (
manifest.passengers.isEmpty && manifest.cargo.count { case (name, _) => !name.equals("MISSING_DRIVER") } == 0 manifest.passengers.isEmpty && manifest.cargo.count { case (name, _) => !name.equals("MISSING_DRIVER") } == 0
) { ) {
//do not delete if vehicle has passengers or cargo //do not delete if vehicle has passengers or cargo
@ -8561,7 +8619,7 @@ class SessionActor extends Actor with MDCContextAware {
None None
} else { } else {
Some(topLevel) Some(topLevel)
}) }
//unregister vehicle and driver whole + GiveWorld //unregister vehicle and driver whole + GiveWorld
continent.Transport ! Zone.Vehicle.Despawn(vehicle) continent.Transport ! Zone.Vehicle.Despawn(vehicle)
taskThenZoneChange( 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. * 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. * This vehicle can be deleted for everyone if no more work can be detected.
* *
* @see `GUIDTask.UnregisterAvatar` * @see `GUIDTask.UnregisterPlayer`
* @see `LoadZoneCommonTransferActivity` * @see `LoadZoneCommonTransferActivity`
* @see `Vehicles.AllGatedOccupantsInSameZone` * @see `Vehicles.AllGatedOccupantsInSameZone`
* @see `PlayerLoaded` * @see `PlayerLoaded`
* @see `TaskBeforeZoneChange` * @see `TaskBeforeZoneChange`
* @see `UnAccessContents` * @see `UnaccessContainer`
* @param vehicle the target vehicle being moved around * @param vehicle the target vehicle being moved around
* @param zoneId the zone in which the vehicle and driver will be placed * @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 * @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. * 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, * When it starts over, which should take an exceptionally long time to achieve,
* it starts counting at one rather than zero. * 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)) => case (Some(vehicle: Vehicle), Some(vguid), Some(seat)) =>
//sit down //sit down
sendResponse(ObjectAttachMessage(vguid, pguid, seat)) sendResponse(ObjectAttachMessage(vguid, pguid, seat))
AccessContents(vehicle) AccessContainer(vehicle)
keepAliveFunc = KeepAlivePersistence keepAliveFunc = KeepAlivePersistence
case _ => ; case _ => ;
//we can't find a vehicle? and we're still here? that's bad //we can't find a vehicle? and we're still here? that's bad

View file

@ -6,6 +6,7 @@ import akka.util.Timeout
import net.psforever.objects.equipment.{Ammo, Equipment} import net.psforever.objects.equipment.{Ammo, Equipment}
import net.psforever.objects.guid.{GUIDTask, Task, TaskResolver} import net.psforever.objects.guid.{GUIDTask, Task, TaskResolver}
import net.psforever.objects.inventory.{Container, InventoryItem} import net.psforever.objects.inventory.{Container, InventoryItem}
import net.psforever.objects.locker.LockerContainer
import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.containable.Containable import net.psforever.objects.serverobject.containable.Containable
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
@ -504,6 +505,215 @@ object WorldSession {
result 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. * If a timeout occurs on the manipulation, declare a terminal transaction failure.
* @see `AskTimeoutException` * @see `AskTimeoutException`

View file

@ -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()
}
}

View file

@ -2,8 +2,10 @@ package net.psforever.objects.avatar
import net.psforever.objects.definition.{AvatarDefinition, BasicDefinition} import net.psforever.objects.definition.{AvatarDefinition, BasicDefinition}
import net.psforever.objects.equipment.{EquipmentSize, EquipmentSlot} import net.psforever.objects.equipment.{EquipmentSize, EquipmentSlot}
import net.psforever.objects.inventory.LocallyRegisteredInventory
import net.psforever.objects.loadouts.{Loadout, SquadLoadout} 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 net.psforever.types._
import org.joda.time.{Duration, LocalDateTime, Seconds} import org.joda.time.{Duration, LocalDateTime, Seconds}
@ -82,7 +84,11 @@ case class Avatar(
loadouts: Seq[Option[Loadout]] = Seq.fill(15)(None), loadouts: Seq[Option[Loadout]] = Seq.fill(15)(None),
squadLoadouts: Seq[Option[SquadLoadout]] = Seq.fill(10)(None), squadLoadouts: Seq[Option[SquadLoadout]] = Seq.fill(10)(None),
implants: Seq[Option[Implant]] = Seq(None, None, 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 deployables: DeployableToolbox = new DeployableToolbox(), // TODO var bad
lookingForSquad: Boolean = false, lookingForSquad: Boolean = false,
var vehicle: Option[PlanetSideGUID] = None, // TODO var bad var vehicle: Option[PlanetSideGUID] = None, // TODO var bad

View file

@ -27,6 +27,8 @@ import net.psforever.services.{RemoverActor, Service}
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.local.{LocalAction, LocalServiceMessage}
import akka.actor.typed import akka.actor.typed
import net.psforever.objects.locker.LockerContainerControl
import scala.concurrent.duration._ import scala.concurrent.duration._
class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Command]) class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Command])

View file

@ -4,7 +4,7 @@ package net.psforever.objects.definition.converter
import net.psforever.objects.Player import net.psforever.objects.Player
import net.psforever.objects.equipment.{Equipment, EquipmentSlot} import net.psforever.objects.equipment.{Equipment, EquipmentSlot}
import net.psforever.packet.game.objectcreate._ 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.annotation.tailrec
import scala.util.{Success, Try} import scala.util.{Success, Try}
@ -175,7 +175,9 @@ object AvatarConverter {
def MakeDetailedInventoryData(obj: Player): InventoryData = { def MakeDetailedInventoryData(obj: Player): InventoryData = {
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] = { private def MakeFifthSlot(obj: Player): List[InternalSlot] = {
obj.Slot(5).Equipment match { obj.Slot(5).Equipment match {
case Some(equip) => 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 _ => case _ =>
Nil Nil
} }

View file

@ -1,9 +1,9 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package net.psforever.objects.definition.converter package net.psforever.objects.definition.converter
import net.psforever.objects.LockerEquipment
import net.psforever.objects.equipment.Equipment import net.psforever.objects.equipment.Equipment
import net.psforever.objects.inventory.GridInventory import net.psforever.objects.inventory.GridInventory
import net.psforever.objects.locker.LockerEquipment
import net.psforever.packet.game.objectcreate._ import net.psforever.packet.game.objectcreate._
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID} import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}

View file

@ -6,6 +6,7 @@ import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.objects.equipment.{Equipment, EquipmentSlot} import net.psforever.objects.equipment.{Equipment, EquipmentSlot}
import net.psforever.objects._ import net.psforever.objects._
import net.psforever.objects.inventory.Container import net.psforever.objects.inventory.Container
import net.psforever.objects.locker.{LockerContainer, LockerEquipment}
import net.psforever.objects.serverobject.turret.WeaponTurret import net.psforever.objects.serverobject.turret.WeaponTurret
import scala.annotation.tailrec import scala.annotation.tailrec
@ -153,7 +154,7 @@ object GUIDTask {
*/ */
def RegisterAvatar(tplayer: Player)(implicit guid: ActorRef): TaskResolver.GiveTask = { def RegisterAvatar(tplayer: Player)(implicit guid: ActorRef): TaskResolver.GiveTask = {
val holsterTasks = VisibleSlotTaskBuilding(tplayer.Holsters(), RegisterEquipment) val holsterTasks = VisibleSlotTaskBuilding(tplayer.Holsters(), RegisterEquipment)
val lockerTask = List(RegisterLocker(tplayer.avatar.locker)) val lockerTask = List(RegisterObjectTask(tplayer.avatar.locker))
val inventoryTasks = RegisterInventory(tplayer) val inventoryTasks = RegisterInventory(tplayer)
TaskResolver.GiveTask(RegisterObjectTask(tplayer).task, holsterTasks ++ lockerTask ++ inventoryTasks) TaskResolver.GiveTask(RegisterObjectTask(tplayer).task, holsterTasks ++ lockerTask ++ inventoryTasks)
} }
@ -311,7 +312,7 @@ object GUIDTask {
*/ */
def UnregisterAvatar(tplayer: Player)(implicit guid: ActorRef): TaskResolver.GiveTask = { def UnregisterAvatar(tplayer: Player)(implicit guid: ActorRef): TaskResolver.GiveTask = {
val holsterTasks = VisibleSlotTaskBuilding(tplayer.Holsters(), UnregisterEquipment) val holsterTasks = VisibleSlotTaskBuilding(tplayer.Holsters(), UnregisterEquipment)
val lockerTask = List(UnregisterLocker(tplayer.avatar.locker)) val lockerTask = List(UnregisterObjectTask(tplayer.avatar.locker))
val inventoryTasks = UnregisterInventory(tplayer) val inventoryTasks = UnregisterInventory(tplayer)
TaskResolver.GiveTask(UnregisterObjectTask(tplayer).task, holsterTasks ++ lockerTask ++ inventoryTasks) TaskResolver.GiveTask(UnregisterObjectTask(tplayer).task, holsterTasks ++ lockerTask ++ inventoryTasks)
} }
@ -368,7 +369,7 @@ object GUIDTask {
* @param guid implicit reference to a unique number system * @param guid implicit reference to a unique number system
* @return a list of `TaskResolver.GiveTask` messages * @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 guid: ActorRef
): List[TaskResolver.GiveTask] = { ): List[TaskResolver.GiveTask] = {
recursiveVisibleSlotTaskBuilding(list.iterator, func) recursiveVisibleSlotTaskBuilding(list.iterator, func)
@ -386,7 +387,7 @@ object GUIDTask {
*/ */
@tailrec private def recursiveVisibleSlotTaskBuilding( @tailrec private def recursiveVisibleSlotTaskBuilding(
iter: Iterator[EquipmentSlot], iter: Iterator[EquipmentSlot],
func: ((Equipment) => TaskResolver.GiveTask), func: Equipment => TaskResolver.GiveTask,
list: List[TaskResolver.GiveTask] = Nil list: List[TaskResolver.GiveTask] = Nil
)(implicit guid: ActorRef): List[TaskResolver.GiveTask] = { )(implicit guid: ActorRef): List[TaskResolver.GiveTask] = {
if (!iter.hasNext) { if (!iter.hasNext) {

View file

@ -24,8 +24,8 @@ class NumberPoolHub(private val source: NumberSource) {
import scala.collection.mutable import scala.collection.mutable
private val hash: mutable.HashMap[String, NumberPool] = mutable.HashMap[String, NumberPool]() private val hash: mutable.HashMap[String, NumberPool] = mutable.HashMap[String, NumberPool]()
private val bigpool: mutable.LongMap[String] = mutable.LongMap[String]() private val bigpool: mutable.LongMap[String] = mutable.LongMap[String]()
hash += "generic" -> new GenericPool(bigpool, source.Size) hash += "generic" -> new GenericPool(bigpool, source.size)
source.FinalizeRestrictions.foreach(i => source.finalizeRestrictions.foreach(i =>
bigpool += i.toLong -> "" bigpool += i.toLong -> ""
) //these numbers can never be pooled; the source can no longer restrict numbers ) //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` * @param number the unique number to attempt to retrieve from the `source`
* @return the object that is assigned to the number * @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 def Numbers: List[Int] = bigpool.keys.map(key => key.toInt).toList
@ -74,14 +74,15 @@ class NumberPoolHub(private val source: NumberSource) {
if (pool.isEmpty) { if (pool.isEmpty) {
throw new IllegalArgumentException(s"can not add empty pool $name") throw new IllegalArgumentException(s"can not add empty pool $name")
} }
if (source.Size <= pool.max) { if (source.max < pool.max) {
throw new IllegalArgumentException(s"can not add pool $name - max(pool) is greater than source.size") 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) bigpool.keys.map(n => n.toInt).toSet.intersect(pool.toSet).toSeq match {
if (collision.nonEmpty) { case Nil => ;
throw new IllegalArgumentException( case collisions =>
s"can not add pool $name - it contains the following redundant numbers: ${collision.toString}" throw new IllegalArgumentException(
) s"can not add pool $name - it contains the following redundant numbers: ${collisions.mkString(",")}"
)
} }
pool.foreach(i => bigpool += i.toLong -> name) pool.foreach(i => bigpool += i.toLong -> name)
hash += name -> new ExclusivePool(pool) hash += name -> new ExclusivePool(pool)
@ -162,7 +163,7 @@ class NumberPoolHub(private val source: NumberSource) {
def WhichPool(obj: IdentifiableEntity): Option[String] = { def WhichPool(obj: IdentifiableEntity): Option[String] = {
try { try {
val number: Int = obj.GUID.guid 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) } if (entry.isDefined && entry.get.Object.contains(obj)) { WhichPool(number) }
else { None } else { None }
} catch { } catch {
@ -228,7 +229,7 @@ class NumberPoolHub(private val source: NumberSource) {
} }
private def register_GetAvailableNumberFromSource(number: Int): Try[LoanedKey] = { private def register_GetAvailableNumberFromSource(number: Int): Try[LoanedKey] = {
source.Available(number) match { source.getAvailable(number) match {
case Some(key) => case Some(key) =>
Success(key) Success(key)
case None => case None =>
@ -243,22 +244,21 @@ class NumberPoolHub(private val source: NumberSource) {
* @return the number the was given to the object * @return the number the was given to the object
*/ */
def register(obj: IdentifiableEntity, name: String): Try[Int] = { def register(obj: IdentifiableEntity, name: String): Try[Int] = {
try { if (obj.HasGUID) {
register_CheckNumberAgainstDesiredPool(obj, name, obj.GUID.guid) register_CheckNumberAgainstDesiredPool(obj, name, obj.GUID.guid)
} catch { } else {
case _: Exception => register_GetPool(name) match {
register_GetPool(name) match { case Success(key) =>
case Success(key) => key.Object = obj
key.Object = obj Success(obj.GUID.guid)
Success(obj.GUID.guid) case Failure(ex) =>
case Failure(ex) => Failure(new Exception(s"trying to register an object but, ${ex.getMessage}"))
Failure(new Exception(s"trying to register an object but, ${ex.getMessage}")) }
}
} }
} }
private def register_CheckNumberAgainstDesiredPool(obj: IdentifiableEntity, name: String, number: Int): Try[Int] = { 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)) { if (directKey.isEmpty || !directKey.get.Object.contains(obj)) {
Failure(new Exception("object already registered, but not to this source")) Failure(new Exception("object already registered, but not to this source"))
} else if (!WhichPool(number).contains(name)) { } else if (!WhichPool(number).contains(name)) {
@ -347,11 +347,34 @@ class NumberPoolHub(private val source: NumberSource) {
case Success(pool) => case Success(pool) =>
val number = obj.GUID.guid val number = obj.GUID.guid
pool.Return(number) pool.Return(number)
source.Return(number) source.returnNumber(number)
obj.Invalidate() obj.Invalidate()
Success(number) Success(number)
case Failure(ex) => 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) => case Some(name) =>
unregister_GetPool(name) unregister_GetPool(name)
case None => 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 * @return the object, if any, previous associated with the number
*/ */
def unregister(number: Int): Try[Option[IdentifiableEntity]] = { def unregister(number: Int): Try[Option[IdentifiableEntity]] = {
if (source.Test(number)) { if (source.test(number)) {
unregister_GetObjectFromSource(number) unregister_GetObjectFromSource(number)
} else { } else {
Failure(new Exception(s"can not unregister a number $number that this source does not own")) 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]] = { private def unregister_GetObjectFromSource(number: Int): Try[Option[IdentifiableEntity]] = {
source.Return(number) match { source.returnNumber(number) match {
case Some(obj) => case Some(obj) =>
unregister_ReturnObjectToPool(obj) unregister_ReturnObjectToPool(obj)
case None => case None =>
@ -403,7 +426,7 @@ class NumberPoolHub(private val source: NumberSource) {
obj.Invalidate() obj.Invalidate()
Success(Some(obj)) Success(Some(obj))
case Failure(ex) => case Failure(ex) =>
source.Available(number) //undo source.getAvailable(number) //undo
Failure(new Exception(s"started unregistering, but ${ex.getMessage}")) 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. * @param number the number to return.
* @return any object previously using this number * @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.<br> * Determines if the object is registered.<br>
@ -451,7 +474,7 @@ class NumberPoolHub(private val source: NumberSource) {
*/ */
def isRegistered(obj: IdentifiableEntity): Boolean = { def isRegistered(obj: IdentifiableEntity): Boolean = {
try { try {
source.Get(obj.GUID.guid) match { source.get(obj.GUID.guid) match {
case Some(monitor) => case Some(monitor) =>
monitor.Object.contains(obj) monitor.Object.contains(obj)
case None => case None =>
@ -474,7 +497,7 @@ class NumberPoolHub(private val source: NumberSource) {
* @see `isRegistered(IdentifiableEntity)` * @see `isRegistered(IdentifiableEntity)`
*/ */
def isRegistered(number: Int): Boolean = { def isRegistered(number: Int): Boolean = {
source.Get(number) match { source.get(number) match {
case Some(monitor) => case Some(monitor) =>
monitor.Policy == AvailabilityPolicy.Leased monitor.Policy == AvailabilityPolicy.Leased
case None => case None =>

View file

@ -73,7 +73,7 @@ object NumberPoolActor {
final case class NoNumber(ex: Throwable, id: Option[Any] = None) 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 * @param number the number
*/ */
final case class ReturnNumber(number: Int, id: Option[Any] = None) final case class ReturnNumber(number: Int, id: Option[Any] = None)

View file

@ -12,9 +12,9 @@ import net.psforever.objects.guid.AvailabilityPolicy
class LoanedKey(private val guid: Int, private val key: Monitor) { class LoanedKey(private val guid: Int, private val key: Monitor) {
def GUID: Int = guid 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 * na
@ -30,18 +30,18 @@ class LoanedKey(private val guid: Int, private val key: Monitor) {
*/ */
def Object_=(obj: Option[IdentifiableEntity]): Option[IdentifiableEntity] = { def Object_=(obj: Option[IdentifiableEntity]): Option[IdentifiableEntity] = {
if ( 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) { if (key.obj.isDefined) {
key.Object.get.Invalidate() key.obj.get.Invalidate()
key.Object = None key.obj = None
} }
key.Object = obj key.obj = obj
if (obj.isDefined) { if (obj.isDefined) {
import net.psforever.types.PlanetSideGUID import net.psforever.types.PlanetSideGUID
obj.get.GUID = PlanetSideGUID(guid) obj.get.GUID = PlanetSideGUID(guid)
} }
} }
key.Object key.obj
} }
} }

View file

@ -5,9 +5,7 @@ import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.objects.guid.AvailabilityPolicy import net.psforever.objects.guid.AvailabilityPolicy
trait Monitor { trait Monitor {
def Policy: AvailabilityPolicy.Value var policy: AvailabilityPolicy.Value
def Object: Option[IdentifiableEntity] var obj: Option[IdentifiableEntity]
def Object_=(objct: Option[IdentifiableEntity]): Option[IdentifiableEntity]
} }

View file

@ -11,8 +11,8 @@ import net.psforever.objects.guid.AvailabilityPolicy
final class SecureKey(private val guid: Int, private val key: Monitor) { final class SecureKey(private val guid: Int, private val key: Monitor) {
def GUID: Int = guid def GUID: Int = guid
def Policy: AvailabilityPolicy.Value = key.Policy def Policy: AvailabilityPolicy.Value = key.policy
import net.psforever.objects.entity.IdentifiableEntity import net.psforever.objects.entity.IdentifiableEntity
def Object: Option[IdentifiableEntity] = key.Object def Object: Option[IdentifiableEntity] = key.obj
} }

View file

@ -46,7 +46,7 @@ abstract class NumberSelector {
* By default, a simple policy for returning numbers has been provided. * 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. * This will not be sufficient for all selection actions that can be implemented so `override` where necessary.
* <br> * <br>
* `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. * In fact, it should modify it by default to provide additional feedback of its process.
* Pass a copy if data mutation is a concern. * Pass a copy if data mutation is a concern.
* @param number the number to be returned * @param number the number to be returned

View file

@ -6,20 +6,7 @@ import net.psforever.objects.guid.AvailabilityPolicy
import net.psforever.objects.guid.key.Monitor import net.psforever.objects.guid.key.Monitor
private class Key extends Monitor { private class Key extends Monitor {
private var policy: AvailabilityPolicy.Value = AvailabilityPolicy.Available var policy: AvailabilityPolicy.Value = AvailabilityPolicy.Available
private var obj: Option[IdentifiableEntity] = None
def Policy: AvailabilityPolicy.Value = policy var obj: Option[IdentifiableEntity] = None
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
}
} }

View file

@ -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.<br>
* <br>
* 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)
}
}

View file

@ -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)
}
}

View file

@ -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). * The purpose of a `NumberSource` is to help facilitate globally unique identifiers (GUID, pl. GUIDs).
*/ */
trait NumberSource { 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. * The count of numbers allocated to this source.
* @return the count * @return the count
*/ */
def Size: Int def size: Int
/** /**
* The count of numbers that can still be drawn. * The count of numbers that can still be drawn.
* @return the count * @return the count
*/ */
def CountAvailable: Int def countAvailable: Int
/** /**
* The count of numbers that can not be drawn. * The count of numbers that can not be drawn.
* @return the count * @return the count
*/ */
def CountUsed: Int def countUsed: Int
/** /**
* Is this number a member of this number source? * Is this number a member of this number source?
* @param number the number * @param number the number
* @return `true`, if it is a member; `false`, otherwise * @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. * Produce an un-modifiable wrapper for the `Monitor` for this number.
* @param number the number * @param number the number
* @return the wrapped `Monitor` * @return the wrapped `Monitor`
*/ */
def Get(number: Int): Option[SecureKey] def get(number: Int): Option[SecureKey]
//def GetAll(list : List[Int]) : List[SecureKey] /**
* Produce an un-modifiable wrapper for the `Monitor` for this entity,
//def GetAll(p : Key => Boolean) : List[SecureKey] * 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. * 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 * @param number the number
* @return the wrapped `Monitor`, or `None` * @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. * Consume a wrapped `Monitor` and release its number from its previous assignment/use.
* @param monitor the `Monitor` * @param monitor the `Monitor`
* @return any object previously using this `Monitor` * @return any object previously using this `Monitor`
*/ */
def Return(monitor: SecureKey): Option[IdentifiableEntity] = { def returnNumber(monitor: SecureKey): Option[IdentifiableEntity] = {
Return(monitor.GUID) returnNumber(monitor.GUID)
} }
/** /**
@ -77,8 +86,8 @@ trait NumberSource {
* @param monitor the `Monitor` * @param monitor the `Monitor`
* @return any object previously using this `Monitor` * @return any object previously using this `Monitor`
*/ */
def Return(monitor: LoanedKey): Option[IdentifiableEntity] = { def returnNumber(monitor: LoanedKey): Option[IdentifiableEntity] = {
Return(monitor.GUID) returnNumber(monitor.GUID)
} }
/** /**
@ -86,21 +95,21 @@ trait NumberSource {
* @param number the number * @param number the number
* @return any object previously using this 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. * 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 * @param number the number
* @return the wrapped `Monitor` * @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`. * Numbers from this source may not longer be marked as `Restricted`.
* @return the `List` of all numbers that have been 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 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`. * 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` * @return a `List` of assignments maintained by all the currently-used number `Monitors`
*/ */
def Clear(): List[IdentifiableEntity] def clear(): List[IdentifiableEntity]
} }

View file

@ -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)
}
}

View file

@ -98,94 +98,3 @@ trait Container {
def Collisions(index: Int, width: Int, height: Int): Try[List[InventoryItem]] = def Collisions(index: Int, width: Int, height: Int): Try[List[InventoryItem]] =
Inventory.CheckCollisionsVar(index, width, height) 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)
// }
// }
//}

View file

@ -191,8 +191,7 @@ class GridInventory extends Container {
} else { } else {
val collisions: mutable.Set[InventoryItem] = mutable.Set[InventoryItem]() val collisions: mutable.Set[InventoryItem] = mutable.Set[InventoryItem]()
items items
.map { case (_, item: InventoryItem) => item } .foreach { case (_, item: InventoryItem) =>
.foreach { item: InventoryItem =>
val actualItemStart: Int = item.start - offset val actualItemStart: Int = item.start - offset
val itemx: Int = actualItemStart % width val itemx: Int = actualItemStart % width
val itemy: 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 //lists with multiple entries represent a group of items that collide
//perform a specific distinct on the list of lists of numeric id overlaps //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 //THEN map each list of list's item id to an item
val out = testGrid.collect { val out = testGrid.values.collect {
case (_, list) if list.size > 1 => list.sortWith(_ < _) case list if list.size > 1 => list.sortWith(_ < _)
} }
recursiveRelatedListCollisions(out.iterator, out.toList).map { list => list.map { items } } recursiveRelatedListCollisions(out.iterator, out.toList).map { list => list.map { items } }
} }

View file

@ -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
}
}

View file

@ -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))
}
}

View file

@ -1,69 +1,24 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2020 PSForever
package net.psforever.objects package net.psforever.objects.locker
import akka.actor.Actor import akka.actor.Actor
import net.psforever.objects.definition.EquipmentDefinition
import net.psforever.objects.equipment.Equipment 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.objects.serverobject.containable.{Containable, ContainableBehavior}
import net.psforever.packet.game.{ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectDetachMessage}
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent 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.Service
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.types.{PlanetSideEmpire, Vector3}
/** /**
* The companion of a `Locker` that is carried with a player * A control agency mainly for manipulating the equipment stowed by a player in a `LockerContainer`
* masquerading as their sixth `EquipmentSlot` object and a sub-inventory item. * and reporting back to a specific xchannel in the event system about these changes.
* The `Player` class refers to it as the "fifth slot" as its permanent slot number is encoded as `0x85`. * @param locker the governed player-facing locker component
* The inventory of this object is accessed using a game world `Locker` object (`mb_locker`). * @param toChannel the channel to which to publish events, typically the owning player's name
*/ */
class LockerContainer extends PlanetSideServerObject with Container { class LockerContainerControl(locker: LockerContainer, toChannel: String)
private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL extends Actor
private val inventory = GridInventory(30, 20) with ContainableBehavior {
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 {
def ContainerObject = locker def ContainerObject = locker
def receive: Receive = def receive: Receive =

View file

@ -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
}

View file

@ -12,7 +12,7 @@ import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.actor.UniqueNumberSystem import net.psforever.objects.guid.actor.UniqueNumberSystem
import net.psforever.objects.guid.key.LoanedKey import net.psforever.objects.guid.key.LoanedKey
import net.psforever.objects.guid.selector.RandomSelector 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.inventory.Container
import net.psforever.objects.serverobject.painbox.{Painbox, PainboxDefinition} import net.psforever.objects.serverobject.painbox.{Painbox, PainboxDefinition}
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo 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 private var accessor: ActorRef = ActorRef.noSender
/** The basic support structure for the globally unique number system used by this `Zone`. */ /** 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. */ /** A synchronized `List` of items (`Equipment`) dropped by players on the ground and can be collected again. */
private val equipmentOnGround: ListBuffer[Equipment] = ListBuffer[Equipment]() 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("f", (30001 to 35000).toList).Selector = new RandomSelector
guid.AddPool("g", (35001 until 40100).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("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 //TODO disabled temporarily to lighten load times
//guid.AddPool("h", (40150 to 45000).toList).Selector = new RandomSelector //guid.AddPool("h", (40150 to 45000).toList).Selector = new RandomSelector
//guid.AddPool("i", (45001 to 50000).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 { building match {
case warpGate: WarpGate => case warpGate: WarpGate =>
warpGate.Faction == faction || warpGate.Faction == PlanetSideEmpire.NEUTRAL || warpGate.Broadcast warpGate.Faction == faction || warpGate.Faction == PlanetSideEmpire.NEUTRAL || warpGate.Broadcast
case building => case _ =>
building.Faction == faction building.Faction == faction
} }
} }
.map { .map {
case (building, spawns) => case (building, spawns: List[SpawnPoint]) =>
(building, spawns.filter(!_.Offline)) (building, spawns.filter(!_.Offline))
} }
.concat( .concat(

View file

@ -364,13 +364,12 @@ class PersistenceMonitor(name: String, squadService: ActorRef, taskResolver: Act
//player has released //player has released
//our last body was turned into a corpse; just the avatar remains //our last body was turned into a corpse; just the avatar remains
//TODO perform any last minute saving now ... //TODO perform any last minute saving now ...
AvatarLogout(avatar)
inZone.GUID(avatar.vehicle) match { inZone.GUID(avatar.vehicle) match {
case Some(obj: Vehicle) if obj.OwnerName.contains(avatar.name) => case Some(obj: Vehicle) if obj.OwnerName.contains(avatar.name) =>
obj.Actor ! Vehicle.Ownership(None) obj.Actor ! Vehicle.Ownership(None)
case _ => ; case _ => ;
} }
taskResolver.tell(GUIDTask.UnregisterLocker(avatar.locker)(inZone.GUID), context.parent) AvatarLogout(avatar)
case _ => case _ =>
//user stalled during initial session, or was caught in between zone transfer //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 `Avatar`
* @see `AvatarAction.ObjectDelete` * @see `AvatarAction.ObjectDelete`
* @see `AvatarServiceMessage` * @see `AvatarServiceMessage`
* @see `GUIDTask.UnregisterAvatar` * @see `GUIDTask.UnregisterPlayer`
* @see `Player` * @see `Player`
* @see `Zone.AvatarEvents` * @see `Zone.AvatarEvents`
* @see `Zone.Population.Release` * @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.Population.tell(Zone.Population.Release(avatar), parent)
inZone.AvatarEvents.tell(AvatarServiceMessage(inZone.id, AvatarAction.ObjectDelete(pguid, pguid)), parent) inZone.AvatarEvents.tell(AvatarServiceMessage(inZone.id, AvatarAction.ObjectDelete(pguid, pguid)), parent)
taskResolver.tell(GUIDTask.UnregisterPlayer(player)(inZone.GUID), parent)
AvatarLogout(avatar) 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) squadService.tell(Service.Leave(Some(avatar.id.toString)), context.parent)
Deployables.Disown(inZone, avatar, context.parent) Deployables.Disown(inZone, avatar, context.parent)
inZone.Population.tell(Zone.Population.Leave(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}") log.info(s"logout of ${avatar.name}")
} }
} }

View file

@ -2,21 +2,14 @@ package net.psforever.zones
import java.io.FileNotFoundException import java.io.FileNotFoundException
import net.psforever.objects.serverobject.terminals.{ import net.psforever.objects.serverobject.terminals.{CaptureTerminal, CaptureTerminalDefinition, ProximityTerminal, ProximityTerminalDefinition, Terminal, TerminalDefinition}
CaptureTerminal,
CaptureTerminalDefinition,
ProximityTerminal,
ProximityTerminalDefinition,
Terminal,
TerminalDefinition
}
import net.psforever.objects.serverobject.mblocker.Locker import net.psforever.objects.serverobject.mblocker.Locker
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import akka.actor.ActorContext import akka.actor.ActorContext
import io.circe._ import io.circe._
import io.circe.parser._ 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.ballistics.Projectile
import net.psforever.objects.definition.BasicDefinition import net.psforever.objects.definition.BasicDefinition
import net.psforever.objects.serverobject.doors.Door 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.pad.{VehicleSpawnPad, VehicleSpawnPadDefinition}
import net.psforever.objects.serverobject.painbox.{Painbox, PainboxDefinition} import net.psforever.objects.serverobject.painbox.{Painbox, PainboxDefinition}
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
import net.psforever.objects.serverobject.structures.{ import net.psforever.objects.serverobject.structures.{Building, BuildingDefinition, FoundationBuilder, StructureType, WarpGate}
Building,
BuildingDefinition,
FoundationBuilder,
StructureType,
WarpGate
}
import net.psforever.objects.serverobject.tube.SpawnTube import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.serverobject.turret.{FacilityTurret, FacilityTurretDefinition} import net.psforever.objects.serverobject.turret.{FacilityTurret, FacilityTurretDefinition}
import net.psforever.objects.zones.{MapInfo, Zone, ZoneInfo, ZoneMap} import net.psforever.objects.zones.{MapInfo, Zone, ZoneInfo, ZoneMap}
import net.psforever.types.{PlanetSideEmpire, Vector3} import net.psforever.types.{PlanetSideEmpire, Vector3}
import net.psforever.util.DefinitionUtil import net.psforever.util.DefinitionUtil
import scala.io.Source import scala.io.Source
import scala.collection.parallel.CollectionConverters._ import scala.collection.parallel.CollectionConverters._
@ -281,6 +269,9 @@ object Zones {
(Projectile.baseUID until Projectile.rangeUID) foreach { (Projectile.baseUID until Projectile.rangeUID) foreach {
zoneMap.addLocalObject(_, LocalProjectile.Constructor) zoneMap.addLocalObject(_, LocalProjectile.Constructor)
} }
40150 until 40450 foreach {
zoneMap.addLocalObject(_, LocalLockerItem.Constructor)
}
lattice.asObject.get(info.value).foreach { obj => lattice.asObject.get(info.value).foreach { obj =>
obj.asArray.get.foreach { entry => obj.asArray.get.foreach { entry =>

View file

@ -5,6 +5,7 @@ import net.psforever.objects.GlobalDefinitions._
import net.psforever.objects._ import net.psforever.objects._
import net.psforever.objects.avatar.{Avatar, BattleRank, Implant} import net.psforever.objects.avatar.{Avatar, BattleRank, Implant}
import net.psforever.objects.definition.ImplantDefinition import net.psforever.objects.definition.ImplantDefinition
import net.psforever.objects.locker.LockerEquipment
import net.psforever.types.{CharacterGender, CharacterVoice, ImplantType, PlanetSideEmpire} import net.psforever.types.{CharacterGender, CharacterVoice, ImplantType, PlanetSideEmpire}
import org.specs2.mutable._ import org.specs2.mutable._

View file

@ -7,6 +7,7 @@ import net.psforever.objects.avatar.Avatar
import net.psforever.objects.definition._ import net.psforever.objects.definition._
import net.psforever.objects.equipment._ import net.psforever.objects.equipment._
import net.psforever.objects.inventory.InventoryTile 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.terminals.Terminal
import net.psforever.objects.serverobject.tube.SpawnTube import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.vehicles.UtilityType import net.psforever.objects.vehicles.UtilityType

View file

@ -8,7 +8,7 @@ import net.psforever.objects._
import net.psforever.objects.ballistics._ import net.psforever.objects.ballistics._
import net.psforever.objects.equipment.JammableUnit import net.psforever.objects.equipment.JammableUnit
import net.psforever.objects.guid.NumberPoolHub 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.damage.Damageable
import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl} import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl}
import net.psforever.objects.serverobject.implantmech.{ImplantTerminalMech, ImplantTerminalMechControl} 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 see specific object type tests in relation to what those object types does above and beyond that during damage
*/ */
class DamageableEntityDamageTest extends ActorTest { 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
@ -313,7 +313,7 @@ class DamageableEntityDamageTest extends ActorTest {
} }
class DamageableEntityDestroyedTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
@ -387,7 +387,7 @@ class DamageableEntityDestroyedTest extends ActorTest {
} }
class DamageableEntityNotDestroyTwice 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
@ -458,7 +458,7 @@ class DamageableEntityNotDestroyTwice extends ActorTest {
} }
class DamageableAmenityTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
@ -546,7 +546,7 @@ class DamageableAmenityTest extends ActorTest {
class DamageableMountableDamageTest 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 //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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
@ -638,7 +638,7 @@ class DamageableMountableDamageTest extends ActorTest {
class DamageableMountableDestroyTest 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 //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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
@ -730,7 +730,7 @@ class DamageableMountableDestroyTest extends ActorTest {
} }
class DamageableWeaponTurretDamageTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -823,7 +823,7 @@ class DamageableWeaponTurretDamageTest extends ActorTest {
} }
class DamageableWeaponTurretJammerTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -918,7 +918,7 @@ class DamageableWeaponTurretJammerTest extends ActorTest {
} }
class DamageableWeaponTurretDestructionTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -1069,7 +1069,7 @@ class DamageableWeaponTurretDestructionTest extends ActorTest {
} }
class DamageableVehicleDamageTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -1174,7 +1174,7 @@ class DamageableVehicleDamageTest extends ActorTest {
} }
class DamageableVehicleDamageMountedTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -1315,7 +1315,7 @@ class DamageableVehicleDamageMountedTest extends ActorTest {
} }
class DamageableVehicleJammeringMountedTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -1428,7 +1428,7 @@ class DamageableVehicleJammeringMountedTest extends ActorTest {
} }
class DamageableVehicleDestroyTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -1531,7 +1531,7 @@ class DamageableVehicleDestroyTest extends ActorTest {
} }
class DamageableVehicleDestroyMountedTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)

View file

@ -7,7 +7,7 @@ import base.ActorTest
import net.psforever.objects.ballistics._ import net.psforever.objects.ballistics._
import net.psforever.objects.ce.DeployedItem import net.psforever.objects.ce.DeployedItem
import net.psforever.objects.guid.NumberPoolHub 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.mount.Mountable
import net.psforever.objects.vital.Vitality import net.psforever.objects.vital.Vitality
import net.psforever.objects.zones.{Zone, ZoneMap} import net.psforever.objects.zones.{Zone, ZoneMap}
@ -300,7 +300,7 @@ class ShieldGeneratorDeployableTest extends Specification {
} }
class ExplosiveDeployableJammerTest extends ActorTest { 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -398,7 +398,7 @@ class ExplosiveDeployableJammerTest extends ActorTest {
} }
class ExplosiveDeployableJammerExplodeTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -508,7 +508,7 @@ class ExplosiveDeployableJammerExplodeTest extends ActorTest {
} }
class ExplosiveDeployableDestructionTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)

View file

@ -8,7 +8,7 @@ import net.psforever.objects.avatar.Avatar
import net.psforever.objects.{Default, GlobalDefinitions, Player, Tool} import net.psforever.objects.{Default, GlobalDefinitions, Player, Tool}
import net.psforever.objects.definition.ToolDefinition import net.psforever.objects.definition.ToolDefinition
import net.psforever.objects.guid.NumberPoolHub 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.CommonMessages
import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.structures.{Building, StructureType} import net.psforever.objects.serverobject.structures.{Building, StructureType}
@ -182,7 +182,7 @@ class FacilityTurretControl4Test extends ActorTest {
} }
class FacilityTurretControlRestorationTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)

View file

@ -8,7 +8,7 @@ import net.psforever.objects.avatar.Avatar
import net.psforever.objects.ballistics._ import net.psforever.objects.ballistics._
import net.psforever.objects.{GlobalDefinitions, Player, Tool} import net.psforever.objects.{GlobalDefinitions, Player, Tool}
import net.psforever.objects.guid.NumberPoolHub 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.CommonMessages
import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl} import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl}
import net.psforever.objects.serverobject.structures.{Building, StructureType} import net.psforever.objects.serverobject.structures.{Building, StructureType}
@ -46,7 +46,7 @@ class GeneratorControlConstructTest extends ActorTest {
} }
class GeneratorControlDamageTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -128,7 +128,7 @@ class GeneratorControlDamageTest extends ActorTest {
} }
class GeneratorControlCriticalTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -218,7 +218,7 @@ class GeneratorControlCriticalTest extends ActorTest {
} }
class GeneratorControlDestroyedTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -341,7 +341,7 @@ class GeneratorControlKillsTest extends ActorTest {
but its SOI information can be loaded with the players manually but its SOI information can be loaded with the players manually
the players need something to catch the die message 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -478,7 +478,7 @@ class GeneratorControlKillsTest extends ActorTest {
} }
class GeneratorControlNotDestroyTwice 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
@ -561,7 +561,7 @@ class GeneratorControlNotDestroyTwice extends ActorTest {
} }
class GeneratorControlNotDamageIfExplodingTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -655,7 +655,7 @@ class GeneratorControlNotDamageIfExplodingTest extends ActorTest {
} }
class GeneratorControlNotRepairIfExplodingTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -753,7 +753,7 @@ class GeneratorControlNotRepairIfExplodingTest extends ActorTest {
} }
class GeneratorControlRepairPastRestorePoint 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)

View file

@ -3,13 +3,13 @@ package objects
import net.psforever.objects.{AmmoBox, SimpleItem, Tool} import net.psforever.objects.{AmmoBox, SimpleItem, Tool}
import net.psforever.objects.definition.SimpleItemDefinition 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.objects.GlobalDefinitions.{bullet_9mm, suppressor}
import net.psforever.types.PlanetSideGUID import net.psforever.types.PlanetSideGUID
import org.specs2.mutable._ import org.specs2.mutable._
import scala.collection.mutable.ListBuffer import scala.collection.mutable.ListBuffer
import scala.util.{Success, Failure} import scala.util.{Failure, Success}
class InventoryTest extends Specification { class InventoryTest extends Specification {
val bullet9mmBox1 = AmmoBox(bullet_9mm) 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 { "InventoryEquiupmentSlot" should {
"insert, collide, insert" in { "insert, collide, insert" in {
val obj: GridInventory = GridInventory(7, 7) val obj: GridInventory = GridInventory(7, 7)

View file

@ -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"
}
}
}

View file

@ -7,7 +7,7 @@ import base.ActorTest
import net.psforever.objects.avatar.{Avatar, PlayerControl} import net.psforever.objects.avatar.{Avatar, PlayerControl}
import net.psforever.objects.ballistics._ import net.psforever.objects.ballistics._
import net.psforever.objects.guid.NumberPoolHub 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.vital.Vitality
import net.psforever.objects.zones.{Zone, ZoneMap} import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.objects._ import net.psforever.objects._
@ -20,7 +20,7 @@ import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import scala.concurrent.duration._ import scala.concurrent.duration._
class PlayerControlHealTest extends ActorTest { 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -106,7 +106,7 @@ class PlayerControlHealTest extends ActorTest {
} }
class PlayerControlHealSelfTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -181,7 +181,7 @@ class PlayerControlHealSelfTest extends ActorTest {
} }
class PlayerControlRepairTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -277,7 +277,7 @@ class PlayerControlRepairTest extends ActorTest {
} }
class PlayerControlRepairSelfTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -352,7 +352,7 @@ class PlayerControlRepairSelfTest extends ActorTest {
} }
class PlayerControlDamageTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -449,7 +449,7 @@ class PlayerControlDamageTest extends ActorTest {
} }
class PlayerControlDeathStandingTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -575,7 +575,7 @@ class PlayerControlDeathStandingTest extends ActorTest {
} }
class PlayerControlDeathSeatedTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)

View file

@ -6,6 +6,7 @@ import net.psforever.objects._
import net.psforever.objects.avatar.Avatar import net.psforever.objects.avatar.Avatar
import net.psforever.objects.definition.{SimpleItemDefinition, SpecialExoSuitDefinition} import net.psforever.objects.definition.{SimpleItemDefinition, SpecialExoSuitDefinition}
import net.psforever.objects.equipment.EquipmentSize import net.psforever.objects.equipment.EquipmentSize
import net.psforever.objects.locker.LockerEquipment
import net.psforever.types.{PlanetSideGUID, _} import net.psforever.types.{PlanetSideGUID, _}
import org.specs2.mutable._ import org.specs2.mutable._

View file

@ -14,13 +14,7 @@ class ProjectileTest extends Specification {
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val fury = Vehicle(GlobalDefinitions.fury) val fury = Vehicle(GlobalDefinitions.fury)
"LocalProjectile" should { "Range" 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"
}
"local projectile range" in { "local projectile range" in {
Projectile.baseUID < Projectile.rangeUID mustEqual true Projectile.baseUID < Projectile.rangeUID mustEqual true
} }

View file

@ -7,7 +7,7 @@ import base.ActorTest
import net.psforever.objects._ import net.psforever.objects._
import net.psforever.objects.avatar.Avatar import net.psforever.objects.avatar.Avatar
import net.psforever.objects.guid.NumberPoolHub 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.CommonMessages
import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl} import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl}
import net.psforever.objects.serverobject.structures.{Building, StructureType} 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 see GeneratorTest in relation to what the generator does above and beyond that during repair
*/ */
class RepairableEntityRepairTest extends ActorTest { 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
@ -100,7 +100,7 @@ class RepairableEntityRepairTest extends ActorTest {
} }
class RepairableEntityNotRepairTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
@ -141,7 +141,7 @@ class RepairableEntityNotRepairTest extends ActorTest {
} }
class RepairableAmenityTest 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
@ -229,7 +229,7 @@ class RepairableAmenityTest extends ActorTest {
} }
class RepairableTurretWeapon 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)
@ -323,7 +323,7 @@ class RepairableTurretWeapon extends ActorTest {
} }
class RepairableVehicleRepair 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) 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 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}
GUID(guid) GUID(guid)

View file

@ -7,7 +7,7 @@ import akka.testkit.TestProbe
import base.ActorTest import base.ActorTest
import net.psforever.actors.zone.{BuildingActor, ZoneActor} import net.psforever.actors.zone.{BuildingActor, ZoneActor}
import net.psforever.objects.guid.{NumberPoolHub, TaskResolver} 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.serverobject.CommonMessages
import net.psforever.objects.{GlobalDefinitions, Ntu, Player, Vehicle} import net.psforever.objects.{GlobalDefinitions, Ntu, Player, Vehicle}
import net.psforever.objects.serverobject.resourcesilo.{ResourceSilo, ResourceSiloControl, ResourceSiloDefinition} import net.psforever.objects.serverobject.resourcesilo.{ResourceSilo, ResourceSiloControl, ResourceSiloDefinition}
@ -94,7 +94,7 @@ class ResourceSiloControlStartupTest extends ActorTest {
} }
class ResourceSiloControlUseTest 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 map = new ZoneMap("test")
val zone = new Zone("test", map, 0) { val zone = new Zone("test", map, 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}

View file

@ -1,8 +1,8 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package objects package objects
import akka.actor.{Actor, ActorContext, Props} import akka.actor.ActorContext
import base.ActorTest import base.FreedContextActorTest
import net.psforever.objects.GlobalDefinitions import net.psforever.objects.GlobalDefinitions
import net.psforever.objects.guid.NumberPoolHub import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.serverobject.ServerObjectBuilder 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.objects.zones.Zone
import net.psforever.types.{PlanetSideGUID, Vector3} import net.psforever.types.{PlanetSideGUID, Vector3}
import scala.concurrent.duration.Duration class BuildingBuilderTest extends FreedContextActorTest {
class BuildingBuilderTest extends ActorTest {
"Building object" should { "Building object" should {
"build" in { "build" in {
val structure: (String, Int, Int, Zone, ActorContext) => Building = Building.Structure(StructureType.Building) val structure: (String, Int, Int, Zone, ActorContext) => Building = Building.Structure(StructureType.Building)
val actor = system.actorOf( val building = FoundationBuilder(structure).Build("building", 10, 10, Zone.Nowhere)(context)
Props(classOf[ServerObjectBuilderTest.BuildingTestActor], structure, "Building", 10, 10, Zone.Nowhere), assert(building ne null)
"building" assert(building.isInstanceOf[Building])
) assert(building.MapId == 10)
actor ! "!" assert(building.Zone == Zone.Nowhere)
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[Building])
assert(reply.asInstanceOf[Building].MapId == 10)
assert(reply.asInstanceOf[Building].Zone == Zone.Nowhere)
} }
} }
} }
class WarpGateBuilderTest extends ActorTest { class WarpGateBuilderTest extends FreedContextActorTest {
"WarpGate object" should { "WarpGate object" should {
"build" in { "build" in {
val structure: (String, Int, Int, Zone, ActorContext) => Building = WarpGate.Structure val structure: (String, Int, Int, Zone, ActorContext) => Building = WarpGate.Structure
val actor = system.actorOf( val building = FoundationBuilder(structure).Build("wgate", 10, 10, Zone.Nowhere)(context)
Props(classOf[ServerObjectBuilderTest.BuildingTestActor], structure, "wgate", 10, 10, Zone.Nowhere), assert(building ne null)
"wgate" assert(building.isInstanceOf[WarpGate])
) assert(building.MapId == 10)
actor ! "!" assert(building.Zone == Zone.Nowhere)
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[Building])
assert(reply.asInstanceOf[Building].MapId == 10)
assert(reply.asInstanceOf[Building].Zone == Zone.Nowhere)
} }
} }
} }
class DoorObjectBuilderTest1 extends ActorTest { class DoorObjectBuilderTest1 extends FreedContextActorTest {
import net.psforever.objects.serverobject.doors.Door import net.psforever.objects.serverobject.doors.Door
"Door object" should { "Door object" should {
"build" in { "build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf( val obj = ServerObjectBuilder(1, Door.Constructor).Build(context, hub)
Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1, Door.Constructor), hub), assert(obj.isInstanceOf[Door])
"door" assert(obj.HasGUID)
) assert(obj.GUID == PlanetSideGUID(1))
actor ! "!" assert(obj == hub(1).get)
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)
} }
} }
} }
class DoorObjectBuilderTest2 extends ActorTest { class DoorObjectBuilderTest2 extends FreedContextActorTest {
import net.psforever.objects.serverobject.doors.Door import net.psforever.objects.serverobject.doors.Door
"Door object" should { "Door object" should {
"build" in { "build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf( val obj = ServerObjectBuilder(1, Door.Constructor(Vector3(1, 2, 3))).Build(context, hub)
Props( assert(obj.isInstanceOf[Door])
classOf[ServerObjectBuilderTest.BuilderTestActor], assert(obj.HasGUID)
ServerObjectBuilder(1, Door.Constructor(Vector3(1, 2, 3))), assert(obj.GUID == PlanetSideGUID(1))
hub assert(obj == hub(1).get)
), assert(obj.Position == Vector3(1, 2, 3))
"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)
} }
} }
} }
class IFFLockObjectBuilderTest extends ActorTest { class IFFLockObjectBuilderTest extends FreedContextActorTest {
import net.psforever.objects.serverobject.locks.IFFLock import net.psforever.objects.serverobject.locks.IFFLock
"IFFLock object" should { "IFFLock object" should {
"build" in { "build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf( val obj = ServerObjectBuilder(1, IFFLock.Constructor(Vector3(1f, 1f, 1f), Vector3(2f, 2f, 2f))).Build(context, hub)
Props( assert(obj.isInstanceOf[IFFLock])
classOf[ServerObjectBuilderTest.BuilderTestActor], assert(obj.HasGUID)
ServerObjectBuilder(1, IFFLock.Constructor(Vector3(0f, 0f, 0f), Vector3(0f, 0f, 0f))), assert(obj.GUID == PlanetSideGUID(1))
hub assert(obj.Position == Vector3(1,1,1))
), assert(obj.Outwards == Vector3(0.034899496f, 0.99939084f, 0.0f))
"lock" assert(obj == hub(1).get)
)
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)
} }
} }
} }
class ImplantTerminalMechObjectBuilderTest extends ActorTest { class ImplantTerminalMechObjectBuilderTest extends FreedContextActorTest {
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
"Implant terminal mech object" should { "Implant terminal mech object" should {
"build" in { "build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf( val obj = ServerObjectBuilder(1, ImplantTerminalMech.Constructor(Vector3.Zero)).Build(context, hub)
Props( assert(obj.isInstanceOf[ImplantTerminalMech])
classOf[ServerObjectBuilderTest.BuilderTestActor], assert(obj.HasGUID)
ServerObjectBuilder(1, ImplantTerminalMech.Constructor(Vector3.Zero)), assert(obj.GUID == PlanetSideGUID(1))
hub assert(obj == hub(1).get)
),
"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)
} }
} }
} }
class TerminalObjectBuilderTest extends ActorTest { class TerminalObjectBuilderTest extends FreedContextActorTest {
import net.psforever.objects.GlobalDefinitions.order_terminal import net.psforever.objects.GlobalDefinitions.order_terminal
import net.psforever.objects.serverobject.terminals.Terminal import net.psforever.objects.serverobject.terminals.Terminal
"Terminal object" should { "Terminal object" should {
"build" in { "build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf( val obj = ServerObjectBuilder(1, Terminal.Constructor(Vector3(1.1f, 2.2f, 3.3f), order_terminal)).Build(context, hub)
Props( assert(obj.isInstanceOf[Terminal])
classOf[ServerObjectBuilderTest.BuilderTestActor], assert(obj.HasGUID)
ServerObjectBuilder(1, Terminal.Constructor(Vector3(1.1f, 2.2f, 3.3f), order_terminal)), assert(obj.GUID == PlanetSideGUID(1))
hub assert(obj.Position == Vector3(1.1f, 2.2f, 3.3f))
), assert(obj == hub(1).get)
"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)
} }
} }
} }
class ProximityTerminalObjectBuilderTest extends ActorTest { class ProximityTerminalObjectBuilderTest extends FreedContextActorTest {
import net.psforever.objects.GlobalDefinitions.medical_terminal import net.psforever.objects.GlobalDefinitions.medical_terminal
import net.psforever.objects.serverobject.terminals.Terminal import net.psforever.objects.serverobject.terminals.Terminal
"Terminal object" should { "Terminal object" should {
"build" in { "build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf( val obj = ServerObjectBuilder(1, ProximityTerminal.Constructor(medical_terminal)).Build(context, hub)
Props( assert(obj.isInstanceOf[Terminal])
classOf[ServerObjectBuilderTest.BuilderTestActor], assert(obj.HasGUID)
ServerObjectBuilder(1, ProximityTerminal.Constructor(medical_terminal)), assert(obj.GUID == PlanetSideGUID(1))
hub assert(obj == hub(1).get)
),
"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)
} }
} }
} }
class VehicleSpawnPadObjectBuilderTest extends ActorTest { class VehicleSpawnPadObjectBuilderTest extends FreedContextActorTest {
import net.psforever.objects.serverobject.pad.VehicleSpawnPad import net.psforever.objects.serverobject.pad.VehicleSpawnPad
"Vehicle spawn pad object" should { "Vehicle spawn pad object" should {
"build" in { "build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf( val obj = ServerObjectBuilder(1,
Props( VehicleSpawnPad.Constructor(
classOf[ServerObjectBuilderTest.BuilderTestActor], Vector3(1.1f, 2.2f, 3.3f), GlobalDefinitions.mb_pad_creation, Vector3(4.4f, 5.5f, 6.6f)
ServerObjectBuilder( )
1, ).Build(context, hub)
VehicleSpawnPad assert(obj.isInstanceOf[VehicleSpawnPad])
.Constructor(Vector3(1.1f, 2.2f, 3.3f), GlobalDefinitions.mb_pad_creation, Vector3(4.4f, 5.5f, 6.6f)) assert(obj.HasGUID)
), assert(obj.GUID == PlanetSideGUID(1))
hub assert(obj.Position == Vector3(1.1f, 2.2f, 3.3f))
), assert(obj.Orientation == Vector3(4.4f, 5.5f, 6.6f))
"pad" assert(obj == hub(1).get)
)
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)
} }
} }
} }
class LocalProjectileBuilderTest extends ActorTest { class LocalProjectileBuilderTest extends FreedContextActorTest {
import net.psforever.objects.LocalProjectile import net.psforever.objects.LocalProjectile
"Local projectile object" should { "Local projectile object" should {
"build" in { "build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf( val obj = ServerObjectBuilder(1, LocalProjectile.Constructor).Build(context, hub)
Props( assert(obj.isInstanceOf[LocalProjectile])
classOf[ServerObjectBuilderTest.BuilderTestActor], assert(obj.HasGUID)
ServerObjectBuilder(1, LocalProjectile.Constructor), assert(obj.GUID == PlanetSideGUID(1))
hub assert(obj == hub(1).get)
),
"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)
} }
} }
} }
class LockerObjectBuilderTest extends ActorTest { class LockerObjectBuilderTest extends FreedContextActorTest {
import net.psforever.objects.serverobject.mblocker.Locker import net.psforever.objects.serverobject.mblocker.Locker
"Locker object" should { "Locker object" should {
"build" in { "build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf( val obj = ServerObjectBuilder(1, Locker.Constructor).Build(context, hub)
Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1, Locker.Constructor), hub), assert(obj.isInstanceOf[Locker])
"locker" assert(obj.HasGUID)
) assert(obj.GUID == PlanetSideGUID(1))
actor ! "!" assert(obj == hub(1).get)
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)
} }
} }
} }
class ResourceSiloObjectBuilderTest extends ActorTest { class ResourceSiloObjectBuilderTest extends FreedContextActorTest {
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
"Resource silo object" should { "Resource silo object" should {
"build" in { "build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf( val obj = ServerObjectBuilder(1, ResourceSilo.Constructor(Vector3(1f, 1f, 1f))).Build(context, hub)
Props( assert(obj.isInstanceOf[ResourceSilo])
classOf[ServerObjectBuilderTest.BuilderTestActor], assert(obj.HasGUID)
ServerObjectBuilder(1, ResourceSilo.Constructor(Vector3(0f, 0f, 0f))), assert(obj.GUID == PlanetSideGUID(1))
hub assert(obj.Position == Vector3(1,1,1))
), assert(obj == hub(1).get)
"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)
} }
} }
} }
class SpawnTubeObjectBuilderTest extends ActorTest { class SpawnTubeObjectBuilderTest extends FreedContextActorTest {
import net.psforever.objects.serverobject.tube.SpawnTube import net.psforever.objects.serverobject.tube.SpawnTube
"Spawn tube object" should { "Spawn tube object" should {
"build" in { "build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf( val obj = ServerObjectBuilder(
Props( 1,
classOf[ServerObjectBuilderTest.BuilderTestActor], SpawnTube.Constructor(Vector3(3980.4062f, 4267.3047f, 257.5625f), Vector3(0, 0, 90))
ServerObjectBuilder(1, SpawnTube.Constructor(Vector3(3980.4062f, 4267.3047f, 257.5625f), Vector3(0, 0, 90))), ).Build(context, hub)
hub assert(obj.isInstanceOf[SpawnTube])
), assert(obj.HasGUID)
"spawn-tube" assert(obj.GUID == PlanetSideGUID(1))
) assert(obj.Position == Vector3(3980.4062f, 4267.3047f, 257.5625f))
actor ! "!" assert(obj.Orientation == Vector3(0, 0, 90))
assert(obj == hub(1).get)
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)
} }
} }
} }
class FacilityTurretObjectBuilderTest extends ActorTest { class FacilityTurretObjectBuilderTest extends FreedContextActorTest {
import net.psforever.objects.GlobalDefinitions.manned_turret import net.psforever.objects.GlobalDefinitions.manned_turret
import net.psforever.objects.serverobject.turret.FacilityTurret import net.psforever.objects.serverobject.turret.FacilityTurret
"FacilityTurretObjectBuilder" should { "FacilityTurretObjectBuilder" should {
"build" in { "build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf( val obj = ServerObjectBuilder(1, FacilityTurret.Constructor(manned_turret)).Build(context, hub)
Props( assert(obj.isInstanceOf[FacilityTurret])
classOf[ServerObjectBuilderTest.BuilderTestActor], assert(obj.HasGUID)
ServerObjectBuilder(1, FacilityTurret.Constructor(manned_turret)), assert(obj.GUID == PlanetSideGUID(1))
hub assert(obj == hub(1).get)
),
"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)
} }
} }
} }
object ServerObjectBuilderTest { object ServerObjectBuilderTest {
import net.psforever.objects.guid.source.LimitedNumberSource import net.psforever.objects.guid.source.MaxNumberSource
def NumberPoolHub: NumberPoolHub = { def NumberPoolHub: NumberPoolHub = {
val obj = new NumberPoolHub(new LimitedNumberSource(2)) val obj = new NumberPoolHub(new MaxNumberSource(2))
obj 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)
}
}
} }

View file

@ -7,7 +7,7 @@ import base.{ActorTest, FreedContextActorTest}
import net.psforever.objects._ import net.psforever.objects._
import net.psforever.objects.definition.{SeatDefinition, VehicleDefinition} import net.psforever.objects.definition.{SeatDefinition, VehicleDefinition}
import net.psforever.objects.guid.NumberPoolHub 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.mount.Mountable
import net.psforever.objects.vehicles._ import net.psforever.objects.vehicles._
import net.psforever.objects.vital.VehicleShieldCharge import net.psforever.objects.vital.VehicleShieldCharge
@ -408,7 +408,7 @@ class VehicleControlPrepareForDeletionPassengerTest extends ActorTest {
class VehicleControlPrepareForDeletionMountedInTest extends FreedContextActorTest { class VehicleControlPrepareForDeletionMountedInTest extends FreedContextActorTest {
ServiceManager.boot 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) { val zone = new Zone("test", new ZoneMap("test"), 0) {
GUID(guid) GUID(guid)
@ -534,7 +534,7 @@ class VehicleControlPrepareForDeletionMountedInTest extends FreedContextActorTes
} }
class VehicleControlPrepareForDeletionMountedCargoTest extends FreedContextActorTest { class VehicleControlPrepareForDeletionMountedCargoTest extends FreedContextActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(10)) val guid = new NumberPoolHub(new MaxNumberSource(10))
ServiceManager.boot ServiceManager.boot
val zone = new Zone("test", new ZoneMap("test"), 0) { val zone = new Zone("test", new ZoneMap("test"), 0) {
GUID(guid) GUID(guid)

View file

@ -7,7 +7,7 @@ import base.ActorTest
import net.psforever.objects.entity.IdentifiableEntity import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.objects.equipment.Equipment import net.psforever.objects.equipment.Equipment
import net.psforever.objects.guid.NumberPoolHub 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.terminals.Terminal
import net.psforever.objects.serverobject.tube.SpawnTube import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects._ 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 { "can have its unique identifier system changed if no objects were added to it" in {
val zone = new Zone("home3", map13, 13) 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.GUID(guid1) mustEqual true
zone.AddPool("pool1", (0 to 50).toList) zone.AddPool("pool1", (0 to 50).toList)
zone.AddPool("pool2", (51 to 75).toList) zone.AddPool("pool2", (51 to 75).toList)
@ -114,7 +114,7 @@ class ZoneTest extends Specification {
registration.isSuccess mustEqual true registration.isSuccess mustEqual true
guid1.WhichPool(obj).contains("pool2") 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 { "Zone" should {
"refuse new number pools after the Actor is started" in { "refuse new number pools after the Actor is started" in {
val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = {} } 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") zone.actor = system.spawn(ZoneActor(zone), "test-add-pool-actor-init")
expectNoMessage(Duration.create(500, "ms")) expectNoMessage(Duration.create(500, "ms"))
@ -133,7 +133,7 @@ class ZoneActorTest extends ActorTest {
"refuse to remove number pools after the Actor is started" in { "refuse to remove number pools after the Actor is started" in {
val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = {} } 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.AddPool("test", 1 to 2)
zone.actor = system.spawn(ZoneActor(zone), "test-remove-pool-actor-init") zone.actor = system.spawn(ZoneActor(zone), "test-remove-pool-actor-init")
expectNoMessage(Duration.create(300, "ms")) expectNoMessage(Duration.create(300, "ms"))
@ -482,7 +482,7 @@ class ZonePopulationTest extends ActorTest {
class ZoneGroundDropItemTest extends ActorTest { class ZoneGroundDropItemTest extends ActorTest {
val item = AmmoBox(GlobalDefinitions.bullet_9mm) val item = AmmoBox(GlobalDefinitions.bullet_9mm)
val hub = new NumberPoolHub(new LimitedNumberSource(20)) val hub = new NumberPoolHub(new MaxNumberSource(20))
hub.register(item, 10) hub.register(item, 10)
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} } val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
zone.GUID(hub) zone.GUID(hub)
@ -507,7 +507,7 @@ class ZoneGroundDropItemTest extends ActorTest {
class ZoneGroundCanNotDropItem1Test extends ActorTest { class ZoneGroundCanNotDropItem1Test extends ActorTest {
val item = AmmoBox(GlobalDefinitions.bullet_9mm) 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 //hub.register(item, 10) //!important
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} } val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
zone.GUID(hub) zone.GUID(hub)
@ -532,7 +532,7 @@ class ZoneGroundCanNotDropItem1Test extends ActorTest {
class ZoneGroundCanNotDropItem2Test extends ActorTest { class ZoneGroundCanNotDropItem2Test extends ActorTest {
val item = AmmoBox(GlobalDefinitions.bullet_9mm) 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 hub.register(item, 10) //!important
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} } val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
//zone.GUID(hub) //!important //zone.GUID(hub) //!important
@ -557,7 +557,7 @@ class ZoneGroundCanNotDropItem2Test extends ActorTest {
class ZoneGroundCanNotDropItem3Test extends ActorTest { class ZoneGroundCanNotDropItem3Test extends ActorTest {
val item = AmmoBox(GlobalDefinitions.bullet_9mm) 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 hub.register(item, 10) //!important
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} } val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
zone.GUID(hub) //!important zone.GUID(hub) //!important
@ -590,7 +590,7 @@ class ZoneGroundCanNotDropItem3Test extends ActorTest {
class ZoneGroundPickupItemTest extends ActorTest { class ZoneGroundPickupItemTest extends ActorTest {
val item = AmmoBox(GlobalDefinitions.bullet_9mm) val item = AmmoBox(GlobalDefinitions.bullet_9mm)
val hub = new NumberPoolHub(new LimitedNumberSource(20)) val hub = new NumberPoolHub(new MaxNumberSource(20))
hub.register(item, 10) hub.register(item, 10)
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} } val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
zone.GUID(hub) zone.GUID(hub)
@ -618,7 +618,7 @@ class ZoneGroundPickupItemTest extends ActorTest {
class ZoneGroundCanNotPickupItemTest extends ActorTest { class ZoneGroundCanNotPickupItemTest extends ActorTest {
val item = AmmoBox(GlobalDefinitions.bullet_9mm) val item = AmmoBox(GlobalDefinitions.bullet_9mm)
val hub = new NumberPoolHub(new LimitedNumberSource(20)) val hub = new NumberPoolHub(new MaxNumberSource(20))
hub.register(item, 10) hub.register(item, 10)
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} } val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
zone.GUID(hub) //still registered to this zone zone.GUID(hub) //still registered to this zone
@ -642,7 +642,7 @@ class ZoneGroundCanNotPickupItemTest extends ActorTest {
class ZoneGroundRemoveItemTest extends ActorTest { class ZoneGroundRemoveItemTest extends ActorTest {
val item = AmmoBox(GlobalDefinitions.bullet_9mm) val item = AmmoBox(GlobalDefinitions.bullet_9mm)
val hub = new NumberPoolHub(new LimitedNumberSource(20)) val hub = new NumberPoolHub(new MaxNumberSource(20))
hub.register(item, 10) hub.register(item, 10)
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} } val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
zone.GUID(hub) //still registered to this zone zone.GUID(hub) //still registered to this zone

View file

@ -5,6 +5,7 @@ import base.ActorTest
import net.psforever.objects._ import net.psforever.objects._
import net.psforever.objects.avatar.Avatar import net.psforever.objects.avatar.Avatar
import net.psforever.objects.guid.{GUIDTask, TaskResolver} import net.psforever.objects.guid.{GUIDTask, TaskResolver}
import net.psforever.objects.locker.LockerEquipment
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire} import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
class GUIDTaskRegisterAvatarTest extends ActorTest { class GUIDTaskRegisterAvatarTest extends ActorTest {
@ -26,7 +27,7 @@ class GUIDTaskRegisterAvatarTest extends ActorTest {
assert(!obj_wep_ammo.HasGUID) assert(!obj_wep_ammo.HasGUID)
assert(!obj_inv_ammo.HasGUID) assert(!obj_inv_ammo.HasGUID)
assert(!obj_locker.HasGUID) assert(!obj_locker.HasGUID)
assert(!obj_locker_ammo.HasGUID) assert(obj_locker_ammo.HasGUID)
taskResolver ! TaskResolver.GiveTask( taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref), new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.RegisterAvatar(obj)(uns)) List(GUIDTask.RegisterAvatar(obj)(uns))

View file

@ -5,6 +5,7 @@ import base.ActorTest
import net.psforever.objects._ import net.psforever.objects._
import net.psforever.objects.avatar.Avatar import net.psforever.objects.avatar.Avatar
import net.psforever.objects.guid.{GUIDTask, TaskResolver} import net.psforever.objects.guid.{GUIDTask, TaskResolver}
import net.psforever.objects.locker.LockerEquipment
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire} import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
class GUIDTaskRegisterPlayerTest extends ActorTest { class GUIDTaskRegisterPlayerTest extends ActorTest {
@ -26,7 +27,7 @@ class GUIDTaskRegisterPlayerTest extends ActorTest {
assert(!obj_wep_ammo.HasGUID) assert(!obj_wep_ammo.HasGUID)
assert(!obj_inv_ammo.HasGUID) assert(!obj_inv_ammo.HasGUID)
assert(!obj_locker.HasGUID) assert(!obj_locker.HasGUID)
assert(!obj_locker_ammo.HasGUID) assert(obj_locker_ammo.HasGUID)
taskResolver ! TaskResolver.GiveTask( taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref), new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.RegisterPlayer(obj)(uns)) List(GUIDTask.RegisterPlayer(obj)(uns))
@ -37,6 +38,6 @@ class GUIDTaskRegisterPlayerTest extends ActorTest {
assert(obj_wep_ammo.HasGUID) assert(obj_wep_ammo.HasGUID)
assert(obj_inv_ammo.HasGUID) assert(obj_inv_ammo.HasGUID)
assert(!obj_locker.HasGUID) assert(!obj_locker.HasGUID)
assert(!obj_locker_ammo.HasGUID) assert(obj_locker_ammo.HasGUID)
} }
} }

View file

@ -8,7 +8,7 @@ import akka.testkit.TestProbe
import net.psforever.objects.entity.IdentifiableEntity import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.objects.guid.actor.{NumberPoolActor, UniqueNumberSystem} import net.psforever.objects.guid.actor.{NumberPoolActor, UniqueNumberSystem}
import net.psforever.objects.guid.selector.RandomSelector 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} import net.psforever.objects.guid.{NumberPoolHub, Task, TaskResolver}
object GUIDTaskTest { object GUIDTaskTest {
@ -26,7 +26,7 @@ object GUIDTaskTest {
import akka.routing.RandomPool import akka.routing.RandomPool
import akka.testkit.TestProbe 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 guid.AddPool("dynamic", (1 to 100).toList).Selector = new RandomSelector //TODO name is hardcoded for now
val uns = system.actorOf( val uns = system.actorOf(
RandomPool(25).props(Props(classOf[UniqueNumberSystem], guid, GUIDTaskTest.AllocateNumberPoolActors(guid))), RandomPool(25).props(Props(classOf[UniqueNumberSystem], guid, GUIDTaskTest.AllocateNumberPoolActors(guid))),

View file

@ -5,6 +5,7 @@ import base.ActorTest
import net.psforever.objects._ import net.psforever.objects._
import net.psforever.objects.avatar.Avatar import net.psforever.objects.avatar.Avatar
import net.psforever.objects.guid.{GUIDTask, TaskResolver} import net.psforever.objects.guid.{GUIDTask, TaskResolver}
import net.psforever.objects.locker.LockerEquipment
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire} import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
class GUIDTaskUnregisterAvatarTest extends ActorTest { class GUIDTaskUnregisterAvatarTest extends ActorTest {
@ -43,6 +44,6 @@ class GUIDTaskUnregisterAvatarTest extends ActorTest {
assert(!obj_wep_ammo.HasGUID) assert(!obj_wep_ammo.HasGUID)
assert(!obj_inv_ammo.HasGUID) assert(!obj_inv_ammo.HasGUID)
assert(!obj_locker.HasGUID) assert(!obj_locker.HasGUID)
assert(!obj_locker_ammo.HasGUID) assert(obj_locker_ammo.HasGUID)
} }
} }

View file

@ -5,6 +5,7 @@ import base.ActorTest
import net.psforever.objects._ import net.psforever.objects._
import net.psforever.objects.avatar.Avatar import net.psforever.objects.avatar.Avatar
import net.psforever.objects.guid.{GUIDTask, TaskResolver} import net.psforever.objects.guid.{GUIDTask, TaskResolver}
import net.psforever.objects.locker.LockerEquipment
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire} import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
class GUIDTaskUnregisterPlayerTest extends ActorTest { class GUIDTaskUnregisterPlayerTest extends ActorTest {

View file

@ -4,7 +4,7 @@ package objects.number
import net.psforever.objects.entity.IdentifiableEntity import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.objects.guid.NumberPoolHub import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.selector.RandomSelector 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 net.psforever.types.PlanetSideGUID
import org.specs2.mutable.Specification import org.specs2.mutable.Specification
@ -20,17 +20,17 @@ class NumberPoolHubTest extends Specification {
"NumberPoolHub" should { "NumberPoolHub" should {
"construct" in { "construct" in {
new NumberPoolHub(new LimitedNumberSource(51)) new NumberPoolHub(new MaxNumberSource(51))
ok ok
} }
"get a pool" in { "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 obj.GetPool("generic").isDefined mustEqual true //default pool
} }
"add a pool" in { "add a pool" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51)) val obj = new NumberPoolHub(new MaxNumberSource(51))
obj.Numbers.isEmpty mustEqual true obj.Numbers.isEmpty mustEqual true
obj.AddPool("fibonacci", numberList) obj.AddPool("fibonacci", numberList)
obj.Numbers.toSet.equals(numberList.toSet) mustEqual true obj.Numbers.toSet.equals(numberList.toSet) mustEqual true
@ -40,7 +40,7 @@ class NumberPoolHubTest extends Specification {
} }
"enumerate the content of all pools" in { "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("fibonacci1", numberList1)
obj.AddPool("fibonacci2", numberList2) obj.AddPool("fibonacci2", numberList2)
numberSet1.intersect(obj.Numbers.toSet) mustEqual numberSet1 numberSet1.intersect(obj.Numbers.toSet) mustEqual numberSet1
@ -49,7 +49,7 @@ class NumberPoolHubTest extends Specification {
} }
"remove a pool" in { "remove a pool" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51)) val obj = new NumberPoolHub(new MaxNumberSource(51))
obj.Numbers.isEmpty mustEqual true obj.Numbers.isEmpty mustEqual true
obj.AddPool("fibonacci", numberList) obj.AddPool("fibonacci", numberList)
obj.Numbers.toSet.equals(numberList.toSet) mustEqual true obj.Numbers.toSet.equals(numberList.toSet) mustEqual true
@ -59,19 +59,19 @@ class NumberPoolHubTest extends Specification {
} }
"block removing the default 'generic' pool" in { "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] obj.RemovePool("generic") must throwA[IllegalArgumentException]
} }
"block adding pools that use already-included numbers" in { "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) obj.AddPool("fibonacci1", numberList)
val numberList4 = 3 :: 7 :: 21 :: 34 :: 45 :: Nil val numberList4 = 3 :: 7 :: 21 :: 34 :: 45 :: Nil
obj.AddPool("fibonacci2", numberList4) must throwA[IllegalArgumentException] obj.AddPool("fibonacci2", numberList4) must throwA[IllegalArgumentException]
} }
"enumerate only the content of all current pools" in { "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("fibonacci1", numberList1)
obj.AddPool("fibonacci2", numberList2) obj.AddPool("fibonacci2", numberList2)
numberSet1.intersect(obj.Numbers.toSet) mustEqual numberSet1 numberSet1.intersect(obj.Numbers.toSet) mustEqual numberSet1
@ -82,7 +82,7 @@ class NumberPoolHubTest extends Specification {
} }
"register an object to a pool" in { "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) hub.AddPool("fibonacci", numberList)
val obj = new EntityTestClass() val obj = new EntityTestClass()
obj.GUID must throwA[Exception] obj.GUID must throwA[Exception]
@ -95,7 +95,7 @@ class NumberPoolHubTest extends Specification {
} }
"lookup a registered object" in { "lookup a registered object" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51)) val hub = new NumberPoolHub(new MaxNumberSource(51))
hub.AddPool("fibonacci", numberList) hub.AddPool("fibonacci", numberList)
val obj = new EntityTestClass() val obj = new EntityTestClass()
hub.register(obj, "fibonacci") match { hub.register(obj, "fibonacci") match {
@ -108,14 +108,14 @@ class NumberPoolHubTest extends Specification {
} }
"lookup the pool of a(n unassigned) number" in { "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("fibonacci1", numberList1)
hub.AddPool("fibonacci2", numberList2) hub.AddPool("fibonacci2", numberList2)
hub.WhichPool(13).contains("fibonacci2") mustEqual true hub.WhichPool(13).contains("fibonacci2") mustEqual true
} }
"lookup the pool of a registered object" in { "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) hub.AddPool("fibonacci", numberList1)
val obj = new EntityTestClass() val obj = new EntityTestClass()
hub.register(obj, "fibonacci") 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 { "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) hub.AddPool("fibonacci", numberList1)
val obj = new EntityTestClass() val obj = new EntityTestClass()
obj.GUID must throwA[Exception] obj.GUID must throwA[Exception]
@ -137,7 +137,7 @@ class NumberPoolHubTest extends Specification {
} }
"register an object to a specific, pooled number (list 1)" in { "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) val hub = new NumberPoolHub(src)
hub.AddPool("fibonacci", numberList) hub.AddPool("fibonacci", numberList)
val obj = new EntityTestClass() val obj = new EntityTestClass()
@ -146,14 +146,14 @@ class NumberPoolHubTest extends Specification {
case Success(number) => case Success(number) =>
obj.GUID mustEqual PlanetSideGUID(number) obj.GUID mustEqual PlanetSideGUID(number)
hub.WhichPool(obj).contains("fibonacci") mustEqual true hub.WhichPool(obj).contains("fibonacci") mustEqual true
src.Available(5).isEmpty mustEqual true src.getAvailable(5).isEmpty mustEqual true
case _ => case _ =>
ko ko
} }
} }
"register an object to a specific, pooled number (list 2)" in { "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) val hub = new NumberPoolHub(src)
hub.AddPool("fibonacci", numberList2) hub.AddPool("fibonacci", numberList2)
val obj = new EntityTestClass() val obj = new EntityTestClass()
@ -162,21 +162,21 @@ class NumberPoolHubTest extends Specification {
case Success(number) => case Success(number) =>
obj.GUID mustEqual PlanetSideGUID(number) obj.GUID mustEqual PlanetSideGUID(number)
hub.WhichPool(obj).contains("fibonacci") mustEqual true hub.WhichPool(obj).contains("fibonacci") mustEqual true
src.Available(13).isEmpty mustEqual true src.getAvailable(13).isEmpty mustEqual true
case _ => case _ =>
ko ko
} }
} }
"register an object without extra specifications; it is assigned to pool 'generic'" in { "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() val obj = new EntityTestClass()
hub.register(obj) hub.register(obj)
hub.WhichPool(obj).contains("generic") mustEqual true hub.WhichPool(obj).contains("generic") mustEqual true
} }
"unregister an object" in { "unregister an object" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51)) val hub = new NumberPoolHub(new MaxNumberSource(51))
hub.AddPool("fibonacci", numberList) hub.AddPool("fibonacci", numberList)
val obj = new EntityTestClass() val obj = new EntityTestClass()
obj.HasGUID mustEqual false obj.HasGUID mustEqual false
@ -190,7 +190,7 @@ class NumberPoolHubTest extends Specification {
} }
"not register an object to a different pool" in { "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("fibonacci1", numberList1)
hub.AddPool("fibonacci2", numberList2) hub.AddPool("fibonacci2", numberList2)
val obj = new EntityTestClass() 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 { "fail to unregister an object that is not registered to this hub" in {
val hub1 = new NumberPoolHub(new LimitedNumberSource(51)) val hub1 = new NumberPoolHub(new MaxNumberSource(51))
val hub2 = new NumberPoolHub(new LimitedNumberSource(51)) val hub2 = new NumberPoolHub(new MaxNumberSource(51))
hub1.AddPool("fibonacci", numberList) hub1.AddPool("fibonacci", numberList)
hub2.AddPool("fibonacci", numberList) hub2.AddPool("fibonacci", numberList)
val obj = new EntityTestClass() val obj = new EntityTestClass()
hub1.register(obj, "fibonacci") hub1.register(obj, "fibonacci")
hub2.unregister(obj) must throwA[Exception] hub2.unregister(obj).isFailure mustEqual true
} }
"pre-register a specific, unused number" in { "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 { hub.register(13) match {
case Success(_) => case Success(_) =>
ok ok
@ -220,7 +220,7 @@ class NumberPoolHubTest extends Specification {
} }
"pre-register a specific, pooled number" in { "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.AddPool("fibonacci", numberList)
hub.register(13) match { hub.register(13) match {
case Success(key) => case Success(key) =>
@ -231,7 +231,7 @@ class NumberPoolHubTest extends Specification {
} }
"pre-register a number from a known pool" in { "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.AddPool("fibonacci", numberList).Selector = new RandomSelector
hub.register("fibonacci") match { hub.register("fibonacci") match {
case Success(key) => case Success(key) =>
@ -242,7 +242,7 @@ class NumberPoolHubTest extends Specification {
} }
"unregister a number" in { "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 hub.AddPool("fibonacci", numberList).Selector = new RandomSelector //leave this tagged on
val obj = new EntityTestClass() val obj = new EntityTestClass()
hub.register(13) match { hub.register(13) match {
@ -263,48 +263,48 @@ class NumberPoolHubTest extends Specification {
} }
"not affect the hidden restricted pool by adding a new pool" in { "not affect the hidden restricted pool by adding a new pool" in {
val src = new LimitedNumberSource(51) val src = new MaxNumberSource(51)
src.Restrict(4) src.restrictNumber(4)
src.Restrict(8) //in fibonacci src.restrictNumber(8) //in fibonacci
src.Restrict(10) src.restrictNumber(10)
src.Restrict(12) src.restrictNumber(12)
val hub = new NumberPoolHub(src) val hub = new NumberPoolHub(src)
hub.AddPool("fibonacci", numberList) must throwA[IllegalArgumentException] hub.AddPool("fibonacci", numberList) must throwA[IllegalArgumentException]
} }
"not register an object to a number belonging to the restricted pool" in { "not register an object to a number belonging to the restricted pool" in {
val src = new LimitedNumberSource(51) val src = new MaxNumberSource(51)
src.Restrict(4) src.restrictNumber(4)
val hub = new NumberPoolHub(src) val hub = new NumberPoolHub(src)
val obj = new EntityTestClass() val obj = new EntityTestClass()
hub.register(obj, 4).isFailure mustEqual true hub.register(obj, 4).isFailure mustEqual true
} }
"not register an object to the restricted pool directly" in { "not register an object to the restricted pool directly" in {
val src = new LimitedNumberSource(51) val src = new MaxNumberSource(51)
// src.Restrict(4) // src.restrictNumber(4)
val hub = new NumberPoolHub(src) val hub = new NumberPoolHub(src)
val obj = new EntityTestClass() val obj = new EntityTestClass()
hub.register(obj, "").isFailure mustEqual true //the empty string represents the restricted pool hub.register(obj, "").isFailure mustEqual true //the empty string represents the restricted pool
} }
"not register a number belonging to the restricted pool" in { "not register a number belonging to the restricted pool" in {
val src = new LimitedNumberSource(51) val src = new MaxNumberSource(51)
src.Restrict(4) src.restrictNumber(4)
val hub = new NumberPoolHub(src) val hub = new NumberPoolHub(src)
hub.register(4).isFailure mustEqual true hub.register(4).isFailure mustEqual true
} }
"not unregister a number belonging to the restricted pool" in { "not unregister a number belonging to the restricted pool" in {
val src = new LimitedNumberSource(51) val src = new MaxNumberSource(51)
src.Restrict(4) src.restrictNumber(4)
val hub = new NumberPoolHub(src) val hub = new NumberPoolHub(src)
hub.unregister(4).isFailure mustEqual true hub.unregister(4).isFailure mustEqual true
} }
"identity an object that is registered to it" in { "identity an object that is registered to it" in {
val hub1 = new NumberPoolHub(new LimitedNumberSource(10)) val hub1 = new NumberPoolHub(new MaxNumberSource(10))
val hub2 = new NumberPoolHub(new LimitedNumberSource(10)) val hub2 = new NumberPoolHub(new MaxNumberSource(10))
val obj1 = new EntityTestClass() val obj1 = new EntityTestClass()
val obj2 = new EntityTestClass() val obj2 = new EntityTestClass()
hub1.register(obj1) hub1.register(obj1)
@ -317,15 +317,15 @@ class NumberPoolHubTest extends Specification {
} }
"identity a number that is registered to it" in { "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 hub1 = new NumberPoolHub(src1)
val src2 = new LimitedNumberSource(10) val src2 = new MaxNumberSource(10)
src2.Restrict(0) src2.restrictNumber(0)
src2.Restrict(1) src2.restrictNumber(1)
src2.Restrict(2) src2.restrictNumber(2)
src2.Restrict(3) src2.restrictNumber(3)
src2.Restrict(4) src2.restrictNumber(4)
src2.Restrict(5) src2.restrictNumber(5)
val hub2 = new NumberPoolHub(src2) val hub2 = new NumberPoolHub(src2)
val obj1 = new EntityTestClass() val obj1 = new EntityTestClass()
val obj2 = new EntityTestClass() val obj2 = new EntityTestClass()

View file

@ -10,62 +10,71 @@ class NumberSourceTest extends Specification {
import net.psforever.objects.entity.IdentifiableEntity import net.psforever.objects.entity.IdentifiableEntity
private class TestClass extends IdentifiableEntity private class TestClass extends IdentifiableEntity
"LimitedNumberSource" should { "MaxNumberSource" should {
import net.psforever.objects.guid.source.LimitedNumberSource import net.psforever.objects.guid.source.MaxNumberSource
"construct" in { "construct" in {
val obj = LimitedNumberSource(25) val obj = MaxNumberSource(25)
obj.Size mustEqual 26 obj.size mustEqual 26
obj.CountAvailable mustEqual 26 obj.countAvailable mustEqual 26
obj.CountUsed mustEqual 0 obj.countUsed mustEqual 0
} }
"get a number" in { "construct failure (negative max value)" in {
val obj = LimitedNumberSource(25) MaxNumberSource(-1) must throwA[IllegalArgumentException]
val result: Option[LoanedKey] = obj.Available(5) }
"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.isDefined mustEqual true
result.get.GUID mustEqual 5 result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Leased result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object.isEmpty mustEqual true result.get.Object.isEmpty mustEqual true
obj.Size mustEqual 26 obj.size mustEqual 26
obj.CountAvailable mustEqual 25 obj.countAvailable mustEqual 25
obj.CountUsed mustEqual 1 obj.countUsed mustEqual 1
} }
"assign the number" in { "assign the number" in {
val obj = LimitedNumberSource(25) val obj = MaxNumberSource(25)
val result: Option[LoanedKey] = obj.Available(5) val result: Option[LoanedKey] = obj.getAvailable(5)
result.isDefined mustEqual true result.isDefined mustEqual true
result.get.Object = new TestClass() result.get.Object = new TestClass()
ok ok
} }
"return a number (unused)" in { "return a number (unused)" in {
val obj = LimitedNumberSource(25) val obj = MaxNumberSource(25)
val result: Option[LoanedKey] = obj.Available(5) val result: Option[LoanedKey] = obj.getAvailable(5)
result.isDefined mustEqual true result.isDefined mustEqual true
result.get.GUID mustEqual 5 result.get.GUID mustEqual 5
obj.CountUsed mustEqual 1 obj.countUsed mustEqual 1
val ret = obj.Return(result.get) val ret = obj.returnNumber(result.get)
ret.isEmpty mustEqual true ret.isEmpty mustEqual true
obj.CountUsed mustEqual 0 obj.countUsed mustEqual 0
} }
"return a number (assigned)" in { "return a number (assigned)" in {
val obj = LimitedNumberSource(25) val obj = MaxNumberSource(25)
val test = new TestClass() val test = new TestClass()
val result: Option[LoanedKey] = obj.Available(5) val result: Option[LoanedKey] = obj.getAvailable(5)
result.isDefined mustEqual true result.isDefined mustEqual true
result.get.GUID mustEqual 5 result.get.GUID mustEqual 5
result.get.Object = test result.get.Object = test
obj.CountUsed mustEqual 1 obj.countUsed mustEqual 1
val ret = obj.Return(result.get) val ret = obj.returnNumber(result.get)
ret.contains(test) mustEqual true ret.contains(test) mustEqual true
obj.CountUsed mustEqual 0 obj.countUsed mustEqual 0
} }
"restrict a number (unassigned)" in { "restrict a number (unassigned)" in {
val obj = LimitedNumberSource(25) val obj = MaxNumberSource(25)
val result: Option[LoanedKey] = obj.Restrict(5) val result: Option[LoanedKey] = obj.restrictNumber(5)
result.isDefined mustEqual true result.isDefined mustEqual true
result.get.GUID mustEqual 5 result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Restricted result.get.Policy mustEqual AvailabilityPolicy.Restricted
@ -73,10 +82,10 @@ class NumberSourceTest extends Specification {
} }
"restrict a number (assigned + multiple assignments)" in { "restrict a number (assigned + multiple assignments)" in {
val obj = LimitedNumberSource(25) val obj = MaxNumberSource(25)
val test1 = new TestClass() val test1 = new TestClass()
val test2 = 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.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Restricted result.get.Policy mustEqual AvailabilityPolicy.Restricted
result.get.Object.isEmpty mustEqual true result.get.Object.isEmpty mustEqual true
@ -89,108 +98,309 @@ class NumberSourceTest extends Specification {
} }
"return a restricted number (correctly fail)" in { "return a restricted number (correctly fail)" in {
val obj = LimitedNumberSource(25) val obj = MaxNumberSource(25)
val test = new TestClass() 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.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Restricted result.get.Policy mustEqual AvailabilityPolicy.Restricted
result.get.Object = test result.get.Object = test
obj.Return(5) obj.returnNumber(5)
val result2: Option[SecureKey] = obj.Get(5) val result2: Option[SecureKey] = obj.get(5)
result2.get.GUID mustEqual 5 result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Restricted result2.get.Policy mustEqual AvailabilityPolicy.Restricted
result2.get.Object.contains(test) mustEqual true result2.get.Object.contains(test) mustEqual true
} }
"return a secure key" in { "return a secure key" in {
val obj = LimitedNumberSource(25) val obj = MaxNumberSource(25)
val test = new TestClass() val test = new TestClass()
val result1: Option[LoanedKey] = obj.Available(5) val result1: Option[LoanedKey] = obj.getAvailable(5)
result1.get.Object = test result1.get.Object = test
test.GUID mustEqual PlanetSideGUID(5) test.GUID mustEqual PlanetSideGUID(5)
val result2: Option[SecureKey] = obj.Get(5) val result2: Option[SecureKey] = obj.get(5)
obj.Return(result2.get).contains(test) mustEqual true obj.returnNumber(result2.get).contains(test) mustEqual true
} }
"restrict a previously-assigned number" in { "restrict a previously-assigned number" in {
val obj = LimitedNumberSource(25) val obj = MaxNumberSource(25)
val test = new TestClass() val test = new TestClass()
val result1: Option[LoanedKey] = obj.Available(5) val result1: Option[LoanedKey] = obj.getAvailable(5)
result1.isDefined mustEqual true result1.isDefined mustEqual true
result1.get.Policy mustEqual AvailabilityPolicy.Leased result1.get.Policy mustEqual AvailabilityPolicy.Leased
result1.get.Object = test result1.get.Object = test
val result2: Option[LoanedKey] = obj.Restrict(5) val result2: Option[LoanedKey] = obj.restrictNumber(5)
result2.isDefined mustEqual true result2.isDefined mustEqual true
result2.get.Policy mustEqual AvailabilityPolicy.Restricted result2.get.Policy mustEqual AvailabilityPolicy.Restricted
result2.get.Object.contains(test) mustEqual true result2.get.Object.contains(test) mustEqual true
} }
"check a number (not previously gotten)" in { "check a number (not previously gotten)" in {
val obj = LimitedNumberSource(25) val obj = MaxNumberSource(25)
val result2: Option[SecureKey] = obj.Get(5) val result2: Option[SecureKey] = obj.get(5)
result2.get.GUID mustEqual 5 result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Available result2.get.Policy mustEqual AvailabilityPolicy.Available
result2.get.Object.isEmpty mustEqual true result2.get.Object.isEmpty mustEqual true
} }
"check a number (previously gotten)" in { "check a number (previously gotten)" in {
val obj = LimitedNumberSource(25) val obj = MaxNumberSource(25)
val result: Option[LoanedKey] = obj.Available(5) val result: Option[LoanedKey] = obj.getAvailable(5)
result.isDefined mustEqual true result.isDefined mustEqual true
result.get.GUID mustEqual 5 result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Leased result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object.isEmpty mustEqual true 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.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Leased result2.get.Policy mustEqual AvailabilityPolicy.Leased
result2.get.Object.isEmpty mustEqual true result2.get.Object.isEmpty mustEqual true
} }
"check a number (assigned)" in { "check a number (assigned)" in {
val obj = LimitedNumberSource(25) val obj = MaxNumberSource(25)
val result: Option[LoanedKey] = obj.Available(5) val result: Option[LoanedKey] = obj.getAvailable(5)
result.isDefined mustEqual true result.isDefined mustEqual true
result.get.GUID mustEqual 5 result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Leased result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object = new TestClass() 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.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Leased result2.get.Policy mustEqual AvailabilityPolicy.Leased
result2.get.Object mustEqual result.get.Object result2.get.Object mustEqual result.get.Object
} }
"check a number (assigned and returned)" in { "check a number (assigned and returned)" in {
val obj = LimitedNumberSource(25) val obj = MaxNumberSource(25)
val test = new TestClass() 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.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object = test 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.Policy mustEqual AvailabilityPolicy.Leased
result2.get.Object.get mustEqual test result2.get.Object.get mustEqual test
obj.Return(5).contains(test) mustEqual true obj.returnNumber(5).contains(test) mustEqual true
val result3: Option[SecureKey] = obj.Get(5) val result3: Option[SecureKey] = obj.get(5)
result3.get.Policy mustEqual AvailabilityPolicy.Available result3.get.Policy mustEqual AvailabilityPolicy.Available
result3.get.Object.isEmpty mustEqual true result3.get.Object.isEmpty mustEqual true
} }
"clear" in { "clear" in {
val obj = LimitedNumberSource(25) val obj = MaxNumberSource(25)
val test1 = new TestClass() val test1 = new TestClass()
val test2 = new TestClass() val test2 = new TestClass()
val test3 = new TestClass() val test3 = new TestClass()
obj.Available(5) //no assignment obj.getAvailable(5) //no assignment
obj.Available(10).get.Object = test1 obj.getAvailable(10).get.Object = test1
obj.Available(15).get.Object = test2 obj.getAvailable(15).get.Object = test2
obj.Restrict(15) obj.restrictNumber(15)
obj.Restrict(20).get.Object = test3 obj.restrictNumber(20).get.Object = test3
obj.CountUsed mustEqual 4 obj.countUsed mustEqual 4
val list: List[IdentifiableEntity] = obj.Clear() val list: List[IdentifiableEntity] = obj.clear()
obj.CountUsed mustEqual 0 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.size mustEqual 3
list.count(obj => obj == test1) mustEqual 1 list.count(obj => obj == test1) mustEqual 1
list.count(obj => obj == test2) mustEqual 1 list.count(obj => obj == test2) mustEqual 1

View file

@ -7,7 +7,7 @@ import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.objects.guid.NumberPoolHub import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.actor.{NumberPoolActor, Register, UniqueNumberSystem, Unregister} import net.psforever.objects.guid.actor.{NumberPoolActor, Register, UniqueNumberSystem, Unregister}
import net.psforever.objects.guid.selector.RandomSelector 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 net.psforever.types.PlanetSideGUID
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -15,7 +15,7 @@ import scala.util.{Failure, Success}
class AllocateNumberPoolActors extends ActorTest { class AllocateNumberPoolActors extends ActorTest {
"AllocateNumberPoolActors" in { "AllocateNumberPoolActors" in {
val src: LimitedNumberSource = LimitedNumberSource(6000) val src: MaxNumberSource = MaxNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src) val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList) guid.AddPool("pool1", (1001 to 2000).toList)
guid.AddPool("pool2", (3001 to 4000).toList) guid.AddPool("pool2", (3001 to 4000).toList)
@ -32,7 +32,7 @@ class AllocateNumberPoolActors extends ActorTest {
class UniqueNumberSystemTest extends ActorTest() { class UniqueNumberSystemTest extends ActorTest() {
"UniqueNumberSystem" should { "UniqueNumberSystem" should {
"constructor" in { "constructor" in {
val src: LimitedNumberSource = LimitedNumberSource(6000) val src: MaxNumberSource = MaxNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src) val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList) guid.AddPool("pool1", (1001 to 2000).toList)
guid.AddPool("pool2", (3001 to 4000).toList) guid.AddPool("pool2", (3001 to 4000).toList)
@ -51,7 +51,7 @@ class UniqueNumberSystemTest1 extends ActorTest() {
"UniqueNumberSystem" should { "UniqueNumberSystem" should {
"Register (success)" in { "Register (success)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000) val src: MaxNumberSource = MaxNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src) val guid: NumberPoolHub = new NumberPoolHub(src)
val pool1 = (1001 to 2000).toList val pool1 = (1001 to 2000).toList
val pool2 = (3001 to 4000).toList val pool2 = (3001 to 4000).toList
@ -63,7 +63,7 @@ class UniqueNumberSystemTest1 extends ActorTest() {
Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystemTest.AllocateNumberPoolActors(guid)), Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystemTest.AllocateNumberPoolActors(guid)),
"uns" "uns"
) )
assert(src.CountUsed == 0) assert(src.countUsed == 0)
//pool1 //pool1
for (_ <- 1 to 100) { for (_ <- 1 to 100) {
val testObj = new EntityTestClass() val testObj = new EntityTestClass()
@ -88,7 +88,7 @@ class UniqueNumberSystemTest1 extends ActorTest() {
assert(msg.isInstanceOf[Success[_]]) assert(msg.isInstanceOf[Success[_]])
assert(pool3.contains(testObj.GUID.guid)) assert(pool3.contains(testObj.GUID.guid))
} }
assert(src.CountUsed == 300) assert(src.countUsed == 300)
} }
} }
} }
@ -98,7 +98,7 @@ class UniqueNumberSystemTest2 extends ActorTest() {
"UniqueNumberSystem" should { "UniqueNumberSystem" should {
"Register (success; already registered)" in { "Register (success; already registered)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000) val src: MaxNumberSource = MaxNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src) val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
guid.AddPool("pool2", (3001 to 4000).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() val testObj = new EntityTestClass()
assert(!testObj.HasGUID) assert(!testObj.HasGUID)
assert(src.CountUsed == 0) assert(src.countUsed == 0)
uns ! Register(testObj, "pool1") uns ! Register(testObj, "pool1")
val msg1 = receiveOne(Duration.create(500, "ms")) val msg1 = receiveOne(Duration.create(500, "ms"))
assert(msg1.isInstanceOf[Success[_]]) assert(msg1.isInstanceOf[Success[_]])
assert(testObj.HasGUID) assert(testObj.HasGUID)
assert(src.CountUsed == 1) assert(src.countUsed == 1)
val id = testObj.GUID.guid val id = testObj.GUID.guid
uns ! Register(testObj, "pool2") //different pool; makes no difference uns ! Register(testObj, "pool2") //different pool; makes no difference
val msg2 = receiveOne(Duration.create(500, "ms")) val msg2 = receiveOne(Duration.create(500, "ms"))
assert(msg2.isInstanceOf[Success[_]]) assert(msg2.isInstanceOf[Success[_]])
assert(testObj.HasGUID) assert(testObj.HasGUID)
assert(src.CountUsed == 1) assert(src.countUsed == 1)
assert(testObj.GUID.guid == id) //unchanged assert(testObj.GUID.guid == id) //unchanged
} }
} }
@ -134,7 +134,7 @@ class UniqueNumberSystemTest3 extends ActorTest() {
"UniqueNumberSystem" should { "UniqueNumberSystem" should {
"Register (failure; no pool)" in { "Register (failure; no pool)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000) val src: MaxNumberSource = MaxNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src) val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
guid.AddPool("pool2", (3001 to 4000).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() val testObj = new EntityTestClass()
assert(!testObj.HasGUID) assert(!testObj.HasGUID)
assert(src.CountUsed == 0) assert(src.countUsed == 0)
uns ! Register(testObj, "pool4") uns ! Register(testObj, "pool4")
val msg1 = receiveOne(Duration.create(500, "ms")) val msg1 = receiveOne(Duration.create(500, "ms"))
assert(msg1.isInstanceOf[Failure[_]]) assert(msg1.isInstanceOf[Failure[_]])
assert(!testObj.HasGUID) assert(!testObj.HasGUID)
assert(src.CountUsed == 0) assert(src.countUsed == 0)
} }
} }
} }
@ -161,7 +161,7 @@ class UniqueNumberSystemTest4 extends ActorTest() {
"UniqueNumberSystem" should { "UniqueNumberSystem" should {
"Register (failure; empty pool)" in { "Register (failure; empty pool)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000) val src: MaxNumberSource = MaxNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src) val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector
@ -190,7 +190,7 @@ class UniqueNumberSystemTest5 extends ActorTest() {
"UniqueNumberSystem" should { "UniqueNumberSystem" should {
"Unregister (success)" in { "Unregister (success)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000) val src: MaxNumberSource = MaxNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src) val guid: NumberPoolHub = new NumberPoolHub(src)
val pool2 = (3001 to 4000).toList val pool2 = (3001 to 4000).toList
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
@ -202,20 +202,20 @@ class UniqueNumberSystemTest5 extends ActorTest() {
) )
val testObj = new EntityTestClass() val testObj = new EntityTestClass()
assert(!testObj.HasGUID) assert(!testObj.HasGUID)
assert(src.CountUsed == 0) assert(src.countUsed == 0)
uns ! Register(testObj, "pool2") uns ! Register(testObj, "pool2")
val msg1 = receiveOne(Duration.create(2000, "ms")) val msg1 = receiveOne(Duration.create(2000, "ms"))
assert(msg1.isInstanceOf[Success[_]]) assert(msg1.isInstanceOf[Success[_]])
assert(testObj.HasGUID) assert(testObj.HasGUID)
assert(pool2.contains(testObj.GUID.guid)) assert(pool2.contains(testObj.GUID.guid))
assert(src.CountUsed == 1) assert(src.countUsed == 1)
uns ! Unregister(testObj) uns ! Unregister(testObj)
val msg2 = receiveOne(Duration.create(2000, "ms")) val msg2 = receiveOne(Duration.create(2000, "ms"))
assert(msg2.isInstanceOf[Success[_]]) assert(msg2.isInstanceOf[Success[_]])
assert(!testObj.HasGUID) assert(!testObj.HasGUID)
assert(src.CountUsed == 0) assert(src.countUsed == 0)
} }
} }
} }
@ -225,7 +225,7 @@ class UniqueNumberSystemTest6 extends ActorTest() {
"UniqueNumberSystem" should { "UniqueNumberSystem" should {
"Unregister (success; object not registered at all)" in { "Unregister (success; object not registered at all)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000) val src: MaxNumberSource = MaxNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src) val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
guid.AddPool("pool2", (3001 to 4000).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() val testObj = new EntityTestClass()
assert(!testObj.HasGUID) assert(!testObj.HasGUID)
assert(src.CountUsed == 0) assert(src.countUsed == 0)
uns ! Unregister(testObj) uns ! Unregister(testObj)
val msg1 = receiveOne(Duration.create(500, "ms")) val msg1 = receiveOne(Duration.create(500, "ms"))
assert(msg1.isInstanceOf[Success[_]]) assert(msg1.isInstanceOf[Success[_]])
assert(!testObj.HasGUID) assert(!testObj.HasGUID)
assert(src.CountUsed == 0) assert(src.countUsed == 0)
} }
} }
} }
@ -252,7 +252,7 @@ class UniqueNumberSystemTest7 extends ActorTest() {
"UniqueNumberSystem" should { "UniqueNumberSystem" should {
"Unregister (failure; number not in system)" in { "Unregister (failure; number not in system)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000) val src: MaxNumberSource = MaxNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src) val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
guid.AddPool("pool2", (3001 to 4000).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() val testObj = new EntityTestClass()
testObj.GUID = PlanetSideGUID(6001) //fake registering; number too high testObj.GUID = PlanetSideGUID(6001) //fake registering; number too high
assert(testObj.HasGUID) assert(testObj.HasGUID)
assert(src.CountUsed == 0) assert(src.countUsed == 0)
uns ! Unregister(testObj) uns ! Unregister(testObj)
val msg1 = receiveOne(Duration.create(500, "ms")) val msg1 = receiveOne(Duration.create(500, "ms"))
assert(msg1.isInstanceOf[Failure[_]]) assert(msg1.isInstanceOf[Failure[_]])
assert(testObj.HasGUID) assert(testObj.HasGUID)
assert(src.CountUsed == 0) assert(src.countUsed == 0)
} }
} }
} }
@ -280,7 +280,7 @@ class UniqueNumberSystemTest8 extends ActorTest() {
"UniqueNumberSystem" should { "UniqueNumberSystem" should {
"Unregister (failure; object is not registered to that number)" in { "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) val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
guid.AddPool("pool2", (3001 to 4000).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() val testObj = new EntityTestClass()
testObj.GUID = PlanetSideGUID(3500) //fake registering testObj.GUID = PlanetSideGUID(3500) //fake registering
assert(testObj.HasGUID) assert(testObj.HasGUID)
assert(src.CountUsed == 0) assert(src.countUsed == 0)
uns ! Unregister(testObj) uns ! Unregister(testObj)
val msg1 = receiveOne(Duration.create(500, "ms")) val msg1 = receiveOne(Duration.create(500, "ms"))
assert(msg1.isInstanceOf[Failure[_]]) assert(msg1.isInstanceOf[Failure[_]])
assert(testObj.HasGUID) assert(testObj.HasGUID)
assert(src.CountUsed == 0) assert(src.countUsed == 0)
} }
} }
} }
@ -308,7 +308,7 @@ class UniqueNumberSystemTest9 extends ActorTest() {
"UniqueNumberSystem" should { "UniqueNumberSystem" should {
"Failures (manually walking the failure cases)" in { "Failures (manually walking the failure cases)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000) val src: MaxNumberSource = MaxNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src) val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector
@ -345,7 +345,7 @@ class UniqueNumberSystemTestA extends ActorTest {
"UniqueNumberSystem" should { "UniqueNumberSystem" should {
"remain consistent between registrations" in { "remain consistent between registrations" in {
val src: LimitedNumberSource = LimitedNumberSource(10) val src: MaxNumberSource = MaxNumberSource(10)
val guid: NumberPoolHub = new NumberPoolHub(src) val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (0 until 10).toList).Selector = new RandomSelector guid.AddPool("pool1", (0 until 10).toList).Selector = new RandomSelector
val uns = system.actorOf( val uns = system.actorOf(
@ -354,9 +354,9 @@ class UniqueNumberSystemTestA extends ActorTest {
) )
expectNoMessage(Duration.create(200, "ms")) 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) }) (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") }) (0 to 5).foreach(_ => { uns ! Register(new EntityTestClass(), "pool1") })
assert(receiveOne(200 milliseconds).isInstanceOf[Success[_]]) //6th 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[_]]) //9th
assert(receiveOne(200 milliseconds).isInstanceOf[Success[_]]) //10th assert(receiveOne(200 milliseconds).isInstanceOf[Success[_]]) //10th
assert(receiveOne(200 milliseconds).isInstanceOf[Failure[_]]) //no more assert(receiveOne(200 milliseconds).isInstanceOf[Failure[_]]) //no more
assert(src.CountUsed == 10) assert(src.countUsed == 10)
} }
} }
} }

View file

@ -7,7 +7,7 @@ import net.psforever.objects.avatar.Avatar
import net.psforever.objects.{Default, GlobalDefinitions, Player} import net.psforever.objects.{Default, GlobalDefinitions, Player}
import net.psforever.objects.definition.SeatDefinition import net.psforever.objects.definition.SeatDefinition
import net.psforever.objects.guid.NumberPoolHub 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.mount.Mountable
import net.psforever.objects.serverobject.implantmech.{ImplantTerminalMech, ImplantTerminalMechControl} import net.psforever.objects.serverobject.implantmech.{ImplantTerminalMech, ImplantTerminalMechControl}
import net.psforever.objects.serverobject.structures.{Building, StructureType} import net.psforever.objects.serverobject.structures.{Building, StructureType}
@ -162,7 +162,7 @@ class ImplantTerminalMechControl5Test extends ActorTest {
object ImplantTerminalMechTest { object ImplantTerminalMechTest {
def SetUpAgents(faction: PlanetSideEmpire.Value)(implicit system: ActorSystem): (Player, ImplantTerminalMech) = { 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 map = new ZoneMap("test")
val zone = new Zone("test", map, 0) { val zone = new Zone("test", map, 0) {
override def SetupNumberPools() = {} override def SetupNumberPools() = {}