Skip to content

Commit eef000b

Browse files
committed
Add infernos to GameState + events
1 parent ddbc21e commit eef000b

File tree

6 files changed

+135
-52
lines changed

6 files changed

+135
-52
lines changed

common/structs.go

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"math/rand"
55

66
r3 "github.com/golang/geo/r3"
7+
s2 "github.com/golang/geo/s2"
78

89
st "github.com/markus-wa/demoinfocs-golang/sendtables"
910
)
@@ -140,7 +141,7 @@ func (e Equipment) UniqueID() int64 {
140141
return e.uniqueID
141142
}
142143

143-
// NewGrenadeProjectile creates a grenade projectile and sets.
144+
// NewGrenadeProjectile creates a grenade projectile and sets the Unique-ID.
144145
//
145146
// Intended for internal use only.
146147
func NewGrenadeProjectile() *GrenadeProjectile {
@@ -180,3 +181,51 @@ func NewSkinEquipment(eqName string, skinID string) Equipment {
180181
func NewPlayer() *Player {
181182
return &Player{RawWeapons: make(map[int]*Equipment)}
182183
}
184+
185+
// Inferno is a list of Fires with helper functions.
186+
// Also contains already extinguished fires.
187+
//
188+
// See also: Inferno.Active() and Fire.IsBurning
189+
type Inferno struct {
190+
EntityID int
191+
Fires []*Fire
192+
193+
// uniqueID is used to distinguish different infernos (which potentially have the same, reused entityID) from each other.
194+
uniqueID int64
195+
}
196+
197+
// Fire is a component of an Inferno.
198+
type Fire struct {
199+
r3.Vector
200+
201+
IsBurning bool
202+
}
203+
204+
// Active returns an Inferno containing only the active fires of the original.
205+
// The returned Inferno will have the same Unique-ID as the original.
206+
func (inf Inferno) Active() Inferno {
207+
res := Inferno{
208+
uniqueID: inf.uniqueID,
209+
}
210+
res.Fires = make([]*Fire, 0, len(inf.Fires))
211+
for i := range inf.Fires {
212+
res.Fires = append(res.Fires, inf.Fires[i])
213+
}
214+
return res
215+
}
216+
217+
// ConvexHull returns the convex hull of all the fires in the inferno.
218+
func (inf Inferno) ConvexHull() *s2.Loop {
219+
q := s2.NewConvexHullQuery()
220+
for i := range inf.Fires {
221+
q.AddPoint(s2.Point{Vector: inf.Fires[i].Vector})
222+
}
223+
return q.ConvexHull()
224+
}
225+
226+
// NewInferno creates a inferno and sets the Unique-ID.
227+
//
228+
// Intended for internal use only.
229+
func NewInferno() *Inferno {
230+
return &Inferno{uniqueID: rand.Int63()}
231+
}

datatables.go

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ func (p *Parser) bindWeapons() {
266266
}
267267
}
268268

269+
p.stParser.ServerClasses().FindByName("CInferno").OnEntityCreated(p.bindNewInferno)
269270
}
270271

271272
// bindGrenadeProjectiles keeps track of the location of live grenades (Parser.gameState.grenadeProjectiles), actively thrown by players.
@@ -277,6 +278,12 @@ func (p *Parser) bindGrenadeProjectiles(entity *st.Entity) {
277278
proj.EntityID = entityID
278279
p.gameState.grenadeProjectiles[entityID] = proj
279280

281+
entity.OnCreateFinished(func() {
282+
p.eventDispatcher.Dispatch(events.NadeProjectileThrownEvent{
283+
Projectile: proj,
284+
})
285+
})
286+
280287
entity.OnDestroy(func() {
281288
p.eventDispatcher.Dispatch(events.NadeProjectileDestroyedEvent{
282289
Projectile: proj,
@@ -322,12 +329,6 @@ func (p *Parser) bindGrenadeProjectiles(entity *st.Entity) {
322329
}
323330
})
324331
}
325-
326-
entity.OnCreateFinished(func() {
327-
p.eventDispatcher.Dispatch(events.NadeProjectileThrownEvent{
328-
Projectile: proj,
329-
})
330-
})
331332
}
332333

333334
func (p *Parser) bindWeapon(entity *st.Entity, wepType common.EquipmentElement) {
@@ -368,3 +369,41 @@ func (p *Parser) bindWeapon(entity *st.Entity, wepType common.EquipmentElement)
368369
wepFix("_pist_deagle", "_pist_revolver", common.EqRevolver)
369370
}
370371
}
372+
373+
func (p *Parser) bindNewInferno(entity *st.Entity) {
374+
entityID := entity.ID()
375+
inf := common.NewInferno()
376+
inf.EntityID = entityID
377+
p.gameState.infernos[entityID] = inf
378+
379+
entity.OnCreateFinished(func() {
380+
p.eventDispatcher.Dispatch(events.InfernoStartedEvent{
381+
Inferno: inf,
382+
})
383+
})
384+
385+
entity.OnDestroy(func() {
386+
p.eventDispatcher.Dispatch(events.InfernoExpiredEvent{
387+
Inferno: inf,
388+
})
389+
})
390+
391+
origin := entity.Position()
392+
nFires := 0
393+
entity.FindProperty("m_fireCount").OnUpdate(func(val st.PropertyValue) {
394+
for i := nFires; i < val.IntVal; i++ {
395+
iStr := fmt.Sprintf("%03d", i)
396+
offset := r3.Vector{
397+
X: float64(entity.FindProperty("m_fireXDelta." + iStr).Value().IntVal),
398+
Y: float64(entity.FindProperty("m_fireYDelta." + iStr).Value().IntVal),
399+
Z: float64(entity.FindProperty("m_fireZDelta." + iStr).Value().IntVal),
400+
}
401+
402+
fire := &common.Fire{Vector: origin.Add(offset)}
403+
entity.BindProperty("m_bFireIsBurning."+iStr, &fire.IsBurning, st.ValTypeBoolInt)
404+
405+
inf.Fires = append(inf.Fires, fire)
406+
}
407+
nFires = val.IntVal
408+
})
409+
}

events/events.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,3 +397,17 @@ type GenericGameEvent struct {
397397
Name string
398398
Data map[string]*msg.CSVCMsg_GameEventKeyT
399399
}
400+
401+
// InfernoStartedEvent signals that the fire of a incendiary or Molotov has just started.
402+
// This is different from the FireNadeStartedEvent because it's sent out when the inferno entity is created instead of on the game-event.
403+
type InfernoStartedEvent struct {
404+
Inferno *common.Inferno
405+
}
406+
407+
// InfernoExpiredEvent signals that all fire from a incendiary or Molotov has extinguished.
408+
// This is different from the FireNadeExpiredEvent event because it's sent out when the inferno entity is destroyed instead of on the game-event.
409+
//
410+
// Mainly useful for getting the final area of an inferno.
411+
type InfernoExpiredEvent struct {
412+
Inferno *common.Inferno
413+
}

examples/nade-trajectories/nade_trajectories.go

Lines changed: 18 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ import (
1818
common "github.com/markus-wa/demoinfocs-golang/common"
1919
events "github.com/markus-wa/demoinfocs-golang/events"
2020
ex "github.com/markus-wa/demoinfocs-golang/examples"
21-
"github.com/markus-wa/demoinfocs-golang/metadata"
22-
st "github.com/markus-wa/demoinfocs-golang/sendtables"
21+
metadata "github.com/markus-wa/demoinfocs-golang/metadata"
2322
)
2423

2524
type nadePath struct {
@@ -39,16 +38,6 @@ var (
3938
curMap metadata.Map
4039
)
4140

42-
type inferno []r3.Vector
43-
44-
func (inf inferno) convexHull() *s2.Loop {
45-
q := s2.NewConvexHullQuery()
46-
for i := range inf {
47-
q.AddPoint(s2.Point{Vector: inf[i]})
48-
}
49-
return q.ConvexHull()
50-
}
51-
5241
// Run like this: go run nade_trajectories.go -demo /path/to/demo.dem > nade_trajectories.jpg
5342
func main() {
5443
f, err := os.Open(ex.DemoPathFromArgs())
@@ -76,50 +65,29 @@ func main() {
7665
nadeTrajectories[id].path = e.Projectile.Trajectory
7766
})
7867

79-
var infernos []*s2.Loop
80-
81-
p.RegisterEventHandler(func(events.DataTablesParsedEvent) {
82-
p.ServerClasses().FindByName("CInferno").OnEntityCreated(func(ent *st.Entity) {
83-
origin := ent.Position()
84-
var fires inferno
85-
var nFires int
86-
ent.FindProperty("m_fireCount").OnUpdate(func(val st.PropertyValue) {
87-
for i := nFires; i < val.IntVal; i++ {
88-
iStr := fmt.Sprintf("%03d", i)
89-
offset := r3.Vector{
90-
X: float64(ent.FindProperty("m_fireXDelta." + iStr).Value().IntVal),
91-
Y: float64(ent.FindProperty("m_fireYDelta." + iStr).Value().IntVal),
92-
Z: float64(ent.FindProperty("m_fireZDelta." + iStr).Value().IntVal),
93-
}
94-
fires = append(fires, origin.Add(offset))
95-
}
96-
nFires = val.IntVal
97-
})
98-
99-
ent.OnDestroy(func() {
100-
infernos = append(infernos, fires.convexHull())
101-
})
102-
})
68+
var infernos []*common.Inferno
69+
70+
p.RegisterEventHandler(func(e events.InfernoExpiredEvent) {
71+
infernos = append(infernos, e.Inferno)
10372
})
10473

10574
var nadeTrajectoriesFirst5Rounds []*nadePath
106-
var infernosFirst5Rounds []*s2.Loop
75+
var infernosFirst5Rounds []*common.Inferno
10776
round := 0
10877
p.RegisterEventHandler(func(events.RoundEndedEvent) {
10978
round++
11079
// We only want the data from the first 5 rounds so the image is not too cluttered
11180
// This is a very cheap way to do it. Won't work with demos that have match-restarts etc.
11281
if round == 5 {
113-
// Copy all nade paths
82+
// Copy nade paths
11483
for _, np := range nadeTrajectories {
11584
nadeTrajectoriesFirst5Rounds = append(nadeTrajectoriesFirst5Rounds, np)
11685
}
11786
nadeTrajectories = make(map[int64]*nadePath)
11887

119-
// And infernos
120-
for _, hull := range infernos {
121-
infernosFirst5Rounds = append(infernosFirst5Rounds, hull)
122-
}
88+
// Copy infernos
89+
infernosFirst5Rounds = make([]*common.Inferno, len(infernos))
90+
copy(infernosFirst5Rounds, infernos)
12391
}
12492
})
12593

@@ -154,18 +122,24 @@ func main() {
154122
})
155123
}
156124

157-
func drawInfernos(gc *draw2dimg.GraphicContext, hulls []*s2.Loop) {
125+
func drawInfernos(gc *draw2dimg.GraphicContext, infernos []*common.Inferno) {
158126
// Draw areas first
159127
gc.SetFillColor(colorInferno)
160128

129+
// Calculate hulls
130+
hulls := make([]*s2.Loop, len(infernos))
131+
for i := range infernos {
132+
hulls[i] = infernos[i].ConvexHull()
133+
}
134+
161135
for _, hull := range hulls {
162136
buildInfernoPath(gc, hull)
163137
gc.Fill()
164138
}
165139

166140
// Then the outline
167141
gc.SetStrokeColor(colorInfernoHull)
168-
gc.SetLineWidth(2) // 2 px wide
142+
gc.SetLineWidth(1) // 1 px wide
169143

170144
for _, hull := range hulls {
171145
buildInfernoPath(gc, hull)
-89.8 KB
Loading

game_state.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ type GameState struct {
1212
ctState TeamState
1313
playersByUserID map[int]*common.Player // Maps user-IDs to players
1414
playersByEntityID map[int]*common.Player // Maps entity-IDs to players
15-
grenadeProjectiles map[int]*common.GrenadeProjectile // Maps entity-IDs to nade-projectiles. That's grenades that have been thrown, but have not yet detonated.
15+
grenadeProjectiles map[int]*common.GrenadeProjectile // Maps entity-IDs to active nade-projectiles. That's grenades that have been thrown, but have not yet detonated.
16+
infernos map[int]*common.Inferno // Maps entity-IDs to active infernos.
1617
entities map[int]*st.Entity // Maps entity IDs to entities
1718
}
1819

@@ -61,6 +62,11 @@ func (gs GameState) GrenadeProjectiles() map[int]*common.GrenadeProjectile {
6162
return gs.grenadeProjectiles
6263
}
6364

65+
// Infernos returns a map from entity-IDs to all currently burning infernos (fires from incendiaries and Molotovs).
66+
func (gs GameState) Infernos() map[int]*common.Inferno {
67+
return gs.infernos
68+
}
69+
6470
// Entities returns all currently existing entities.
6571
func (gs GameState) Entities() map[int]*st.Entity {
6672
return gs.entities
@@ -71,6 +77,7 @@ func newGameState() GameState {
7177
playersByEntityID: make(map[int]*common.Player),
7278
playersByUserID: make(map[int]*common.Player),
7379
grenadeProjectiles: make(map[int]*common.GrenadeProjectile),
80+
infernos: make(map[int]*common.Inferno),
7481
entities: make(map[int]*st.Entity),
7582
}
7683
}

0 commit comments

Comments
 (0)