public override void Close(Player player) { base.Close(player); if (VictimId == null) { return; } var victimGuid = new ObjectGuid(VictimId.Value); if (!victimGuid.IsPlayer()) { // monster corpses -- after anyone with access to the locked corpse loots, // becomes open to anyone? or only after the killer loots? IsLooted = true; } else { var killerGuid = new ObjectGuid(KillerId ?? 0); // player corpses -- after corpse owner or killer loots, becomes open to anyone? if (player != null && (player.Guid == killerGuid || player.Guid == victimGuid)) { IsLooted = true; } } }
/// <summary> /// Make sure this is called from within a lock(biotaCacheMutex) /// </summary> private void TryPerformMaintenance() { if (lastMaintenanceInterval + MaintenanceInterval > DateTime.UtcNow) { return; } var removals = new Collection <uint>(); foreach (var kvp in biotaCache) { if (ObjectGuid.IsPlayer(kvp.Key)) { if (kvp.Value.LastSeen + PlayerBiotaRetentionTime < DateTime.UtcNow) { removals.Add(kvp.Key); } } else { if (kvp.Value.LastSeen + NonPlayerBiotaRetentionTime < DateTime.UtcNow) { removals.Add(kvp.Key); } } } foreach (var removal in removals) { biotaCache.Remove(removal); } lastMaintenanceInterval = DateTime.UtcNow; }
public override void HandleActionOnCollideEnd(ObjectGuid playerId) { if (!playerId.IsPlayer()) { return; } if (Players.Any(k => k == playerId)) { Players.Remove(playerId); } }
/// <summary> /// Restore a WorldObject from the database. /// </summary> public Container(Biota biota) : base(biota) { SetEphemeralValues(); // A player has their possessions passed via the ctor. All other world objects must load their own inventory if (!(this is Player) && !ObjectGuid.IsPlayer(ContainerId ?? 0)) { DatabaseManager.Shard.GetInventoryInParallel(biota.Id, false, biotas => { EnqueueAction(new ActionEventDelegate(() => SortBiotasIntoInventory(biotas))); }); } }
public Unit GetUnit(WorldObject u, ObjectGuid guid) { if (guid.IsPlayer()) { return(GetPlayer(u, guid)); } if (guid.IsPet()) { return(GetPet(u, guid)); } return(GetCreature(u, guid)); }
static bool HandleGameObjectDeleteCommand(StringArguments args, CommandHandler handler) { // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r string id = handler.ExtractKeyFromLink(args, "Hgameobject"); if (string.IsNullOrEmpty(id)) { return(false); } if (!ulong.TryParse(id, out ulong guidLow) || guidLow == 0) { return(false); } Player player = handler.GetSession().GetPlayer(); // force respawn to make sure we find something player.GetMap().RemoveRespawnTime(SpawnObjectType.GameObject, guidLow, true); GameObject obj = handler.GetObjectFromPlayerMapByDbGuid(guidLow); if (!obj) { handler.SendSysMessage(CypherStrings.CommandObjnotfound, guidLow); return(false); } ObjectGuid ownerGuid = obj.GetOwnerGUID(); if (ownerGuid.IsEmpty()) { Unit owner = Global.ObjAccessor.GetUnit(player, ownerGuid); if (!owner || !ownerGuid.IsPlayer()) { handler.SendSysMessage(CypherStrings.CommandDelobjrefercreature, ownerGuid.ToString(), obj.GetGUID().ToString()); return(false); } owner.RemoveGameObject(obj, false); } obj.SetRespawnTime(0); // not save respawn time obj.Delete(); obj.DeleteFromDB(); handler.SendSysMessage(CypherStrings.CommandDelobjmessage, obj.GetGUID().ToString()); return(true); }
public override void HandleActionOnCollide(ObjectGuid playerId) { if (!playerId.IsPlayer()) { return; } if (!Players.Any(k => k == playerId)) { Players.Add(playerId); } if (ActionLoop == null) { ActionLoop = NextActionLoop; NextActionLoop.EnqueueChain(); } }
/// <summary> /// Restore a WorldObject from the database. /// </summary> public Container(Biota biota) : base(biota) { if (Biota.TryRemoveProperty(PropertyBool.Open, out _, BiotaDatabaseLock)) { ChangesDetected = true; } SetEphemeralValues(); // A player has their possessions passed via the ctor. All other world objects must load their own inventory if (!(this is Player) && !ObjectGuid.IsPlayer(ContainerId ?? 0)) { DatabaseManager.Shard.GetInventoryInParallel(biota.Id, false, biotas => { EnqueueAction(new ActionEventDelegate(() => SortBiotasIntoInventory(biotas))); }); } }
public void HandleActionPutItemInContainer(ObjectGuid itemGuid, ObjectGuid containerGuid, int placement = 0) { Container container; if (containerGuid.IsPlayer()) { container = this; } else { // Ok I am going into player pack - not the main pack. // TODO pick up here - I have a generic object for a container, need to find out why. container = (Container)GetInventoryItem(containerGuid); } // is this something I already have? If not, it has to be a pickup - do the pickup and out. if (!HasInventoryItem(itemGuid) && !HasWieldedItem(itemGuid)) { // This is a pickup into our main pack. PickupItem(container, itemGuid, placement, PropertyInstanceId.Container); return; } // Ok, I know my container and I know I must have the item so let's get it. WorldObject item = GetInventoryItem(itemGuid); // check wilded. if (item == null) { item = GetWieldedItem(itemGuid); } // Was I equiped? If so, lets take care of that and unequip if (item.WielderId != null) { UnwieldItem(container, item, placement); return; } // if were are still here, this needs to do a pack pack or main pack move. MoveItem(ref item, container, placement); }
static bool HandleGameObjectDeleteCommand(StringArguments args, CommandHandler handler) { // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r string id = handler.ExtractKeyFromLink(args, "Hgameobject"); if (string.IsNullOrEmpty(id)) { return(false); } if (!ulong.TryParse(id, out ulong spawnId) || spawnId == 0) { return(false); } GameObject obj = handler.GetObjectFromPlayerMapByDbGuid(spawnId); if (obj != null) { Player player = handler.GetSession().GetPlayer(); ObjectGuid ownerGuid = obj.GetOwnerGUID(); if (!ownerGuid.IsEmpty()) { Unit owner = Global.ObjAccessor.GetUnit(player, ownerGuid); if (!owner || !ownerGuid.IsPlayer()) { handler.SendSysMessage(CypherStrings.CommandDelobjrefercreature, ownerGuid.ToString(), obj.GetGUID().ToString()); return(false); } owner.RemoveGameObject(obj, false); } } if (GameObject.DeleteFromDB(spawnId)) { handler.SendSysMessage(CypherStrings.CommandDelobjmessage, spawnId); return(true); } handler.SendSysMessage(CypherStrings.CommandObjnotfound, obj.GetGUID().ToString()); return(false); }
public override Biota GetBiota(uint id) { if (ObjectGuid.IsPlayer(id)) { var context = new ShardDbContext(); var biota = GetBiota(context, id); if (biota != null) { BiotaContexts.Add(biota, context); } return(biota); } using (var context = new ShardDbContext()) { context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; return(GetBiota(context, id)); } }
private void TryAddToCache(ShardDbContext context, Biota biota) { lock (biotaCacheMutex) { if (ObjectGuid.IsPlayer(biota.Id)) { if (PlayerBiotaRetentionTime > TimeSpan.Zero) { biotaCache[biota.Id] = new CacheObject <Biota> { LastSeen = DateTime.UtcNow, Context = context, CachedObject = biota } } ; } else if (NonPlayerBiotaRetentionTime > TimeSpan.Zero) { biotaCache[biota.Id] = new CacheObject <Biota> { LastSeen = DateTime.UtcNow, Context = context, CachedObject = biota } } ; } }
public override Biota GetBiota(uint id, bool doNotAddToCache = false) { if (ObjectGuid.IsPlayer(id)) { if (PlayerBiotaRetentionTime > TimeSpan.Zero) { var context = new ShardDbContext(); var biota = GetBiota(context, id, doNotAddToCache); // This will add the result into the caches return(biota); } } else if (NonPlayerBiotaRetentionTime > TimeSpan.Zero) { var context = new ShardDbContext(); var biota = GetBiota(context, id, doNotAddToCache); // This will add the result into the caches return(biota); } return(base.GetBiota(id, doNotAddToCache)); }
public bool IsAi() { return(!PlayerGuid.IsPlayer()); }
/// <summary> /// Restore a WorldObject from the database. /// </summary> public Container(Biota biota) : base(biota) { if (Biota.TryRemoveProperty(PropertyBool.Open, BiotaDatabaseLock)) { ChangesDetected = true; } // This is a temporary fix for objects that were loaded with this PR when EncumbranceVal was not treated as ephemeral. 2020-03-28 // This can be removed later. if (Biota.PropertiesInt.ContainsKey(PropertyInt.EncumbranceVal)) { var weenie = DatabaseManager.World.GetCachedWeenie(biota.WeenieClassId); if (weenie != null && weenie.PropertiesInt.TryGetValue(PropertyInt.EncumbranceVal, out var value)) { if (biota.PropertiesInt[PropertyInt.EncumbranceVal] != value) { biota.PropertiesInt[PropertyInt.EncumbranceVal] = value; ChangesDetected = true; } } else { biota.PropertiesInt.Remove(PropertyInt.EncumbranceVal); ChangesDetected = true; } } // This is a temporary fix for objects that were loaded with this PR when Value was not treated as ephemeral. 2020-03-28 // This can be removed later. if (!(this is Creature) && Biota.PropertiesInt.ContainsKey(PropertyInt.Value)) { var weenie = DatabaseManager.World.GetCachedWeenie(biota.WeenieClassId); if (weenie != null && weenie.PropertiesInt.TryGetValue(PropertyInt.Value, out var value)) { if (biota.PropertiesInt[PropertyInt.Value] != value) { biota.PropertiesInt[PropertyInt.Value] = value; ChangesDetected = true; } } else { biota.PropertiesInt.Remove(PropertyInt.Value); ChangesDetected = true; } } InitializePropertyDictionaries(); SetEphemeralValues(true); // A player has their possessions passed via the ctor. All other world objects must load their own inventory if (!(this is Player) && !ObjectGuid.IsPlayer(ContainerId ?? 0)) { DatabaseManager.Shard.GetInventoryInParallel(biota.Id, false, biotas => { //EnqueueAction(new ActionEventDelegate(() => SortBiotasIntoInventory(biotas))); SortBiotasIntoInventory(biotas); }); } }
public static void HandleServerStatus(Session session, params string[] parameters) { // This is formatted very similarly to GDL. var sb = new StringBuilder(); var proc = Process.GetCurrentProcess(); sb.Append($"Server Status:{'\n'}"); sb.Append($"Host Info: {Environment.OSVersion}, vCPU: {Environment.ProcessorCount}{'\n'}"); var runTime = DateTime.Now - proc.StartTime; sb.Append($"Server Runtime: {(int)runTime.TotalHours}h {runTime.Minutes}m {runTime.Seconds}s{'\n'}"); sb.Append($"Total CPU Time: {(int)proc.TotalProcessorTime.TotalHours}h {proc.TotalProcessorTime.Minutes}m {proc.TotalProcessorTime.Seconds}s, Threads: {proc.Threads.Count}{'\n'}"); // todo, add actual system memory used/avail sb.Append($"{(proc.PrivateMemorySize64 >> 20):N0} MB used{'\n'}"); // sb.Append($"{(proc.PrivateMemorySize64 >> 20)} MB used, xxxx / yyyy MB physical mem free.{'\n'}"); sb.Append($"{NetworkManager.GetSessionCount():N0} connections, {NetworkManager.GetUniqueSessionEndpointCount():N0} unique connections, {PlayerManager.GetOnlineCount():N0} players online{'\n'}"); sb.Append($"Total Accounts Created: {DatabaseManager.Authentication.GetAccountCount():N0}, Total Characters Created: {(PlayerManager.GetOfflineCount() + PlayerManager.GetOnlineCount()):N0}{'\n'}"); // 330 active objects, 1931 total objects(16777216 buckets.) // todo, expand this var loadedLandblocks = LandblockManager.GetLoadedLandblocks(); int dormantLandblocks = 0, activeDungeonLandblocks = 0, dormantDungeonLandblocks = 0; int players = 0, creatures = 0, missiles = 0, other = 0, total = 0; foreach (var landblock in loadedLandblocks) { if (landblock.IsDormant) { dormantLandblocks++; } if (landblock.IsDungeon) { if (landblock.IsDormant) { dormantDungeonLandblocks++; } else { activeDungeonLandblocks++; } } foreach (var worldObject in landblock.GetAllWorldObjectsForDiagnostics()) { if (worldObject is Player) { players++; } else if (worldObject is Creature) { creatures++; } else if (worldObject.Missile ?? false) { missiles++; } else { other++; } total++; } } sb.Append($"Landblocks: {(loadedLandblocks.Count - dormantLandblocks):N0} active ({activeDungeonLandblocks:N0} dungeons), {dormantLandblocks:N0} dormant ({dormantDungeonLandblocks:N0} dungeons), Landblock Groups: {LandblockManager.LandblockGroupsCount:N0} - Players: {players:N0}, Creatures: {creatures:N0}, Missiles: {missiles:N0}, Other: {other:N0}, Total: {total:N0}.{'\n'}"); // 11 total blocks loaded. 11 active. 0 pending dormancy. 0 dormant. 314 unloaded. // 11 total blocks loaded. 11 active. 0 pending dormancy. 0 dormant. 314 unloaded. if (ServerPerformanceMonitor.IsRunning) { sb.Append($"Server Performance Monitor - UpdateGameWorld ~5m {ServerPerformanceMonitor.GetEventHistory5m(ServerPerformanceMonitor.MonitorType.UpdateGameWorld_Entire).AverageEventDuration:N3}, ~1h {ServerPerformanceMonitor.GetEventHistory1h(ServerPerformanceMonitor.MonitorType.UpdateGameWorld_Entire).AverageEventDuration:N3} s{'\n'}"); } else { sb.Append($"Server Performance Monitor - Not running. To start use /serverperformance start{'\n'}"); } sb.Append($"Threading - WorldThreadCount: {ConfigManager.Config.Server.Threading.LandblockManagerParallelOptions.MaxDegreeOfParallelism}, Multithread Physics: {ConfigManager.Config.Server.Threading.MultiThreadedLandblockGroupPhysicsTicking}, Multithread Non-Physics: {ConfigManager.Config.Server.Threading.MultiThreadedLandblockGroupTicking}, DatabaseThreadCount: {ConfigManager.Config.Server.Threading.DatabaseParallelOptions.MaxDegreeOfParallelism}{'\n'}"); sb.Append($"Physics Cache Counts - BSPCache: {BSPCache.Count:N0}, GfxObjCache: {GfxObjCache.Count:N0}, PolygonCache: {PolygonCache.Count:N0}, VertexCache: {VertexCache.Count:N0}{'\n'}"); sb.Append($"Total Server Objects: {ServerObjectManager.ServerObjects.Count:N0}{'\n'}"); sb.Append($"World DB Cache Counts - Weenies: {DatabaseManager.World.GetWeenieCacheCount():N0}, LandblockInstances: {DatabaseManager.World.GetLandblockInstancesCacheCount():N0}, PointsOfInterest: {DatabaseManager.World.GetPointsOfInterestCacheCount():N0}, Cookbooks: {DatabaseManager.World.GetCookbookCacheCount():N0}, Spells: {DatabaseManager.World.GetSpellCacheCount():N0}, Encounters: {DatabaseManager.World.GetEncounterCacheCount():N0}, Events: {DatabaseManager.World.GetEventsCacheCount():N0}{'\n'}"); sb.Append($"Shard DB Counts - Biotas: {DatabaseManager.Shard.BaseDatabase.GetBiotaCount():N0}{'\n'}"); if (DatabaseManager.Shard.BaseDatabase is ShardDatabaseWithCaching shardDatabaseWithCaching) { var biotaIds = shardDatabaseWithCaching.GetBiotaCacheKeys(); var playerBiotaIds = biotaIds.Count(id => ObjectGuid.IsPlayer(id)); var nonPlayerBiotaIds = biotaIds.Count - playerBiotaIds; sb.Append($"Shard DB Cache Counts - Player Biotas: {playerBiotaIds} ~ {shardDatabaseWithCaching.PlayerBiotaRetentionTime.TotalMinutes:N0} m, Non Players {nonPlayerBiotaIds} ~ {shardDatabaseWithCaching.NonPlayerBiotaRetentionTime.TotalMinutes:N0} m{'\n'}"); } sb.Append(GuidManager.GetDynamicGuidDebugInfo() + '\n'); sb.Append($"Portal.dat has {DatManager.PortalDat.FileCache.Count:N0} files cached of {DatManager.PortalDat.AllFiles.Count:N0} total{'\n'}"); sb.Append($"Cell.dat has {DatManager.CellDat.FileCache.Count:N0} files cached of {DatManager.CellDat.AllFiles.Count:N0} total{'\n'}"); CommandHandlerHelper.WriteOutputInfo(session, $"{sb}"); }
public override bool RemoveBiota(Biota biota, ReaderWriterLockSlim rwLock) { if (BiotaContexts.TryGetValue(biota, out var cachedContext)) { BiotaContexts.Remove(biota); rwLock.EnterReadLock(); try { cachedContext.Biota.Remove(biota); Exception firstException = null; retry: try { cachedContext.SaveChanges(); if (firstException != null) { log.Debug($"[DATABASE] RemoveBiota 0x{biota.Id:X8}:{biota.GetProperty(PropertyString.Name)} retry succeeded after initial exception of: {firstException.GetFullMessage()}"); } return(true); } catch (Exception ex) { if (firstException == null) { firstException = ex; goto retry; } // Character name might be in use or some other fault log.Error($"[DATABASE] RemoveBiota 0x{biota.Id:X8}:{biota.GetProperty(PropertyString.Name)} failed first attempt with exception: {firstException}"); log.Error($"[DATABASE] RemoveBiota 0x{biota.Id:X8}:{biota.GetProperty(PropertyString.Name)} failed second attempt with exception: {ex}"); return(false); } } finally { rwLock.ExitReadLock(); cachedContext.Dispose(); } } if (!ObjectGuid.IsPlayer(biota.Id)) { using (var context = new ShardDbContext()) { var existingBiota = context.Biota .AsNoTracking() .FirstOrDefault(r => r.Id == biota.Id); if (existingBiota == null) { return(true); } rwLock.EnterWriteLock(); try { context.Biota.Remove(biota); Exception firstException = null; retry: try { context.SaveChanges(); if (firstException != null) { log.Debug($"[DATABASE] RemoveBiota 0x{biota.Id:X8}:{biota.GetProperty(PropertyString.Name)} retry succeeded after initial exception of: {firstException.GetFullMessage()}"); } return(true); } catch (Exception ex) { if (firstException == null) { firstException = ex; goto retry; } // Character name might be in use or some other fault log.Error($"[DATABASE] RemoveBiota 0x{biota.Id:X8}:{biota.GetProperty(PropertyString.Name)} failed first attempt with exception: {firstException}"); log.Error($"[DATABASE] RemoveBiota 0x{biota.Id:X8}:{biota.GetProperty(PropertyString.Name)} failed second attempt with exception: {ex}"); return(false); } } finally { rwLock.ExitWriteLock(); } } } // If we got here, the biota didn't come from the database through this class. // Most likely, it doesn't exist in the database, so, no need to remove. return(true); }
public override bool SaveBiota(Biota biota, ReaderWriterLockSlim rwLock) { if (BiotaContexts.TryGetValue(biota, out var cachedContext)) { rwLock.EnterReadLock(); try { SetBiotaPopulatedCollections(biota); Exception firstException = null; retry: try { cachedContext.SaveChanges(); if (firstException != null) { log.Debug($"[DATABASE] SaveBiota 0x{biota.Id:X8}:{biota.GetProperty(PropertyString.Name)} retry succeeded after initial exception of: {firstException.GetFullMessage()}"); } return(true); } catch (Exception ex) { if (firstException == null) { firstException = ex; goto retry; } // Character name might be in use or some other fault log.Error($"[DATABASE] SaveBiota 0x{biota.Id:X8}:{biota.GetProperty(PropertyString.Name)} failed first attempt with exception: {firstException}"); log.Error($"[DATABASE] SaveBiota 0x{biota.Id:X8}:{biota.GetProperty(PropertyString.Name)} failed second attempt with exception: {ex}"); return(false); } } finally { rwLock.ExitReadLock(); } } if (ObjectGuid.IsPlayer(biota.Id)) { var context = new ShardDbContext(); BiotaContexts.Add(biota, context); rwLock.EnterReadLock(); try { SetBiotaPopulatedCollections(biota); context.Biota.Add(biota); Exception firstException = null; retry: try { context.SaveChanges(); if (firstException != null) { log.Debug($"[DATABASE] SaveBiota 0x{biota.Id:X8}:{biota.GetProperty(PropertyString.Name)} retry succeeded after initial exception of: {firstException.GetFullMessage()}"); } return(true); } catch (Exception ex) { if (firstException == null) { firstException = ex; goto retry; } // Character name might be in use or some other fault log.Error($"[DATABASE] SaveBiota 0x{biota.Id:X8}:{biota.GetProperty(PropertyString.Name)} failed first attempt with exception: {firstException}"); log.Error($"[DATABASE] SaveBiota 0x{biota.Id:X8}:{biota.GetProperty(PropertyString.Name)} failed second attempt with exception: {ex}"); return(false); } } finally { rwLock.ExitReadLock(); } } using (var context = new ShardDbContext()) { var existingBiota = GetBiota(context, biota.Id); rwLock.EnterReadLock(); try { SetBiotaPopulatedCollections(biota); if (existingBiota == null) { context.Biota.Add(biota); } else { UpdateBiota(context, existingBiota, biota); } Exception firstException = null; retry: try { context.SaveChanges(); if (firstException != null) { log.Debug($"[DATABASE] SaveBiota 0x{biota.Id:X8}:{biota.GetProperty(PropertyString.Name)} retry succeeded after initial exception of: {firstException.GetFullMessage()}"); } return(true); } catch (Exception ex) { if (firstException == null) { firstException = ex; goto retry; } // Character name might be in use or some other fault log.Error($"[DATABASE] SaveBiota 0x{biota.Id:X8}:{biota.GetProperty(PropertyString.Name)} failed first attempt with exception: {firstException}"); log.Error($"[DATABASE] SaveBiota 0x{biota.Id:X8}:{biota.GetProperty(PropertyString.Name)} failed second attempt with exception: {ex}"); return(false); } } finally { rwLock.ExitReadLock(); } } }