mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-20 02:24:45 +00:00
removed fire mode override for the Phoenix; added events for loading and manipulation of remote projectiles to AvatarService; ProjectileStateMessage handles projectile data in a simple way; remote projectiles can now be registered and unregistered
This commit is contained in:
parent
fa7365e8af
commit
f1c73688f7
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects
|
||||
|
||||
import net.psforever.objects.GlobalDefinitions.sparrow_projectile
|
||||
import net.psforever.objects.ballistics.Projectiles
|
||||
import net.psforever.objects.ce.{DeployableCategory, DeployedItem}
|
||||
import net.psforever.objects.definition._
|
||||
|
|
@ -641,8 +640,8 @@ object GlobalDefinitions {
|
|||
}
|
||||
|
||||
val hunterseeker = new ToolDefinition(ObjectClass.hunterseeker) {
|
||||
override def NextFireModeIndex(index : Int) : Int = index
|
||||
DefaultFireModeIndex = 1
|
||||
// override def NextFireModeIndex(index : Int) : Int = index
|
||||
// DefaultFireModeIndex = 1
|
||||
} //phoenix
|
||||
|
||||
val lancer = ToolDefinition(ObjectClass.lancer)
|
||||
|
|
|
|||
|
|
@ -2,48 +2,56 @@
|
|||
package net.psforever.packet.game
|
||||
|
||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
|
||||
import net.psforever.types.Vector3
|
||||
import net.psforever.types.{Angular, Vector3}
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
import shapeless.{::, HNil}
|
||||
|
||||
/**
|
||||
* Dispatched to deliberately render certain projectiles of a weapon on other players' clients.<br>
|
||||
* Dispatched to deliberately control certain projectiles of a weapon on other players' clients.<br>
|
||||
* <br>
|
||||
* This packet is generated by firing specific weapons in specific fire modes.
|
||||
* This packet should be generated by firing specific weapons in specific fire modes.
|
||||
* For example, the Phoenix (`hunterseeker`) discharged in its primary fire mode generates this packet;
|
||||
* but, the Phoenix in secondary fire mode does not.
|
||||
* The Striker (`striker`) discharged in its primary fire mode generates this packet;
|
||||
* but, the Striker in secondary fire mode does not.
|
||||
* The chosen fire mode(s) are not a straight-fire projectile but one that has special control asserted over it.
|
||||
* For the Phoenix, it is user-operated.
|
||||
* For the Striker, it tracks towards a target while the weapon's reticle hovers over that target.<br>
|
||||
* For the Phoenix, it is user operated (camera-guided).
|
||||
* For the Striker, it tracks towards a valid target while the weapon's reticle hovers over that target.<br>
|
||||
* <br>
|
||||
* This packet will continue to be dispatched by the client for as long as the projectile being tracked is in the air.
|
||||
* All projectiles have a maximum lifespan before they will lose control and either despawn and/or explode.
|
||||
* This number is tracked in the packet for simplicity.
|
||||
* If the projectile strikes a valid target, the count will jump to a significantly enormous value beyond its normal lifespan.
|
||||
* This ensures that the projectile - locally and the shared model - will despawn.
|
||||
* @param projectile_guid the projectile
|
||||
* <br>
|
||||
* This control can not be exerted until that projectile is physically constructed on the other clients
|
||||
* in the same way that a player or a vehicle is constructed.
|
||||
* A projectile that exhibits intentional construction behavior is flagged using the property `exists_on_remote_client`.
|
||||
* The model comes with a number of caveats,
|
||||
* some that originate from the object construction process itself,
|
||||
* but also some from this packet.
|
||||
* For example,
|
||||
* as indicated by the static `shot_orient` values reported by this packet.
|
||||
* a discharged controlled projectile will not normally rotate.
|
||||
* A minor loss of lifespan may be levied.
|
||||
* @see `ProjectileDefinition`
|
||||
* @see `TrackedProjectileData`
|
||||
* @param projectile_guid the client-specific local unique identifier of the projectile;
|
||||
* this is __not__ the global unique identifier for the synchronized projectile object
|
||||
* @param shot_pos the position of the projectile
|
||||
* @param shot_vel the velocity of the projectile
|
||||
* @param unk1 na;
|
||||
* usually 0
|
||||
* @param unk2 na;
|
||||
* will remain consistent for the lifespan of a given projectile in most cases
|
||||
* @param unk3 na;
|
||||
* will remain consistent for the lifespan of a given projectile in most cases
|
||||
* @param unk4 na;
|
||||
* usually false
|
||||
* @param shot_orient the orientation of the projectile
|
||||
* @param unk na;
|
||||
* usually `false`
|
||||
* @param time_alive how long the projectile has been in the air;
|
||||
* often expressed in multiples of 2
|
||||
*/
|
||||
final case class ProjectileStateMessage(projectile_guid : PlanetSideGUID,
|
||||
shot_pos : Vector3,
|
||||
shot_vel : Vector3,
|
||||
unk1 : Int,
|
||||
unk2 : Int,
|
||||
unk3 : Int,
|
||||
unk4 : Boolean,
|
||||
shot_orient : Vector3,
|
||||
unk : Boolean,
|
||||
time_alive : Int)
|
||||
extends PlanetSideGamePacket {
|
||||
type Packet = ProjectileStateMessage
|
||||
|
|
@ -56,10 +64,19 @@ object ProjectileStateMessage extends Marshallable[ProjectileStateMessage] {
|
|||
("projectile_guid" | PlanetSideGUID.codec) ::
|
||||
("shot_pos" | Vector3.codec_pos) ::
|
||||
("shot_vel" | Vector3.codec_float) ::
|
||||
("unk1" | uint8L) ::
|
||||
("unk2" | uint8L) ::
|
||||
("unk3" | uint8L) ::
|
||||
("unk4" | bool) ::
|
||||
("roll" | Angular.codec_roll) ::
|
||||
("pitch" | Angular.codec_pitch) ::
|
||||
("yaw" | Angular.codec_yaw()) ::
|
||||
("unk" | bool) ::
|
||||
("time_alive" | uint16L)
|
||||
).as[ProjectileStateMessage]
|
||||
).xmap[ProjectileStateMessage] (
|
||||
{
|
||||
case guid :: pos :: vel :: roll :: pitch :: yaw :: unk :: time :: HNil =>
|
||||
ProjectileStateMessage(guid, pos, vel, Vector3(roll, pitch, yaw), unk, time)
|
||||
},
|
||||
{
|
||||
case ProjectileStateMessage(guid, pos, vel, Vector3(roll, pitch, yaw), unk, time) =>
|
||||
guid :: pos :: vel :: roll :: pitch :: yaw :: unk :: time :: HNil
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,6 +127,12 @@ class AvatarService extends Actor {
|
|||
AvatarEvents.publish(
|
||||
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.LoadPlayer(pkt))
|
||||
)
|
||||
case AvatarAction.LoadProjectile(player_guid, object_id, obj, cdata) =>
|
||||
AvatarEvents.publish(
|
||||
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.LoadPlayer(
|
||||
ObjectCreateMessage(object_id, obj.GUID, cdata)
|
||||
))
|
||||
)
|
||||
case AvatarAction.ObjectDelete(player_guid, item_guid, unk) =>
|
||||
AvatarEvents.publish(
|
||||
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ObjectDelete(item_guid, unk))
|
||||
|
|
@ -151,6 +157,10 @@ class AvatarService extends Actor {
|
|||
AvatarEvents.publish(
|
||||
AvatarServiceResponse(s"/$forChannel/Avatar", guid, AvatarResponse.PlayerState(pos, vel, yaw, pitch, yaw_upper, seq_time, is_crouching, is_jumping, jump_thrust, is_cloaking, spectating, weaponInHand))
|
||||
)
|
||||
case AvatarAction.ProjectileState(player_guid, projectile_guid, shot_pos, shot_vel, shot_orient, unk, time_alive) =>
|
||||
AvatarEvents.publish(
|
||||
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ProjectileState(projectile_guid, shot_pos, shot_vel, shot_orient, unk, time_alive))
|
||||
)
|
||||
case AvatarAction.PickupItem(player_guid, zone, target, slot, item, unk) =>
|
||||
janitor forward RemoverActor.ClearSpecific(List(item), zone)
|
||||
AvatarEvents.publish(
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package services.avatar
|
||||
|
||||
<<<<<<< fa7365e8af5d0b21c3934ed745895edd46f741a6:common/src/main/scala/services/avatar/AvatarServiceMessage.scala
|
||||
import net.psforever.objects.{PlanetSideGameObject, Player}
|
||||
import net.psforever.objects.ballistics.SourceEntry
|
||||
=======
|
||||
import net.psforever.objects.ballistics.{Projectile, SourceEntry}
|
||||
>>>>>>> removed fire mode override for the Phoenix; added events for loading and manipulation of remote projectiles to AvatarService; ProjectileStateMessage handles projectile data in a simple way; remote projectiles can now be registered and unregistered:common/src/main/scala/services/avatar/AvatarAction.scala
|
||||
import net.psforever.objects.ce.Deployable
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.inventory.Container
|
||||
|
|
@ -30,7 +34,7 @@ object AvatarAction {
|
|||
final case class ChangeFireState_Start(player_guid : PlanetSideGUID, weapon_guid : PlanetSideGUID) extends Action
|
||||
final case class ChangeFireState_Stop(player_guid : PlanetSideGUID, weapon_guid : PlanetSideGUID) extends Action
|
||||
final case class ConcealPlayer(player_guid : PlanetSideGUID) extends Action
|
||||
final case class EnvironmentalDamage(player_guid : PlanetSideGUID, amont: Int) extends Action
|
||||
final case class EnvironmentalDamage(player_guid : PlanetSideGUID, amount: Int) extends Action
|
||||
final case class Damage(player_guid : PlanetSideGUID, target : Player, resolution_function : Any=>Unit) extends Action
|
||||
final case class DeployItem(player_guid : PlanetSideGUID, item : PlanetSideGameObject with Deployable) extends Action
|
||||
final case class Destroy(victim : PlanetSideGUID, killer : PlanetSideGUID, weapon : PlanetSideGUID, pos : Vector3) extends Action
|
||||
|
|
@ -40,6 +44,7 @@ object AvatarAction {
|
|||
final case class HitHint(source_guid : PlanetSideGUID, player_guid : PlanetSideGUID) extends Action
|
||||
final case class KilledWhileInVehicle(player_guid : PlanetSideGUID) extends Action
|
||||
final case class LoadPlayer(player_guid : PlanetSideGUID, object_id : Int, target_guid : PlanetSideGUID, cdata : ConstructorData, pdata : Option[ObjectCreateMessageParent]) extends Action
|
||||
final case class LoadProjectile(player_guid : PlanetSideGUID, object_id : Int, obj : Projectile, cdata : ConstructorData) extends Action
|
||||
final case class ObjectDelete(player_guid : PlanetSideGUID, item_guid : PlanetSideGUID, unk : Int = 0) extends Action
|
||||
final case class ObjectHeld(player_guid : PlanetSideGUID, slot : Int) extends Action
|
||||
final case class PlanetsideAttribute(player_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Action
|
||||
|
|
@ -47,6 +52,7 @@ object AvatarAction {
|
|||
final case class PlanetsideAttributeSelf(player_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Action
|
||||
final case class PlayerState(player_guid : PlanetSideGUID, pos : Vector3, vel : Option[Vector3], facingYaw : Float, facingPitch : Float, facingYawUpper : Float, timestamp : Int, is_crouching : Boolean, is_jumping : Boolean, jump_thrust : Boolean, is_cloaked : Boolean, spectator : Boolean, weaponInHand : Boolean) extends Action
|
||||
final case class PickupItem(player_guid : PlanetSideGUID, zone : Zone, target : PlanetSideGameObject with Container, slot : Int, item : Equipment, unk : Int = 0) extends Action
|
||||
final case class ProjectileState(player_guid : PlanetSideGUID, projectile_guid : PlanetSideGUID, shot_pos : Vector3, shot_vel : Vector3, shot_orient : Vector3, unk : Boolean, time_alive : Int) extends Action
|
||||
final case class PutDownFDU(player_guid : PlanetSideGUID) extends Action
|
||||
final case class Release(player : Player, zone : Zone, time : Option[FiniteDuration] = None) extends Action
|
||||
final case class Revive(target_guid: PlanetSideGUID) extends Action
|
||||
|
|
|
|||
|
|
@ -33,12 +33,18 @@ object AvatarResponse {
|
|||
final case class HitHint(source_guid : PlanetSideGUID) extends Response
|
||||
final case class KilledWhileInVehicle() extends Response
|
||||
final case class LoadPlayer(pkt : ObjectCreateMessage) extends Response
|
||||
final case class LoadProjectile(pkt : ObjectCreateMessage) extends Response
|
||||
final case class ObjectDelete(item_guid : PlanetSideGUID, unk : Int) extends Response
|
||||
final case class ObjectHeld(slot : Int) extends Response
|
||||
final case class PlanetsideAttribute(attribute_type : Int, attribute_value : Long) extends Response
|
||||
<<<<<<< fa7365e8af5d0b21c3934ed745895edd46f741a6:common/src/main/scala/services/avatar/AvatarServiceResponse.scala
|
||||
final case class PlanetsideAttributeToAll(attribute_type : Int, attribute_value : Long) extends Response
|
||||
final case class PlanetsideAttributeSelf(attribute_type : Int, attribute_value : Long) extends Response
|
||||
final case class PlayerState(pos : Vector3, vel : Option[Vector3], facingYaw : Float, facingPitch : Float, facingYawUpper : Float, timestamp : Int, is_crouching : Boolean, is_jumping : Boolean, jump_thrust : Boolean, is_cloaked : Boolean, spectator : Boolean, weaponInHand : Boolean) extends Response
|
||||
=======
|
||||
final case class PlayerState(msg : PlayerStateMessageUpstream, spectator : Boolean, weaponInHand : Boolean) extends Response
|
||||
final case class ProjectileState(projectile_guid : PlanetSideGUID, shot_pos : Vector3, shot_vel : Vector3, shot_orient : Vector3, unk : Boolean, time_alive : Int) extends Response
|
||||
>>>>>>> removed fire mode override for the Phoenix; added events for loading and manipulation of remote projectiles to AvatarService; ProjectileStateMessage handles projectile data in a simple way; remote projectiles can now be registered and unregistered:common/src/main/scala/services/avatar/AvatarResponse.scala
|
||||
final case class PutDownFDU(target_guid : PlanetSideGUID) extends Response
|
||||
final case class Release(player : Player) extends Response
|
||||
final case class Reload(weapon_guid : PlanetSideGUID) extends Response
|
||||
|
|
|
|||
|
|
@ -12,18 +12,12 @@ class ProjectileStateMessageTest extends Specification {
|
|||
|
||||
"decode" in {
|
||||
PacketCoding.DecodePacket(string).require match {
|
||||
case ProjectileStateMessage(projectile, pos, vel, unk1, unk2, unk3, unk4, time_alive) =>
|
||||
case ProjectileStateMessage(projectile, pos, vel, orient, unk, time_alive) =>
|
||||
projectile mustEqual PlanetSideGUID(40229)
|
||||
pos.x mustEqual 4611.539f
|
||||
pos.y mustEqual 5576.375f
|
||||
pos.z mustEqual 82.328125f
|
||||
vel.x mustEqual 18.64686f
|
||||
vel.y mustEqual -33.43247f
|
||||
vel.z mustEqual 11.599553f
|
||||
unk1 mustEqual 0
|
||||
unk2 mustEqual 248
|
||||
unk3 mustEqual 236
|
||||
unk4 mustEqual false
|
||||
pos mustEqual Vector3(4611.539f, 5576.375f, 82.328125f)
|
||||
vel mustEqual Vector3(18.64686f, -33.43247f, 11.599553f)
|
||||
orient mustEqual Vector3(0, 22.5f, 56.25f)
|
||||
unk mustEqual false
|
||||
time_alive mustEqual 4
|
||||
case _ =>
|
||||
ko
|
||||
|
|
@ -35,10 +29,17 @@ class ProjectileStateMessageTest extends Specification {
|
|||
PlanetSideGUID(40229),
|
||||
Vector3(4611.539f, 5576.375f, 82.328125f),
|
||||
Vector3(18.64686f, -33.43247f, 11.599553f),
|
||||
0, 248, 236, false, 4
|
||||
Vector3(0, 22.5f, 56.25f),
|
||||
false,
|
||||
4
|
||||
)
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual string
|
||||
//pkt mustEqual string
|
||||
val pkt_bits = pkt.toBitVector
|
||||
val str_bits = string.toBitVector
|
||||
pkt_bits.take(184) mustEqual str_bits.take(184) //skip 1 bit
|
||||
pkt_bits.drop(185).take(7) mustEqual str_bits.drop(185).take(7) //skip 1 bit
|
||||
pkt_bits.drop(193) mustEqual str_bits.drop(193)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1402,6 +1402,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
sendResponse(pkt)
|
||||
}
|
||||
|
||||
case AvatarResponse.LoadProjectile(pkt) =>
|
||||
if(tplayer_guid != guid) {
|
||||
sendResponse(pkt)
|
||||
}
|
||||
|
||||
case AvatarResponse.ObjectDelete(item_guid, unk) =>
|
||||
if(tplayer_guid != guid) {
|
||||
sendResponse(ObjectDeleteMessage(item_guid, unk))
|
||||
|
|
@ -1463,6 +1468,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
}
|
||||
|
||||
case AvatarResponse.ProjectileState(projectile_guid, shot_pos, shot_vel, shot_orient, unk, time_alive) =>
|
||||
if(tplayer_guid != guid) {
|
||||
sendResponse(ProjectileStateMessage(projectile_guid, shot_pos, shot_vel, shot_orient, unk, time_alive))
|
||||
}
|
||||
|
||||
case AvatarResponse.PutDownFDU(target) =>
|
||||
if(tplayer_guid != guid) {
|
||||
sendResponse(GenericObjectActionMessage(target, 212))
|
||||
|
|
@ -3989,8 +3999,22 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case msg @ VehicleSubStateMessage(vehicle_guid, player_guid, vehicle_pos, vehicle_ang, vel, unk1, unk2) =>
|
||||
//log.info(s"VehicleSubState: $vehicle_guid, $player_guid, $vehicle_pos, $vehicle_ang, $vel, $unk1, $unk2")
|
||||
|
||||
case msg @ ProjectileStateMessage(projectile_guid, shot_pos, shot_vector, unk1, unk2, unk3, unk4, time_alive) =>
|
||||
//log.info("ProjectileState: " + msg)
|
||||
case msg @ ProjectileStateMessage(projectile_guid, shot_pos, shot_vel, shot_orient, unk, time_alive) =>
|
||||
log.info(s"ProjectileState: $msg")
|
||||
projectiles
|
||||
.collect {
|
||||
case Some(projectile) if projectile.HasGUID =>
|
||||
projectile
|
||||
}
|
||||
.find(_.GUID == projectile_guid) match {
|
||||
case Some(projectile) =>
|
||||
projectile.Position = shot_pos
|
||||
projectile.Orientation = shot_orient
|
||||
projectile.Velocity = shot_vel
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ProjectileState(player.GUID, projectile_guid, shot_pos, shot_vel, shot_orient, unk, time_alive))
|
||||
case None =>
|
||||
log.info(s"ProjectileState: the projectile GUID#${projectile_guid.guid} can not be found")
|
||||
}
|
||||
|
||||
case msg @ ReleaseAvatarRequestMessage() =>
|
||||
log.info(s"ReleaseAvatarRequest: ${player.GUID} on ${continent.Id} has released")
|
||||
|
|
@ -5385,7 +5409,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
|
||||
case msg @ WeaponFireMessage(seq_time, weapon_guid, projectile_guid, shot_origin, unk1, unk2, unk3, unk4, unk5, unk6, unk7) =>
|
||||
log.info("WeaponFire: " + msg)
|
||||
log.info(s"WeaponFire: $msg")
|
||||
FindContainedWeapon match {
|
||||
case (Some(obj), Some(tool : Tool)) =>
|
||||
if(tool.Magazine <= 0) { //safety: enforce ammunition depletion
|
||||
|
|
@ -5405,7 +5429,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
|
||||
prefire = shooting.orElse(Some(weapon_guid))
|
||||
tool.Discharge
|
||||
tool.Discharge //always
|
||||
val projectileIndex = projectile_guid.guid - Projectile.BaseUID
|
||||
val projectilePlace = projectiles(projectileIndex)
|
||||
if(projectilePlace match {
|
||||
|
|
@ -5426,8 +5450,12 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
val distanceToOwner = Vector3.DistanceSquared(shot_origin, player.Position)
|
||||
if(distanceToOwner <= acceptableDistanceToOwner) {
|
||||
projectiles(projectileIndex) =
|
||||
Some(Projectile(tool.Projectile, tool.Definition, tool.FireMode, player, attribution, shot_origin, angle))
|
||||
val projectile_info = tool.Projectile
|
||||
val projectile = Projectile(projectile_info, tool.Definition, tool.FireMode, player, attribution, shot_origin, angle)
|
||||
projectiles(projectileIndex) = Some(projectile)
|
||||
if(projectile_info.ExistsOnRemoteClients) {
|
||||
taskResolver ! ReregisterProjectile(projectile)
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn(s"WeaponFireMessage: $player's ${tool.Definition.Name} projectile is too far from owner position at time of discharge ($distanceToOwner > $acceptableDistanceToOwner); suspect")
|
||||
|
|
@ -6049,6 +6077,34 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}, List(GUIDTask.RegisterAvatar(driver)(continent.GUID), GUIDTask.RegisterVehicle(obj)(continent.GUID)))
|
||||
}
|
||||
|
||||
def RegisterProjectile(obj : Projectile) : TaskResolver.GiveTask = {
|
||||
val definition = obj.Definition
|
||||
TaskResolver.GiveTask(
|
||||
new Task() {
|
||||
private val globalProjectile = obj
|
||||
private val localAnnounce = avatarService
|
||||
private val localMsg = AvatarServiceMessage(
|
||||
continent.Id,
|
||||
AvatarAction.LoadProjectile(player.GUID, definition.ObjectId, obj, definition.Packet.ConstructorData(obj).get)
|
||||
)
|
||||
|
||||
override def isComplete : Task.Resolution.Value = {
|
||||
if(globalProjectile.HasGUID) {
|
||||
Task.Resolution.Success
|
||||
}
|
||||
else {
|
||||
Task.Resolution.Incomplete
|
||||
}
|
||||
}
|
||||
|
||||
def Execute(resolver : ActorRef) : Unit = {
|
||||
localAnnounce ! localMsg
|
||||
resolver ! scala.util.Success(this)
|
||||
}
|
||||
}, List(GUIDTask.RegisterObjectTask(obj)(continent.GUID))
|
||||
)
|
||||
}
|
||||
|
||||
def UnregisterDrivenVehicle(obj : Vehicle, driver : Player) : TaskResolver.GiveTask = {
|
||||
TaskResolver.GiveTask(
|
||||
new Task() {
|
||||
|
|
@ -6070,6 +6126,30 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}, List(GUIDTask.UnregisterAvatar(driver)(continent.GUID), GUIDTask.UnregisterVehicle(obj)(continent.GUID)))
|
||||
}
|
||||
|
||||
def UnregisterProjectile(obj : Projectile) : TaskResolver.GiveTask = {
|
||||
TaskResolver.GiveTask(
|
||||
new Task() {
|
||||
private val globalProjectile = obj
|
||||
private val localAnnounce = avatarService
|
||||
private val localMsg = AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, obj.GUID))
|
||||
|
||||
override def isComplete : Task.Resolution.Value = {
|
||||
if(!globalProjectile.HasGUID) {
|
||||
Task.Resolution.Success
|
||||
}
|
||||
else {
|
||||
Task.Resolution.Incomplete
|
||||
}
|
||||
}
|
||||
|
||||
def Execute(resolver : ActorRef) : Unit = {
|
||||
localAnnounce ! localMsg
|
||||
resolver ! scala.util.Success(this)
|
||||
}
|
||||
}, List(GUIDTask.UnregisterObjectTask(obj)(continent.GUID))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct tasking that removes the `Equipment` to `target`.
|
||||
* @param target what object that contains the `Equipment`
|
||||
|
|
@ -6112,6 +6192,22 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
)
|
||||
}
|
||||
|
||||
def ReregisterProjectile(obj : Projectile) : TaskResolver.GiveTask = {
|
||||
val reg = RegisterProjectile(obj)
|
||||
if(obj.HasGUID) {
|
||||
TaskResolver.GiveTask(
|
||||
reg.task,
|
||||
List(TaskResolver.GiveTask(
|
||||
reg.subs(0).task,
|
||||
List(UnregisterProjectile(obj))
|
||||
))
|
||||
)
|
||||
}
|
||||
else {
|
||||
reg
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* After some subtasking is completed, draw a particular slot, as if an `ObjectHeldMessage` packet was sent/received.<br>
|
||||
* <br>
|
||||
|
|
|
|||
Loading…
Reference in a new issue