diff --git a/pkg/demoinfocs/common/player_test.go b/pkg/demoinfocs/common/player_test.go index 75412177..0db2f1e9 100644 --- a/pkg/demoinfocs/common/player_test.go +++ b/pkg/demoinfocs/common/player_test.go @@ -409,7 +409,8 @@ func TestPlayer_PositionEyes(t *testing.T) { } func TestPlayer_PositionEyes_EntityNil(t *testing.T) { - pl := new(Player) + pl := &Player{} + pl.demoInfoProvider = s1DemoInfoProvider assert.Empty(t, pl.PositionEyes()) } diff --git a/pkg/demoinfocs/datatables.go b/pkg/demoinfocs/datatables.go index ae5e3b94..82cff6fa 100644 --- a/pkg/demoinfocs/datatables.go +++ b/pkg/demoinfocs/datatables.go @@ -2,6 +2,7 @@ package demoinfocs import ( "fmt" + "math" "strings" "github.com/golang/geo/r3" @@ -122,6 +123,8 @@ func (p *parser) bindBomb() { site = events.BombsiteA case 2: site = events.BombsiteB + case 0: + site = p.getClosestBombsiteFromPosition(planter.Position()) } if !p.disableMimicSource1GameEvents { @@ -305,18 +308,36 @@ func (p *parser) bindBombSites() { playerResource.BindProperty("m_bombsiteCenterB", &p.bombsiteB.center, st.ValTypeVector) }) - p.stParser.ServerClasses().FindByName("CBaseTrigger").OnEntityCreated(func(baseTrigger st.Entity) { + onBombTargetEntityCreated := func(target st.Entity) { t := new(boundingBoxInformation) - p.triggers[baseTrigger.ID()] = t + p.triggers[target.ID()] = t + var ( + minPropName string + maxPropName string + ) if p.isSource2() { - baseTrigger.BindProperty("m_vecMins", &t.min, st.ValTypeVector) - baseTrigger.BindProperty("m_vecMaxs", &t.max, st.ValTypeVector) + minPropName = "m_vecMins" + maxPropName = "m_vecMaxs" } else { - baseTrigger.BindProperty("m_Collision.m_vecMins", &t.min, st.ValTypeVector) - baseTrigger.BindProperty("m_Collision.m_vecMaxs", &t.max, st.ValTypeVector) + minPropName = "m_Collision.m_vecMins" + maxPropName = "m_Collision.m_vecMaxs" } - }) + + target.BindProperty(minPropName, &t.min, st.ValTypeVector) + target.BindProperty(maxPropName, &t.max, st.ValTypeVector) + } + + if p.isSource2() { + // CBombTarget is not available with CS2 demos created in the early days of the limited test. + bombTargetClass := p.stParser.ServerClasses().FindByName("CBombTarget") + if bombTargetClass != nil { + bombTargetClass.OnEntityCreated(onBombTargetEntityCreated) + return + } + } + + p.stParser.ServerClasses().FindByName("CBaseTrigger").OnEntityCreated(onBombTargetEntityCreated) } func (p *parser) bindPlayers() { @@ -899,10 +920,10 @@ func (p *parser) bindWeaponS2(entity st.Entity) { // - The player is inside the buy zone // - The player's money has increased AND the weapon entity is destroyed at the same tick (unfortunately the money is updated first) var ( - owner *common.Player - oldOwnerMoney int + owner *common.Player + oldOwnerMoney int lastMoneyUpdateTick int - lastMoneyIncreased bool + lastMoneyIncreased bool ) entity.Property("m_hOwnerEntity").OnUpdate(func(val st.PropertyValue) { @@ -1300,3 +1321,18 @@ func (p *parser) bindHostages() { }) }) } + +func getDistanceBetweenVectors(vectorA r3.Vector, vectorB r3.Vector) float64 { + return math.Sqrt(math.Pow(vectorA.X-vectorB.X, 2) + math.Pow(vectorA.Y-vectorB.Y, 2) + math.Pow(vectorA.Z-vectorB.Z, 2)) +} + +func (p *parser) getClosestBombsiteFromPosition(position r3.Vector) events.Bombsite { + distanceFromBombsiteA := getDistanceBetweenVectors(position, p.bombsiteA.center) + distanceFromBombsiteB := getDistanceBetweenVectors(position, p.bombsiteB.center) + + if distanceFromBombsiteA < distanceFromBombsiteB { + return events.BombsiteA + } + + return events.BombsiteB +} diff --git a/pkg/demoinfocs/datatables_test.go b/pkg/demoinfocs/datatables_test.go index 0f1cbea7..bb025535 100644 --- a/pkg/demoinfocs/datatables_test.go +++ b/pkg/demoinfocs/datatables_test.go @@ -3,6 +3,7 @@ package demoinfocs import ( "testing" + "github.com/golang/geo/r3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -130,6 +131,24 @@ func fakePlayerEntity(id int) *stfake.Entity { return entity } +func TestParser_GetClosestBombsiteFromPosition(t *testing.T) { + p := newParser() + p.bombsiteA = bombsite{ + center: r3.Vector{X: 2, Y: 3, Z: 1}, + } + p.bombsiteB = bombsite{ + center: r3.Vector{X: 4, Y: 5, Z: 7}, + } + + site := p.getClosestBombsiteFromPosition(r3.Vector{X: -2, Y: 2, Z: 2}) + + assert.Equal(t, events.BombsiteA, site) + + site = p.getClosestBombsiteFromPosition(r3.Vector{X: 3, Y: 6, Z: 5}) + + assert.Equal(t, events.BombsiteB, site) +} + func configurePlayerEntityMock(id int, entity *stfake.Entity) { entity.On("ID").Return(id) diff --git a/pkg/demoinfocs/events/events.go b/pkg/demoinfocs/events/events.go index a2be3382..bca46458 100644 --- a/pkg/demoinfocs/events/events.go +++ b/pkg/demoinfocs/events/events.go @@ -289,20 +289,20 @@ type BombEventIf interface { implementsBombEventIf() } -type bombsite rune +type Bombsite rune // Bombsite identifiers const ( - BomsiteUnknown bombsite = 0 - BombsiteA bombsite = 'A' - BombsiteB bombsite = 'B' + BomsiteUnknown Bombsite = 0 + BombsiteA Bombsite = 'A' + BombsiteB Bombsite = 'B' ) // BombEvent contains the common attributes of bomb events. Dont register // handlers on this tho, you want BombEventIf for that. type BombEvent struct { Player *common.Player - Site bombsite + Site Bombsite } // Make BombEvent implement BombEventIf