Example #1
0
        /// <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);
            }
        }
Example #2
0
        /// <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);
            }
        }
Example #3
0
        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);
        }
Example #4
0
        /// <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);
        }
Example #5
0
        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);
        }
Example #6
0
        /// <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);
        }
Example #7
0
        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);
            }
        }
Example #8
0
        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);
            }
        }
Example #9
0
        /// <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);
        }
Example #10
0
        /// <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);
            }
        }