Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PlayerInfo functionality #1

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
22 changes: 22 additions & 0 deletions a2sPlayerRequest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package steam

import (
"bytes"

"github.com/golang/glog"
)

type A2SPlayerRequest struct {
c ChallengeResponse
}

func (a A2SPlayerRequest) MarshalBinary() []byte {
buf := new(bytes.Buffer)

writeRequestPrefix(buf)
writeByte(buf, 'U')
buf.Write(a.c.GetChallange())

glog.V(2).Infof("steam: a2SPlayerRequest buffer: %v", buf.Bytes())
return buf.Bytes()
}
56 changes: 56 additions & 0 deletions a2sPlayerResponse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package steam

import (
"bytes"
"errors"
"fmt"

"github.com/golang/glog"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is goimports run on this code?

)

type Player struct {
index byte
name string
score int32
duration float32
}

type A2SPlayersResponse struct {
playersCount byte
players []Player
}

func (a *A2SPlayersResponse) UnMarshalBinary(data []byte) (err error) {
glog.V(2).Infof("steam: unmarshalling binary for A2SPlayersResponse: %v", data)
buf := bytes.NewBuffer(data)

if header := readByte(buf); header != 0x44 {
return errors.New("steam: invalid header in the a2splayersresponse")
}

a.playersCount = readByte(buf)
a.players = make([]Player, a.playersCount)

for i := 0; i < int(a.playersCount); i++ {
p := &a.players[i]
p.index = readByte(buf)
p.name = readString(buf)
p.score = readLong(buf)
p.duration = readFloat(buf)
}

return nil
}

func (a *A2SPlayersResponse) String() string {
buf := new(bytes.Buffer)

writeString(buf, fmt.Sprintf("players count: %v\n\n", a.playersCount))
for _, player := range a.players {
writeString(buf, fmt.Sprintf("player index: %v\n", player.index))
writeString(buf, fmt.Sprintf("player name: %v\n", player.name))
writeString(buf, fmt.Sprintf("player score: %v\n", player.score))
writeString(buf, fmt.Sprintf("player duration: %v seconds\n\n", player.duration))
}
return buf.String()
}
21 changes: 21 additions & 0 deletions challengeRequest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package steam

import (
"bytes"

"github.com/golang/glog"
)

type ChallengeRequest struct {
}

func (ChallengeRequest) MarshalBinary() []byte {
buf := new(bytes.Buffer)

writeRequestPrefix(buf)
writeByte(buf, 'U')
writeRequestPrefix(buf)

glog.V(2).Infof("steam: challengeRequest buffer: %v", buf.Bytes())
return buf.Bytes()
}
28 changes: 28 additions & 0 deletions challengeResponse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package steam
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whats with the file name this is not java!?


import (
"bytes"
"fmt"

"github.com/golang/glog"
)

type ChallengeResponse []byte

func (c ChallengeResponse) GetChallange() (challenge []byte) {
glog.V(2).Infof("steam: getting challenge from %v", c)

return c[(len(c) - 4):]
}

func (c ChallengeResponse) String() string {
buf := new(bytes.Buffer)

writeString(buf, fmt.Sprint("challengeResponse: ["))
for i := 0; i < len(c); i++ {
writeString(buf, fmt.Sprintf("%x ", c[i]))
}
writeString(buf, fmt.Sprint("]"))

return buf.String()
}
5 changes: 5 additions & 0 deletions comm.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const (
type ServerType int

func (st *ServerType) UnmarshalBinary(data []byte) error {
glog.V(3).Infof("steam: unmarshalling binary %v for server type ", data)
switch data[0] {
case 'd':
*st = STDedicated
Expand Down Expand Up @@ -51,6 +52,7 @@ var serverTypeStrings = map[ServerType]string{
type Environment int

func (e *Environment) UnmarshalBinary(data []byte) error {
glog.V(3).Infof("steam: unmarshalling binary %v for env ", data)
switch data[0] {
case 'l':
*e = ELinux
Expand Down Expand Up @@ -86,6 +88,7 @@ var environmentStrings = map[Environment]string{
type Visibility int

func (v *Visibility) UnmarshalBinary(data []byte) error {
glog.V(3).Infof("steam: unmarshalling binary %v for visibility ", data)
switch data[0] {
case 0:
*v = VPublic
Expand Down Expand Up @@ -155,6 +158,7 @@ func (InfoRequest) MarshalBinary() ([]byte, error) {
writeByte(buf, 'T')
writeString(buf, "Source Engine Query")

glog.V(3).Infof("steam: marshaled binary. buffer: %v", buf)
return buf.Bytes(), nil
}

Expand Down Expand Up @@ -193,6 +197,7 @@ const (
)

func (r *InfoResponse) UnmarshalBinary(data []byte) (err error) {
glog.V(3).Infof("steam: unmarshalling binary %v", data)
defer func() {
if e := recover(); e != nil {
err = e.(parseError)
Expand Down
5 changes: 5 additions & 0 deletions samples/sample.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"flag"
"fmt"

"github.com/kidoman/go-steam"
Expand All @@ -15,13 +16,17 @@ var addresses = []string{
}

func main() {
flag.Parse()
for _, address := range addresses {
server := &steam.Server{Addr: address}
ping, err := server.Ping()
must(err)
info, err := server.Info()
must(err)
playerInfo, err := server.PLayerInfo()
must(err)
fmt.Printf("%v: %v with ping %v\n", address, info, ping)
fmt.Printf("players info: %v\n", playerInfo)
}
}

Expand Down
52 changes: 48 additions & 4 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package steam
import (
"errors"
"time"

"github.com/golang/glog"
)

// Server represents a Source server.
Expand Down Expand Up @@ -53,6 +55,7 @@ func (s *Server) Ping() (time.Duration, error) {
return 0, err
}

glog.V(3).Infof("steam: sending data %v via socket in ping", data)
start := time.Now()
s.socket.send(data)
if _, err := s.socket.receive(); err != nil {
Expand All @@ -74,10 +77,7 @@ func (s *Server) Info() (*InfoResponse, error) {
return nil, err
}

if err := s.socket.send(data); err != nil {
return nil, err
}
b, err := s.socket.receive()
b, err := s.sendAndRecieve(data)
if err != nil {
return nil, err
}
Expand All @@ -89,3 +89,47 @@ func (s *Server) Info() (*InfoResponse, error) {

return res, nil
}

// PlayerInfo retrieves players information on the server.
func (s *Server) PLayerInfo() (*A2SPlayersResponse, error) {
if err := s.init(); err != nil {
return nil, err
}

data := ChallengeRequest{}.MarshalBinary()

b, err := s.sendAndRecieve(data)
if err != nil {
return nil, err
}

challengeRes := ChallengeResponse(b)
data = A2SPlayerRequest{challengeRes}.MarshalBinary()

b, err = s.sendAndRecieve(data)
if err != nil {
return nil, err
}

a2sPlayerRes := new(A2SPlayersResponse)

if err := a2sPlayerRes.UnMarshalBinary(b); err != nil {
return nil, err
}

return a2sPlayerRes, nil
}

func (s *Server) sendAndRecieve(data []byte) ([]byte, error) {
glog.V(3).Infof("steam: sending data %v via socket in info", data)
if err := s.socket.send(data); err != nil {
return nil, err
}

b, err := s.socket.receive()
if err != nil {
return nil, err
}
glog.V(3).Infof("steam: received data %v via socket", b)
return b, nil
}
3 changes: 3 additions & 0 deletions socket.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package steam
import (
"errors"
"net"

"github.com/golang/glog"
)

type socket struct {
Expand All @@ -29,6 +31,7 @@ func (s *socket) close() {
}

func (s *socket) send(payload []byte) error {
glog.V(3).Infof("steam: writing %v to UDP", payload)
n, err := s.conn.WriteToUDP(payload, s.raddr)
if err != nil {
return err
Expand Down
16 changes: 16 additions & 0 deletions wire.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,22 @@ func readLongLong(buf *bytes.Buffer) int64 {
return int64(t[0] + t[1]<<8 + t[2]<<16 + t[3]<<24 + t[4]<<32 + t[5]<<40 + t[6]<<48 + t[7]<<56)
}

func readLong(buf *bytes.Buffer) int32 {
var t [4]byte
n, err := buf.Read(t[:])
if err != nil {
triggerError(errCouldNotReadData)
}
if n != 4 {
triggerError(errNotEnoughDataInResponse)
}
return int32(t[0] + t[1]<<8 + t[2]<<16 + t[3]<<24)
}

func readFloat(buf *bytes.Buffer) float32 {
return float32(readLong(buf))
}

func readString(buf *bytes.Buffer) string {
bytes, err := buf.ReadBytes(0)
if err != nil {
Expand Down