first commit

This commit is contained in:
2026-02-26 17:52:48 +09:00
commit dabf1f3ba9
49 changed files with 14883 additions and 0 deletions

150
internal/world/aoi_test.go Normal file
View File

@@ -0,0 +1,150 @@
package world
import (
"testing"
"a301_game_server/internal/entity"
"a301_game_server/pkg/mathutil"
pb "a301_game_server/proto/gen/pb"
)
// mockEntity is a minimal entity for testing.
type mockEntity struct {
id uint64
pos mathutil.Vec3
}
func (m *mockEntity) EntityID() uint64 { return m.id }
func (m *mockEntity) EntityType() entity.Type { return entity.TypePlayer }
func (m *mockEntity) Position() mathutil.Vec3 { return m.pos }
func (m *mockEntity) SetPosition(p mathutil.Vec3) { m.pos = p }
func (m *mockEntity) Rotation() float32 { return 0 }
func (m *mockEntity) SetRotation(float32) {}
func (m *mockEntity) ToProto() *pb.EntityState { return &pb.EntityState{EntityId: m.id} }
func TestBroadcastAllAOI_GetNearby(t *testing.T) {
aoi := NewBroadcastAllAOI()
e1 := &mockEntity{id: 1, pos: mathutil.NewVec3(0, 0, 0)}
e2 := &mockEntity{id: 2, pos: mathutil.NewVec3(100, 0, 100)}
e3 := &mockEntity{id: 3, pos: mathutil.NewVec3(999, 0, 999)}
aoi.Add(e1)
aoi.Add(e2)
aoi.Add(e3)
// With broadcast-all, everyone sees everyone.
nearby := aoi.GetNearby(e1)
if len(nearby) != 2 {
t.Errorf("expected 2 nearby, got %d", len(nearby))
}
}
func TestBroadcastAllAOI_Remove(t *testing.T) {
aoi := NewBroadcastAllAOI()
e1 := &mockEntity{id: 1}
e2 := &mockEntity{id: 2}
aoi.Add(e1)
aoi.Add(e2)
events := aoi.Remove(e1)
if len(events) != 1 {
t.Errorf("expected 1 leave event, got %d", len(events))
}
if events[0].Type != AOILeave {
t.Errorf("expected AOILeave event")
}
nearby := aoi.GetNearby(e2)
if len(nearby) != 0 {
t.Errorf("expected 0 nearby after removal, got %d", len(nearby))
}
}
func TestGridAOI_NearbyInSameCell(t *testing.T) {
aoi := NewGridAOI(50, 2)
e1 := &mockEntity{id: 1, pos: mathutil.NewVec3(10, 0, 10)}
e2 := &mockEntity{id: 2, pos: mathutil.NewVec3(20, 0, 20)}
aoi.Add(e1)
aoi.Add(e2)
nearby := aoi.GetNearby(e1)
if len(nearby) != 1 {
t.Errorf("expected 1 nearby, got %d", len(nearby))
}
if nearby[0].EntityID() != 2 {
t.Errorf("expected entity 2, got %d", nearby[0].EntityID())
}
}
func TestGridAOI_FarAwayNotVisible(t *testing.T) {
aoi := NewGridAOI(50, 1) // viewRange=1 means 3x3 grid = 150 units visibility
e1 := &mockEntity{id: 1, pos: mathutil.NewVec3(0, 0, 0)}
e2 := &mockEntity{id: 2, pos: mathutil.NewVec3(500, 0, 500)} // far away
aoi.Add(e1)
aoi.Add(e2)
nearby := aoi.GetNearby(e1)
if len(nearby) != 0 {
t.Errorf("expected 0 nearby for far entity, got %d", len(nearby))
}
}
func TestGridAOI_MoveGeneratesEvents(t *testing.T) {
aoi := NewGridAOI(50, 1)
e1 := &mockEntity{id: 1, pos: mathutil.NewVec3(0, 0, 0)}
e2 := &mockEntity{id: 2, pos: mathutil.NewVec3(200, 0, 200)}
aoi.Add(e1)
aoi.Add(e2)
// Initially not visible to each other.
nearby := aoi.GetNearby(e1)
if len(nearby) != 0 {
t.Fatalf("expected not visible initially, got %d", len(nearby))
}
// Move e2 close to e1.
oldPos := e2.pos
e2.pos = mathutil.NewVec3(10, 0, 10)
events := aoi.UpdatePosition(e2, oldPos, e2.pos)
// Should generate enter events (e1 sees e2, e2 sees e1).
enterCount := 0
for _, evt := range events {
if evt.Type == AOIEnter {
enterCount++
}
}
if enterCount != 2 {
t.Errorf("expected 2 enter events, got %d", enterCount)
}
}
func TestGridAOI_ToggleComparison(t *testing.T) {
// Demonstrates the difference between BroadcastAll and Grid AOI.
e1 := &mockEntity{id: 1, pos: mathutil.NewVec3(0, 0, 0)}
e2 := &mockEntity{id: 2, pos: mathutil.NewVec3(500, 0, 500)}
// BroadcastAll: both visible
broadcast := NewBroadcastAllAOI()
broadcast.Add(e1)
broadcast.Add(e2)
if len(broadcast.GetNearby(e1)) != 1 {
t.Error("broadcast-all should see all entities")
}
// Grid: e2 not visible from e1 (too far)
grid := NewGridAOI(50, 1)
grid.Add(e1)
grid.Add(e2)
if len(grid.GetNearby(e1)) != 0 {
t.Error("grid AOI should NOT see distant entities")
}
}