Skip to content

Commit 2f76be2

Browse files
committed
fix(api): avoid rebuilding dealer defaults during spawn
Cache built dealer defaults when they are registered and use that cached configuration when wiring recommendation hooks at runtime. This prevents unrelated dealer default callbacks from being re-executed for third-party NPCs during spawn, which was causing null reference failures on NPCs that did not actually use recommendation defaults.
1 parent 3f93c76 commit 2f76be2

1 file changed

Lines changed: 37 additions & 3 deletions

File tree

S1API/Entities/NPC.cs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ public abstract class NPC : Saveable, IEntity, IHealth
118118
internal static readonly System.Collections.Generic.Dictionary<System.Type, System.Action<NPCRelationshipDataBuilder>> TypeToRelationshipDefaults = new System.Collections.Generic.Dictionary<System.Type, System.Action<NPCRelationshipDataBuilder>>();
119119
private static readonly System.Collections.Generic.Dictionary<System.Type, System.Action<RandomInventoryItemsBuilder>> TypeToRandomInventoryDefaults = new System.Collections.Generic.Dictionary<System.Type, System.Action<RandomInventoryItemsBuilder>>();
120120
private static readonly System.Collections.Generic.Dictionary<System.Type, System.Action<DealerDataBuilder>> TypeToDealerDefaults = new System.Collections.Generic.Dictionary<System.Type, System.Action<DealerDataBuilder>>();
121+
private static readonly System.Collections.Generic.Dictionary<System.Type, DealerDataBuilder.DealerConfigData> TypeToBuiltDealerDefaults = new System.Collections.Generic.Dictionary<System.Type, DealerDataBuilder.DealerConfigData>();
121122
private static readonly System.Collections.Generic.Dictionary<System.Type, (Vector3 position, Quaternion rotation)> TypeToSpawnPosition = new System.Collections.Generic.Dictionary<System.Type, (Vector3, Quaternion)>();
122123
private static readonly System.Collections.Generic.HashSet<System.Type> CustomerTypes = new System.Collections.Generic.HashSet<System.Type>();
123124
private static readonly System.Collections.Generic.HashSet<System.Type> DealerTypes = new System.Collections.Generic.HashSet<System.Type>();
@@ -927,7 +928,20 @@ internal static void RegisterDealerDefaultsForType(System.Type npcType, System.A
927928
{
928929
if (npcType == null || configure == null)
929930
return;
931+
930932
TypeToDealerDefaults[npcType] = configure;
933+
934+
try
935+
{
936+
var builder = new DealerDataBuilder();
937+
configure(builder);
938+
TypeToBuiltDealerDefaults[npcType] = builder.BuildInternal();
939+
}
940+
catch (Exception ex)
941+
{
942+
TypeToBuiltDealerDefaults.Remove(npcType);
943+
Logger.Warning($"[S1API] Failed to cache dealer defaults for '{npcType.Name}': {ex.Message}");
944+
}
931945
}
932946

933947
internal static void RegisterDealerType(System.Type npcType)
@@ -959,14 +973,33 @@ internal static System.Action<DealerDataBuilder> GetDealerDefaultsForType(System
959973
return cfg;
960974
}
961975

976+
internal static DealerDataBuilder.DealerConfigData GetBuiltDealerDefaultsForType(System.Type npcType)
977+
{
978+
if (npcType == null)
979+
return null;
980+
981+
TypeToBuiltDealerDefaults.TryGetValue(npcType, out var cfg);
982+
return cfg;
983+
}
984+
962985
internal static DealerDataBuilder.DealerConfigData BuildDealerDefaultsForType(System.Type npcType)
963986
{
987+
var cached = GetBuiltDealerDefaultsForType(npcType);
988+
if (cached != null)
989+
return cached;
990+
964991
var cfg = GetDealerDefaultsForType(npcType);
965992
if (cfg == null)
966993
return null;
994+
967995
var builder = new DealerDataBuilder();
968996
cfg(builder);
969-
return builder.BuildInternal();
997+
var built = builder.BuildInternal();
998+
999+
if (npcType != null)
1000+
TypeToBuiltDealerDefaults[npcType] = built;
1001+
1002+
return built;
9701003
}
9711004

9721005
internal static void RegisterRandomInventoryDefaultsForType(System.Type npcType, System.Action<RandomInventoryItemsBuilder> configure)
@@ -3075,13 +3108,14 @@ private static void CheckAndSetCustomNpcsReady()
30753108

30763109
private void ApplyDealerRecommendationDefaults()
30773110
{
3078-
if (!IsDealerType(GetType()))
3111+
var npcType = GetType();
3112+
if (!IsDealerType(npcType))
30793113
{
30803114
ClearDealerRecommendationHooks();
30813115
return;
30823116
}
30833117

3084-
var defaults = BuildDealerDefaultsForType(GetType());
3118+
var defaults = GetBuiltDealerDefaultsForType(npcType);
30853119
if (defaults == null || defaults.Recommendations.Count == 0)
30863120
{
30873121
ClearDealerRecommendationHooks();

0 commit comments

Comments
 (0)