Skip to content

Commit c8598f3

Browse files
committed
Add PropertyEntry.Bind() & Entity.BindProperty()
Utility functions for directly binding a property's value to a pointer
1 parent 3f4e564 commit c8598f3

File tree

2 files changed

+123
-101
lines changed

2 files changed

+123
-101
lines changed

datatables.go

Lines changed: 51 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -70,18 +70,10 @@ func (p *Parser) bindTeamScores() {
7070
var flagImage string
7171
score := 0
7272

73-
event.Entity.FindProperty("m_iTeamNum").OnUpdate(func(val st.PropValue) {
74-
teamID = val.IntVal
75-
})
76-
event.Entity.FindProperty("m_szClanTeamname").OnUpdate(func(val st.PropValue) {
77-
clanName = val.StringVal
78-
})
79-
event.Entity.FindProperty("m_szTeamFlagImage").OnUpdate(func(val st.PropValue) {
80-
flagImage = val.StringVal
81-
})
82-
event.Entity.FindProperty("m_scoreTotal").OnUpdate(func(val st.PropValue) {
83-
score = val.IntVal
84-
})
73+
event.Entity.BindProperty("m_iTeamNum", &teamID, st.ValTypeInt)
74+
event.Entity.BindProperty("m_szClanTeamname", &clanName, st.ValTypeString)
75+
event.Entity.BindProperty("m_szTeamFlagImage", &flagImage, st.ValTypeString)
76+
event.Entity.BindProperty("m_scoreTotal", &score, st.ValTypeInt)
8577

8678
event.Entity.FindProperty("m_szTeamname").OnUpdate(func(val st.PropValue) {
8779
team := val.StringVal
@@ -111,40 +103,26 @@ func (p *Parser) bindTeamScores() {
111103

112104
// Register direct updates for the future
113105
// Except for teamId, it doesn't change; players swap teams instead
114-
event.Entity.FindProperty("m_szClanTeamname").OnUpdate(func(val st.PropValue) {
115-
s.clanName = val.StringVal
116-
})
117-
event.Entity.FindProperty("m_szTeamFlagImage").OnUpdate(func(val st.PropValue) {
118-
s.flag = val.StringVal
119-
})
120-
event.Entity.FindProperty("m_scoreTotal").OnUpdate(func(val st.PropValue) {
121-
s.score = val.IntVal
122-
})
106+
event.Entity.BindProperty("m_szClanTeamname", &s.clanName, st.ValTypeString)
107+
event.Entity.BindProperty("m_szTeamFlagImage", &s.flag, st.ValTypeString)
108+
event.Entity.BindProperty("m_scoreTotal", &s.score, st.ValTypeInt)
123109
}
124110
})
125111
})
126112
}
127113

128114
func (p *Parser) bindBombSites() {
129115
p.stParser.FindServerClassByName("CCSPlayerResource").RegisterEntityCreatedHandler(func(playerResource st.EntityCreatedEvent) {
130-
playerResource.Entity.FindProperty("m_bombsiteCenterA").OnUpdate(func(center st.PropValue) {
131-
p.bombsiteA.center = center.VectorVal
132-
})
133-
playerResource.Entity.FindProperty("m_bombsiteCenterB").OnUpdate(func(center st.PropValue) {
134-
p.bombsiteB.center = center.VectorVal
135-
})
116+
playerResource.Entity.BindProperty("m_bombsiteCenterA", &p.bombsiteA.center, st.ValTypeVector)
117+
playerResource.Entity.BindProperty("m_bombsiteCenterB", &p.bombsiteB.center, st.ValTypeVector)
136118
})
137119

138120
p.stParser.FindServerClassByName("CBaseTrigger").RegisterEntityCreatedHandler(func(baseTrigger st.EntityCreatedEvent) {
139121
t := new(boundingBoxInformation)
140122
p.triggers[baseTrigger.Entity.ID] = t
141123

142-
baseTrigger.Entity.FindProperty("m_Collision.m_vecMins").OnUpdate(func(vec st.PropValue) {
143-
t.min = vec.VectorVal
144-
})
145-
baseTrigger.Entity.FindProperty("m_Collision.m_vecMaxs").OnUpdate(func(vec st.PropValue) {
146-
t.max = vec.VectorVal
147-
})
124+
baseTrigger.Entity.BindProperty("m_Collision.m_vecMins", &t.min, st.ValTypeVector)
125+
baseTrigger.Entity.BindProperty("m_Collision.m_vecMaxs", &t.max, st.ValTypeVector)
148126
})
149127
}
150128

@@ -158,23 +136,14 @@ func (p *Parser) bindPlayers() {
158136
i2 := i // Copy so it stays the same (for passing to handlers)
159137
iStr := fmt.Sprintf("%03d", i)
160138

161-
pr.Entity.FindProperty("m_szClan." + iStr).OnUpdate(func(val st.PropValue) {
162-
p.additionalPlayerInfo[i2].ClanTag = val.StringVal
163-
})
164-
165-
setIntLazy := func(prop string, setter func(int)) {
166-
pr.Entity.FindProperty(prop).OnUpdate(func(val st.PropValue) {
167-
setter(val.IntVal)
168-
})
169-
}
170-
171-
setIntLazy("m_iPing."+iStr, func(val int) { p.additionalPlayerInfo[i2].Ping = val })
172-
setIntLazy("m_iScore."+iStr, func(val int) { p.additionalPlayerInfo[i2].Score = val })
173-
setIntLazy("m_iKills."+iStr, func(val int) { p.additionalPlayerInfo[i2].Kills = val })
174-
setIntLazy("m_iDeaths."+iStr, func(val int) { p.additionalPlayerInfo[i2].Deaths = val })
175-
setIntLazy("m_iAssists."+iStr, func(val int) { p.additionalPlayerInfo[i2].Assists = val })
176-
setIntLazy("m_iMVPs."+iStr, func(val int) { p.additionalPlayerInfo[i2].MVPs = val })
177-
setIntLazy("m_iTotalCashSpent."+iStr, func(val int) { p.additionalPlayerInfo[i2].TotalCashSpent = val })
139+
pr.Entity.BindProperty("m_szClan."+iStr, &p.additionalPlayerInfo[i2].ClanTag, st.ValTypeString)
140+
pr.Entity.BindProperty("m_iPing."+iStr, &p.additionalPlayerInfo[i2].Ping, st.ValTypeInt)
141+
pr.Entity.BindProperty("m_iScore."+iStr, &p.additionalPlayerInfo[i2].Score, st.ValTypeInt)
142+
pr.Entity.BindProperty("m_iKills."+iStr, &p.additionalPlayerInfo[i2].Kills, st.ValTypeInt)
143+
pr.Entity.BindProperty("m_iDeaths."+iStr, &p.additionalPlayerInfo[i2].Deaths, st.ValTypeInt)
144+
pr.Entity.BindProperty("m_iAssists."+iStr, &p.additionalPlayerInfo[i2].Assists, st.ValTypeInt)
145+
pr.Entity.BindProperty("m_iMVPs."+iStr, &p.additionalPlayerInfo[i2].MVPs, st.ValTypeInt)
146+
pr.Entity.BindProperty("m_iTotalCashSpent."+iStr, &p.additionalPlayerInfo[i2].TotalCashSpent, st.ValTypeInt)
178147
}
179148
})
180149
}
@@ -194,59 +163,40 @@ func (p *Parser) bindNewPlayer(playerEntity *st.Entity) {
194163
pl.EntityID = playerEntity.ID
195164
pl.Entity = playerEntity
196165

166+
// Position
197167
playerEntity.FindProperty("cslocaldata.m_vecOrigin").OnUpdate(func(val st.PropValue) {
198168
pl.Position.X = val.VectorVal.X
199169
pl.Position.Y = val.VectorVal.Y
200170
})
171+
playerEntity.BindProperty("cslocaldata.m_vecOrigin[2]", &pl.Position.Z, st.ValTypeFloat64)
201172

202-
playerEntity.FindProperty("cslocaldata.m_vecOrigin[2]").OnUpdate(func(val st.PropValue) {
203-
pl.Position.Z = float64(val.FloatVal)
204-
})
205-
173+
// General info
206174
playerEntity.FindProperty("m_iTeamNum").OnUpdate(func(val st.PropValue) {
207-
pl.Team = common.Team(val.IntVal)
175+
pl.Team = common.Team(val.IntVal) // Need to cast to team so we can't use BindProperty
208176
})
209-
210-
// Some helpers because I cant be arsed
211-
setIntLazy := func(prop string, setter func(int)) {
212-
playerEntity.FindProperty(prop).OnUpdate(func(val st.PropValue) {
213-
setter(val.IntVal)
214-
})
215-
}
216-
217-
setFloatLazy := func(prop string, setter func(float32)) {
218-
playerEntity.FindProperty(prop).OnUpdate(func(val st.PropValue) {
219-
setter(val.FloatVal)
220-
})
221-
}
222-
223-
setFloat64Lazy := func(prop string, setter func(float64)) {
224-
playerEntity.FindProperty(prop).OnUpdate(func(val st.PropValue) {
225-
setter(float64(val.FloatVal))
226-
})
227-
}
228-
229-
setIntLazy("m_iHealth", func(val int) { pl.Hp = val })
230-
setIntLazy("m_ArmorValue", func(val int) { pl.Armor = val })
231-
setIntLazy("m_bHasDefuser", func(val int) { pl.HasDefuseKit = val == 1 })
232-
setIntLazy("m_bHasHelmet", func(val int) { pl.HasHelmet = val == 1 })
233-
setIntLazy("localdata.m_Local.m_bDucking", func(val int) { pl.IsDucking = val == 1 })
234-
setIntLazy("m_iAccount", func(val int) { pl.Money = val })
235-
236-
setFloatLazy("m_angEyeAngles[1]", func(val float32) { pl.ViewDirectionX = val })
237-
setFloatLazy("m_angEyeAngles[0]", func(val float32) { pl.ViewDirectionY = val })
238-
setFloatLazy("m_flFlashDuration", func(val float32) { pl.FlashDuration = val })
239-
240-
setFloat64Lazy("localdata.m_vecVelocity[0]", func(val float64) { pl.Velocity.X = val })
241-
setFloat64Lazy("localdata.m_vecVelocity[1]", func(val float64) { pl.Velocity.Y = val })
242-
setFloat64Lazy("localdata.m_vecVelocity[2]", func(val float64) { pl.Velocity.Z = val })
243-
244-
setIntLazy("m_unCurrentEquipmentValue", func(val int) { pl.CurrentEquipmentValue = val })
245-
setIntLazy("m_unRoundStartEquipmentValue", func(val int) { pl.RoundStartEquipmentValue = val })
246-
setIntLazy("m_unFreezetimeEndEquipmentValue", func(val int) { pl.FreezetimeEndEquipmentValue = val })
247-
177+
playerEntity.BindProperty("m_iHealth", &pl.Hp, st.ValTypeInt)
178+
playerEntity.BindProperty("m_ArmorValue", &pl.Armor, st.ValTypeInt)
179+
playerEntity.BindProperty("m_bHasDefuser", &pl.HasDefuseKit, st.ValTypeBoolInt)
180+
playerEntity.BindProperty("m_bHasHelmet", &pl.HasHelmet, st.ValTypeBoolInt)
181+
playerEntity.BindProperty("localdata.m_Local.m_bDucking", &pl.IsDucking, st.ValTypeBoolInt)
182+
playerEntity.BindProperty("m_iAccount", &pl.Money, st.ValTypeInt)
183+
184+
playerEntity.BindProperty("m_angEyeAngles[1]", &pl.ViewDirectionX, st.ValTypeFloat32)
185+
playerEntity.BindProperty("m_angEyeAngles[0]", &pl.ViewDirectionY, st.ValTypeFloat32)
186+
playerEntity.BindProperty("m_flFlashDuration", &pl.FlashDuration, st.ValTypeFloat32)
187+
188+
// Velocity
189+
playerEntity.BindProperty("localdata.m_vecVelocity[0]", &pl.Velocity.X, st.ValTypeFloat64)
190+
playerEntity.BindProperty("localdata.m_vecVelocity[1]", &pl.Velocity.Y, st.ValTypeFloat64)
191+
playerEntity.BindProperty("localdata.m_vecVelocity[2]", &pl.Velocity.Z, st.ValTypeFloat64)
192+
193+
// Eq value
194+
playerEntity.BindProperty("m_unCurrentEquipmentValue", &pl.CurrentEquipmentValue, st.ValTypeInt)
195+
playerEntity.BindProperty("m_unRoundStartEquipmentValue", &pl.RoundStartEquipmentValue, st.ValTypeInt)
196+
playerEntity.BindProperty("m_unFreezetimeEndEquipmentValue", &pl.FreezetimeEndEquipmentValue, st.ValTypeInt)
197+
198+
// Weapons
248199
wepPrefix := playerWeaponPrePrefix + playerWeaponPrefix
249-
250200
for _, prop := range playerEntity.Props() {
251201
if prop.Entry().Name() == playerWeaponPrefix+"000" {
252202
wepPrefix = playerWeaponPrefix
@@ -255,7 +205,6 @@ func (p *Parser) bindNewPlayer(playerEntity *st.Entity) {
255205
}
256206

257207
var cache [maxWeapons]int
258-
259208
for i := range cache {
260209
i2 := i // Copy for passing to handler
261210
playerEntity.FindProperty(wepPrefix + fmt.Sprintf("%03d", i)).OnUpdate(func(val st.PropValue) {
@@ -282,11 +231,14 @@ func (p *Parser) bindNewPlayer(playerEntity *st.Entity) {
282231
})
283232
}
284233

285-
setIntLazy("m_hActiveWeapon", func(val int) { pl.ActiveWeaponID = val & indexMask })
234+
// Active weapon
235+
playerEntity.FindProperty("m_hActiveWeapon").OnUpdate(func(val st.PropValue) {
236+
pl.ActiveWeaponID = val.IntVal & indexMask
237+
})
286238

287239
for i := 0; i < 32; i++ {
288240
i2 := i // Copy so it stays the same
289-
setIntLazy("m_iAmmo."+fmt.Sprintf("%03d", i2), func(val int) { pl.AmmoLeft[i2] = val })
241+
playerEntity.BindProperty("m_iAmmo."+fmt.Sprintf("%03d", i2), &pl.AmmoLeft[i2], st.ValTypeInt)
290242
}
291243
}
292244

@@ -375,9 +327,7 @@ func (p *Parser) bindWeapon(event st.EntityCreatedEvent) {
375327
eq.AmmoInMagazine = val.IntVal - 1
376328
})
377329

378-
event.Entity.FindProperty("LocalWeaponData.m_iPrimaryAmmoType").OnUpdate(func(val st.PropValue) {
379-
eq.AmmoType = val.IntVal
380-
})
330+
event.Entity.BindProperty("LocalWeaponData.m_iPrimaryAmmoType", &eq.AmmoType, st.ValTypeInt)
381331

382332
wepFix := func(ok string, change string, changer func()) {
383333
event.Entity.FindProperty("m_nModelIndex").OnUpdate(func(val st.PropValue) {

sendtables/entity.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ func (e *Entity) FindProperty(name string) *PropertyEntry {
4040
return prop
4141
}
4242

43+
// BindProperty combines FindProperty() & PropertyEntry.Bind() into one.
44+
// Essentially binds a property's value to a pointer.
45+
// See the docs of the two individual functions for more info.
46+
func (e *Entity) BindProperty(name string, variable interface{}, valueType propertyValueType) {
47+
e.FindProperty(name).Bind(variable, valueType)
48+
}
49+
4350
var updatedPropIndicesPool = sync.Pool{
4451
New: func() interface{} {
4552
s := make([]int, 0, 8)
@@ -219,5 +226,70 @@ func (pe *PropertyEntry) OnUpdate(handler PropertyUpdateHandler) {
219226
pe.updateHandlers = append(pe.updateHandlers, handler)
220227
}
221228

229+
type propertyValueType int
230+
231+
// Possible types of property values.
232+
// See PropertyEntry.Bind()
233+
const (
234+
ValTypeInt propertyValueType = iota
235+
ValTypeFloat32
236+
ValTypeFloat64
237+
ValTypeString
238+
ValTypeVector
239+
ValTypeArray
240+
ValTypeBoolInt // Int that is treated as bool (1 -> true, != 1 -> false)
241+
)
242+
243+
/*
244+
Bind binds a property's value to a pointer.
245+
246+
Example:
247+
var i int
248+
PropertyEntry.Bind(&i, ValTypeInt)
249+
250+
This will bind the property's value to i so every time it's updated i is updated as well.
251+
252+
The valueType indicates which field of the PropValue to use for the binding.
253+
*/
254+
func (pe *PropertyEntry) Bind(variable interface{}, valueType propertyValueType) {
255+
var binder PropertyUpdateHandler
256+
switch valueType {
257+
case ValTypeInt:
258+
binder = func(val PropValue) {
259+
*(variable.(*int)) = val.IntVal
260+
}
261+
case ValTypeBoolInt:
262+
binder = func(val PropValue) {
263+
*(variable.(*bool)) = val.IntVal == 1
264+
}
265+
266+
case ValTypeFloat32:
267+
binder = func(val PropValue) {
268+
*(variable.(*float32)) = val.FloatVal
269+
}
270+
271+
case ValTypeFloat64:
272+
binder = func(val PropValue) {
273+
*(variable.(*float64)) = float64(val.FloatVal)
274+
}
275+
276+
case ValTypeString:
277+
binder = func(val PropValue) {
278+
*(variable.(*string)) = val.StringVal
279+
}
280+
281+
case ValTypeVector:
282+
binder = func(val PropValue) {
283+
*(variable.(*r3.Vector)) = val.VectorVal
284+
}
285+
286+
case ValTypeArray:
287+
binder = func(val PropValue) {
288+
*(variable.(*[]PropValue)) = val.ArrayVal
289+
}
290+
}
291+
pe.OnUpdate(binder)
292+
}
293+
222294
// PropertyUpdateHandler is the interface for handlers that are interested in PropertyEntry changes.
223295
type PropertyUpdateHandler func(PropValue)

0 commit comments

Comments
 (0)