/// <summary> /// Loads the backing store landblock structure<para /> /// This function is thread safe /// </summary> /// <param name="blockCellID">Any landblock + cell ID within the landblock</param> public static Landblock get_landblock(uint blockCellID) { // client implementation /*if (Landblocks == null || Landblocks.Count == 0) * return null; * * if (!LandDefs.inbound_valid_cellid(cellID) || cellID >= 0x100) * return null; * * var local_lcoord = LandDefs.blockid_to_lcoord(LoadedCellID); * var global_lcoord = LandDefs.gid_to_lcoord(cellID); * * var xDiff = ((int)global_lcoord.Value.X + 8 * MidRadius - (int)local_lcoord.Value.X) / 8; * var yDiff = ((int)global_lcoord.Value.Y + 8 * MidRadius - (int)local_lcoord.Value.Y) / 8; * * if (xDiff < 0 || yDiff < 0 || xDiff < MidWidth || yDiff < MidWidth) * return null; * * return Landblocks[yDiff + xDiff * MidWidth];*/ var landblockID = blockCellID | 0xFFFF; // check if landblock is already cached if (Landblocks.TryGetValue(landblockID, out var landblock)) { return(landblock); } lock (landblockMutex) { // check if landblock is already cached, this time under the lock. if (Landblocks.TryGetValue(landblockID, out landblock)) { return(landblock); } // if not, load into cache landblock = new Landblock(DBObj.GetCellLandblock(landblockID)); if (Landblocks.TryAdd(landblockID, landblock)) { landblock.PostInit(); // ensure landblock manager loaded var lbid = new LandblockId(landblockID); if (!LandblockManager.IsLoaded(lbid)) { // this can happen from encounter spawns sliding down walkable slopes... //log.Debug($"{landblockID:X8} requested from LScape, but not loaded from LandblockManager, adding"); LandblockManager.GetLandblock(lbid, false, false); } } else { Landblocks.TryGetValue(landblockID, out landblock); } return(landblock); } }
/// <summary> /// Loads the backing store landblock structure<para /> /// This function is thread safe /// </summary> /// <param name="blockCellID">Any landblock + cell ID within the landblock</param> public static Landblock get_landblock(uint blockCellID) { var landblockID = blockCellID | 0xFFFF; if (PhysicsEngine.Instance.Server) { var lbid = new LandblockId(landblockID); var lbmLandblock = LandblockManager.GetLandblock(lbid, false, false); return(lbmLandblock.PhysicsLandblock); } // client implementation /*if (Landblocks == null || Landblocks.Count == 0) * return null; * * if (!LandDefs.inbound_valid_cellid(cellID) || cellID >= 0x100) * return null; * * var local_lcoord = LandDefs.blockid_to_lcoord(LoadedCellID); * var global_lcoord = LandDefs.gid_to_lcoord(cellID); * * var xDiff = ((int)global_lcoord.Value.X + 8 * MidRadius - (int)local_lcoord.Value.X) / 8; * var yDiff = ((int)global_lcoord.Value.Y + 8 * MidRadius - (int)local_lcoord.Value.Y) / 8; * * if (xDiff < 0 || yDiff < 0 || xDiff < MidWidth || yDiff < MidWidth) * return null; * * return Landblocks[yDiff + xDiff * MidWidth];*/ // check if landblock is already cached if (Landblocks.TryGetValue(landblockID, out var landblock)) { return(landblock); } lock (landblockMutex) { // check if landblock is already cached, this time under the lock. if (Landblocks.TryGetValue(landblockID, out landblock)) { return(landblock); } // if not, load into cache landblock = new Landblock(DBObj.GetCellLandblock(landblockID)); if (Landblocks.TryAdd(landblockID, landblock)) { landblock.PostInit(); } else { Landblocks.TryGetValue(landblockID, out landblock); } return(landblock); } }
public House GetDungeonHouse() { var landblockId = new LandblockId(House.DungeonLandblockID); var isLoaded = LandblockManager.IsLoaded(landblockId); if (!isLoaded) { return(null); } var loaded = LandblockManager.GetLandblock(landblockId, false); var wos = loaded.GetWorldObjectsForPhysicsHandling(); return(wos.FirstOrDefault(wo => wo.WeenieClassId == House.WeenieClassId) as House); }
/// <summary> /// Called when a player dies, in conjunction with Die() /// </summary> /// <param name="lastDamager">The last damager that landed the death blow</param> /// <param name="damageType">The damage type for the death message</param> public override DeathMessage OnDeath(WorldObject lastDamager, DamageType damageType, bool criticalHit = false) { var deathMessage = base.OnDeath(lastDamager, damageType, criticalHit); lastDamager.EmoteManager.OnKill(this); var playerMsg = string.Format(deathMessage.Victim, Name, lastDamager.Name); var msgYourDeath = new GameEventYourDeath(Session, playerMsg); Session.Network.EnqueueSend(msgYourDeath); // broadcast to nearby players var nearbyMsg = string.Format(deathMessage.Broadcast, Name, lastDamager.Name); var broadcastMsg = new GameMessageSystemChat(nearbyMsg, ChatMessageType.Broadcast); var excludePlayers = new List <Player>(); if (lastDamager is Player lastDamagerPlayer) { excludePlayers.Add(lastDamagerPlayer); } var nearbyPlayers = EnqueueBroadcast(excludePlayers, false, broadcastMsg); excludePlayers.AddRange(nearbyPlayers); excludePlayers.Add(this); // exclude self if (Fellowship != null) { Fellowship.OnDeath(this); } // if the player's lifestone is in a different landblock, also broadcast their demise to that landblock if (Sanctuary != null && Location.Landblock != Sanctuary.Landblock) { // ActionBroadcastKill might not work if other players around lifestone aren't aware of this player yet... // this existing broadcast method is also based on the current visible objects to the player, // and the player hasn't entered portal space or teleported back to the lifestone yet, so this doesn't work //ActionBroadcastKill(nearbyMsg, Guid, lastDamager.Guid); // instead, we get all of the players in the lifestone landblock + adjacent landblocks, // and possibly limit that to some radius around the landblock? var lifestoneBlock = LandblockManager.GetLandblock(new LandblockId(Sanctuary.Landblock << 16 | 0xFFFF), true); lifestoneBlock.EnqueueBroadcast(excludePlayers, true, broadcastMsg); } return(deathMessage); }
public House GetHouse() { if (HouseInstance == null) { return(House); } var houseGuid = HouseInstance.Value; var landblock = (ushort)((houseGuid >> 12) & 0xFFFF); var landblockId = new LandblockId((uint)(landblock << 16 | 0xFFFF)); var isLoaded = LandblockManager.IsLoaded(landblockId); if (!isLoaded) { return(House); } var loaded = LandblockManager.GetLandblock(landblockId, false); return(loaded.GetObject(new ObjectGuid(houseGuid)) as House); }
/// <summary> /// Called when a player dies, in conjunction with Die() /// </summary> /// <param name="lastDamager">The last damager that landed the death blow</param> /// <param name="damageType">The damage type for the death message</param> public override DeathMessage OnDeath(DamageHistoryInfo lastDamager, DamageType damageType, bool criticalHit = false) { var topDamager = DamageHistory.GetTopDamager(false); HandlePKDeathBroadcast(lastDamager, topDamager); var deathMessage = base.OnDeath(lastDamager, damageType, criticalHit); var lastDamagerObj = lastDamager?.TryGetAttacker(); if (lastDamagerObj != null) { lastDamagerObj.EmoteManager.OnKill(this); } var playerMsg = ""; if (lastDamager != null) { playerMsg = string.Format(deathMessage.Victim, Name, lastDamager.Name); } else { playerMsg = deathMessage.Victim; } var msgYourDeath = new GameEventVictimNotification(Session, playerMsg); Session.Network.EnqueueSend(msgYourDeath); // broadcast to nearby players var nearbyMsg = ""; if (lastDamager != null) { nearbyMsg = string.Format(deathMessage.Broadcast, Name, lastDamager.Name); } else { nearbyMsg = deathMessage.Broadcast; } var broadcastMsg = new GameMessagePlayerKilled(nearbyMsg, Guid, lastDamager?.Guid ?? ObjectGuid.Invalid); log.Debug("[CORPSE] " + nearbyMsg); var excludePlayers = new List <Player>(); var nearbyPlayers = EnqueueBroadcast(excludePlayers, false, broadcastMsg); excludePlayers.AddRange(nearbyPlayers); if (Fellowship != null) { Fellowship.OnDeath(this); } // if the player's lifestone is in a different landblock, also broadcast their demise to that landblock if (PropertyManager.GetBool("lifestone_broadcast_death").Item&& Sanctuary != null && Location.Landblock != Sanctuary.Landblock) { // ActionBroadcastKill might not work if other players around lifestone aren't aware of this player yet... // this existing broadcast method is also based on the current visible objects to the player, // and the player hasn't entered portal space or teleported back to the lifestone yet, so this doesn't work //ActionBroadcastKill(nearbyMsg, Guid, lastDamager.Guid); // instead, we get all of the players in the lifestone landblock + adjacent landblocks, // and possibly limit that to some radius around the landblock? var lifestoneBlock = LandblockManager.GetLandblock(new LandblockId(Sanctuary.Landblock << 16 | 0xFFFF), true); lifestoneBlock.EnqueueBroadcast(excludePlayers, true, Sanctuary, LocalBroadcastRangeSq, broadcastMsg); } return(deathMessage); }
public void LogOut_Inner(bool clientSessionTerminatedAbruptly = false) { if (Fellowship != null) { FellowshipQuit(false); } if (IsTrading && TradePartner != null) { var tradePartner = PlayerManager.GetOnlinePlayer(TradePartner); if (tradePartner != null) { tradePartner.HandleActionCloseTradeNegotiations(); } } if (!clientSessionTerminatedAbruptly) { // Thie retail server sends a ChatRoomTracker 0x0295 first, then the status message, 0x028B. It does them one at a time for each individual channel. // The ChatRoomTracker message doesn't seem to change at all. // For the purpose of ACE, we simplify this process. var general = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "General"); var trade = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "Trade"); var lfg = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "LFG"); var roleplay = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "Roleplay"); Session.Network.EnqueueSend(general, trade, lfg, roleplay); } if (CurrentActivePet != null) { CurrentActivePet.Destroy(); } if (CurrentLandblock != null) { var logout = new Motion(MotionStance.NonCombat, MotionCommand.LogOut); EnqueueBroadcastMotion(logout); EnqueueBroadcastPhysicsState(); var logoutChain = new ActionChain(); var motionTable = DatManager.PortalDat.ReadFromDat <MotionTable>((uint)MotionTableId); float logoutAnimationLength = motionTable.GetAnimationLength(MotionCommand.LogOut); logoutChain.AddDelaySeconds(logoutAnimationLength); // remove the player from landblock management -- after the animation has run logoutChain.AddAction(this, () => { if (CurrentLandblock == null) { log.Debug($"0x{Guid}:{Name}.LogOut_Inner.logoutChain: CurrentLandblock is null, unable to remove from a landblock..."); if (Location != null) { log.Debug($"0x{Guid}:{Name}.LogOut_Inner.logoutChain: Location is not null, Location = {Location.ToLOCString()}"); } } CurrentLandblock?.RemoveWorldObject(Guid, false); SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); }); // close any open landblock containers (chests / corpses) if (LastOpenedContainerId != ObjectGuid.Invalid) { var container = CurrentLandblock.GetObject(LastOpenedContainerId) as Container; if (container != null) { container.Close(this); } } logoutChain.EnqueueChain(); } else { log.Debug($"0x{Guid}:{Name}.LogOut_Inner: CurrentLandblock is null"); if (Location != null) { log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Location is not null, Location = {Location.ToLOCString()}"); var validLoadedLandblock = LandblockManager.GetLandblock(Location.LandblockId, false); if (validLoadedLandblock.GetObject(Guid.Full) != null) { log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Player is still on landblock, removing..."); validLoadedLandblock.RemoveWorldObject(Guid, false); } else { log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Player is not found on the landblock Location references."); } } else { log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Location is null"); } SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); } }
public void LogOut_Inner(bool clientSessionTerminatedAbruptly = false) { IsBusy = true; IsLoggingOut = true; if (Fellowship != null) { FellowshipQuit(false); } if (IsTrading && TradePartner != ObjectGuid.Invalid) { var tradePartner = PlayerManager.GetOnlinePlayer(TradePartner); if (tradePartner != null) { tradePartner.HandleActionCloseTradeNegotiations(); } } if (!clientSessionTerminatedAbruptly) { if (PropertyManager.GetBool("use_turbine_chat").Item) { if (GetCharacterOption(CharacterOption.ListenToGeneralChat)) { LeaveTurbineChatChannel("General"); } if (GetCharacterOption(CharacterOption.ListenToTradeChat)) { LeaveTurbineChatChannel("Trade"); } if (GetCharacterOption(CharacterOption.ListenToLFGChat)) { LeaveTurbineChatChannel("LFG"); } if (GetCharacterOption(CharacterOption.ListenToRoleplayChat)) { LeaveTurbineChatChannel("Roleplay"); } if (GetCharacterOption(CharacterOption.ListenToAllegianceChat) && Allegiance != null) { LeaveTurbineChatChannel("Allegiance"); } if (GetCharacterOption(CharacterOption.ListenToSocietyChat) && Society != FactionBits.None) { LeaveTurbineChatChannel("Society"); } } } if (CurrentActivePet != null) { CurrentActivePet.Destroy(); } if (CurrentLandblock != null) { var logout = new Motion(MotionStance.NonCombat, MotionCommand.LogOut); EnqueueBroadcastMotion(logout); EnqueueBroadcastPhysicsState(); var logoutChain = new ActionChain(); var motionTable = DatManager.PortalDat.ReadFromDat <MotionTable>((uint)MotionTableId); float logoutAnimationLength = motionTable.GetAnimationLength(MotionCommand.LogOut); logoutChain.AddDelaySeconds(logoutAnimationLength); // remove the player from landblock management -- after the animation has run logoutChain.AddAction(this, () => { if (CurrentLandblock == null) { log.Debug($"0x{Guid}:{Name}.LogOut_Inner.logoutChain: CurrentLandblock is null, unable to remove from a landblock..."); if (Location != null) { log.Debug($"0x{Guid}:{Name}.LogOut_Inner.logoutChain: Location is not null, Location = {Location.ToLOCString()}"); } } CurrentLandblock?.RemoveWorldObject(Guid, false); SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); }); // close any open landblock containers (chests / corpses) if (LastOpenedContainerId != ObjectGuid.Invalid) { var container = CurrentLandblock.GetObject(LastOpenedContainerId) as Container; if (container != null) { container.Close(this); } } logoutChain.EnqueueChain(); } else { log.Debug($"0x{Guid}:{Name}.LogOut_Inner: CurrentLandblock is null"); if (Location != null) { log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Location is not null, Location = {Location.ToLOCString()}"); var validLoadedLandblock = LandblockManager.GetLandblock(Location.LandblockId, false); if (validLoadedLandblock.GetObject(Guid.Full) != null) { log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Player is still on landblock, removing..."); validLoadedLandblock.RemoveWorldObject(Guid, false); } else { log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Player is not found on the landblock Location references."); } } else { log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Location is null"); } SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); } }
/// <summary> /// Called when a player dies, in conjunction with Die() /// </summary> /// <param name="lastDamager">The last damager that landed the death blow</param> /// <param name="damageType">The damage type for the death message</param> public override DeathMessage OnDeath(WorldObject lastDamager, DamageType damageType, bool criticalHit = false) { if (DamageHistory.TopDamager is Player pkPlayer) { if (IsPKDeath(pkPlayer)) { pkPlayer.PkTimestamp = Time.GetUnixTime(); pkPlayer.PlayerKillsPk++; var globalPKDe = $"{lastDamager.Name} has defeated {Name}!"; if ((Location.Cell & 0xFFFF) < 0x100) { globalPKDe += $" The kill occured at {Location.GetMapCoordStr()}"; } globalPKDe += "\n[PKDe]"; PlayerManager.BroadcastToAll(new GameMessageSystemChat(globalPKDe, ChatMessageType.Broadcast)); } else if (IsPKLiteDeath(pkPlayer)) { pkPlayer.PlayerKillsPkl++; } } var deathMessage = base.OnDeath(lastDamager, damageType, criticalHit); if (lastDamager != null) { lastDamager.EmoteManager.OnKill(this); } var playerMsg = ""; if (lastDamager != null) { playerMsg = string.Format(deathMessage.Victim, Name, lastDamager.Name); } else { playerMsg = deathMessage.Victim; } var msgYourDeath = new GameEventYourDeath(Session, playerMsg); Session.Network.EnqueueSend(msgYourDeath); // broadcast to nearby players var nearbyMsg = ""; if (lastDamager != null) { nearbyMsg = string.Format(deathMessage.Broadcast, Name, lastDamager.Name); } else { nearbyMsg = deathMessage.Broadcast; } var broadcastMsg = new GameMessageSystemChat(nearbyMsg, ChatMessageType.Broadcast); log.Debug("[CORPSE] " + nearbyMsg); var excludePlayers = new List <Player>(); if (lastDamager is Player lastDamagerPlayer) { excludePlayers.Add(lastDamagerPlayer); } var nearbyPlayers = EnqueueBroadcast(excludePlayers, false, broadcastMsg); excludePlayers.AddRange(nearbyPlayers); excludePlayers.Add(this); // exclude self if (Fellowship != null) { Fellowship.OnDeath(this); } // if the player's lifestone is in a different landblock, also broadcast their demise to that landblock if (Sanctuary != null && Location.Landblock != Sanctuary.Landblock) { // ActionBroadcastKill might not work if other players around lifestone aren't aware of this player yet... // this existing broadcast method is also based on the current visible objects to the player, // and the player hasn't entered portal space or teleported back to the lifestone yet, so this doesn't work //ActionBroadcastKill(nearbyMsg, Guid, lastDamager.Guid); // instead, we get all of the players in the lifestone landblock + adjacent landblocks, // and possibly limit that to some radius around the landblock? var lifestoneBlock = LandblockManager.GetLandblock(new LandblockId(Sanctuary.Landblock << 16 | 0xFFFF), true); lifestoneBlock.EnqueueBroadcast(excludePlayers, true, broadcastMsg); } return(deathMessage); }
/// <summary> /// Loads the backing store landblock structure<para /> /// This function is thread safe /// </summary> /// <param name="iBlockCellID">Any instance + landblock + cell ID within the landblock</param> public static Landblock get_landblock(ulong iBlockCellID) { /*if ((iBlockCellID | 0xFFFF) == 0x1D9FFFF) * { * Console.WriteLine(System.Environment.StackTrace); * var debug = true; * }*/ if (PhysicsEngine.Instance.Server) { var lbmLandblock = LandblockManager.GetLandblock(iBlockCellID, false, false); return(lbmLandblock.PhysicsLandblock); } // client implementation /*if (Landblocks == null || Landblocks.Count == 0) * return null; * * if (!LandDefs.inbound_valid_cellid(cellID) || cellID >= 0x100) * return null; * * var local_lcoord = LandDefs.blockid_to_lcoord(LoadedCellID); * var global_lcoord = LandDefs.gid_to_lcoord(cellID); * * var xDiff = ((int)global_lcoord.Value.X + 8 * MidRadius - (int)local_lcoord.Value.X) / 8; * var yDiff = ((int)global_lcoord.Value.Y + 8 * MidRadius - (int)local_lcoord.Value.Y) / 8; * * if (xDiff < 0 || yDiff < 0 || xDiff < MidWidth || yDiff < MidWidth) * return null; * * return Landblocks[yDiff + xDiff * MidWidth];*/ var iLandblockID = iBlockCellID | 0xFFFF; // check if landblock is already cached if (Landblocks.TryGetValue(iLandblockID, out var landblock)) { return(landblock); } lock (landblockMutex) { // check if landblock is already cached, this time under the lock. if (Landblocks.TryGetValue(iLandblockID, out landblock)) { return(landblock); } // if not, load into cache var instance = BlockCell.GetInstance(iLandblockID); landblock = new Landblock(DBObj.GetCellLandblock((uint)iLandblockID), instance); if (Landblocks.TryAdd(iLandblockID, landblock)) { landblock.PostInit(); } else { Landblocks.TryGetValue(iLandblockID, out landblock); } return(landblock); } }