From 4ec067865c03912939de7f445e8b98beb1781051 Mon Sep 17 00:00:00 2001 From: doglightning Date: Fri, 24 Apr 2026 11:06:09 -0400 Subject: [PATCH] fix(physics2d): entity collision type to cardinal id --- .../physics2d/component/active_contacts.go | 12 +++++---- .../physics2d/internal/contact_flush.go | 4 +-- pkg/plugin/physics2d/internal/runtime.go | 27 +++++-------------- 3 files changed, 15 insertions(+), 28 deletions(-) diff --git a/pkg/plugin/physics2d/component/active_contacts.go b/pkg/plugin/physics2d/component/active_contacts.go index d854103a4..f7f3e03ea 100644 --- a/pkg/plugin/physics2d/component/active_contacts.go +++ b/pkg/plugin/physics2d/component/active_contacts.go @@ -1,5 +1,7 @@ package component +import "github.com/argus-labs/world-engine/pkg/cardinal" + // PhysicsSingletonTag marks the single entity that holds physics plugin state (ActiveContacts). type PhysicsSingletonTag struct{} @@ -8,11 +10,11 @@ func (PhysicsSingletonTag) Name() string { return "physics_singleton_tag" } // ContactPairEntry is one active contact pair tracked by the physics engine. Entries are // normalized: EntityA < EntityB (or if equal, ShapeIndexA <= ShapeIndexB). type ContactPairEntry struct { - EntityA uint64 `json:"a"` - ShapeIndexA int `json:"sa"` - EntityB uint64 `json:"b"` - ShapeIndexB int `json:"sb"` - IsSensor bool `json:"sensor"` + EntityA cardinal.EntityID `json:"a"` + ShapeIndexA int `json:"sa"` + EntityB cardinal.EntityID `json:"b"` + ShapeIndexB int `json:"sb"` + IsSensor bool `json:"sensor"` // Fixture filters for normalized EntityA/B (recovery End / trigger vs contact routing). // Omitempty keeps older snapshots valid. FilterACategoryBits uint64 `json:"fa_cat,omitempty"` diff --git a/pkg/plugin/physics2d/internal/contact_flush.go b/pkg/plugin/physics2d/internal/contact_flush.go index 59e7a1bfa..d76163f20 100644 --- a/pkg/plugin/physics2d/internal/contact_flush.go +++ b/pkg/plugin/physics2d/internal/contact_flush.go @@ -258,8 +258,8 @@ func lessBufferedContactEvent(a, b BufferedContactEvent) bool { return a.Kind < b.Kind } return lessContactPairByEndpoints( - uint64(a.EntityA), a.ShapeIndexA, uint64(a.EntityB), a.ShapeIndexB, - uint64(b.EntityA), b.ShapeIndexA, uint64(b.EntityB), b.ShapeIndexB, + a.EntityA, a.ShapeIndexA, a.EntityB, a.ShapeIndexB, + b.EntityA, b.ShapeIndexA, b.EntityB, b.ShapeIndexB, ) } diff --git a/pkg/plugin/physics2d/internal/runtime.go b/pkg/plugin/physics2d/internal/runtime.go index 7ba19fc45..c1b252f0e 100644 --- a/pkg/plugin/physics2d/internal/runtime.go +++ b/pkg/plugin/physics2d/internal/runtime.go @@ -1,7 +1,6 @@ package internal import ( - "math" "sort" "github.com/argus-labs/world-engine/pkg/cardinal" @@ -125,15 +124,10 @@ func (rt *PhysicsRuntime) PruneActiveContactsInvolvingEntity(entityID cardinal.E func (rt *PhysicsRuntime) LoadActiveContactsFromComponent(ac component.ActiveContacts) { rt.ActiveContacts = make(map[ContactPairKey]ContactPairInfo, len(ac.Pairs)) for _, p := range ac.Pairs { - entityA, okA := entityIDFromUint64(p.EntityA) - entityB, okB := entityIDFromUint64(p.EntityB) - if !okA || !okB { - continue - } key := ContactPairKey{ - EntityA: entityA, + EntityA: p.EntityA, ShapeIndexA: p.ShapeIndexA, - EntityB: entityB, + EntityB: p.EntityB, ShapeIndexB: p.ShapeIndexB, } rt.ActiveContacts[key] = ContactPairInfo{ @@ -153,15 +147,6 @@ func (rt *PhysicsRuntime) LoadActiveContactsFromComponent(ac component.ActiveCon rt.ActiveContactsDirty = false } -// entityIDFromUint64 maps persisted wire format (uint64) to cardinal.EntityID (uint32). -// Oversized values are rejected so corrupt snapshots cannot truncate silently. -func entityIDFromUint64(u uint64) (cardinal.EntityID, bool) { - if u > math.MaxUint32 { - return 0, false - } - return cardinal.EntityID(uint32(u)), true -} - // ActiveContactsToComponent converts the working map to the ECS component format (sorted // slice for deterministic snapshots). func (rt *PhysicsRuntime) ActiveContactsToComponent() component.ActiveContacts { @@ -171,9 +156,9 @@ func (rt *PhysicsRuntime) ActiveContactsToComponent() component.ActiveContacts { pairs := make([]component.ContactPairEntry, 0, len(rt.ActiveContacts)) for key, info := range rt.ActiveContacts { pairs = append(pairs, component.ContactPairEntry{ - EntityA: uint64(key.EntityA), + EntityA: key.EntityA, ShapeIndexA: key.ShapeIndexA, - EntityB: uint64(key.EntityB), + EntityB: key.EntityB, ShapeIndexB: key.ShapeIndexB, IsSensor: info.IsSensor, FilterACategoryBits: info.FilterA.CategoryBits, @@ -208,8 +193,8 @@ func lessContactPairEntry(a, b component.ContactPairEntry) bool { // lessContactPairByEndpoints compares (entityA, shapeIndexA, entityB, shapeIndexB) lexicographically. func lessContactPairByEndpoints( - aEA uint64, aSA int, aEB uint64, aSB int, - bEA uint64, bSA int, bEB uint64, bSB int, + aEA cardinal.EntityID, aSA int, aEB cardinal.EntityID, aSB int, + bEA cardinal.EntityID, bSA int, bEB cardinal.EntityID, bSB int, ) bool { if aEA != bEA { return aEA < bEA