Skip to content

Commit c5bf753

Browse files
committed
fix(npc): address role review feedback
1 parent 0f74c8d commit c5bf753

5 files changed

Lines changed: 42 additions & 7 deletions

File tree

S1API.Tests/Entities/CustomNpcReadinessPolicyTests.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using S1API.Entities;
22
using S1API.Internal.Entities;
33
using S1API.Internal.Patches;
4+
using S1API.Internal.Utils;
45

56
namespace S1API.Tests.Entities;
67

@@ -14,6 +15,16 @@ public void ClientHydrationSignalsReadyOnlyAfterEveryCustomNpcTypeCompletes()
1415

1516
try
1617
{
18+
foreach (Type npcType in ReflectionUtils.GetDerivedClasses<NPC>())
19+
{
20+
if (npcType.Assembly != typeof(NPC).Assembly
21+
&& npcType != typeof(DealerNpc)
22+
&& npcType != typeof(CustomerNpc))
23+
{
24+
NPC.FinalizedCustomNpcTypes.Add(npcType);
25+
}
26+
}
27+
1728
var dealer = TestObjectFactory.CreateUninitialized<DealerNpc>();
1829
var customer = TestObjectFactory.CreateUninitialized<CustomerNpc>();
1930

S1API.Tests/Entities/NPCRoleDeclarationTests.cs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,8 @@ public void IsCustomerIsVirtualReadOnlyBooleanDefaultingToFalse()
1111
{
1212
PropertyInfo? property = typeof(NPC).GetProperty(nameof(NPC.IsCustomer));
1313
MethodInfo? getter = property?.GetMethod;
14-
Type npcType = typeof(CustomNpcReadinessPolicyTests).GetNestedType(
15-
"DealerNpc",
16-
BindingFlags.NonPublic)!;
1714
var npc = (NPC)System.Runtime.CompilerServices.RuntimeHelpers
18-
.GetUninitializedObject(npcType);
15+
.GetUninitializedObject(typeof(RoleTestNpc));
1916

2017
Assert.NotNull(property);
2118
Assert.Equal(typeof(bool), property!.PropertyType);
@@ -25,6 +22,25 @@ public void IsCustomerIsVirtualReadOnlyBooleanDefaultingToFalse()
2522
Assert.False(npc.IsCustomer);
2623
}
2724

25+
[Fact]
26+
public void DeclaredPropertiesRejectsNullType()
27+
{
28+
ArgumentNullException exception = Assert.Throws<ArgumentNullException>(
29+
() => NpcRoleDeclarationResolver.GetDeclaredProperties(null!));
30+
31+
Assert.Equal("npcType", exception.ParamName);
32+
}
33+
34+
[Fact]
35+
public void DeclaredPropertiesRejectsNonNpcType()
36+
{
37+
ArgumentException exception = Assert.Throws<ArgumentException>(
38+
() => NpcRoleDeclarationResolver.GetDeclaredProperties(typeof(string)));
39+
40+
Assert.Equal("npcType", exception.ParamName);
41+
Assert.Contains("does not derive from", exception.Message);
42+
}
43+
2844
[Theory]
2945
[InlineData(false, false, false, false)]
3046
[InlineData(false, true, false, false)]
@@ -132,4 +148,11 @@ public void LegacyEnsureMethodsRemainFluentNonErrorObsoleteShims(
132148
private static NPCPrefabBuilder CompileLegacyFluentCalls(NPCPrefabBuilder builder) =>
133149
builder.EnsureCustomer().EnsureDealer().EnsureSupplier();
134150
#pragma warning restore CS0618
151+
152+
private sealed class RoleTestNpc : NPC
153+
{
154+
internal override void CreateInternal()
155+
{
156+
}
157+
}
135158
}

S1API/Entities/Schedule/NPCScheduleBuilder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,8 @@ public LocationBasedActionSpecBuilder LocationBased(Vector3 destination, int sta
374374
/// <returns>This builder instance for method chaining.</returns>
375375
/// <remarks>
376376
/// As of v0.4.2f4, deal handling is now automatic through the DealerAttendDealBehaviour system.
377-
/// This method is kept for backwards compatibility but is a no-op. Dealer NPCs set up with
378-
/// Dealer NPCs automatically handle deals when contracts are assigned.
377+
/// This method is kept for backwards compatibility but is a no-op. Dealer NPCs
378+
/// automatically handle deals when contracts are assigned.
379379
/// </remarks>
380380
[System.Obsolete("HandleDeal is no longer needed as of game version 0.4.2f4. Deal handling is now automatic through DealerAttendDealBehaviour.")]
381381
public PrefabScheduleBuilder HandleDeal(int startTime, string? name = null)

skills/schedule-one-custom-npcs/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Follow this order:
2121

2222
Keep these responsibilities separate:
2323

24-
- `ConfigurePrefab(...)`: identity, icon, spawn position, relationship defaults, customer defaults, dealer defaults, inventory defaults, schedule, and required `Ensure*` components.
24+
- `ConfigurePrefab(...)`: identity, icon, spawn position, relationship defaults, customer defaults, dealer defaults, inventory defaults, schedule, and action-specific `Ensure*` calls such as `plan.EnsureDealSignal()`. Role infrastructure comes automatically from `IsCustomer`, `IsDealer`, and `IsSupplier`; do not add `EnsureCustomer()`, `EnsureDealer()`, or `EnsureSupplier()`.
2525
- `OnCreated()`: `base.OnCreated()`, `Appearance.Build()`, `Schedule.Enable()`, `Schedule.InitializeActions()` when needed, dialogue wiring, event subscriptions, text messages, and runtime state.
2626

2727
Do not move persistent customer, dealer, relationship, or schedule defaults into runtime code.

skills/schedule-one-custom-npcs/references/example-project-patterns.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Use when the NPC is visible in the world, directly interactable, and participate
1111
Recommended structure:
1212

1313
```csharp
14+
public override bool IsPhysical => true;
1415
public override bool IsCustomer => true;
1516

1617
builder.WithIdentity(...)

0 commit comments

Comments
 (0)