- edited description
[#bugs] The `AfterPlayerBodyChangeEvent` event handler for `IPlayerPart` appears not to ...
Marked for crossposting by: kernelmethod
Message (jump):
<kernelmethod> The
AfterPlayerBodyChangeEvent
event handler forIPlayerPart
appears not to work correctly; as far as I can tell the check for whether the new body already has the target part typically fails (I believe becauseIPlayerPart
and its ancestors are missing an appropriate override forEquals
), and so the part always gets added again.Proof-of-concept is below. To reproduce:
1. Dominate another creature
2. Clone yourself
3. Return to your original bodyProof-of-concept mod:
```csharp
using System;
using XRL;
using XRL.Core;
using XRL.World;
using XRL.World.Parts;namespace Kernelmethod.ExampleMod
{
[PlayerMutator]
public class MyPlayerMutator : IPlayerMutator
{
public void mutate(GameObject player)
{
player.AddPart<TestPart>();
}
}
- ``` [HasCallAfterGameLoadedAttribute]
public class AddPartsToPlayerHandler
{
[CallAfterGameLoadedAttribute]
public static void AddPartsCallback()
{
GameObject player = XRLCore.Core?.Game?.Player?.Body;if (player == null) return; player.RequirePart<TestPart>();
}
}[Serializable]
public class TestPart : IPlayerPart {
public override void Initialize() {
MetricsManager.LogInfo($"TestPart initialized on {ParentObject.DisplayName}");
}public override bool WantEvent(int ID, int cascade) { return base.WantEvent(ID, cascade) || ID == AfterPlayerBodyChangeEvent.ID; } public override bool HandleEvent(AfterPlayerBodyChangeEvent E) { if (E.NewBody != null) MetricsManager.LogInfo($"contains part: {E.NewBody.PartsList.Contains(this)}"); return base.HandleEvent(E); }
} ```
}
```
Comments (4)
-
-
using System; using XRL; using XRL.Core; using XRL.World; using XRL.World.Parts; namespace Kernelmethod.ExampleMod { [PlayerMutator] public class MyPlayerMutator : IPlayerMutator { public void mutate(GameObject player) { player.AddPart<TestPart>(); } } [HasCallAfterGameLoadedAttribute] public class AddPartsToPlayerHandler { [CallAfterGameLoadedAttribute] public static void AddPartsCallback() { GameObject player = XRLCore.Core?.Game?.Player?.Body; if (player == null) return; player.RequirePart<TestPart>(); } } [Serializable] public class TestPart : IPlayerPart { public override void Initialize() { MetricsManager.LogInfo($"TestPart initialized on {ParentObject.DisplayName}"); } public override bool WantEvent(int ID, int cascade) { return base.WantEvent(ID, cascade) || ID == AfterPlayerBodyChangeEvent.ID; } public override bool HandleEvent(AfterPlayerBodyChangeEvent E) { if (E.NewBody != null) MetricsManager.LogInfo($"contains part: {E.NewBody.PartsList.Contains(this)}"); return base.HandleEvent(E); } } }
Player.log should reveal that after the third step is completed, the part gets added twice to the original player:
@kernelmethod ➜ Parts git:(main) grep -E "TestPart" ~/.config/unity3d/Freehold\ Games/CavesOfQud/Player.log INFO - TestPart initialized on Emepichiji Ki INFO - TestPart initialized on watervine farmer INFO - TestPart initialized on Emepichiji Ki INFO - TestPart initialized on Emepichiji Ki
-
- changed version to 1.0
- changed milestone to moddability
-
assigned issue to
-
- changed status to resolved
Ah, it just shouldn’t be deep-copied in the first place (it's meant to be a singleton)
Fixed in 206.75public override IPart DeepCopy(GameObject Parent) => null;
in the inheriting part should fix it in the meantime
- Log in to comment