protected override void HandleMessage(EntityActorMessageContext messageContext, DefaultEntityActorStateContainer state, InteractWithEntityActorMessage message) { if(Logger.IsDebugEnabled) Logger.Debug($"Entity: {message.EntityInteracting} Interacted with Creature: {state.EntityGuid}"); messageContext.Sender.Tell(new AddPlayerExperienceActorMessage(50)); //Let's create the path data. IMovementGenerator<GameObject> movementGenerator = MovementGeneratorMappable.RetrieveEntity(state.EntityGuid); var playerMovementGenerator = MovementGeneratorMappable.RetrieveEntity(message.EntityInteracting); //WARNING: NEVER DO THIS, NOT SAFE TO ACCESS PLAYER DATA. Vector3 creatureCurrentPosition = movementGenerator.CurrentPosition; Vector3 playerCurrentPosition = playerMovementGenerator.CurrentPosition; UnityAsyncHelper.UnityMainThreadContext.Post(o => { var path = new NavMeshPath(); NavMesh.CalculatePath(creatureCurrentPosition, playerCurrentPosition, NavMesh.AllAreas, path); if(path.status != NavMeshPathStatus.PathComplete) if(Logger.IsWarnEnabled) Logger.Warn($"Produced invalid PathResult: {path.status} for Entity: {state.EntityGuid} Start: {creatureCurrentPosition} End: {playerCurrentPosition}"); //Don't broadcast if not invalid if(path.status == NavMeshPathStatus.PathComplete) messageContext.Entity.Tell(new CreatureSetPathMovementMessage(creatureCurrentPosition, path.corners)); }, null); }
/// <inheritdoc /> protected override Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, ClientMovementDataUpdateRequest payload, NetworkEntityGuid guid) { try { IMovementGenerator <GameObject> generator = MovementGenerator.RetrieveEntity(guid); IMovementData movementData = MovementDataMap.RetrieveEntity(guid); PositionChangeMovementData changeMovementData = BuildPositionChangeMovementData(payload, generator, movementData); MovementDataMap.ReplaceObject(guid, changeMovementData); IActorRef playerActorRef = ActorReferenceMappable.RetrieveEntity(guid); playerActorRef.TellSelf(new PlayerMovementStateChangedMessage(changeMovementData.Direction)); //If the generator is running, we should use its initial position instead of the last movement data's position. MovementGenerator.ReplaceObject(guid, BuildCharacterControllerMovementGenerator(guid, changeMovementData, generator, movementData)); } catch (Exception e) { if (Logger.IsErrorEnabled) { Logger.Error($"Failed to update MovementData for GUID: {guid} Reason: {e.Message}"); } throw; } return(Task.CompletedTask); }
/// <inheritdoc /> protected override Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, ClientRotationDataUpdateRequest payload, NetworkEntityGuid guid) { try { IMovementGenerator <GameObject> generator = MovementGenerator.RetrieveEntity(guid); IMovementData movementData = MovementDataMap.RetrieveEntity(guid); //TODO: This is a temporary hack, we nee d abetter solluition if (movementData is PositionChangeMovementData posChangeMoveDat) { Vector2 direction = posChangeMoveDat.Direction; //TODO: Sanity check position sent. //TODO: Sanity check timestamp MovementDataMap.ReplaceObject(guid, new PositionChangeMovementData(payload.TimeStamp, payload.ClientCurrentPosition, direction, payload.Rotation)); } else { throw new NotImplementedException($"TODO: Implement rotation when dealing with: {movementData.GetType().Name} type movement."); } OnPlayerRotationChanged?.Invoke(this, new PlayerRotiationChangeEventArgs(guid, payload.Rotation)); } catch (Exception e) { if (Logger.IsErrorEnabled) { Logger.Error($"Failed to update MovementData for GUID: {guid} Reason: {e.Message}"); } throw; } return(Task.CompletedTask); }
protected override void HandleMessage(EntityActorMessageContext messageContext, DefaultEntityActorStateContainer state, CreatureSetPathMovementMessage message) { PathBasedMovementData data = new PathBasedMovementData(message.PathPoints, TimeService.CurrentLocalTime); IMovementGenerator <GameObject> generator = MovementGeneratorFactory.Create(new EntityAssociatedData <IMovementData>(state.EntityGuid, data)); MovementDataMappable.ReplaceObject(state.EntityGuid, data); MovementGeneratorMappable.ReplaceObject(state.EntityGuid, generator); }
protected override void OnEventFired(object source, EntityCreationFinishedEventArgs args) { IMovementData movementData = MovementDataMappable.RetrieveEntity(args.EntityGuid); IMovementGenerator <IWorldObject> generator = MovementGeneratorFactory.Create(new EntityAssociatedData <IMovementData>(args.EntityGuid, movementData)); MovementGeneratorMappable.AddObject(args.EntityGuid, generator); }
protected override void OnEventFired(object source, EntityWorldObjectCreatedEventArgs args) { IMovementData movementData = MovementDataMappable.RetrieveEntity(args.EntityGuid); IMovementGenerator <IWorldObject> generator = MovementGeneratorFactory.Create(new EntityAssociatedData <IMovementData>(args.EntityGuid, movementData)); MovementGeneratorMappable.AddObject(args.EntityGuid, generator); InitializePosition(args.EntityGuid, movementData, generator, args.WorldReprensetation); }
private ZoneServerCharacterLocationSaveRequest CreatedLocationSaveData([NotNull] NetworkEntityGuid guid) { if (guid == null) { throw new ArgumentNullException(nameof(guid)); } //TODO: Check that the entity actually exists IMovementGenerator <GameObject> movementData = MovementDataMap.RetrieveEntity(guid); return(new ZoneServerCharacterLocationSaveRequest(movementData.CurrentPosition)); }
/// <inheritdoc /> public override Task HandleMessage(IPeerMessageContext <GameClientPacketPayload> context, MovementDataUpdateEventPayload payload) { if (!payload.HasMovementData) { if (Logger.IsWarnEnabled) { Logger.Warn($"Empty movement update packet received."); } return(Task.CompletedTask); } foreach (var movementUpdate in payload.MovementDatas) { if (!KnownEntities.isEntityKnown(movementUpdate.EntityGuid)) { if (Logger.IsInfoEnabled) { Logger.Info($"TODO: Received movement update too soon. Must enable deferred movement update queueing for entities that are about to spawn."); } continue; } try { IMovementGenerator <IWorldObject> generator = MovementGeneratorFactory.Create(movementUpdate); //We just initialize this casually, the next update tick in Unity3D will start the movement generator, the old generator actually might be running right now //at the time this is set. MovementGeneratorMappable.ReplaceObject(movementUpdate.EntityGuid, generator); MovementDataMappable.ReplaceObject(movementUpdate.EntityGuid, movementUpdate.Data); } catch (Exception e) { string error = $"Failed to handle Movement Data for Entity: {movementUpdate.EntityGuid} Type: {movementUpdate.Data.GetType().Name} Error: {e.Message}"; if (Logger.IsErrorEnabled) { Logger.Error(error); } throw new InvalidOperationException(error, e); } } return(Task.CompletedTask); }
public void HandleMovementUpdate(EntityAssociatedData <IMovementData> movementUpdate, bool forceHandleLocal = false) { if (!KnownEntities.isEntityKnown(movementUpdate.EntityGuid)) { if (Logger.IsInfoEnabled) { Logger.Info($"TODO: Received movement update too soon. Must enable deferred movement update queueing for entities that are about to spawn."); } return; } try { if (!forceHandleLocal) { //Cheap check, and we're on another thread so performance doesn't really matter if (movementUpdate.EntityGuid == PlayerDetails.LocalPlayerGuid) { if (movementUpdate.Data.isUserCreated) { return; //don't handle user created movement data about ourselves. It'll just make movement abit janky locally. } } } IMovementGenerator <GameObject> generator = MovementGeneratorFactory.Create(movementUpdate); //We just initialize this casually, the next update tick in Unity3D will start the movement generator, the old generator actually might be running right now //at the time this is set. MovementGeneratorMappable.ReplaceObject(movementUpdate.EntityGuid, generator); MovementDataMappable.ReplaceObject(movementUpdate.EntityGuid, movementUpdate.Data); } catch (Exception e) { string error = $"Failed to handle Movement Data for Entity: {movementUpdate.EntityGuid} Type: {movementUpdate.Data.GetType().Name} Error: {e.Message}"; if (Logger.IsErrorEnabled) { Logger.Error(error); } throw new InvalidOperationException(error, e); } }
public void SetEscortPaused(bool on) { if (!HasEscortState(EscortState.Escorting)) { return; } if (on) { AddEscortState(EscortState.Paused); IMovementGenerator movementGenerator = me.GetMotionMaster().GetMotionSlot(MovementSlot.Idle); if (movementGenerator != null) { movementGenerator.Pause(0); } } else { RemoveEscortState(EscortState.Paused); _resume = true; } }
/// <inheritdoc /> protected override Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, ClientSetClickToMovePathRequestPayload payload, NetworkEntityGuid guid) { try { IMovementGenerator <GameObject> generator = MovementGenerator.RetrieveEntity(guid); IMovementData movementData = MovementDataMap.RetrieveEntity(guid); PathBasedMovementData changeMovementData = BuildPathData(payload, generator, movementData, guid); //If it doesn't have more one point reject it if (changeMovementData.MovementPath.Count < 2) { return(Task.CompletedTask); } MovementDataMap.ReplaceObject(guid, changeMovementData); IActorRef playerActorRef = ActorReferenceMappable.RetrieveEntity(guid); Vector3 direction3D = (changeMovementData.MovementPath[1] - changeMovementData.MovementPath[0]); Vector2 direction2D = new Vector2(direction3D.x, direction3D.z).normalized; playerActorRef.TellSelf(new PlayerMovementStateChangedMessage(direction2D)); //If the generator is running, we should use its initial position instead of the last movement data's position. MovementGenerator.ReplaceObject(guid, new PathMovementGenerator(changeMovementData)); } catch (Exception e) { if (Logger.IsErrorEnabled) { Logger.Error($"Failed to update MovementData for GUID: {guid} Reason: {e.Message}"); } throw; } return(Task.CompletedTask); }
private void InitializePosition([JetBrains.Annotations.NotNull] NetworkEntityGuid guid, [JetBrains.Annotations.NotNull] IMovementData movementData, [JetBrains.Annotations.NotNull] IMovementGenerator <IWorldObject> movementGenerator, [JetBrains.Annotations.NotNull] IWorldObject entityWorldObject) { if (guid == null) { throw new ArgumentNullException(nameof(guid)); } if (movementData == null) { throw new ArgumentNullException(nameof(movementData)); } if (movementGenerator == null) { throw new ArgumentNullException(nameof(movementGenerator)); } if (entityWorldObject == null) { throw new ArgumentNullException(nameof(entityWorldObject)); } //We need to fast forward the fake/stub WorldObject so that we can get an accurate initial position. if (movementData is PathBasedMovementData) { IWorldObject worldObjectStub = new WorldObjectStub((int)movementData.InitialPosition.x - Client.baseX, (int)movementData.InitialPosition.z - Client.baseY); //At this point, the worldObjectStub actually will have the correct initial position movementGenerator.Update(worldObjectStub, TimeService.CurrentRemoteTime); entityWorldObject.DirectSetPosition(worldObjectStub.CurrentX, worldObjectStub.CurrentY); } else { entityWorldObject.setPos((int)movementData.InitialPosition.x - Client.baseX, (int)movementData.InitialPosition.z - Client.baseY); } }
void HandleMoveWorldportAck() { // ignore unexpected far teleports if (!GetPlayer().IsBeingTeleportedFar()) { return; } bool seamlessTeleport = GetPlayer().IsBeingTeleportedSeamlessly(); GetPlayer().SetSemaphoreTeleportFar(false); // get the teleport destination WorldLocation loc = GetPlayer().GetTeleportDest(); // possible errors in the coordinate validity check if (!GridDefines.IsValidMapCoord(loc)) { LogoutPlayer(false); return; } // get the destination map entry, not the current one, this will fix homebind and reset greeting MapRecord mapEntry = CliDB.MapStorage.LookupByKey(loc.GetMapId()); InstanceTemplate mInstance = Global.ObjectMgr.GetInstanceTemplate(loc.GetMapId()); // reset instance validity, except if going to an instance inside an instance if (!GetPlayer().m_InstanceValid&& mInstance == null) { GetPlayer().m_InstanceValid = true; } Map oldMap = GetPlayer().GetMap(); Map newMap = Global.MapMgr.CreateMap(loc.GetMapId(), GetPlayer()); if (GetPlayer().IsInWorld) { Log.outError(LogFilter.Network, "Player (Name {0}) is still in world when teleported from map {1} to new map {2}", GetPlayer().GetName(), oldMap.GetId(), loc.GetMapId()); oldMap.RemovePlayerFromMap(GetPlayer(), false); } // relocate the player to the teleport destination // the CannotEnter checks are done in TeleporTo but conditions may change // while the player is in transit, for example the map may get full if (newMap == null || newMap.CannotEnter(GetPlayer()) != 0) { Log.outError(LogFilter.Network, "Map {0} could not be created for {1} ({2}), porting player to homebind", loc.GetMapId(), newMap ? newMap.GetMapName() : "Unknown", GetPlayer().GetGUID().ToString()); GetPlayer().TeleportTo(GetPlayer().GetHomebind()); return; } float z = loc.GetPositionZ(); if (GetPlayer().HasUnitMovementFlag(MovementFlag.Hover)) { z += GetPlayer().m_unitData.HoverHeight; } GetPlayer().Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation()); GetPlayer().SetFallInformation(0, GetPlayer().GetPositionZ()); GetPlayer().ResetMap(); GetPlayer().SetMap(newMap); ResumeToken resumeToken = new ResumeToken(); resumeToken.SequenceIndex = _player.m_movementCounter; resumeToken.Reason = seamlessTeleport ? 2 : 1u; SendPacket(resumeToken); if (!seamlessTeleport) { GetPlayer().SendInitialPacketsBeforeAddToMap(); } if (!GetPlayer().GetMap().AddPlayerToMap(GetPlayer(), !seamlessTeleport)) { Log.outError(LogFilter.Network, "WORLD: failed to teleport player {0} ({1}) to map {2} ({3}) because of unknown reason!", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), loc.GetMapId(), newMap ? newMap.GetMapName() : "Unknown"); GetPlayer().ResetMap(); GetPlayer().SetMap(oldMap); GetPlayer().TeleportTo(GetPlayer().GetHomebind()); return; } // Battleground state prepare (in case join to BG), at relogin/tele player not invited // only add to bg group and object, if the player was invited (else he entered through command) if (GetPlayer().InBattleground()) { // cleanup setting if outdated if (!mapEntry.IsBattlegroundOrArena()) { // We're not in BG GetPlayer().SetBattlegroundId(0, BattlegroundTypeId.None); // reset destination bg team GetPlayer().SetBGTeam(0); } // join to bg case else { Battleground bg = GetPlayer().GetBattleground(); if (bg) { if (GetPlayer().IsInvitedForBattlegroundInstance(GetPlayer().GetBattlegroundId())) { bg.AddPlayer(GetPlayer()); } } } } if (!seamlessTeleport) { GetPlayer().SendInitialPacketsAfterAddToMap(); } else { GetPlayer().UpdateVisibilityForPlayer(); Garrison garrison = GetPlayer().GetGarrison(); if (garrison != null) { garrison.SendRemoteInfo(); } } // flight fast teleport case if (GetPlayer().GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Flight) { if (!GetPlayer().InBattleground()) { if (!seamlessTeleport) { // short preparations to continue flight IMovementGenerator movementGenerator = GetPlayer().GetMotionMaster().Top(); movementGenerator.Initialize(GetPlayer()); } return; } // Battlegroundstate prepare, stop flight GetPlayer().GetMotionMaster().MovementExpired(); GetPlayer().CleanupAfterTaxiFlight(); } // resurrect character at enter into instance where his corpse exist after add to map if (mapEntry.IsDungeon() && !GetPlayer().IsAlive()) { if (GetPlayer().GetCorpseLocation().GetMapId() == mapEntry.Id) { GetPlayer().ResurrectPlayer(0.5f, false); GetPlayer().SpawnCorpseBones(); } } bool allowMount = !mapEntry.IsDungeon() || mapEntry.IsBattlegroundOrArena(); if (mInstance != null) { // check if this instance has a reset time and send it to player if so Difficulty diff = newMap.GetDifficultyID(); MapDifficultyRecord mapDiff = Global.DB2Mgr.GetMapDifficultyData(mapEntry.Id, diff); if (mapDiff != null) { if (mapDiff.GetRaidDuration() != 0) { long timeReset = Global.InstanceSaveMgr.GetResetTimeFor(mapEntry.Id, diff); if (timeReset != 0) { uint timeleft = (uint)(timeReset - Time.UnixTime); GetPlayer().SendInstanceResetWarning(mapEntry.Id, diff, timeleft, true); } } } // check if instance is valid if (!GetPlayer().CheckInstanceValidity(false)) { GetPlayer().m_InstanceValid = false; } // instance mounting is handled in InstanceTemplate allowMount = mInstance.AllowMount; } // mount allow check if (!allowMount) { GetPlayer().RemoveAurasByType(AuraType.Mounted); } // update zone immediately, otherwise leave channel will cause crash in mtmap uint newzone, newarea; GetPlayer().GetZoneAndAreaId(out newzone, out newarea); GetPlayer().UpdateZone(newzone, newarea); // honorless target if (GetPlayer().pvpInfo.IsHostile) { GetPlayer().CastSpell(GetPlayer(), 2479, true); } // in friendly area else if (GetPlayer().IsPvP() && !GetPlayer().HasPlayerFlag(PlayerFlags.InPVP)) { GetPlayer().UpdatePvP(false, false); } // resummon pet GetPlayer().ResummonPetTemporaryUnSummonedIfAny(); //lets process all delayed operations on successful teleport GetPlayer().ProcessDelayedOperations(); }
private CharacterControllerInputMovementGenerator BuildCharacterControllerMovementGenerator(NetworkEntityGuid guid, PositionChangeMovementData data, IMovementGenerator <GameObject> generator, IMovementData movementData) { //TODO: Sanity check timestamp and position. //We used to use the last generators current position //However we now use the hint position from the client. //This NEEDS to be sanity checked before used. //This semi-authorative approach is less secure but more responsive for the user. return(new CharacterControllerInputMovementGenerator(data, new Lazy <CharacterController>(() => this.CharacterControllerMappable.RetrieveEntity(guid)), data.InitialPosition)); }
public override void UpdateAI(uint diff) { //Waypoint Updating if (HasEscortState(EscortState.Escorting) && !me.IsEngaged() && !HasEscortState(EscortState.Returning)) { if (_pauseTimer <= diff) { if (!HasEscortState(EscortState.Paused)) { _pauseTimer = 0; if (_ended) { _ended = false; me.GetMotionMaster().MoveIdle(); if (_despawnAtEnd) { Log.outDebug(LogFilter.Scripts, "EscortAI.UpdateAI: reached end of waypoints, despawning at end"); if (_returnToStart) { Position respawnPosition = new Position(); float orientation; me.GetRespawnPosition(out respawnPosition.posX, out respawnPosition.posY, out respawnPosition.posZ, out orientation); respawnPosition.SetOrientation(orientation); me.GetMotionMaster().MovePoint(EscortPointIds.Home, respawnPosition); Log.outDebug(LogFilter.Scripts, $"EscortAI.UpdateAI: returning to spawn location: {respawnPosition}"); } else if (_instantRespawn) { me.Respawn(); } else { me.DespawnOrUnsummon(); } } Log.outDebug(LogFilter.Scripts, "EscortAI.UpdateAI: reached end of waypoints"); RemoveEscortState(EscortState.Escorting); return; } if (!_started) { _started = true; me.GetMotionMaster().MovePath(_path, false); } else if (_resume) { _resume = false; IMovementGenerator movementGenerator = me.GetMotionMaster().GetMotionSlot(MovementSlot.Idle); if (movementGenerator != null) { movementGenerator.Resume(0); } } } } else { _pauseTimer -= diff; } } //Check if player or any member of his group is within range if (_despawnAtFar && HasEscortState(EscortState.Escorting) && !_playerGUID.IsEmpty() && !me.GetVictim() && !HasEscortState(EscortState.Returning)) { if (_playerCheckTimer <= diff) { if (!IsPlayerOrGroupInRange()) { Log.outDebug(LogFilter.Scripts, "EscortAI failed because player/group was to far away or not found"); bool isEscort = false; CreatureData creatureData = me.GetCreatureData(); if (creatureData != null) { isEscort = (WorldConfig.GetBoolValue(WorldCfg.RespawnDynamicEscortNpc) && creatureData.spawnGroupData.flags.HasAnyFlag(SpawnGroupFlags.EscortQuestNpc)); } if (_instantRespawn && !isEscort) { me.DespawnOrUnsummon(0, TimeSpan.FromSeconds(1)); } else if (_instantRespawn && isEscort) { me.GetMap().RemoveRespawnTime(SpawnObjectType.Creature, me.GetSpawnId(), true); } else { me.DespawnOrUnsummon(); } return; } _playerCheckTimer = 1000; } else { _playerCheckTimer -= diff; } } UpdateEscortAI(diff); }
private PositionChangeMovementData BuildPositionChangeMovementData(ClientMovementDataUpdateRequest payload, IMovementGenerator <GameObject> generator, IMovementData originalMovementData) { //TODO: Sanity check timestamp and position. //So, originally we used authorative time and position but now we semi-trust the client. //We need to verify the send timestamp is not too far off and also sanity check the position too. return(new PositionChangeMovementData(payload.Timestamp, payload.CurrentClientPosition, payload.MovementInput, originalMovementData.Rotation)); }
public bool SetCharmedBy(Unit charmer, CharmType type, AuraApplication aurApp = null) { if (!charmer) { return(false); } // dismount players when charmed if (IsTypeId(TypeId.Player)) { RemoveAurasByType(AuraType.Mounted); } if (charmer.IsTypeId(TypeId.Player)) { charmer.RemoveAurasByType(AuraType.Mounted); } Cypher.Assert(type != CharmType.Possess || charmer.IsTypeId(TypeId.Player)); Cypher.Assert((type == CharmType.Vehicle) == IsVehicle()); Log.outDebug(LogFilter.Unit, "SetCharmedBy: charmer {0} (GUID {1}), charmed {2} (GUID {3}), type {4}.", charmer.GetEntry(), charmer.GetGUID().ToString(), GetEntry(), GetGUID().ToString(), type); if (this == charmer) { Log.outFatal(LogFilter.Unit, "Unit:SetCharmedBy: Unit {0} (GUID {1}) is trying to charm itself!", GetEntry(), GetGUID().ToString()); return(false); } if (IsTypeId(TypeId.Player) && ToPlayer().GetTransport()) { Log.outFatal(LogFilter.Unit, "Unit:SetCharmedBy: Player on transport is trying to charm {0} (GUID {1})", GetEntry(), GetGUID().ToString()); return(false); } // Already charmed if (!GetCharmerGUID().IsEmpty()) { Log.outFatal(LogFilter.Unit, "Unit:SetCharmedBy: {0} (GUID {1}) has already been charmed but {2} (GUID {3}) is trying to charm it!", GetEntry(), GetGUID().ToString(), charmer.GetEntry(), charmer.GetGUID().ToString()); return(false); } CastStop(); CombatStop(); // @todo CombatStop(true) may cause crash (interrupt spells) Player playerCharmer = charmer.ToPlayer(); // Charmer stop charming if (playerCharmer) { playerCharmer.StopCastingCharm(); playerCharmer.StopCastingBindSight(); } // Charmed stop charming if (IsTypeId(TypeId.Player)) { ToPlayer().StopCastingCharm(); ToPlayer().StopCastingBindSight(); } // StopCastingCharm may remove a possessed pet? if (!IsInWorld) { Log.outFatal(LogFilter.Unit, "Unit:SetCharmedBy: {0} (GUID {1}) is not in world but {2} (GUID {3}) is trying to charm it!", GetEntry(), GetGUID().ToString(), charmer.GetEntry(), charmer.GetGUID().ToString()); return(false); } // charm is set by aura, and aura effect remove handler was called during apply handler execution // prevent undefined behaviour if (aurApp != null && aurApp.GetRemoveMode() != 0) { return(false); } _oldFactionId = GetFaction(); SetFaction(charmer.GetFaction()); // Set charmed charmer.SetCharm(this, true); if (IsTypeId(TypeId.Unit)) { IMovementGenerator movementGenerator = GetMotionMaster().GetMotionSlot(MovementSlot.Idle); if (movementGenerator != null) { movementGenerator.Pause(0); } GetMotionMaster().Clear(MovementSlot.Active); StopMoving(); ToCreature().GetAI().OnCharmed(true); } else { Player player = ToPlayer(); if (player) { if (player.IsAFK()) { player.ToggleAFK(); } if (charmer.IsTypeId(TypeId.Unit)) // we are charmed by a creature { // change AI to charmed AI on next Update tick NeedChangeAI = true; if (IsAIEnabled) { IsAIEnabled = false; player.GetAI().OnCharmed(true); } } player.SetClientControl(this, false); } } // charm is set by aura, and aura effect remove handler was called during apply handler execution // prevent undefined behaviour if (aurApp != null && aurApp.GetRemoveMode() != 0) { return(false); } // Pets already have a properly initialized CharmInfo, don't overwrite it. if (type != CharmType.Vehicle && GetCharmInfo() == null) { InitCharmInfo(); if (type == CharmType.Possess) { GetCharmInfo().InitPossessCreateSpells(); } else { GetCharmInfo().InitCharmCreateSpells(); } } if (playerCharmer) { switch (type) { case CharmType.Vehicle: AddUnitFlag(UnitFlags.PlayerControlled); playerCharmer.SetClientControl(this, true); playerCharmer.VehicleSpellInitialize(); break; case CharmType.Possess: AddUnitState(UnitState.Possessed); AddUnitFlag(UnitFlags.PlayerControlled); charmer.AddUnitFlag(UnitFlags.RemoveClientControl); playerCharmer.SetClientControl(this, true); playerCharmer.PossessSpellInitialize(); break; case CharmType.Charm: if (IsTypeId(TypeId.Unit) && charmer.GetClass() == Class.Warlock) { CreatureTemplate cinfo = ToCreature().GetCreatureTemplate(); if (cinfo != null && cinfo.CreatureType == CreatureType.Demon) { // to prevent client crash SetClass(Class.Mage); // just to enable stat window if (GetCharmInfo() != null) { GetCharmInfo().SetPetNumber(Global.ObjectMgr.GeneratePetNumber(), true); } // if charmed two demons the same session, the 2nd gets the 1st one's name SetPetNameTimestamp((uint)GameTime.GetGameTime()); // cast can't be helped } } playerCharmer.CharmSpellInitialize(); break; default: case CharmType.Convert: break; } } return(true); }
private PathBasedMovementData BuildPathData(ClientSetClickToMovePathRequestPayload payload, IMovementGenerator <GameObject> generator, IMovementData originalMovementData, NetworkEntityGuid guid) { //TODO: Sanity check timestamp and position. //So, originally we used authorative time and position but now we semi-trust the client. //We need to verify the send timestamp is not too far off and also sanity check the position too. Vector3[] path = payload.PathData.MovementPath.ToArrayTryAvoidCopy(); Vector3[] fullPath = new Vector3[path.Length + 1]; //If we haven't even started the last movement generator from the last click. if (generator.isStarted) { //Force the current position as the start point of the path. fullPath[0] = generator.CurrentPosition; } else { //We need to use the last WorldTransform because //the last movement generator has not started. WorldTransform transform = TransformMap.RetrieveEntity(guid); fullPath[0] = new Vector3(transform.PositionX, transform.PositionY, transform.PositionZ); } Array.Copy(path, 0, fullPath, 1, path.Length); return(new PathBasedMovementData(fullPath, TimeService.CurrentLocalTime)); }