From de5b95d2d39ed3d47da4a212c870128b967f28ca Mon Sep 17 00:00:00 2001 From: Ty Conner Date: Sat, 17 Feb 2024 11:50:23 -0500 Subject: [PATCH 1/8] Adjust Encounter generation --- .../Command/Handlers/DeveloperCommands.cs | 8 +++ Source/ACE.Server/Entity/GeneratorProfile.cs | 33 +++++++++ Source/ACE.Server/Entity/Landblock.cs | 2 + .../WorldObjects/WorldObject_Generators.cs | 69 +++++++++++++++++-- 4 files changed, 108 insertions(+), 4 deletions(-) diff --git a/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs b/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs index cad9e528d1..349955a707 100644 --- a/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs +++ b/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs @@ -2741,6 +2741,7 @@ public static void HandleGeneratorDump(Session session, params string[] paramete msg += $"Generator WCID: {wo.WeenieClassId}\n"; msg += $"Generator WeenieClassName: {wo.WeenieClassName}\n"; msg += $"Generator WeenieType: {wo.WeenieType.ToString()}\n"; + msg += $"Generator IsEncounter: {wo.IsEncounter}\n"; msg += $"Generator Status: {(wo.GeneratorDisabled ? "Disabled" : "Enabled")}\n"; msg += $"GeneratorType: {wo.GeneratorType.ToString()}\n"; msg += $"GeneratorTimeType: {wo.GeneratorTimeType.ToString()}\n"; @@ -2782,6 +2783,13 @@ public static void HandleGeneratorDump(Session session, params string[] paramete msg += $"IsMaxed: {profile.IsMaxed}\n"; if (!profile.IsMaxed) msg += $"IsAvailable: {profile.IsAvailable}{(profile.IsAvailable ? "" : $", NextAvailable: {profile.NextAvailable.ToLocalTime()}")}\n"; + msg += $"AdjustedProbability: {wo.GetAdjustedProbability(activeProfile)} / {wo.GetTotalProbability()}\n"; + msg += $"MostRecentSpawnTime: {profile.MostRecentSpawnTime.ToLocalTime()}\n"; + if (wo.IsEncounter) + { + msg += $"Timeout: {profile.MostRecentSpawnTime.AddSeconds(profile.Delay * profile.MaxCreate).ToLocalTime()}\n"; + msg += $"HasAwakeCreatures: {profile.HasAwakeCreatures}\n"; + } msg += $"--====--\n"; if (profile.Spawned.Count > 0) { diff --git a/Source/ACE.Server/Entity/GeneratorProfile.cs b/Source/ACE.Server/Entity/GeneratorProfile.cs index fc859c02e9..4b934c7f46 100644 --- a/Source/ACE.Server/Entity/GeneratorProfile.cs +++ b/Source/ACE.Server/Entity/GeneratorProfile.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Numerics; using log4net; @@ -114,6 +115,11 @@ public float Delay } } + /// + /// DateTime for when the profile last spawned something + /// + public DateTime MostRecentSpawnTime { get; set; } = DateTime.MinValue; + /// /// DateTime for when the profile is available as a possible spawn choice /// @@ -129,6 +135,30 @@ public float Delay /// public bool IsMaxed => MaxCreate != -1 && CurrentCreate >= MaxCreate; + /// + /// Returns TRUE if this profile has any Creatures with IsAwake being true + /// + public bool HasAwakeCreatures + { + get + { + foreach (var spawn in Spawned.Values) + { + var wo = spawn.TryGetWorldObject(); + if (wo != null) + { + if (wo is Creature creature && creature.IsAwake) + return true; + + if (wo.IsGenerator && wo.GeneratorProfiles.Any(p => p.HasAwakeCreatures)) + return true; + } + } + + return false; + } + } + /// /// The generator world object for this profile /// @@ -214,6 +244,8 @@ public void ProcessQueue() Spawned.Add(obj.Guid.Full, woi); } + + MostRecentSpawnTime = DateTime.UtcNow; } } else @@ -618,6 +650,7 @@ private void CleanupProfile() Spawned.Clear(); SpawnQueue.Clear(); + MostRecentSpawnTime = DateTime.MinValue; NextAvailable = DateTime.UtcNow; GeneratedTreasureItem = false; diff --git a/Source/ACE.Server/Entity/Landblock.cs b/Source/ACE.Server/Entity/Landblock.cs index 23e911f913..35386cdd39 100644 --- a/Source/ACE.Server/Entity/Landblock.cs +++ b/Source/ACE.Server/Entity/Landblock.cs @@ -277,6 +277,8 @@ private void SpawnEncounters() if (wo == null) continue; + wo.IsEncounter = true; + actionQueue.EnqueueAction(new ActionEventDelegate(() => { var xPos = Math.Clamp(encounter.CellX * 24.0f, 0.5f, 191.5f); diff --git a/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs b/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs index 6915571303..ab4e064fc5 100644 --- a/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs +++ b/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs @@ -25,7 +25,12 @@ partial class WorldObject /// (spawns other world objects) /// public bool IsGenerator { get => GeneratorProfiles != null && GeneratorProfiles.Count > 0; } - + + /// + /// Is this WorldObject created from an Encounter, Set by Landblock + /// + public bool IsEncounter { get; set; } + //public List History = new List(); /// @@ -308,7 +313,7 @@ public int GetSpawnObjectsForProfile(GeneratorProfile profile) if (numObjects == 0 && initCreate == 0) log.Warn($"[GENERATOR] 0x{Guid}:{WeenieClassId} {Name}.GetSpawnObjectsForProfile(profile[{profile.LinkId}]): profile.InitCreate = {profile.InitCreate} | profile.MaxCreate = {profile.MaxCreate} | profile.WeenieClassId = {profile.WeenieClassId} | Profile Init invalid, cannot spawn."); else if (numObjects == 0) - log.Warn($"[GENERATOR] 0x{Guid}:{WeenieClassId} {Name}.GetSpawnObjectsForProfile(profile[{profile.LinkId}]): profile.InitCreate = {profile.InitCreate} | profile.MaxCreate = {profile.MaxCreate} | profile.WeenieClassId = {profile.WeenieClassId} | genSlotsAvailable = {genSlotsAvailable} | profileSlotsAvailable = {profileSlotsAvailable} | numObjects = {numObjects}, cannot spawn."); + log.Warn($"[GENERATOR] 0x{Guid}:{WeenieClassId} {Name}.GetSpawnObjectsForProfile(profile[{profile.LinkId}]): profile.InitCreate = {profile.InitCreate} | profile.MaxCreate = {profile.MaxCreate} | profile.WeenieClassId = {profile.WeenieClassId} | genSlotsAvailable = {genSlotsAvailable} | profileSlotsAvailable = {profileSlotsAvailable} | numObjects = {numObjects}, cannot spawn."); return numObjects; } @@ -355,7 +360,7 @@ public void CheckGeneratorStatus() case GeneratorTimeType.Day: CheckTimeOfDayStatus(); break; - } + } } /// @@ -364,7 +369,7 @@ public void CheckGeneratorStatus() public void CheckTimeOfDayStatus() { var prevDisabled = GeneratorDisabled; - + var isDay = Timers.CurrentInGameTime.IsDay; var isDayGenerator = GeneratorTimeType == GeneratorTimeType.Day; @@ -656,6 +661,8 @@ public void Generator_Generate() { //Console.WriteLine($"{Name}.Generator_Generate({RegenerationInterval})"); + CheckForStaleEncounters(); + if (!GeneratorDisabled) { if (CurrentlyPoweringUp) @@ -684,6 +691,8 @@ public void Generator_Generate() foreach (var profile in GeneratorProfiles) profile.Spawn_HeartBeat(); + + //CheckForStaleEncounters(); } public virtual void ResetGenerator() @@ -703,5 +712,57 @@ public virtual void ResetGenerator() } return null; } + + /// + /// If Generator has been marked an Encounter by Landblock, check for idle, stale profiles and reset them for long lived landblocks. + /// + public void CheckForStaleEncounters() + { + if (!IsEncounter) return; + + ////var orderedProfiles = GeneratorProfiles.Where(p => p.Spawned.Any()).OrderBy(p => p.MostRecentSpawnTime); + //var orderedProfiles = GeneratorProfiles.Where(p => p.IsMaxed).OrderBy(p => p.MostRecentSpawnTime); + + //var oldestProfile = orderedProfiles.FirstOrDefault(); + + //if (oldestProfile != null) + //{ + // var timeout = oldestProfile.MostRecentSpawnTime.AddMinutes(5); + // //var timeout = oldestProfile.MostRecentSpawnTime.AddSeconds(oldestProfile.Delay * oldestProfile.MaxCreate); + + // //if (DateTime.UtcNow > timeout) + // //{ + // // oldestProfile.DestroyAll(); + // //} + + // if (DateTime.UtcNow > timeout) + // { + // //var rng = ThreadSafeRandom.Next(0.0f, GetTotalProbability()); + // //var rng = ThreadSafeRandom.Next(0.0f, GetMaxProbability()); + // var rng = ThreadSafeRandom.Next(0.0f, 1.0f); + + // //var oldestProfileIdx = GeneratorProfiles.IndexOf(oldestProfile); + // //var probability = GetAdjustedProbability(oldestProfileIdx); + // var probability = 0.10f; + + // if (rng < probability) + // oldestProfile.Reset(); + // } + //} + + //var orderedIdleStaleProfiles = GeneratorProfiles.Where(p => p.IsMaxed && !p.HasAwakeCreatures && (DateTime.UtcNow > p.MostRecentSpawnTime.AddSeconds(p.Delay * p.MaxCreate))) + // .OrderBy(p => p.MostRecentSpawnTime); + + var idleStaleProfiles = GeneratorProfiles.Where(p => p.IsMaxed && !p.HasAwakeCreatures && (DateTime.UtcNow > p.MostRecentSpawnTime.AddSeconds(p.Delay * p.MaxCreate))); + + foreach (var profile in idleStaleProfiles) + { + var rng = ThreadSafeRandom.Next(0.0f, 1.0f); + var probability = 0.10f; + + if (rng < probability) + profile.Reset(); + } + } } } From e85a3e35f4bdbccfd00a77c42de1ab474deec1d0 Mon Sep 17 00:00:00 2001 From: Ty Conner Date: Sat, 17 Feb 2024 12:11:30 -0500 Subject: [PATCH 2/8] Add HasOpenContainers --- .../Command/Handlers/DeveloperCommands.cs | 2 +- Source/ACE.Server/Entity/GeneratorProfile.cs | 24 +++++++++++++++++++ .../WorldObjects/WorldObject_Generators.cs | 2 +- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs b/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs index 349955a707..cfe6d294cc 100644 --- a/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs +++ b/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs @@ -2788,7 +2788,7 @@ public static void HandleGeneratorDump(Session session, params string[] paramete if (wo.IsEncounter) { msg += $"Timeout: {profile.MostRecentSpawnTime.AddSeconds(profile.Delay * profile.MaxCreate).ToLocalTime()}\n"; - msg += $"HasAwakeCreatures: {profile.HasAwakeCreatures}\n"; + msg += $"HasAwakeCreatures: {profile.HasAwakeCreatures} | HasOpenContainers: {profile.HasOpenContainers}\n"; } msg += $"--====--\n"; if (profile.Spawned.Count > 0) diff --git a/Source/ACE.Server/Entity/GeneratorProfile.cs b/Source/ACE.Server/Entity/GeneratorProfile.cs index 4b934c7f46..3ec1eda183 100644 --- a/Source/ACE.Server/Entity/GeneratorProfile.cs +++ b/Source/ACE.Server/Entity/GeneratorProfile.cs @@ -159,6 +159,30 @@ public bool HasAwakeCreatures } } + /// + /// Returns TRUE if this profile has any Containers with IsOpen being true + /// + public bool HasOpenContainers + { + get + { + foreach (var spawn in Spawned.Values) + { + var wo = spawn.TryGetWorldObject(); + if (wo != null) + { + if (wo is Container container && container.IsOpen) + return true; + + if (wo.IsGenerator && wo.GeneratorProfiles.Any(p => p.HasOpenContainers)) + return true; + } + } + + return false; + } + } + /// /// The generator world object for this profile /// diff --git a/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs b/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs index ab4e064fc5..8eaac2cb09 100644 --- a/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs +++ b/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs @@ -753,7 +753,7 @@ public void CheckForStaleEncounters() //var orderedIdleStaleProfiles = GeneratorProfiles.Where(p => p.IsMaxed && !p.HasAwakeCreatures && (DateTime.UtcNow > p.MostRecentSpawnTime.AddSeconds(p.Delay * p.MaxCreate))) // .OrderBy(p => p.MostRecentSpawnTime); - var idleStaleProfiles = GeneratorProfiles.Where(p => p.IsMaxed && !p.HasAwakeCreatures && (DateTime.UtcNow > p.MostRecentSpawnTime.AddSeconds(p.Delay * p.MaxCreate))); + var idleStaleProfiles = GeneratorProfiles.Where(p => p.IsMaxed && !p.HasAwakeCreatures && !p.HasOpenContainers && (DateTime.UtcNow > p.MostRecentSpawnTime.AddSeconds(p.Delay * p.MaxCreate))); foreach (var profile in idleStaleProfiles) { From d3c44718f4213cfeede0a05e43a213c334124370 Mon Sep 17 00:00:00 2001 From: Ty Conner Date: Sat, 17 Feb 2024 13:09:27 -0500 Subject: [PATCH 3/8] Adjust logic a bit --- .../Command/Handlers/DeveloperCommands.cs | 4 +- Source/ACE.Server/Entity/GeneratorProfile.cs | 37 ++++++---------- .../WorldObjects/WorldObject_Generators.cs | 43 +------------------ 3 files changed, 17 insertions(+), 67 deletions(-) diff --git a/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs b/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs index cfe6d294cc..acc2bfb20c 100644 --- a/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs +++ b/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs @@ -2787,8 +2787,8 @@ public static void HandleGeneratorDump(Session session, params string[] paramete msg += $"MostRecentSpawnTime: {profile.MostRecentSpawnTime.ToLocalTime()}\n"; if (wo.IsEncounter) { - msg += $"Timeout: {profile.MostRecentSpawnTime.AddSeconds(profile.Delay * profile.MaxCreate).ToLocalTime()}\n"; - msg += $"HasAwakeCreatures: {profile.HasAwakeCreatures} | HasOpenContainers: {profile.HasOpenContainers}\n"; + msg += $"StaleTime: {profile.StaleTime.ToLocalTime()}\n"; + msg += $"HasAwakeCreaturesOrOpenContainers: {profile.HasAwakeCreaturesOrOpenContainers}\n"; } msg += $"--====--\n"; if (profile.Spawned.Count > 0) diff --git a/Source/ACE.Server/Entity/GeneratorProfile.cs b/Source/ACE.Server/Entity/GeneratorProfile.cs index 3ec1eda183..3327251c12 100644 --- a/Source/ACE.Server/Entity/GeneratorProfile.cs +++ b/Source/ACE.Server/Entity/GeneratorProfile.cs @@ -5,6 +5,7 @@ using log4net; +using ACE.Common; using ACE.Database; using ACE.Entity; using ACE.Entity.Enum; @@ -120,6 +121,11 @@ public float Delay /// public DateTime MostRecentSpawnTime { get; set; } = DateTime.MinValue; + /// + /// DateTime for when the profile is considered stale + /// + public DateTime StaleTime { get; set; } = DateTime.MinValue; + /// /// DateTime for when the profile is available as a possible spawn choice /// @@ -136,9 +142,9 @@ public float Delay public bool IsMaxed => MaxCreate != -1 && CurrentCreate >= MaxCreate; /// - /// Returns TRUE if this profile has any Creatures with IsAwake being true + /// Returns TRUE if this profile has any Creatures with IsAwake being true or any Containers with IsOpen being true /// - public bool HasAwakeCreatures + public bool HasAwakeCreaturesOrOpenContainers { get { @@ -150,31 +156,10 @@ public bool HasAwakeCreatures if (wo is Creature creature && creature.IsAwake) return true; - if (wo.IsGenerator && wo.GeneratorProfiles.Any(p => p.HasAwakeCreatures)) - return true; - } - } - - return false; - } - } - - /// - /// Returns TRUE if this profile has any Containers with IsOpen being true - /// - public bool HasOpenContainers - { - get - { - foreach (var spawn in Spawned.Values) - { - var wo = spawn.TryGetWorldObject(); - if (wo != null) - { if (wo is Container container && container.IsOpen) return true; - if (wo.IsGenerator && wo.GeneratorProfiles.Any(p => p.HasOpenContainers)) + if (wo.IsGenerator && wo.GeneratorProfiles.Any(p => p.HasAwakeCreaturesOrOpenContainers)) return true; } } @@ -270,6 +255,9 @@ public void ProcessQueue() } MostRecentSpawnTime = DateTime.UtcNow; + + var variance = ThreadSafeRandom.Next(0, Delay); + StaleTime = DateTime.UtcNow.AddSeconds(Delay * MaxCreate + variance); } } else @@ -675,6 +663,7 @@ private void CleanupProfile() SpawnQueue.Clear(); MostRecentSpawnTime = DateTime.MinValue; + StaleTime = DateTime.MinValue; NextAvailable = DateTime.UtcNow; GeneratedTreasureItem = false; diff --git a/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs b/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs index 8eaac2cb09..94673c0eec 100644 --- a/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs +++ b/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs @@ -720,49 +720,10 @@ public void CheckForStaleEncounters() { if (!IsEncounter) return; - ////var orderedProfiles = GeneratorProfiles.Where(p => p.Spawned.Any()).OrderBy(p => p.MostRecentSpawnTime); - //var orderedProfiles = GeneratorProfiles.Where(p => p.IsMaxed).OrderBy(p => p.MostRecentSpawnTime); - - //var oldestProfile = orderedProfiles.FirstOrDefault(); - - //if (oldestProfile != null) - //{ - // var timeout = oldestProfile.MostRecentSpawnTime.AddMinutes(5); - // //var timeout = oldestProfile.MostRecentSpawnTime.AddSeconds(oldestProfile.Delay * oldestProfile.MaxCreate); - - // //if (DateTime.UtcNow > timeout) - // //{ - // // oldestProfile.DestroyAll(); - // //} - - // if (DateTime.UtcNow > timeout) - // { - // //var rng = ThreadSafeRandom.Next(0.0f, GetTotalProbability()); - // //var rng = ThreadSafeRandom.Next(0.0f, GetMaxProbability()); - // var rng = ThreadSafeRandom.Next(0.0f, 1.0f); - - // //var oldestProfileIdx = GeneratorProfiles.IndexOf(oldestProfile); - // //var probability = GetAdjustedProbability(oldestProfileIdx); - // var probability = 0.10f; - - // if (rng < probability) - // oldestProfile.Reset(); - // } - //} - - //var orderedIdleStaleProfiles = GeneratorProfiles.Where(p => p.IsMaxed && !p.HasAwakeCreatures && (DateTime.UtcNow > p.MostRecentSpawnTime.AddSeconds(p.Delay * p.MaxCreate))) - // .OrderBy(p => p.MostRecentSpawnTime); - - var idleStaleProfiles = GeneratorProfiles.Where(p => p.IsMaxed && !p.HasAwakeCreatures && !p.HasOpenContainers && (DateTime.UtcNow > p.MostRecentSpawnTime.AddSeconds(p.Delay * p.MaxCreate))); + var idleStaleProfiles = GeneratorProfiles.Where(p => p.IsMaxed && (DateTime.UtcNow > p.StaleTime) && !p.HasAwakeCreaturesOrOpenContainers); foreach (var profile in idleStaleProfiles) - { - var rng = ThreadSafeRandom.Next(0.0f, 1.0f); - var probability = 0.10f; - - if (rng < probability) - profile.Reset(); - } + profile.Reset(); } } } From 556da0c489f4ea634fb039a977dc3522be8c3861 Mon Sep 17 00:00:00 2001 From: Ty Conner Date: Sun, 18 Feb 2024 13:40:12 -0500 Subject: [PATCH 4/8] IsAbleToBeMarkedStale --- .../Command/Handlers/DeveloperCommands.cs | 12 +++- Source/ACE.Server/Entity/GeneratorProfile.cs | 59 ++++++++++++++----- .../WorldObjects/WorldObject_Generators.cs | 7 ++- 3 files changed, 58 insertions(+), 20 deletions(-) diff --git a/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs b/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs index acc2bfb20c..c78f1b9e47 100644 --- a/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs +++ b/Source/ACE.Server/Command/Handlers/DeveloperCommands.cs @@ -2786,9 +2786,15 @@ public static void HandleGeneratorDump(Session session, params string[] paramete msg += $"AdjustedProbability: {wo.GetAdjustedProbability(activeProfile)} / {wo.GetTotalProbability()}\n"; msg += $"MostRecentSpawnTime: {profile.MostRecentSpawnTime.ToLocalTime()}\n"; if (wo.IsEncounter) - { - msg += $"StaleTime: {profile.StaleTime.ToLocalTime()}\n"; - msg += $"HasAwakeCreaturesOrOpenContainers: {profile.HasAwakeCreaturesOrOpenContainers}\n"; + { + var hasNonWorldObjects = 0; + var hasAwakeCreatures = 0; + var hasOpenContainers = 0; + var hasUnlockedChests = 0; + var isAbleToBeMarkedStale = profile.IsAbleToBeMarkedStale(ref hasNonWorldObjects, ref hasAwakeCreatures, ref hasOpenContainers, ref hasUnlockedChests); + msg += $"IsAbleToBeMarkedStale: {isAbleToBeMarkedStale}\n"; + if (isAbleToBeMarkedStale) + msg += $"StaleTime: {profile.StaleTime.ToLocalTime()}\n"; } msg += $"--====--\n"; if (profile.Spawned.Count > 0) diff --git a/Source/ACE.Server/Entity/GeneratorProfile.cs b/Source/ACE.Server/Entity/GeneratorProfile.cs index 3327251c12..22d61c548e 100644 --- a/Source/ACE.Server/Entity/GeneratorProfile.cs +++ b/Source/ACE.Server/Entity/GeneratorProfile.cs @@ -141,31 +141,58 @@ public float Delay /// public bool IsMaxed => MaxCreate != -1 && CurrentCreate >= MaxCreate; - /// - /// Returns TRUE if this profile has any Creatures with IsAwake being true or any Containers with IsOpen being true - /// - public bool HasAwakeCreaturesOrOpenContainers + ///// + ///// Returns TRUE if this profile has any non-Creature WorldObjects, Creatures with IsAwake being false, any Containers with IsOpen being false, + ///// any Chests with DefaultLocked true and IsLocked being true + ///// + public bool IsAbleToBeMarkedStale(ref int hasNonWorldObjects, ref int hasAwakeCreatures, ref int hasOpenContainers, ref int hasUnlockedChests) { - get + //var hasNonWorldObjects = 0; + //var hasAwakeCreatures = 0; + //var hasOpenContainers = 0; + //var hasUnlockedChests = 0; + + if (Spawned.Count == 0) + return false; + + foreach (var spawn in Spawned.Values) { - foreach (var spawn in Spawned.Values) + var wo = spawn.TryGetWorldObject(); + if (wo != null) { - var wo = spawn.TryGetWorldObject(); - if (wo != null) + if (wo is not Creature && !wo.IsGenerator) + hasNonWorldObjects++; + + if (wo.IsGenerator) { - if (wo is Creature creature && creature.IsAwake) - return true; + //if (wo is not Creature) + // hasNonWorldObjects++; - if (wo is Container container && container.IsOpen) - return true; + //if (wo is not Creature && wo is not GenericObject) + // hasNonWorldObjects++; - if (wo.IsGenerator && wo.GeneratorProfiles.Any(p => p.HasAwakeCreaturesOrOpenContainers)) - return true; + //if (wo is Switch) + // hasNonWorldObjects++; + + foreach (var profile in wo.GeneratorProfiles) + { + if (profile.IsAbleToBeMarkedStale(ref hasNonWorldObjects, ref hasAwakeCreatures, ref hasOpenContainers, ref hasUnlockedChests)) + hasNonWorldObjects++; + } } - } - return false; + if (wo is Creature creature && creature.IsAwake) + hasAwakeCreatures++; + + if (wo is Container container && container.IsOpen) + hasOpenContainers++; + + if (wo is Chest chest && (chest.GetProperty(PropertyBool.DefaultLocked) ?? false) && !chest.IsLocked) + hasUnlockedChests++; + } } + + return hasNonWorldObjects > 0 && hasAwakeCreatures == 0 && hasOpenContainers == 0 && hasUnlockedChests == 0; } /// diff --git a/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs b/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs index 94673c0eec..452ac6f2b9 100644 --- a/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs +++ b/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs @@ -720,7 +720,12 @@ public void CheckForStaleEncounters() { if (!IsEncounter) return; - var idleStaleProfiles = GeneratorProfiles.Where(p => p.IsMaxed && (DateTime.UtcNow > p.StaleTime) && !p.HasAwakeCreaturesOrOpenContainers); + var hasNonWorldObjects = 0; + var hasAwakeCreatures = 0; + var hasOpenContainers = 0; + var hasUnlockedChests = 0; + + var idleStaleProfiles = GeneratorProfiles.Where(p => p.IsMaxed && (DateTime.UtcNow > p.StaleTime) && p.IsAbleToBeMarkedStale(ref hasNonWorldObjects, ref hasAwakeCreatures, ref hasOpenContainers, ref hasUnlockedChests)); foreach (var profile in idleStaleProfiles) profile.Reset(); From 208a4029b054347fabf7a1288caade3bf89902bb Mon Sep 17 00:00:00 2001 From: Ty Conner Date: Fri, 23 Feb 2024 21:16:05 -0500 Subject: [PATCH 5/8] Update WorldObject_Generators.cs --- Source/ACE.Server/WorldObjects/WorldObject_Generators.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs b/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs index 452ac6f2b9..9ba531b559 100644 --- a/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs +++ b/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs @@ -728,7 +728,10 @@ public void CheckForStaleEncounters() var idleStaleProfiles = GeneratorProfiles.Where(p => p.IsMaxed && (DateTime.UtcNow > p.StaleTime) && p.IsAbleToBeMarkedStale(ref hasNonWorldObjects, ref hasAwakeCreatures, ref hasOpenContainers, ref hasUnlockedChests)); foreach (var profile in idleStaleProfiles) + { profile.Reset(); + profile.NextAvailable = DateTime.UtcNow.AddSeconds(profile.Delay); + } } } } From 6772c0c38321ebcc9bd706ab48a34ba2042d50f2 Mon Sep 17 00:00:00 2001 From: Ty Conner Date: Sun, 25 Feb 2024 14:07:35 -0500 Subject: [PATCH 6/8] Update GeneratorProfile.cs --- Source/ACE.Server/Entity/GeneratorProfile.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Source/ACE.Server/Entity/GeneratorProfile.cs b/Source/ACE.Server/Entity/GeneratorProfile.cs index 22d61c548e..07a3664d39 100644 --- a/Source/ACE.Server/Entity/GeneratorProfile.cs +++ b/Source/ACE.Server/Entity/GeneratorProfile.cs @@ -246,6 +246,16 @@ public void Enqueue(int numObjects = 1) break; }*/ SpawnQueue.Add(GetSpawnTime()); + + //if (Generator.IsEncounter) + //{ + // Generator.CurrentLandblock?.NotifyEncounterGenerators(Generator, (int)Id); + // foreach (var landblock in Generator.CurrentLandblock?.Adjacents) + // landblock.NotifyEncounterGenerators(Generator, (int)Id); + //} + + //if (Generator.IsEncounter) + // Generator.CurrentLandblock?.RegisterEncounterProfileUsed(Generator, Id, Delay); } } @@ -283,8 +293,13 @@ public void ProcessQueue() MostRecentSpawnTime = DateTime.UtcNow; - var variance = ThreadSafeRandom.Next(0, Delay); - StaleTime = DateTime.UtcNow.AddSeconds(Delay * MaxCreate + variance); + if (Generator.IsEncounter) + { + var variance = ThreadSafeRandom.Next(0, Delay); + StaleTime = DateTime.UtcNow.AddSeconds(Delay * MaxCreate + variance); + + //Generator.CurrentLandblock?.NotifyEncounterGenerators(Generator, (int)Id); + } } } else From 798b09757a536934c9e22d1ca696ee5d61ec71b9 Mon Sep 17 00:00:00 2001 From: Ty Conner Date: Sun, 25 Feb 2024 14:07:38 -0500 Subject: [PATCH 7/8] Update Landblock.cs --- Source/ACE.Server/Entity/Landblock.cs | 47 +++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/Source/ACE.Server/Entity/Landblock.cs b/Source/ACE.Server/Entity/Landblock.cs index 35386cdd39..ae8c365cbe 100644 --- a/Source/ACE.Server/Entity/Landblock.cs +++ b/Source/ACE.Server/Entity/Landblock.cs @@ -1351,5 +1351,52 @@ public void DoEnvironChange(EnvironChangeType environChangeType) else SendEnvironSound(environChangeType); } + + //public void NotifyEncounterGenerators(WorldObject generator, int profileId) + //{ + // //if (string.IsNullOrWhiteSpace(message)) return; + + // //foreach (var wo in worldObjects.Values.Where(w => w.HearLocalSignals).ToList()) + // //{ + // // if (emitter == wo) continue; + + // // if (emitter.IsWithinUseRadiusOf(wo, wo.HearLocalSignalsRadius)) + // // { + // // //Console.WriteLine($"{wo.Name}.EmoteManager.OnLocalSignal({emitter.Name}, {message})"); + // // wo.EmoteManager.OnLocalSignal(emitter, message); + // // } + // //} + + // var nextAvailable = DateTime.UtcNow.AddSeconds(generator.GeneratorProfiles[profileId].Delay); + + // var encounterGenerators = worldObjects.Values.Where(w => w.WeenieClassId == generator.WeenieClassId && w.Guid != generator.Guid).ToList(); + // foreach (var encounterGenerator in encounterGenerators) + // { + // encounterGenerator.GeneratorProfiles[profileId].NextAvailable = nextAvailable; + // } + //} + + //private readonly Dictionary> EncounterSomething = new(); + + //public void RegisterEncounterProfileUsed(WorldObject generator, uint profileId, float delay) + //{ + // EncounterSomething.TryAdd(generator.WeenieClassId, new()); + + // EncounterSomething[generator.WeenieClassId][(int)profileId] = DateTime.UtcNow.AddSeconds(delay); + //} + + //public bool CheckEncounterProfileIsAvailable(WorldObject generator, uint profileId) + //{ + // if (!EncounterSomething.TryGetValue(generator.WeenieClassId, out var encounter)) + // return true; + + // if (!encounter.TryGetValue((int)profileId, out var nextAvailable)) + // return true; + + // if (DateTime.UtcNow > nextAvailable) + // return true; + + // return false; + //} } } From b3daac3af3c1c21f9b596ae8e1f247a17a6ef329 Mon Sep 17 00:00:00 2001 From: Ty Conner Date: Sun, 25 Feb 2024 14:07:40 -0500 Subject: [PATCH 8/8] Update WorldObject_Generators.cs --- .../WorldObjects/WorldObject_Generators.cs | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs b/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs index 9ba531b559..747d83102b 100644 --- a/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs +++ b/Source/ACE.Server/WorldObjects/WorldObject_Generators.cs @@ -121,8 +121,9 @@ public void SelectAProfile() //var totalProbability = rng_selected ? GetTotalProbability() : 1.0f; //var rng = ThreadSafeRandom.Next(0.0f, totalProbability); - //var rng = ThreadSafeRandom.Next(0.0f, 1.0f); - var rng = ThreadSafeRandom.Next(0.0f, GetTotalProbability()); + var rng = ThreadSafeRandom.Next(0.0f, 1.0f); + //var rng = ThreadSafeRandom.Next(0.0f, GetTotalProbability()); + //var rng = ThreadSafeRandom.Next(0.0f, GetMaxProbability()); for (var i = 0; i < GeneratorProfiles.Count; i++) { @@ -140,6 +141,30 @@ public void SelectAProfile() if (!profile.IsAvailable) continue; + //if (IsEncounter && CurrentLandblock != null && !CurrentLandblock.CheckEncounterProfileIsAvailable(this, profile.Id)) + // continue; + //if (IsEncounter) + //{ + // if (CurrentLandblock != null) + // { + // if (!CurrentLandblock.CheckEncounterProfileIsAvailable(this, profile.Id)) + // continue; + + // //var adjacentIsAvailable = true; + // //foreach(var adjacent in CurrentLandblock.Adjacents) + // //{ + // // if (!adjacent.CheckEncounterProfileIsAvailable(this, profile.Id)) + // // { + // // adjacentIsAvailable = false; + // // break; + // // } + // //} + + // //if (!adjacentIsAvailable) + // // continue; + // } + //} + if (profile.RegenLocationType.HasFlag(RegenLocationType.Treasure)) { if (profile.Biota.InitCreate > 1) @@ -156,8 +181,8 @@ public void SelectAProfile() } //var probability = rng_selected ? GetAdjustedProbability(i) : profile.Biota.Probability; - //var probability = profile.Biota.Probability; - var probability = GetAdjustedProbability(i); + var probability = profile.Biota.Probability; + //var probability = GetAdjustedProbability(i); if (rng < probability || probability == -1) {