Skip to content

Commit

Permalink
fix(tf2e): Ensure older compatibility structs are populated (#34)
Browse files Browse the repository at this point in the history
Previously compatibility objects are not populated when new protocol versions are used. For instance, when receiving a version 9 performance info response, the version 6 performance object would be empty. Users who are still using the older object will receive no values.

This attempts to provide backwards compatibility for both performance info and match info. Where possible the older structs will have the appropriate fields set, however they may not contain all available information as the specification will have changed.
  • Loading branch information
lwaddicor authored Apr 18, 2023
1 parent 3a9da6c commit 341cd7a
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 12 deletions.
11 changes: 8 additions & 3 deletions lib/svrquery/protocol/titanfall/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ func (q *queryer) Query() (resp protocol.Responser, err error) {
if err = r.Read(&i.PerformanceInfoV9); err != nil {
return nil, err
}
i.PerformanceInfo = i.PerformanceInfoV9.PerformanceInfo
} else if i.Version > 4 {
// PerformanceInfo.
if err = r.Read(&i.PerformanceInfo); err != nil {
Expand All @@ -178,16 +179,19 @@ func (q *queryer) Query() (resp protocol.Responser, err error) {
if err = r.Read(&i.MatchStateV10); err != nil {
return nil, err
}
i.MatchStateV9 = i.MatchStateV10.MatchStateV9
i.MatchStateV6 = i.MatchStateV10.toV6()
} else if i.Version >= 9 {
if err = r.Read(&i.MatchStateV9); err != nil {
return nil, err
}
i.MatchStateV6 = i.MatchStateV9.toV6()
} else if i.Version > 5 {
// MatchState and Teams.
if err = r.Read(&i.MatchState); err != nil {
// MatchStateV6 and Teams.
if err = r.Read(&i.MatchStateV6); err != nil {
return nil, err
}
} else if err = r.Read(&i.MatchState.MatchStateV2); err != nil {
} else if err = r.Read(&i.MatchStateV6.MatchStateV2); err != nil {
return nil, err
}

Expand All @@ -210,6 +214,7 @@ func (q *queryer) instanceInfo(r *common.BinaryReader, i *Info) (err error) {
if err = r.Read(&i.InstanceInfoV8); err != nil {
return err
}
i.InstanceInfo = i.InstanceInfoV8.toV1()
} else {
if err = r.Read(&i.InstanceInfo); err != nil {
return err
Expand Down
18 changes: 12 additions & 6 deletions lib/svrquery/protocol/titanfall/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ var (
Map: "mp_rr_desertlands_64k_x_64k",
},
PerformanceInfo: PerformanceInfo{},
MatchState: MatchState{
MatchStateV6: MatchStateV6{
MatchStateV2: MatchStateV2{
Phase: 2,
MaxRounds: 1,
Expand All @@ -51,6 +51,7 @@ var (
TimePassed: 0,
MaxScore: 50,
},
TeamsLeftWithPlayersNum: 0,
},
}
)
Expand All @@ -75,7 +76,7 @@ func TestQuery(t *testing.T) {
AverageUserCommandTime: 3,
MaxUserCommandTime: 4,
}
v7.MatchState.TeamsLeftWithPlayersNum = 6
v7.MatchStateV6.TeamsLeftWithPlayersNum = 6

v8 := v7
v8.Version = 8
Expand All @@ -87,7 +88,6 @@ func TestQuery(t *testing.T) {
HealthFlags: 0,
RandomServerID: 0,
}
v8.InstanceInfo = InstanceInfo{}

v9 := v8
v9.Version = 9
Expand All @@ -98,13 +98,20 @@ func TestQuery(t *testing.T) {
CommitMemory: 8472,
ResidentMemory: 3901,
}
v9.PerformanceInfo = PerformanceInfo{}
// Newer version of the match state are dramatically different to the older ones. So wipe with a new copy that
// looks like what will be retained by the compatability code.
v9.MatchStateV9 = MatchStateV9{
Phase: 3,
TimePassed: 0,
TeamsLeftWithPlayersNum: 0,
}
v9.MatchState = MatchState{}
v9.MatchStateV6 = MatchStateV6{
MatchStateV2: MatchStateV2{
Phase: 3,
TimePassed: 0,
},
TeamsLeftWithPlayersNum: 0,
}

v10 := v9
v10.Version = 10
Expand All @@ -117,7 +124,6 @@ func TestQuery(t *testing.T) {
CurrentEntityPropertyCount: 2,
MaxEntityPropertyCount: 5,
}
v10.MatchStateV9 = MatchStateV9{}

cases := []struct {
name string
Expand Down
32 changes: 29 additions & 3 deletions lib/svrquery/protocol/titanfall/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type Info struct {
// Version 9+
PerformanceInfoV9
// Version 2+
MatchState
MatchStateV6
// Version 9+
MatchStateV9
// Version 10+
Expand Down Expand Up @@ -77,6 +77,7 @@ type InstanceInfo struct {
}

// InstanceInfoV8 represents instance information contained in a query response.
// We use a separate structure as the order is important for parsing.
type InstanceInfoV8 struct {
Retail byte
InstanceType byte
Expand All @@ -86,6 +87,17 @@ type InstanceInfoV8 struct {
RandomServerID uint32
}

// toV1 converts the V8 instance info to the V1 format.
func (i InstanceInfoV8) toV1() InstanceInfo {
return InstanceInfo{
Retail: i.Retail,
InstanceType: i.InstanceType,
ClientCRC: i.ClientCRC,
NetProtocol: i.NetProtocol,
RandomServerID: uint64(i.RandomServerID),
}
}

// HealthFlags allows us to read the health bits and output them
// in an easy to consume json format.
type HealthFlags uint32
Expand Down Expand Up @@ -200,6 +212,20 @@ type MatchStateV9 struct {
TeamsLeftWithPlayersNum uint16
}

// toV6 converts the V9 match state to the V6 format. Preserving fields where possible.
func (m MatchStateV9) toV6() MatchStateV6 {
// The older version of the match state is dramatically different to the new version so not
// all information is available through the backwards compatibility interface.
return MatchStateV6{
// The v2 stricture
MatchStateV2: MatchStateV2{
Phase: m.Phase,
TimePassed: m.TimePassed,
},
TeamsLeftWithPlayersNum: m.TeamsLeftWithPlayersNum,
}
}

// MatchStateV2 represents match state contained in a query response.
// This contains a legacy v2 version of matchstate
type MatchStateV2 struct {
Expand All @@ -212,8 +238,8 @@ type MatchStateV2 struct {
MaxScore uint16
}

// MatchState represents match state contained in a query response.
type MatchState struct {
// MatchStateV6 represents match state contained in a query response.
type MatchStateV6 struct {
MatchStateV2
TeamsLeftWithPlayersNum uint16
}
Expand Down

0 comments on commit 341cd7a

Please sign in to comment.