mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-15 08:24:39 +00:00
commit
c5246d5f10
7 changed files with 161 additions and 27 deletions
|
|
@ -500,6 +500,8 @@ object GlobalDefinitions {
|
||||||
|
|
||||||
val spawn_pad = new ObjectDefinition(800) { Name = "spawn_pad" }
|
val spawn_pad = new ObjectDefinition(800) { Name = "spawn_pad" }
|
||||||
|
|
||||||
|
val mb_locker = new ObjectDefinition(524) { Name = "mb_locker" }
|
||||||
|
|
||||||
val lock_external = new IFFLockDefinition
|
val lock_external = new IFFLockDefinition
|
||||||
|
|
||||||
val door = new DoorDefinition
|
val door = new DoorDefinition
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,55 @@
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.definition.EquipmentDefinition
|
import net.psforever.objects.definition.EquipmentDefinition
|
||||||
import net.psforever.objects.definition.converter.LockerContainerConverter
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.objects.equipment.{Equipment, EquipmentSize}
|
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
|
||||||
import net.psforever.objects.inventory.GridInventory
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
|
||||||
class LockerContainer extends Equipment {
|
import scala.annotation.tailrec
|
||||||
|
|
||||||
|
class LockerContainer extends Equipment with Container {
|
||||||
private val inventory = GridInventory(30, 20)
|
private val inventory = GridInventory(30, 20)
|
||||||
|
|
||||||
def Inventory : GridInventory = inventory
|
def Inventory : GridInventory = inventory
|
||||||
|
|
||||||
|
def VisibleSlots : Set[Int] = Set.empty[Int]
|
||||||
|
|
||||||
|
override def Slot(slot : Int) : EquipmentSlot = {
|
||||||
|
if(inventory.Offset <= slot && slot <= inventory.LastIndex) {
|
||||||
|
inventory.Slot(slot)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
OffhandEquipmentSlot.BlockedSlot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def Fit(obj : Equipment) : Option[Int] = inventory.Fit(obj.Definition.Tile)
|
def Fit(obj : Equipment) : Option[Int] = inventory.Fit(obj.Definition.Tile)
|
||||||
|
|
||||||
|
def Find(guid : PlanetSideGUID) : Option[Int] = {
|
||||||
|
findInInventory(inventory.Items.values.iterator, guid) match {
|
||||||
|
case Some(index) =>
|
||||||
|
Some(index)
|
||||||
|
case None =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@tailrec private def findInInventory(iter : Iterator[InventoryItem], guid : PlanetSideGUID) : Option[Int] = {
|
||||||
|
if(!iter.hasNext) {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val item = iter.next
|
||||||
|
if(item.obj.GUID == guid) {
|
||||||
|
Some(item.start)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
findInInventory(iter, guid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def Definition : EquipmentDefinition = GlobalDefinitions.locker_container
|
def Definition : EquipmentDefinition = GlobalDefinitions.locker_container
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -20,11 +58,4 @@ object LockerContainer {
|
||||||
def apply() : LockerContainer = {
|
def apply() : LockerContainer = {
|
||||||
new LockerContainer()
|
new LockerContainer()
|
||||||
}
|
}
|
||||||
|
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
|
||||||
def apply(guid : PlanetSideGUID) : LockerContainer = {
|
|
||||||
val obj = new LockerContainer()
|
|
||||||
obj.GUID = guid
|
|
||||||
obj
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,8 @@ class Player(private val name : String,
|
||||||
|
|
||||||
def Inventory : GridInventory = inventory
|
def Inventory : GridInventory = inventory
|
||||||
|
|
||||||
|
def Locker : LockerContainer = fifthSlot.Equipment.get.asInstanceOf[LockerContainer]
|
||||||
|
|
||||||
def Fit(obj : Equipment) : Option[Int] = {
|
def Fit(obj : Equipment) : Option[Int] = {
|
||||||
recursiveHolsterFit(holsters.iterator, obj.Size) match {
|
recursiveHolsterFit(holsters.iterator, obj.Size) match {
|
||||||
case Some(index) =>
|
case Some(index) =>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package net.psforever.objects.serverobject.mblocker
|
||||||
|
|
||||||
|
import akka.actor.ActorContext
|
||||||
|
import net.psforever.objects.GlobalDefinitions
|
||||||
|
import net.psforever.objects.definition.ObjectDefinition
|
||||||
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
|
|
||||||
|
class Locker extends PlanetSideServerObject {
|
||||||
|
def Definition : ObjectDefinition = GlobalDefinitions.mb_locker
|
||||||
|
}
|
||||||
|
|
||||||
|
object Locker {
|
||||||
|
/**
|
||||||
|
* Overloaded constructor.
|
||||||
|
* @return a `VehicleSpawnPad` object
|
||||||
|
*/
|
||||||
|
def apply() : Locker = {
|
||||||
|
new Locker()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate an configure a `Locker` 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;
|
||||||
|
* not necessary for this object, but required by signature
|
||||||
|
* @return the `Locker` object
|
||||||
|
*/
|
||||||
|
def Constructor(id : Int, context : ActorContext) : Locker = {
|
||||||
|
val obj = Locker()
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
package objects
|
package objects
|
||||||
|
|
||||||
import akka.actor.{Actor, Props}
|
import akka.actor.{Actor, Props}
|
||||||
import net.psforever.objects.GlobalDefinitions.order_terminal
|
|
||||||
import net.psforever.objects.guid.NumberPoolHub
|
import net.psforever.objects.guid.NumberPoolHub
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.objects.serverobject.ServerObjectBuilder
|
import net.psforever.objects.serverobject.ServerObjectBuilder
|
||||||
|
|
@ -62,6 +61,7 @@ class ImplantTerminalMechObjectBuilderTest extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
class TerminalObjectBuilderTest extends ActorTest {
|
class TerminalObjectBuilderTest extends ActorTest {
|
||||||
|
import net.psforever.objects.GlobalDefinitions.order_terminal
|
||||||
import net.psforever.objects.serverobject.terminals.Terminal
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
"TerminalObjectBuilder" should {
|
"TerminalObjectBuilder" should {
|
||||||
"build" in {
|
"build" in {
|
||||||
|
|
@ -99,6 +99,24 @@ class VehicleSpawnPadObjectBuilderTest extends ActorTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LockerObjectBuilderTest extends ActorTest {
|
||||||
|
import net.psforever.objects.serverobject.mblocker.Locker
|
||||||
|
"LockerObjectBuilder" should {
|
||||||
|
"build" in {
|
||||||
|
val hub = ServerObjectBuilderTest.NumberPoolHub
|
||||||
|
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1,
|
||||||
|
Locker.Constructor), hub), "locker")
|
||||||
|
actor ! "!"
|
||||||
|
|
||||||
|
val reply = receiveOne(Duration.create(1000, "ms"))
|
||||||
|
assert(reply.isInstanceOf[Locker])
|
||||||
|
assert(reply.asInstanceOf[Locker].HasGUID)
|
||||||
|
assert(reply.asInstanceOf[Locker].GUID == PlanetSideGUID(1))
|
||||||
|
assert(reply == hub(1).get)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object ServerObjectBuilderTest {
|
object ServerObjectBuilderTest {
|
||||||
import net.psforever.objects.guid.source.LimitedNumberSource
|
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||||
def NumberPoolHub : NumberPoolHub = {
|
def NumberPoolHub : NumberPoolHub = {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import net.psforever.objects.serverobject.ServerObjectBuilder
|
||||||
import net.psforever.objects.serverobject.doors.Door
|
import net.psforever.objects.serverobject.doors.Door
|
||||||
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
|
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
|
||||||
import net.psforever.objects.serverobject.locks.IFFLock
|
import net.psforever.objects.serverobject.locks.IFFLock
|
||||||
|
import net.psforever.objects.serverobject.mblocker.Locker
|
||||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||||
import net.psforever.objects.serverobject.terminals.Terminal
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
|
|
@ -62,6 +63,14 @@ object Maps {
|
||||||
LocalObject(ServerObjectBuilder(529, ImplantTerminalMech.Constructor)) //Hart C
|
LocalObject(ServerObjectBuilder(529, ImplantTerminalMech.Constructor)) //Hart C
|
||||||
LocalObject(ServerObjectBuilder(556, IFFLock.Constructor))
|
LocalObject(ServerObjectBuilder(556, IFFLock.Constructor))
|
||||||
LocalObject(ServerObjectBuilder(558, IFFLock.Constructor))
|
LocalObject(ServerObjectBuilder(558, IFFLock.Constructor))
|
||||||
|
LocalObject(ServerObjectBuilder(686, Locker.Constructor))
|
||||||
|
LocalObject(ServerObjectBuilder(687, Locker.Constructor))
|
||||||
|
LocalObject(ServerObjectBuilder(688, Locker.Constructor))
|
||||||
|
LocalObject(ServerObjectBuilder(689, Locker.Constructor))
|
||||||
|
LocalObject(ServerObjectBuilder(690, Locker.Constructor))
|
||||||
|
LocalObject(ServerObjectBuilder(691, Locker.Constructor))
|
||||||
|
LocalObject(ServerObjectBuilder(692, Locker.Constructor))
|
||||||
|
LocalObject(ServerObjectBuilder(693, Locker.Constructor))
|
||||||
LocalObject(ServerObjectBuilder(186, Terminal.Constructor(cert_terminal)))
|
LocalObject(ServerObjectBuilder(186, Terminal.Constructor(cert_terminal)))
|
||||||
LocalObject(ServerObjectBuilder(187, Terminal.Constructor(cert_terminal)))
|
LocalObject(ServerObjectBuilder(187, Terminal.Constructor(cert_terminal)))
|
||||||
LocalObject(ServerObjectBuilder(188, Terminal.Constructor(cert_terminal)))
|
LocalObject(ServerObjectBuilder(188, Terminal.Constructor(cert_terminal)))
|
||||||
|
|
@ -95,17 +104,17 @@ object Maps {
|
||||||
ObjectToBase(330, 29)
|
ObjectToBase(330, 29)
|
||||||
ObjectToBase(332, 29)
|
ObjectToBase(332, 29)
|
||||||
//ObjectToBase(520, 29)
|
//ObjectToBase(520, 29)
|
||||||
ObjectToBase(522, 29)
|
ObjectToBase(522, 2)
|
||||||
ObjectToBase(523, 29)
|
ObjectToBase(523, 2)
|
||||||
ObjectToBase(524, 29)
|
ObjectToBase(524, 2)
|
||||||
ObjectToBase(525, 29)
|
ObjectToBase(525, 2)
|
||||||
ObjectToBase(526, 29)
|
ObjectToBase(526, 2)
|
||||||
ObjectToBase(527, 29)
|
ObjectToBase(527, 2)
|
||||||
ObjectToBase(528, 29)
|
ObjectToBase(528, 2)
|
||||||
ObjectToBase(529, 29)
|
ObjectToBase(529, 2)
|
||||||
ObjectToBase(556, 29)
|
ObjectToBase(556, 29)
|
||||||
ObjectToBase(558, 29)
|
ObjectToBase(558, 29)
|
||||||
ObjectToBase(1081, 29)
|
ObjectToBase(1081, 2)
|
||||||
ObjectToBase(1063, 2) //TODO unowned courtyard terminal?
|
ObjectToBase(1063, 2) //TODO unowned courtyard terminal?
|
||||||
ObjectToBase(500, 2) //TODO unowned courtyard spawnpad?
|
ObjectToBase(500, 2) //TODO unowned courtyard spawnpad?
|
||||||
ObjectToBase(304, 2) //TODO unowned courtyard terminal?
|
ObjectToBase(304, 2) //TODO unowned courtyard terminal?
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObjec
|
||||||
import net.psforever.objects.serverobject.doors.Door
|
import net.psforever.objects.serverobject.doors.Door
|
||||||
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
|
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
|
||||||
import net.psforever.objects.serverobject.locks.IFFLock
|
import net.psforever.objects.serverobject.locks.IFFLock
|
||||||
|
import net.psforever.objects.serverobject.mblocker.Locker
|
||||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||||
import net.psforever.objects.serverobject.terminals.Terminal
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
import net.psforever.objects.vehicles.{AccessPermissionGroup, VehicleLockState}
|
import net.psforever.objects.vehicles.{AccessPermissionGroup, VehicleLockState}
|
||||||
|
|
@ -48,6 +49,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
var continent : Zone = null
|
var continent : Zone = null
|
||||||
var progressBarValue : Option[Float] = None
|
var progressBarValue : Option[Float] = None
|
||||||
var shooting : Option[PlanetSideGUID] = None
|
var shooting : Option[PlanetSideGUID] = None
|
||||||
|
var accessedContainer : Option[PlanetSideGameObject with Container] = None
|
||||||
|
|
||||||
var clientKeepAlive : Cancellable = DefaultCancellable.obj
|
var clientKeepAlive : Cancellable = DefaultCancellable.obj
|
||||||
var progressBarUpdate : Cancellable = DefaultCancellable.obj
|
var progressBarUpdate : Cancellable = DefaultCancellable.obj
|
||||||
|
|
@ -1460,7 +1462,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
previousBox.Capacity = capacity
|
previousBox.Capacity = capacity
|
||||||
}
|
}
|
||||||
|
|
||||||
if(previousBox.Capacity > 0) {
|
if(previousBox.Capacity > 0) {
|
||||||
//TODO split previousBox into AmmoBox objects of appropriate max capacity, e.g., 100 9mm -> 2 x 50 9mm
|
//TODO split previousBox into AmmoBox objects of appropriate max capacity, e.g., 100 9mm -> 2 x 50 9mm
|
||||||
obj.Inventory.Fit(previousBox.Definition.Tile) match {
|
obj.Inventory.Fit(previousBox.Definition.Tile) match {
|
||||||
|
|
@ -1677,13 +1679,24 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
|
|
||||||
case Some(obj : Equipment) =>
|
case Some(obj : Equipment) =>
|
||||||
player.Find(object_guid) match { //player should be holding it
|
val findFunc : PlanetSideGameObject with Container => Option[(PlanetSideGameObject with Container, Option[Int])] = FindInLocalContainer(object_guid)
|
||||||
case Some(slot) =>
|
|
||||||
taskResolver ! RemoveEquipmentFromSlot(player, player.Slot(slot).Equipment.get, slot)
|
findFunc(player)
|
||||||
|
.orElse(findFunc(player.Locker))
|
||||||
|
.orElse(accessedContainer match {
|
||||||
|
case Some(parent) =>
|
||||||
|
findFunc(parent)
|
||||||
|
case None =>
|
||||||
|
None
|
||||||
|
}) match {
|
||||||
|
case Some((parent, Some(slot))) =>
|
||||||
|
taskResolver ! RemoveEquipmentFromSlot(parent, obj, slot)
|
||||||
log.info(s"RequestDestroy: equipment $object_guid")
|
log.info(s"RequestDestroy: equipment $object_guid")
|
||||||
case None =>
|
|
||||||
|
case _ =>
|
||||||
|
//TODO search for item on ground
|
||||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectDeleteMessage(object_guid, 0)))
|
sendResponse(PacketCoding.CreateGamePacket(0, ObjectDeleteMessage(object_guid, 0)))
|
||||||
log.warn(s"RequestDestroy: object $object_guid not found in player hands")
|
log.warn(s"RequestDestroy: object $object_guid not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
case None =>
|
case None =>
|
||||||
|
|
@ -1698,6 +1711,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
log.info("ObjectDelete: " + msg)
|
log.info("ObjectDelete: " + msg)
|
||||||
|
|
||||||
case msg @ MoveItemMessage(item_guid, source_guid, destination_guid, dest, unk1) =>
|
case msg @ MoveItemMessage(item_guid, source_guid, destination_guid, dest, unk1) =>
|
||||||
|
log.info(s"MoveItem: $msg")
|
||||||
(continent.GUID(source_guid), continent.GUID(destination_guid), continent.GUID(item_guid)) match {
|
(continent.GUID(source_guid), continent.GUID(destination_guid), continent.GUID(item_guid)) match {
|
||||||
case (Some(source : Container), Some(destination : Container), Some(item : Equipment)) =>
|
case (Some(source : Container), Some(destination : Container), Some(item : Equipment)) =>
|
||||||
source.Find(item_guid) match {
|
source.Find(item_guid) match {
|
||||||
|
|
@ -1842,6 +1856,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Some(obj : Locker) =>
|
||||||
|
val container = player.Locker
|
||||||
|
accessedContainer = Some(container)
|
||||||
|
sendResponse(PacketCoding.CreateGamePacket(0, UseItemMessage(avatar_guid, unk1, container.GUID, unk2, unk3, unk4, unk5, unk6, unk7, unk8, 456)))
|
||||||
|
|
||||||
case Some(obj : Vehicle) =>
|
case Some(obj : Vehicle) =>
|
||||||
if(obj.Faction == player.Faction) {
|
if(obj.Faction == player.Faction) {
|
||||||
val equipment = player.Slot(player.DrawnSlot).Equipment
|
val equipment = player.Slot(player.DrawnSlot).Equipment
|
||||||
|
|
@ -1856,6 +1875,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
//access to trunk
|
//access to trunk
|
||||||
if(obj.AccessingTrunk.isEmpty) {
|
if(obj.AccessingTrunk.isEmpty) {
|
||||||
obj.AccessingTrunk = player.GUID
|
obj.AccessingTrunk = player.GUID
|
||||||
|
accessedContainer = Some(obj)
|
||||||
AccessContents(obj)
|
AccessContents(obj)
|
||||||
sendResponse(PacketCoding.CreateGamePacket(0, UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType)))
|
sendResponse(PacketCoding.CreateGamePacket(0, UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType)))
|
||||||
}
|
}
|
||||||
|
|
@ -1900,6 +1920,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
|
|
||||||
case _ =>;
|
case _ =>;
|
||||||
}
|
}
|
||||||
|
accessedContainer = None
|
||||||
|
|
||||||
case msg @ DeployObjectMessage(guid, unk1, pos, roll, pitch, yaw, unk2) =>
|
case msg @ DeployObjectMessage(guid, unk1, pos, roll, pitch, yaw, unk2) =>
|
||||||
log.info("DeployObject: " + msg)
|
log.info("DeployObject: " + msg)
|
||||||
|
|
@ -2891,6 +2912,24 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
GlobalDefinitions.isCavernEquipment(objDef) || (faction != tplayer.Faction && faction != PlanetSideEmpire.NEUTRAL)
|
GlobalDefinitions.isCavernEquipment(objDef) || (faction != tplayer.Faction && faction != PlanetSideEmpire.NEUTRAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an object globally unique identifier, search in a given location for it.
|
||||||
|
* @param object_guid the object
|
||||||
|
* @param parent a `Container` object wherein to search
|
||||||
|
* @return an optional tuple that contains two values;
|
||||||
|
* the first value is the container that matched correctly with the object's GUID;
|
||||||
|
* the second value is the slot position of the object
|
||||||
|
*/
|
||||||
|
def FindInLocalContainer(object_guid : PlanetSideGUID)(parent : PlanetSideGameObject with Container) : Option[(PlanetSideGameObject with Container, Option[Int])] = {
|
||||||
|
val slot : Option[Int] = parent.Find(object_guid)
|
||||||
|
slot match {
|
||||||
|
case place @ Some(_) =>
|
||||||
|
Some(parent, slot)
|
||||||
|
case None =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def failWithError(error : String) = {
|
def failWithError(error : String) = {
|
||||||
log.error(error)
|
log.error(error)
|
||||||
sendResponse(PacketCoding.CreateControlPacket(ConnectionClose()))
|
sendResponse(PacketCoding.CreateControlPacket(ConnectionClose()))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue