├── index.html
├── .gitignore
├── netmsg
├── disconnect.proto
├── connect_response.proto
├── make.sh
├── update_player.proto
├── kind.go
├── disconnect.pb.go
├── connect_response.pb.go
└── update_player.pb.go
├── gameclient
├── client.go
├── client_js.go
└── client_nonjs.go
├── README.md
├── gameserver
├── server.go
└── client.go
├── client.go
├── server.go
└── main.go
/index.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /*.exe
2 | /networkplatformer-go
3 | /*.js
4 | /*.js.map
5 |
--------------------------------------------------------------------------------
/netmsg/disconnect.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package netmsg;
3 |
4 | message DisconnectPlayer {
5 | int32 ClientSlot = 1;
6 | }
7 |
--------------------------------------------------------------------------------
/netmsg/connect_response.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package netmsg;
3 |
4 | message ConnectResponse {
5 | int32 ClientSlot = 1;
6 | double X = 2;
7 | double Y = 3;
8 | }
9 |
--------------------------------------------------------------------------------
/netmsg/make.sh:
--------------------------------------------------------------------------------
1 | # Build the net messages with protocol buffers
2 |
3 | protoc --gofast_out=. connect_response.proto
4 | protoc --gofast_out=. update_player.proto
5 | protoc --gofast_out=. disconnect.proto
6 |
--------------------------------------------------------------------------------
/netmsg/update_player.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package netmsg;
3 |
4 | message UpdatePlayer {
5 | int32 ClientSlot = 1;
6 | double X = 2;
7 | double Y = 3;
8 | bool IsKeyLeftPressed = 4;
9 | bool IsKeyRightPressed = 5;
10 | }
11 |
--------------------------------------------------------------------------------
/netmsg/kind.go:
--------------------------------------------------------------------------------
1 | package netmsg
2 |
3 | type Kind byte
4 |
5 | const (
6 | MsgUnknown Kind = 0 + iota
7 | MsgConnectResponse = 1
8 | MsgUpdatePlayer = 2
9 | MsgDisconnectPlayer = 3
10 | )
11 |
12 | var kindToString = []string{
13 | MsgUnknown: "MsgUnknown",
14 | MsgConnectResponse: "MsgConnectResponse",
15 | MsgUpdatePlayer: "MsgUpdatePlayer",
16 | MsgDisconnectPlayer: "MsgDisconnectPlayer",
17 | }
18 |
19 | func (kind Kind) String() string {
20 | kindAsInt := int(kind)
21 | if kindAsInt >= 0 && kindAsInt < len(kindToString) {
22 | return kindToString[kind]
23 | }
24 | return "MsgUnknown"
25 | }
26 |
--------------------------------------------------------------------------------
/gameclient/client.go:
--------------------------------------------------------------------------------
1 | package gameclient
2 |
3 | import "time"
4 |
5 | const (
6 | // Time allowed to write a message to the peer.
7 | writeWait = 5000 * time.Millisecond
8 |
9 | // Time allowed to read the next pong message from the peer.
10 | pongWait = 60 * time.Second
11 |
12 | // Send pings to peer with this period. Must be less than pongWait.
13 | pingPeriod = (pongWait * 9) / 10
14 |
15 | // Maximum message size allowed from peer.
16 | maxMessageSize = 512
17 | )
18 |
19 | type clientShared struct {
20 | // Inbound messages from the server.
21 | recv chan []byte
22 |
23 | // Disconnect
24 | disconnect chan bool
25 | }
26 |
27 | func newClientShared() clientShared {
28 | return clientShared{
29 | recv: make(chan []byte, 256),
30 | disconnect: make(chan bool),
31 | }
32 | }
33 |
34 | func (c *clientShared) ChRecv() chan []byte { return c.recv }
35 |
36 | func (c *clientShared) ChDisconnected() chan bool { return c.disconnect }
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Networked Platformer Proof of Concept in Golang
2 |
3 | This is a thrown together remix of the [Ebiten platformer example](https://github.com/hajimehoshi/ebiten/tree/master/examples/platformer).
4 | The difference is that this allows you to host a Websocket server and connect with native or web clients.
5 |
6 | **!!!Warning!!!**
7 |
8 | This has bugs, sub-optimal networking code and poor error handling. This was hastily put together to show that this
9 | is possible with Go. Use this more as a loose guide to getting started!
10 |
11 | **!!!Warning!!!**
12 |
13 | ## Install
14 |
15 | ```
16 | go get github.com/silbinarywolf/networkplatformer-go
17 | ```
18 |
19 | ## Requirements
20 |
21 | * Golang 1.10+
22 | * [Gorilla Websockets](https://github.com/gorilla/websocket) (for native client and server)
23 | * [GopherJS Websockets](https://github.com/gopherjs/websocket) (for JavaScript client)
24 |
25 | ## How to use
26 |
27 | These commands were all tested on Windows, running via Git Bash.
28 |
29 | Build and run server
30 | ```
31 | go build && ./networkplatformer-go.exe --server
32 | ```
33 |
34 | Build and run client
35 | ```
36 | go build && ./networkplatformer-go.exe
37 | ```
38 |
39 | Build web client (requires GopherJS is installed)
40 | ```
41 | GOOS=linux gopherjs build
42 | ```
43 | Then open "index.html" in your browser of choice to run it. (Tested Chrome and Firefox)
44 |
--------------------------------------------------------------------------------
/gameclient/client_js.go:
--------------------------------------------------------------------------------
1 | // +build js
2 |
3 | package gameclient
4 |
5 | import (
6 | "net"
7 |
8 | "github.com/gopherjs/websocket"
9 | )
10 |
11 | type Client struct {
12 | clientShared
13 |
14 | conn net.Conn
15 |
16 | // Outbound messages to the server.
17 | send chan []byte
18 | }
19 |
20 | func NewClient() *Client {
21 | return &Client{
22 | clientShared: newClientShared(),
23 | conn: nil,
24 | }
25 | }
26 |
27 | func (c *Client) Dial(addr string) error {
28 | conn, err := websocket.Dial("ws://" + addr + "/ws") // Blocks until connection is established.
29 | if err != nil {
30 | // handle error
31 | return err
32 | }
33 | c.conn = conn
34 | return nil
35 | }
36 |
37 | func (c *Client) DialTLS(addr string) error {
38 | conn, err := websocket.Dial("wss://" + addr + "/ws") // Blocks until connection is established.
39 | if err != nil {
40 | // handle error
41 | return err
42 | }
43 | c.conn = conn
44 | return nil
45 | }
46 |
47 | func (c *Client) Listen() error {
48 | err := c.readPump() // this is blocking
49 | c.disconnect <- true
50 | c.conn.Close()
51 | return err
52 | }
53 |
54 | func (c *Client) SendMessage(message []byte) {
55 | // NOTE(Jake): 2018-05-27
56 | //
57 | // This is not blocking, at least for JavaScript impl. of Websocket.
58 | //
59 | // We also don't need to add a write deadline because its non-blocking.
60 | // (this function returns nil)
61 | //
62 | //c.conn.SetWriteDeadline(time.Now().Add(writeWait))
63 | c.conn.Write(message)
64 | }
65 |
66 | func (c *Client) readPump() error {
67 | conn := c.conn
68 | for {
69 | // NOTE(Jake): 2018-06-20
70 | //
71 | // Disabling this in hopes that it fixes timeout issues
72 | // on the server. JavaScript impl. might not need this
73 | // and might just close automatically after X amount of time.
74 | //
75 | //conn.SetReadDeadline(time.Now().Add(pongWait))
76 |
77 | // todo(Jake): 2018-05-27
78 | //
79 | // Perhaps profile / figure out how keep allocations here low?
80 | // Maybe this isnt even a big deal?
81 | //
82 | buf := make([]byte, 1024)
83 | size, err := conn.Read(buf) // Blocks until a WebSocket frame is received.
84 | if err != nil {
85 | // handle error
86 | return err
87 | }
88 | buf = buf[:size]
89 | c.recv <- buf
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/gameclient/client_nonjs.go:
--------------------------------------------------------------------------------
1 | // +build darwin freebsd linux windows
2 | // +build !js
3 | // +build !android
4 | // +build !ios
5 |
6 | package gameclient
7 |
8 | import (
9 | "log"
10 | "time"
11 |
12 | "github.com/gorilla/websocket"
13 | )
14 |
15 | type Client struct {
16 | clientShared
17 | conn *websocket.Conn
18 |
19 | // Outbound messages to the server.
20 | send chan []byte
21 | }
22 |
23 | func NewClient() *Client {
24 | return &Client{
25 | clientShared: newClientShared(),
26 | conn: nil,
27 | send: make(chan []byte, 256),
28 | }
29 | }
30 |
31 | func (c *Client) Dial(addr string) error {
32 | conn, _, err := websocket.DefaultDialer.Dial("ws://"+addr+"/ws", nil)
33 | if err != nil {
34 | return err
35 | }
36 | c.conn = conn
37 | return nil
38 | }
39 |
40 | func (c *Client) DialTLS(addr string) error {
41 | conn, _, err := websocket.DefaultDialer.Dial("wss://"+addr+"/ws", nil)
42 | if err != nil {
43 | return err
44 | }
45 | c.conn = conn
46 | return nil
47 | }
48 |
49 | func (c *Client) Listen() {
50 | go c.writePump()
51 | go c.readPump()
52 | }
53 |
54 | func (c *Client) ChRecv() chan []byte { return c.recv }
55 |
56 | func (c *Client) SendMessage(message []byte) {
57 | c.send <- message
58 | }
59 |
60 | // readPump pumps messages from the websocket connection to the hub.
61 | //
62 | // The application runs readPump in a per-connection goroutine. The application
63 | // ensures that there is at most one reader on a connection by executing all
64 | // reads from this goroutine.
65 | func (c *Client) readPump() {
66 | defer func() {
67 | c.conn.Close()
68 | c.disconnect <- true
69 | }()
70 | c.conn.SetReadLimit(maxMessageSize)
71 | c.conn.SetReadDeadline(time.Now().Add(pongWait))
72 | c.conn.SetPongHandler(func(string) error { c.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil })
73 | for {
74 | _, buf, err := c.conn.ReadMessage()
75 | if err != nil {
76 | if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
77 | log.Printf("error: %v", err)
78 | }
79 | break
80 | }
81 | c.recv <- buf
82 | }
83 | }
84 |
85 | // writePump pumps messages from the hub to the websocket connection.
86 | //
87 | // A goroutine running writePump is started for each connection. The
88 | // application ensures that there is at most one writer to a connection by
89 | // executing all writes from this goroutine.
90 | func (c *Client) writePump() {
91 | ticker := time.NewTicker(pingPeriod)
92 | defer func() {
93 | ticker.Stop()
94 | c.conn.Close()
95 | c.disconnect <- true
96 | }()
97 | for {
98 | select {
99 | case message, ok := <-c.send:
100 | c.conn.SetWriteDeadline(time.Now().Add(writeWait))
101 | if !ok {
102 | // The hub closed the channel.
103 | c.conn.WriteMessage(websocket.CloseMessage, []byte{})
104 | return
105 | }
106 |
107 | w, err := c.conn.NextWriter(websocket.BinaryMessage)
108 | if err != nil {
109 | return
110 | }
111 | w.Write(message)
112 |
113 | if err := w.Close(); err != nil {
114 | return
115 | }
116 | case <-ticker.C:
117 | c.conn.SetWriteDeadline(time.Now().Add(writeWait))
118 | if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
119 | return
120 | }
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/gameserver/server.go:
--------------------------------------------------------------------------------
1 | package gameserver
2 |
3 | import (
4 | "errors"
5 | "log"
6 | "net/http"
7 | )
8 |
9 | const (
10 | maxClients = 256
11 | )
12 |
13 | var (
14 | ErrNoMoreClientSlots = errors.New("No more free client slots.")
15 | )
16 |
17 | type Server struct {
18 | addr string
19 |
20 | //
21 | clientSlots []bool
22 |
23 | // Registered clients.
24 | clients map[*Client]bool
25 |
26 | // Inbound messages from the clients.
27 | broadcast chan Message
28 |
29 | // Register requests from the clients.
30 | register chan *Client
31 |
32 | // Unregister requests from clients.
33 | unregister chan *Client
34 | }
35 |
36 | // Create new chat server.
37 | func NewServer(pattern string) *Server {
38 | return &Server{
39 | addr: ":8080",
40 | clientSlots: make([]bool, maxClients),
41 | broadcast: make(chan Message),
42 | register: make(chan *Client),
43 | unregister: make(chan *Client),
44 | clients: make(map[*Client]bool),
45 | }
46 | }
47 |
48 | // Listen and serve.
49 | // It serves client connection and broadcast request.
50 | func (s *Server) Listen() {
51 | http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
52 | s.serveWs(w, r)
53 | })
54 | println("Listening server...")
55 | err := http.ListenAndServe(s.addr, nil)
56 | if err != nil {
57 | println("Failed to listen:", err.Error())
58 | }
59 | }
60 |
61 | func (s *Server) ListenTLS(sslCert string, sslKey string) {
62 | http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
63 | s.serveWs(w, r)
64 | })
65 | println("Listening server...")
66 | err := http.ListenAndServeTLS(s.addr, sslCert, sslKey, nil)
67 | if err != nil {
68 | println("Failed to listen:", err.Error())
69 | }
70 | }
71 |
72 | func (s *Server) ChRegister() chan *Client { return s.register }
73 |
74 | func (s *Server) ChUnregister() chan *Client { return s.unregister }
75 |
76 | func (s *Server) ChBroadcast() chan Message { return s.broadcast }
77 |
78 | func (s *Server) GetMaxClients() int32 { return int32(len(s.clientSlots)) }
79 |
80 | func (s *Server) GetClients() map[*Client]bool { return s.clients }
81 |
82 | func (s *Server) HasClient(c *Client) bool {
83 | _, ok := s.clients[c]
84 | return ok
85 | }
86 |
87 | func (s *Server) RegisterClient(c *Client, data interface{}) {
88 | c.data = data
89 | s.clients[c] = true
90 | }
91 |
92 | func (s *Server) RemoveClient(c *Client) bool {
93 | if _, ok := s.clients[c]; ok {
94 | s.clientSlots[c.clientSlot] = false
95 | close(c.send)
96 | delete(s.clients, c)
97 | return true
98 | }
99 | return false
100 | }
101 |
102 | // serveWs handles websocket requests from the peer.
103 | func (s *Server) serveWs(w http.ResponseWriter, r *http.Request) {
104 | conn, err := upgrader.Upgrade(w, r, nil)
105 | if err != nil {
106 | log.Println(err)
107 | return
108 | }
109 | clientSlot, err := s.getNextFreeClientSlot()
110 | if err != nil {
111 | log.Println(err)
112 | return
113 | }
114 | client := &Client{
115 | server: s,
116 | conn: conn,
117 | clientSlot: clientSlot,
118 | send: make(chan []byte, 256),
119 | }
120 | s.clientSlots[clientSlot] = true
121 | client.server.register <- client
122 |
123 | // Allow collection of memory referenced by the caller by doing all work in
124 | // new goroutines.
125 | go client.writePump()
126 | go client.readPump()
127 |
128 | println("Client connected!")
129 | }
130 |
131 | func (s *Server) getNextFreeClientSlot() (int32, error) {
132 | maxClients := s.GetMaxClients()
133 | for i := int32(0); i < maxClients; i++ {
134 | if !s.clientSlots[i] {
135 | return i, nil
136 | }
137 | }
138 | return 0, ErrNoMoreClientSlots
139 | }
140 |
--------------------------------------------------------------------------------
/client.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "time"
6 |
7 | "github.com/gogo/protobuf/proto"
8 | "github.com/silbinarywolf/networkplatformer-go/gameclient"
9 | "github.com/silbinarywolf/networkplatformer-go/netmsg"
10 | )
11 |
12 | const (
13 | maxClients = 256
14 | )
15 |
16 | var (
17 | client *Client
18 | isConnected = false
19 | lastWorldUpdateTimer time.Time
20 | )
21 |
22 | type Client struct {
23 | *gameclient.Client
24 | clientSlots []*Char
25 | }
26 |
27 | func NewClient() *Client {
28 | server := &Client{
29 | Client: gameclient.NewClient(),
30 | clientSlots: make([]*Char, maxClients),
31 | }
32 | return server
33 | }
34 |
35 | func (c *Client) Update() {
36 | RecvMsgLoop:
37 | for {
38 | select {
39 | case buf := <-c.ChRecv():
40 | kind := netmsg.Kind(buf[0])
41 | buf = buf[1:]
42 | switch kind {
43 | case netmsg.MsgConnectResponse:
44 | recvMsg := &netmsg.ConnectResponse{}
45 | err := recvMsg.Unmarshal(buf)
46 | if err != nil {
47 | log.Fatal("marshaling error: ", err)
48 | break
49 | }
50 |
51 | // Receive starting pos from server and add to chars to simulate
52 | you.X = recvMsg.X
53 | you.Y = recvMsg.Y
54 | chars = append(chars, you)
55 | isConnected = true
56 |
57 | // Last time we received an update about the world
58 | lastWorldUpdateTimer = time.Now()
59 |
60 | log.Printf("%s: received login data: %v\n", kind, recvMsg)
61 | case netmsg.MsgUpdatePlayer:
62 | recvMsg := &netmsg.UpdatePlayer{}
63 | err := recvMsg.Unmarshal(buf)
64 | if err != nil {
65 | log.Fatal("marshaling error: ", err)
66 | break
67 | }
68 | clientSlot := recvMsg.GetClientSlot()
69 | char := c.clientSlots[clientSlot]
70 | if char == nil {
71 | // Create char if they don't exist
72 | char = &Char{}
73 | chars = append(chars, char)
74 | c.clientSlots[clientSlot] = char
75 | }
76 | char.X = recvMsg.X
77 | char.Y = recvMsg.Y
78 | char.isKeyLeftPressed = recvMsg.IsKeyLeftPressed
79 | char.isKeyRightPressed = recvMsg.IsKeyRightPressed
80 | case netmsg.MsgDisconnectPlayer:
81 | recvMsg := &netmsg.DisconnectPlayer{}
82 | err := recvMsg.Unmarshal(buf)
83 | if err != nil {
84 | log.Fatal("marshaling error: ", err)
85 | break
86 | }
87 | clientSlot := recvMsg.GetClientSlot()
88 | char := c.clientSlots[clientSlot]
89 | if char == nil {
90 | continue
91 | }
92 | char.RemoveFromSimulation()
93 | c.clientSlots[clientSlot] = nil
94 | default:
95 | log.Printf("Unhandled netmsg kind: %s, with data: %v", kind.String(), buf)
96 | }
97 | case <-c.ChDisconnected():
98 | isConnected = false
99 | you.RemoveFromSimulation()
100 |
101 | log.Println("Lost connection to server")
102 | default:
103 | // no more messages
104 | break RecvMsgLoop
105 | }
106 | }
107 |
108 | //
109 | if you != nil && isConnected {
110 | elapsed := time.Since(lastWorldUpdateTimer)
111 | if elapsed > 15*time.Millisecond {
112 | lastWorldUpdateTimer = time.Now()
113 |
114 | // Send update data to server
115 | sendMsg := netmsg.UpdatePlayer{
116 | X: you.X,
117 | Y: you.Y,
118 | IsKeyLeftPressed: you.isKeyLeftPressed,
119 | IsKeyRightPressed: you.isKeyRightPressed,
120 | }
121 | data, err := proto.Marshal(&sendMsg)
122 | if err != nil {
123 | log.Fatal("client update: marshaling error: ", err)
124 | }
125 |
126 | // send update message to server
127 | packetData := make([]byte, 1, len(data)+1)
128 | packetData[0] = netmsg.MsgUpdatePlayer
129 | packetData = append(packetData, data...)
130 | client.SendMessage(packetData)
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/gameserver/client.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package gameserver
6 |
7 | import (
8 | "net/http"
9 | "time"
10 |
11 | "github.com/gorilla/websocket"
12 | )
13 |
14 | const (
15 | // Time allowed to write a message to the peer.
16 | writeWait = 1000 * time.Millisecond
17 |
18 | // Time allowed to read the next pong message from the peer.
19 | pongWait = 60 * time.Second
20 |
21 | // Send pings to peer with this period. Must be less than pongWait.
22 | pingPeriod = (pongWait * 9) / 10
23 |
24 | // Maximum message size allowed from peer.
25 | maxMessageSize = 128
26 | )
27 |
28 | var upgrader = websocket.Upgrader{
29 | ReadBufferSize: 1024,
30 | WriteBufferSize: 1024,
31 | CheckOrigin: func(r *http.Request) bool {
32 | // todo(Jake): Make sure this URL is validated.
33 | println("Client from URL: ", r.URL.String())
34 | return true
35 | },
36 | }
37 |
38 | type Message struct {
39 | client *Client
40 | data []byte
41 | }
42 |
43 | func (message *Message) Client() *Client { return message.client }
44 | func (message *Message) Data() []byte { return message.data }
45 |
46 | // Client is a middleman between the websocket connection and the hub.
47 | type Client struct {
48 | server *Server
49 |
50 | // The websocket connection.
51 | conn *websocket.Conn
52 |
53 | // Buffered channel of outbound messages.
54 | send chan []byte
55 |
56 | // Client slot
57 | clientSlot int32
58 |
59 | // Arbitrary data for user-code use. Store the related player entity, etc.
60 | data interface{}
61 | }
62 |
63 | func (c *Client) SetData(data interface{}) {
64 | c.data = data
65 | }
66 |
67 | func (c *Client) Data() interface{} {
68 | return c.data
69 | }
70 |
71 | func (c *Client) ClientSlot() int32 {
72 | return c.clientSlot
73 | }
74 |
75 | func (c *Client) SendMessage(message []byte) {
76 | c.send <- message
77 | }
78 |
79 | // readPump pumps messages from the websocket connection to the hub.
80 | //
81 | // The application runs readPump in a per-connection goroutine. The application
82 | // ensures that there is at most one reader on a connection by executing all
83 | // reads from this goroutine.
84 | func (c *Client) readPump() {
85 | c.conn.SetReadLimit(maxMessageSize)
86 | c.conn.SetReadDeadline(time.Now().Add(pongWait))
87 | c.conn.SetPongHandler(func(string) error { c.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil })
88 | for {
89 | _, buf, err := c.conn.ReadMessage()
90 | if err != nil {
91 | if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
92 | println("websocket.IsUnexpectedCloseError: " + err.Error())
93 | }
94 | break
95 | }
96 | //message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1))
97 | c.server.broadcast <- Message{
98 | client: c,
99 | data: buf,
100 | }
101 | }
102 | c.server.unregister <- c
103 | c.conn.Close()
104 | }
105 |
106 | // writePump pumps messages from the hub to the websocket connection.
107 | //
108 | // A goroutine running writePump is started for each connection. The
109 | // application ensures that there is at most one writer to a connection by
110 | // executing all writes from this goroutine.
111 | func (c *Client) writePump() {
112 | ticker := time.NewTicker(pingPeriod)
113 | defer func() {
114 | ticker.Stop()
115 | c.conn.Close()
116 | }()
117 | for {
118 | select {
119 | case message, ok := <-c.send:
120 | c.conn.SetWriteDeadline(time.Now().Add(writeWait))
121 | if !ok {
122 | // The server closed the channel.
123 | c.conn.WriteMessage(websocket.CloseMessage, []byte{})
124 | return
125 | }
126 |
127 | w, err := c.conn.NextWriter(websocket.BinaryMessage)
128 | if err != nil {
129 | return
130 | }
131 | w.Write(message)
132 |
133 | if err := w.Close(); err != nil {
134 | println("Client disconnected. Err = ", err)
135 | return
136 | }
137 | case <-ticker.C:
138 | c.conn.SetWriteDeadline(time.Now().Add(writeWait))
139 | if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
140 | return
141 | }
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "math/rand"
6 | "time"
7 |
8 | "github.com/gogo/protobuf/proto"
9 | "github.com/silbinarywolf/networkplatformer-go/gameserver"
10 | "github.com/silbinarywolf/networkplatformer-go/netmsg"
11 | )
12 |
13 | var (
14 | server *Server
15 | )
16 |
17 | type Server struct {
18 | *gameserver.Server
19 | }
20 |
21 | func NewServer() *Server {
22 | server := &Server{
23 | Server: gameserver.NewServer("/abgame"),
24 | }
25 | return server
26 | }
27 |
28 | func (s *Server) Update() {
29 | RecvMsgLoop:
30 | for {
31 | select {
32 | case client := <-s.ChRegister():
33 | clientSlot := int32(client.ClientSlot())
34 |
35 | // Create player instance
36 | char := &Char{
37 | X: float64(rand.Int63n(90) + 130),
38 | Y: float64(380),
39 | }
40 |
41 | // Create client
42 | s.RegisterClient(client, char)
43 |
44 | // Add client to simulation
45 | chars = append(chars, char)
46 |
47 | // Send connection response
48 | {
49 | sendMsg := netmsg.ConnectResponse{
50 | ClientSlot: clientSlot,
51 | X: char.X,
52 | Y: char.Y,
53 | }
54 | data, err := proto.Marshal(&sendMsg)
55 | if err != nil {
56 | log.Fatal("client connect: marshaling error: ", err)
57 | }
58 |
59 | // Send to connecting player their information
60 | packetData := make([]byte, 1, len(data)+1)
61 | packetData[0] = netmsg.MsgConnectResponse
62 | packetData = append(packetData, data...)
63 | client.SendMessage(packetData)
64 | }
65 | case client := <-s.ChUnregister():
66 | if s.RemoveClient(client) {
67 | char := client.Data().(*Char)
68 | char.RemoveFromSimulation()
69 |
70 | log.Printf("client #%d disconnected", client.ClientSlot())
71 |
72 | // Tell clients player disconnected
73 | sendMsg := netmsg.DisconnectPlayer{
74 | ClientSlot: int32(client.ClientSlot()),
75 | }
76 | data, err := proto.Marshal(&sendMsg)
77 | if err != nil {
78 | log.Fatal("client connect: marshaling error: ", err)
79 | }
80 |
81 | // Send disconnected player
82 | packetData := make([]byte, 1, len(data)+1)
83 | packetData[0] = netmsg.MsgDisconnectPlayer
84 | packetData = append(packetData, data...)
85 | for otherClient := range s.GetClients() {
86 | if otherClient == client {
87 | continue
88 | }
89 | otherClient.SendMessage(packetData)
90 | }
91 | }
92 | case message := <-s.ChBroadcast():
93 | var (
94 | client = message.Client()
95 | buf = message.Data()
96 | )
97 | kind := netmsg.Kind(buf[0])
98 | buf = buf[1:]
99 | switch kind {
100 | case netmsg.MsgUpdatePlayer:
101 | // Receive update
102 | recvMsg := &netmsg.UpdatePlayer{}
103 | err := recvMsg.Unmarshal(buf)
104 | if err != nil {
105 | log.Fatal("unmarshaling error: ", err)
106 | break
107 | }
108 | char := client.Data().(*Char)
109 | char.X = recvMsg.X
110 | char.Y = recvMsg.Y
111 | char.isKeyLeftPressed = recvMsg.IsKeyLeftPressed
112 | char.isKeyRightPressed = recvMsg.IsKeyRightPressed
113 | default:
114 | log.Printf("Unhandled netmsg kind: %s, with data: %v\n", kind.String(), buf)
115 | }
116 | default:
117 | // no-op
118 | break RecvMsgLoop
119 | }
120 | }
121 |
122 | // Send updates to clients
123 | for client := range s.GetClients() {
124 | char := client.Data().(*Char)
125 | elapsed := time.Since(char.lastUpdatedTimer)
126 | if elapsed > 15*time.Millisecond {
127 | // Reset countdown till next update
128 | char.lastUpdatedTimer = time.Now()
129 |
130 | // Send update to other players
131 | sendMsg := netmsg.UpdatePlayer{
132 | ClientSlot: int32(client.ClientSlot()),
133 | X: char.X,
134 | Y: char.Y,
135 | IsKeyLeftPressed: char.isKeyLeftPressed,
136 | IsKeyRightPressed: char.isKeyRightPressed,
137 | }
138 | data, err := proto.Marshal(&sendMsg)
139 | if err != nil {
140 | log.Fatal("client update: marshaling error: ", err)
141 | }
142 | packetData := make([]byte, 1, len(data)+1)
143 | packetData[0] = netmsg.MsgUpdatePlayer
144 | packetData = append(packetData, data...)
145 | for otherClient := range s.GetClients() {
146 | if otherClient == client {
147 | continue
148 | }
149 | otherClient.SendMessage(packetData)
150 | }
151 | }
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 The Ebiten Authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package main
16 |
17 | import (
18 | "bytes"
19 | "fmt"
20 | "image"
21 | _ "image/png"
22 | "os"
23 | "time"
24 |
25 | "github.com/hajimehoshi/ebiten"
26 | "github.com/hajimehoshi/ebiten/ebitenutil"
27 | rplatformer "github.com/hajimehoshi/ebiten/examples/resources/images/platformer"
28 | )
29 |
30 | const (
31 | // Settings
32 | screenWidth = 1024
33 | screenHeight = 512
34 | )
35 |
36 | var (
37 | leftSprite *ebiten.Image
38 | rightSprite *ebiten.Image
39 | idleSprite *ebiten.Image
40 | backgroundImage *ebiten.Image
41 | )
42 |
43 | func init() {
44 | // Preload images
45 | img, _, err := image.Decode(bytes.NewReader(rplatformer.Right_png))
46 | if err != nil {
47 | panic(err)
48 | }
49 | rightSprite, _ = ebiten.NewImageFromImage(img, ebiten.FilterDefault)
50 |
51 | img, _, err = image.Decode(bytes.NewReader(rplatformer.Left_png))
52 | if err != nil {
53 | panic(err)
54 | }
55 | leftSprite, _ = ebiten.NewImageFromImage(img, ebiten.FilterDefault)
56 |
57 | img, _, err = image.Decode(bytes.NewReader(rplatformer.MainChar_png))
58 | if err != nil {
59 | panic(err)
60 | }
61 | idleSprite, _ = ebiten.NewImageFromImage(img, ebiten.FilterDefault)
62 |
63 | img, _, err = image.Decode(bytes.NewReader(rplatformer.Background_png))
64 | if err != nil {
65 | panic(err)
66 | }
67 | backgroundImage, _ = ebiten.NewImageFromImage(img, ebiten.FilterDefault)
68 | }
69 |
70 | type Char struct {
71 | X float64
72 | Y float64
73 | sprite *ebiten.Image
74 | isKeyLeftPressed bool
75 | isKeyRightPressed bool
76 |
77 | // used by server only
78 | lastUpdatedTimer time.Time
79 | }
80 |
81 | func (c *Char) RemoveFromSimulation() {
82 | // Unordered remove
83 | for i, char := range chars {
84 | if char == c {
85 | chars[i] = chars[len(chars)-1] // Replace it with the last one.
86 | chars = chars[:len(chars)-1] // delete last element
87 | return
88 | }
89 | }
90 | }
91 |
92 | var (
93 | you *Char = &Char{
94 | X: 50,
95 | Y: 380,
96 | }
97 | chars []*Char = make([]*Char, 0, 256)
98 | )
99 |
100 | func update(screen *ebiten.Image) error {
101 | // Read/write network information
102 | if server != nil {
103 | server.Update()
104 | }
105 | if client != nil {
106 | client.Update()
107 | }
108 |
109 | // Controls
110 | if you != nil {
111 | you.isKeyLeftPressed = false
112 | you.isKeyRightPressed = false
113 | if ebiten.IsKeyPressed(ebiten.KeyA) || ebiten.IsKeyPressed(ebiten.KeyLeft) {
114 | you.isKeyLeftPressed = true
115 | } else if ebiten.IsKeyPressed(ebiten.KeyD) || ebiten.IsKeyPressed(ebiten.KeyRight) {
116 | you.isKeyRightPressed = true
117 | }
118 | }
119 |
120 | // Simulate
121 | for _, char := range chars {
122 | char.sprite = idleSprite
123 | if char.isKeyLeftPressed {
124 | // Selects preloaded sprite
125 | char.sprite = leftSprite
126 | // Moves character 3px right
127 | char.X -= 3
128 | } else if char.isKeyRightPressed {
129 | // Selects preloaded sprite
130 | char.sprite = rightSprite
131 | // Moves character 3px left
132 | char.X += 3
133 | }
134 | }
135 |
136 | if ebiten.IsRunningSlowly() {
137 | return nil
138 | }
139 |
140 | // Draws Background Image
141 | op := &ebiten.DrawImageOptions{}
142 | op.GeoM.Scale(0.5, 0.5)
143 | screen.DrawImage(backgroundImage, op)
144 |
145 | // Draws selected sprite image
146 | for _, char := range chars {
147 | if char.sprite == nil {
148 | continue
149 | }
150 | op = &ebiten.DrawImageOptions{}
151 | op.GeoM.Scale(0.5, 0.5)
152 | op.GeoM.Translate(char.X, char.Y)
153 | screen.DrawImage(char.sprite, op)
154 | }
155 |
156 | // FPS counter
157 | fps := fmt.Sprintf("FPS: %f", ebiten.CurrentFPS())
158 | ebitenutil.DebugPrint(screen, fps)
159 |
160 | return nil
161 | }
162 |
163 | func main() {
164 | // Setup network
165 | isServer := false
166 | if len(os.Args) > 1 {
167 | firstArg := os.Args[1]
168 | if firstArg == "--server" {
169 | isServer = true
170 | }
171 | }
172 | if isServer {
173 | server = NewServer()
174 | go server.Listen()
175 | } else {
176 | client = NewClient()
177 | err := client.Dial("localhost:8080")
178 | if err != nil {
179 | panic(err)
180 | }
181 | go client.Listen()
182 | }
183 |
184 | // This is required so the server can run when the window isn't focused.
185 | ebiten.SetRunnableInBackground(true)
186 |
187 | if err := ebiten.Run(update, screenWidth, screenHeight, 1, "Platformer (Ebiten Demo)"); err != nil {
188 | panic(err)
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/netmsg/disconnect.pb.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-gogo. DO NOT EDIT.
2 | // source: disconnect.proto
3 |
4 | /*
5 | Package netmsg is a generated protocol buffer package.
6 |
7 | It is generated from these files:
8 | disconnect.proto
9 |
10 | It has these top-level messages:
11 | DisconnectPlayer
12 | */
13 | package netmsg
14 |
15 | import proto "github.com/golang/protobuf/proto"
16 | import fmt "fmt"
17 | import math "math"
18 |
19 | import io "io"
20 |
21 | // Reference imports to suppress errors if they are not otherwise used.
22 | var _ = proto.Marshal
23 | var _ = fmt.Errorf
24 | var _ = math.Inf
25 |
26 | // This is a compile-time assertion to ensure that this generated file
27 | // is compatible with the proto package it is being compiled against.
28 | // A compilation error at this line likely means your copy of the
29 | // proto package needs to be updated.
30 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
31 |
32 | type DisconnectPlayer struct {
33 | ClientSlot int32 `protobuf:"varint,1,opt,name=ClientSlot,proto3" json:"ClientSlot,omitempty"`
34 | }
35 |
36 | func (m *DisconnectPlayer) Reset() { *m = DisconnectPlayer{} }
37 | func (m *DisconnectPlayer) String() string { return proto.CompactTextString(m) }
38 | func (*DisconnectPlayer) ProtoMessage() {}
39 | func (*DisconnectPlayer) Descriptor() ([]byte, []int) { return fileDescriptorDisconnect, []int{0} }
40 |
41 | func (m *DisconnectPlayer) GetClientSlot() int32 {
42 | if m != nil {
43 | return m.ClientSlot
44 | }
45 | return 0
46 | }
47 |
48 | func init() {
49 | proto.RegisterType((*DisconnectPlayer)(nil), "netmsg.DisconnectPlayer")
50 | }
51 | func (m *DisconnectPlayer) Marshal() (dAtA []byte, err error) {
52 | size := m.Size()
53 | dAtA = make([]byte, size)
54 | n, err := m.MarshalTo(dAtA)
55 | if err != nil {
56 | return nil, err
57 | }
58 | return dAtA[:n], nil
59 | }
60 |
61 | func (m *DisconnectPlayer) MarshalTo(dAtA []byte) (int, error) {
62 | var i int
63 | _ = i
64 | var l int
65 | _ = l
66 | if m.ClientSlot != 0 {
67 | dAtA[i] = 0x8
68 | i++
69 | i = encodeVarintDisconnect(dAtA, i, uint64(m.ClientSlot))
70 | }
71 | return i, nil
72 | }
73 |
74 | func encodeVarintDisconnect(dAtA []byte, offset int, v uint64) int {
75 | for v >= 1<<7 {
76 | dAtA[offset] = uint8(v&0x7f | 0x80)
77 | v >>= 7
78 | offset++
79 | }
80 | dAtA[offset] = uint8(v)
81 | return offset + 1
82 | }
83 | func (m *DisconnectPlayer) Size() (n int) {
84 | var l int
85 | _ = l
86 | if m.ClientSlot != 0 {
87 | n += 1 + sovDisconnect(uint64(m.ClientSlot))
88 | }
89 | return n
90 | }
91 |
92 | func sovDisconnect(x uint64) (n int) {
93 | for {
94 | n++
95 | x >>= 7
96 | if x == 0 {
97 | break
98 | }
99 | }
100 | return n
101 | }
102 | func sozDisconnect(x uint64) (n int) {
103 | return sovDisconnect(uint64((x << 1) ^ uint64((int64(x) >> 63))))
104 | }
105 | func (m *DisconnectPlayer) Unmarshal(dAtA []byte) error {
106 | l := len(dAtA)
107 | iNdEx := 0
108 | for iNdEx < l {
109 | preIndex := iNdEx
110 | var wire uint64
111 | for shift := uint(0); ; shift += 7 {
112 | if shift >= 64 {
113 | return ErrIntOverflowDisconnect
114 | }
115 | if iNdEx >= l {
116 | return io.ErrUnexpectedEOF
117 | }
118 | b := dAtA[iNdEx]
119 | iNdEx++
120 | wire |= (uint64(b) & 0x7F) << shift
121 | if b < 0x80 {
122 | break
123 | }
124 | }
125 | fieldNum := int32(wire >> 3)
126 | wireType := int(wire & 0x7)
127 | if wireType == 4 {
128 | return fmt.Errorf("proto: DisconnectPlayer: wiretype end group for non-group")
129 | }
130 | if fieldNum <= 0 {
131 | return fmt.Errorf("proto: DisconnectPlayer: illegal tag %d (wire type %d)", fieldNum, wire)
132 | }
133 | switch fieldNum {
134 | case 1:
135 | if wireType != 0 {
136 | return fmt.Errorf("proto: wrong wireType = %d for field ClientSlot", wireType)
137 | }
138 | m.ClientSlot = 0
139 | for shift := uint(0); ; shift += 7 {
140 | if shift >= 64 {
141 | return ErrIntOverflowDisconnect
142 | }
143 | if iNdEx >= l {
144 | return io.ErrUnexpectedEOF
145 | }
146 | b := dAtA[iNdEx]
147 | iNdEx++
148 | m.ClientSlot |= (int32(b) & 0x7F) << shift
149 | if b < 0x80 {
150 | break
151 | }
152 | }
153 | default:
154 | iNdEx = preIndex
155 | skippy, err := skipDisconnect(dAtA[iNdEx:])
156 | if err != nil {
157 | return err
158 | }
159 | if skippy < 0 {
160 | return ErrInvalidLengthDisconnect
161 | }
162 | if (iNdEx + skippy) > l {
163 | return io.ErrUnexpectedEOF
164 | }
165 | iNdEx += skippy
166 | }
167 | }
168 |
169 | if iNdEx > l {
170 | return io.ErrUnexpectedEOF
171 | }
172 | return nil
173 | }
174 | func skipDisconnect(dAtA []byte) (n int, err error) {
175 | l := len(dAtA)
176 | iNdEx := 0
177 | for iNdEx < l {
178 | var wire uint64
179 | for shift := uint(0); ; shift += 7 {
180 | if shift >= 64 {
181 | return 0, ErrIntOverflowDisconnect
182 | }
183 | if iNdEx >= l {
184 | return 0, io.ErrUnexpectedEOF
185 | }
186 | b := dAtA[iNdEx]
187 | iNdEx++
188 | wire |= (uint64(b) & 0x7F) << shift
189 | if b < 0x80 {
190 | break
191 | }
192 | }
193 | wireType := int(wire & 0x7)
194 | switch wireType {
195 | case 0:
196 | for shift := uint(0); ; shift += 7 {
197 | if shift >= 64 {
198 | return 0, ErrIntOverflowDisconnect
199 | }
200 | if iNdEx >= l {
201 | return 0, io.ErrUnexpectedEOF
202 | }
203 | iNdEx++
204 | if dAtA[iNdEx-1] < 0x80 {
205 | break
206 | }
207 | }
208 | return iNdEx, nil
209 | case 1:
210 | iNdEx += 8
211 | return iNdEx, nil
212 | case 2:
213 | var length int
214 | for shift := uint(0); ; shift += 7 {
215 | if shift >= 64 {
216 | return 0, ErrIntOverflowDisconnect
217 | }
218 | if iNdEx >= l {
219 | return 0, io.ErrUnexpectedEOF
220 | }
221 | b := dAtA[iNdEx]
222 | iNdEx++
223 | length |= (int(b) & 0x7F) << shift
224 | if b < 0x80 {
225 | break
226 | }
227 | }
228 | iNdEx += length
229 | if length < 0 {
230 | return 0, ErrInvalidLengthDisconnect
231 | }
232 | return iNdEx, nil
233 | case 3:
234 | for {
235 | var innerWire uint64
236 | var start int = iNdEx
237 | for shift := uint(0); ; shift += 7 {
238 | if shift >= 64 {
239 | return 0, ErrIntOverflowDisconnect
240 | }
241 | if iNdEx >= l {
242 | return 0, io.ErrUnexpectedEOF
243 | }
244 | b := dAtA[iNdEx]
245 | iNdEx++
246 | innerWire |= (uint64(b) & 0x7F) << shift
247 | if b < 0x80 {
248 | break
249 | }
250 | }
251 | innerWireType := int(innerWire & 0x7)
252 | if innerWireType == 4 {
253 | break
254 | }
255 | next, err := skipDisconnect(dAtA[start:])
256 | if err != nil {
257 | return 0, err
258 | }
259 | iNdEx = start + next
260 | }
261 | return iNdEx, nil
262 | case 4:
263 | return iNdEx, nil
264 | case 5:
265 | iNdEx += 4
266 | return iNdEx, nil
267 | default:
268 | return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
269 | }
270 | }
271 | panic("unreachable")
272 | }
273 |
274 | var (
275 | ErrInvalidLengthDisconnect = fmt.Errorf("proto: negative length found during unmarshaling")
276 | ErrIntOverflowDisconnect = fmt.Errorf("proto: integer overflow")
277 | )
278 |
279 | func init() { proto.RegisterFile("disconnect.proto", fileDescriptorDisconnect) }
280 |
281 | var fileDescriptorDisconnect = []byte{
282 | // 110 bytes of a gzipped FileDescriptorProto
283 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x48, 0xc9, 0x2c, 0x4e,
284 | 0xce, 0xcf, 0xcb, 0x4b, 0x4d, 0x2e, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0xcb, 0x4b,
285 | 0x2d, 0xc9, 0x2d, 0x4e, 0x57, 0x32, 0xe2, 0x12, 0x70, 0x81, 0xcb, 0x05, 0xe4, 0x24, 0x56, 0xa6,
286 | 0x16, 0x09, 0xc9, 0x71, 0x71, 0x39, 0xe7, 0x64, 0xa6, 0xe6, 0x95, 0x04, 0xe7, 0xe4, 0x97, 0x48,
287 | 0x30, 0x2a, 0x30, 0x6a, 0xb0, 0x06, 0x21, 0x89, 0x38, 0x09, 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1,
288 | 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x33, 0x1e, 0xcb, 0x31, 0x24, 0xb1, 0x81, 0x0d, 0x35,
289 | 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xac, 0xa1, 0xcd, 0x84, 0x68, 0x00, 0x00, 0x00,
290 | }
291 |
--------------------------------------------------------------------------------
/netmsg/connect_response.pb.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-gogo. DO NOT EDIT.
2 | // source: connect_response.proto
3 |
4 | /*
5 | Package netmsg is a generated protocol buffer package.
6 |
7 | It is generated from these files:
8 | connect_response.proto
9 |
10 | It has these top-level messages:
11 | ConnectResponse
12 | */
13 | package netmsg
14 |
15 | import proto "github.com/golang/protobuf/proto"
16 | import fmt "fmt"
17 | import math "math"
18 |
19 | import binary "encoding/binary"
20 |
21 | import io "io"
22 |
23 | // Reference imports to suppress errors if they are not otherwise used.
24 | var _ = proto.Marshal
25 | var _ = fmt.Errorf
26 | var _ = math.Inf
27 |
28 | // This is a compile-time assertion to ensure that this generated file
29 | // is compatible with the proto package it is being compiled against.
30 | // A compilation error at this line likely means your copy of the
31 | // proto package needs to be updated.
32 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
33 |
34 | type ConnectResponse struct {
35 | ClientSlot int32 `protobuf:"varint,1,opt,name=ClientSlot,proto3" json:"ClientSlot,omitempty"`
36 | X float64 `protobuf:"fixed64,2,opt,name=X,proto3" json:"X,omitempty"`
37 | Y float64 `protobuf:"fixed64,3,opt,name=Y,proto3" json:"Y,omitempty"`
38 | }
39 |
40 | func (m *ConnectResponse) Reset() { *m = ConnectResponse{} }
41 | func (m *ConnectResponse) String() string { return proto.CompactTextString(m) }
42 | func (*ConnectResponse) ProtoMessage() {}
43 | func (*ConnectResponse) Descriptor() ([]byte, []int) { return fileDescriptorConnectResponse, []int{0} }
44 |
45 | func (m *ConnectResponse) GetClientSlot() int32 {
46 | if m != nil {
47 | return m.ClientSlot
48 | }
49 | return 0
50 | }
51 |
52 | func (m *ConnectResponse) GetX() float64 {
53 | if m != nil {
54 | return m.X
55 | }
56 | return 0
57 | }
58 |
59 | func (m *ConnectResponse) GetY() float64 {
60 | if m != nil {
61 | return m.Y
62 | }
63 | return 0
64 | }
65 |
66 | func init() {
67 | proto.RegisterType((*ConnectResponse)(nil), "netmsg.ConnectResponse")
68 | }
69 | func (m *ConnectResponse) Marshal() (dAtA []byte, err error) {
70 | size := m.Size()
71 | dAtA = make([]byte, size)
72 | n, err := m.MarshalTo(dAtA)
73 | if err != nil {
74 | return nil, err
75 | }
76 | return dAtA[:n], nil
77 | }
78 |
79 | func (m *ConnectResponse) MarshalTo(dAtA []byte) (int, error) {
80 | var i int
81 | _ = i
82 | var l int
83 | _ = l
84 | if m.ClientSlot != 0 {
85 | dAtA[i] = 0x8
86 | i++
87 | i = encodeVarintConnectResponse(dAtA, i, uint64(m.ClientSlot))
88 | }
89 | if m.X != 0 {
90 | dAtA[i] = 0x11
91 | i++
92 | binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.X))))
93 | i += 8
94 | }
95 | if m.Y != 0 {
96 | dAtA[i] = 0x19
97 | i++
98 | binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Y))))
99 | i += 8
100 | }
101 | return i, nil
102 | }
103 |
104 | func encodeVarintConnectResponse(dAtA []byte, offset int, v uint64) int {
105 | for v >= 1<<7 {
106 | dAtA[offset] = uint8(v&0x7f | 0x80)
107 | v >>= 7
108 | offset++
109 | }
110 | dAtA[offset] = uint8(v)
111 | return offset + 1
112 | }
113 | func (m *ConnectResponse) Size() (n int) {
114 | var l int
115 | _ = l
116 | if m.ClientSlot != 0 {
117 | n += 1 + sovConnectResponse(uint64(m.ClientSlot))
118 | }
119 | if m.X != 0 {
120 | n += 9
121 | }
122 | if m.Y != 0 {
123 | n += 9
124 | }
125 | return n
126 | }
127 |
128 | func sovConnectResponse(x uint64) (n int) {
129 | for {
130 | n++
131 | x >>= 7
132 | if x == 0 {
133 | break
134 | }
135 | }
136 | return n
137 | }
138 | func sozConnectResponse(x uint64) (n int) {
139 | return sovConnectResponse(uint64((x << 1) ^ uint64((int64(x) >> 63))))
140 | }
141 | func (m *ConnectResponse) Unmarshal(dAtA []byte) error {
142 | l := len(dAtA)
143 | iNdEx := 0
144 | for iNdEx < l {
145 | preIndex := iNdEx
146 | var wire uint64
147 | for shift := uint(0); ; shift += 7 {
148 | if shift >= 64 {
149 | return ErrIntOverflowConnectResponse
150 | }
151 | if iNdEx >= l {
152 | return io.ErrUnexpectedEOF
153 | }
154 | b := dAtA[iNdEx]
155 | iNdEx++
156 | wire |= (uint64(b) & 0x7F) << shift
157 | if b < 0x80 {
158 | break
159 | }
160 | }
161 | fieldNum := int32(wire >> 3)
162 | wireType := int(wire & 0x7)
163 | if wireType == 4 {
164 | return fmt.Errorf("proto: ConnectResponse: wiretype end group for non-group")
165 | }
166 | if fieldNum <= 0 {
167 | return fmt.Errorf("proto: ConnectResponse: illegal tag %d (wire type %d)", fieldNum, wire)
168 | }
169 | switch fieldNum {
170 | case 1:
171 | if wireType != 0 {
172 | return fmt.Errorf("proto: wrong wireType = %d for field ClientSlot", wireType)
173 | }
174 | m.ClientSlot = 0
175 | for shift := uint(0); ; shift += 7 {
176 | if shift >= 64 {
177 | return ErrIntOverflowConnectResponse
178 | }
179 | if iNdEx >= l {
180 | return io.ErrUnexpectedEOF
181 | }
182 | b := dAtA[iNdEx]
183 | iNdEx++
184 | m.ClientSlot |= (int32(b) & 0x7F) << shift
185 | if b < 0x80 {
186 | break
187 | }
188 | }
189 | case 2:
190 | if wireType != 1 {
191 | return fmt.Errorf("proto: wrong wireType = %d for field X", wireType)
192 | }
193 | var v uint64
194 | if (iNdEx + 8) > l {
195 | return io.ErrUnexpectedEOF
196 | }
197 | v = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))
198 | iNdEx += 8
199 | m.X = float64(math.Float64frombits(v))
200 | case 3:
201 | if wireType != 1 {
202 | return fmt.Errorf("proto: wrong wireType = %d for field Y", wireType)
203 | }
204 | var v uint64
205 | if (iNdEx + 8) > l {
206 | return io.ErrUnexpectedEOF
207 | }
208 | v = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))
209 | iNdEx += 8
210 | m.Y = float64(math.Float64frombits(v))
211 | default:
212 | iNdEx = preIndex
213 | skippy, err := skipConnectResponse(dAtA[iNdEx:])
214 | if err != nil {
215 | return err
216 | }
217 | if skippy < 0 {
218 | return ErrInvalidLengthConnectResponse
219 | }
220 | if (iNdEx + skippy) > l {
221 | return io.ErrUnexpectedEOF
222 | }
223 | iNdEx += skippy
224 | }
225 | }
226 |
227 | if iNdEx > l {
228 | return io.ErrUnexpectedEOF
229 | }
230 | return nil
231 | }
232 | func skipConnectResponse(dAtA []byte) (n int, err error) {
233 | l := len(dAtA)
234 | iNdEx := 0
235 | for iNdEx < l {
236 | var wire uint64
237 | for shift := uint(0); ; shift += 7 {
238 | if shift >= 64 {
239 | return 0, ErrIntOverflowConnectResponse
240 | }
241 | if iNdEx >= l {
242 | return 0, io.ErrUnexpectedEOF
243 | }
244 | b := dAtA[iNdEx]
245 | iNdEx++
246 | wire |= (uint64(b) & 0x7F) << shift
247 | if b < 0x80 {
248 | break
249 | }
250 | }
251 | wireType := int(wire & 0x7)
252 | switch wireType {
253 | case 0:
254 | for shift := uint(0); ; shift += 7 {
255 | if shift >= 64 {
256 | return 0, ErrIntOverflowConnectResponse
257 | }
258 | if iNdEx >= l {
259 | return 0, io.ErrUnexpectedEOF
260 | }
261 | iNdEx++
262 | if dAtA[iNdEx-1] < 0x80 {
263 | break
264 | }
265 | }
266 | return iNdEx, nil
267 | case 1:
268 | iNdEx += 8
269 | return iNdEx, nil
270 | case 2:
271 | var length int
272 | for shift := uint(0); ; shift += 7 {
273 | if shift >= 64 {
274 | return 0, ErrIntOverflowConnectResponse
275 | }
276 | if iNdEx >= l {
277 | return 0, io.ErrUnexpectedEOF
278 | }
279 | b := dAtA[iNdEx]
280 | iNdEx++
281 | length |= (int(b) & 0x7F) << shift
282 | if b < 0x80 {
283 | break
284 | }
285 | }
286 | iNdEx += length
287 | if length < 0 {
288 | return 0, ErrInvalidLengthConnectResponse
289 | }
290 | return iNdEx, nil
291 | case 3:
292 | for {
293 | var innerWire uint64
294 | var start int = iNdEx
295 | for shift := uint(0); ; shift += 7 {
296 | if shift >= 64 {
297 | return 0, ErrIntOverflowConnectResponse
298 | }
299 | if iNdEx >= l {
300 | return 0, io.ErrUnexpectedEOF
301 | }
302 | b := dAtA[iNdEx]
303 | iNdEx++
304 | innerWire |= (uint64(b) & 0x7F) << shift
305 | if b < 0x80 {
306 | break
307 | }
308 | }
309 | innerWireType := int(innerWire & 0x7)
310 | if innerWireType == 4 {
311 | break
312 | }
313 | next, err := skipConnectResponse(dAtA[start:])
314 | if err != nil {
315 | return 0, err
316 | }
317 | iNdEx = start + next
318 | }
319 | return iNdEx, nil
320 | case 4:
321 | return iNdEx, nil
322 | case 5:
323 | iNdEx += 4
324 | return iNdEx, nil
325 | default:
326 | return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
327 | }
328 | }
329 | panic("unreachable")
330 | }
331 |
332 | var (
333 | ErrInvalidLengthConnectResponse = fmt.Errorf("proto: negative length found during unmarshaling")
334 | ErrIntOverflowConnectResponse = fmt.Errorf("proto: integer overflow")
335 | )
336 |
337 | func init() { proto.RegisterFile("connect_response.proto", fileDescriptorConnectResponse) }
338 |
339 | var fileDescriptorConnectResponse = []byte{
340 | // 135 bytes of a gzipped FileDescriptorProto
341 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4b, 0xce, 0xcf, 0xcb,
342 | 0x4b, 0x4d, 0x2e, 0x89, 0x2f, 0x4a, 0x2d, 0x2e, 0xc8, 0xcf, 0x2b, 0x4e, 0xd5, 0x2b, 0x28, 0xca,
343 | 0x2f, 0xc9, 0x17, 0x62, 0xcb, 0x4b, 0x2d, 0xc9, 0x2d, 0x4e, 0x57, 0xf2, 0xe5, 0xe2, 0x77, 0x86,
344 | 0xa8, 0x08, 0x82, 0x2a, 0x10, 0x92, 0xe3, 0xe2, 0x72, 0xce, 0xc9, 0x4c, 0xcd, 0x2b, 0x09, 0xce,
345 | 0xc9, 0x2f, 0x91, 0x60, 0x54, 0x60, 0xd4, 0x60, 0x0d, 0x42, 0x12, 0x11, 0xe2, 0xe1, 0x62, 0x8c,
346 | 0x90, 0x60, 0x52, 0x60, 0xd4, 0x60, 0x0c, 0x62, 0x8c, 0x00, 0xf1, 0x22, 0x25, 0x98, 0x21, 0xbc,
347 | 0x48, 0x27, 0x81, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71,
348 | 0xc6, 0x63, 0x39, 0x86, 0x24, 0x36, 0xb0, 0x7d, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03,
349 | 0x94, 0x49, 0x55, 0x89, 0x00, 0x00, 0x00,
350 | }
351 |
--------------------------------------------------------------------------------
/netmsg/update_player.pb.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-gogo. DO NOT EDIT.
2 | // source: update_player.proto
3 |
4 | /*
5 | Package netmsg is a generated protocol buffer package.
6 |
7 | It is generated from these files:
8 | update_player.proto
9 |
10 | It has these top-level messages:
11 | UpdatePlayer
12 | */
13 | package netmsg
14 |
15 | import proto "github.com/golang/protobuf/proto"
16 | import fmt "fmt"
17 | import math "math"
18 |
19 | import binary "encoding/binary"
20 |
21 | import io "io"
22 |
23 | // Reference imports to suppress errors if they are not otherwise used.
24 | var _ = proto.Marshal
25 | var _ = fmt.Errorf
26 | var _ = math.Inf
27 |
28 | // This is a compile-time assertion to ensure that this generated file
29 | // is compatible with the proto package it is being compiled against.
30 | // A compilation error at this line likely means your copy of the
31 | // proto package needs to be updated.
32 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
33 |
34 | type UpdatePlayer struct {
35 | ClientSlot int32 `protobuf:"varint,1,opt,name=ClientSlot,proto3" json:"ClientSlot,omitempty"`
36 | X float64 `protobuf:"fixed64,2,opt,name=X,proto3" json:"X,omitempty"`
37 | Y float64 `protobuf:"fixed64,3,opt,name=Y,proto3" json:"Y,omitempty"`
38 | IsKeyLeftPressed bool `protobuf:"varint,4,opt,name=IsKeyLeftPressed,proto3" json:"IsKeyLeftPressed,omitempty"`
39 | IsKeyRightPressed bool `protobuf:"varint,5,opt,name=IsKeyRightPressed,proto3" json:"IsKeyRightPressed,omitempty"`
40 | }
41 |
42 | func (m *UpdatePlayer) Reset() { *m = UpdatePlayer{} }
43 | func (m *UpdatePlayer) String() string { return proto.CompactTextString(m) }
44 | func (*UpdatePlayer) ProtoMessage() {}
45 | func (*UpdatePlayer) Descriptor() ([]byte, []int) { return fileDescriptorUpdatePlayer, []int{0} }
46 |
47 | func (m *UpdatePlayer) GetClientSlot() int32 {
48 | if m != nil {
49 | return m.ClientSlot
50 | }
51 | return 0
52 | }
53 |
54 | func (m *UpdatePlayer) GetX() float64 {
55 | if m != nil {
56 | return m.X
57 | }
58 | return 0
59 | }
60 |
61 | func (m *UpdatePlayer) GetY() float64 {
62 | if m != nil {
63 | return m.Y
64 | }
65 | return 0
66 | }
67 |
68 | func (m *UpdatePlayer) GetIsKeyLeftPressed() bool {
69 | if m != nil {
70 | return m.IsKeyLeftPressed
71 | }
72 | return false
73 | }
74 |
75 | func (m *UpdatePlayer) GetIsKeyRightPressed() bool {
76 | if m != nil {
77 | return m.IsKeyRightPressed
78 | }
79 | return false
80 | }
81 |
82 | func init() {
83 | proto.RegisterType((*UpdatePlayer)(nil), "netmsg.UpdatePlayer")
84 | }
85 | func (m *UpdatePlayer) Marshal() (dAtA []byte, err error) {
86 | size := m.Size()
87 | dAtA = make([]byte, size)
88 | n, err := m.MarshalTo(dAtA)
89 | if err != nil {
90 | return nil, err
91 | }
92 | return dAtA[:n], nil
93 | }
94 |
95 | func (m *UpdatePlayer) MarshalTo(dAtA []byte) (int, error) {
96 | var i int
97 | _ = i
98 | var l int
99 | _ = l
100 | if m.ClientSlot != 0 {
101 | dAtA[i] = 0x8
102 | i++
103 | i = encodeVarintUpdatePlayer(dAtA, i, uint64(m.ClientSlot))
104 | }
105 | if m.X != 0 {
106 | dAtA[i] = 0x11
107 | i++
108 | binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.X))))
109 | i += 8
110 | }
111 | if m.Y != 0 {
112 | dAtA[i] = 0x19
113 | i++
114 | binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Y))))
115 | i += 8
116 | }
117 | if m.IsKeyLeftPressed {
118 | dAtA[i] = 0x20
119 | i++
120 | if m.IsKeyLeftPressed {
121 | dAtA[i] = 1
122 | } else {
123 | dAtA[i] = 0
124 | }
125 | i++
126 | }
127 | if m.IsKeyRightPressed {
128 | dAtA[i] = 0x28
129 | i++
130 | if m.IsKeyRightPressed {
131 | dAtA[i] = 1
132 | } else {
133 | dAtA[i] = 0
134 | }
135 | i++
136 | }
137 | return i, nil
138 | }
139 |
140 | func encodeVarintUpdatePlayer(dAtA []byte, offset int, v uint64) int {
141 | for v >= 1<<7 {
142 | dAtA[offset] = uint8(v&0x7f | 0x80)
143 | v >>= 7
144 | offset++
145 | }
146 | dAtA[offset] = uint8(v)
147 | return offset + 1
148 | }
149 | func (m *UpdatePlayer) Size() (n int) {
150 | var l int
151 | _ = l
152 | if m.ClientSlot != 0 {
153 | n += 1 + sovUpdatePlayer(uint64(m.ClientSlot))
154 | }
155 | if m.X != 0 {
156 | n += 9
157 | }
158 | if m.Y != 0 {
159 | n += 9
160 | }
161 | if m.IsKeyLeftPressed {
162 | n += 2
163 | }
164 | if m.IsKeyRightPressed {
165 | n += 2
166 | }
167 | return n
168 | }
169 |
170 | func sovUpdatePlayer(x uint64) (n int) {
171 | for {
172 | n++
173 | x >>= 7
174 | if x == 0 {
175 | break
176 | }
177 | }
178 | return n
179 | }
180 | func sozUpdatePlayer(x uint64) (n int) {
181 | return sovUpdatePlayer(uint64((x << 1) ^ uint64((int64(x) >> 63))))
182 | }
183 | func (m *UpdatePlayer) Unmarshal(dAtA []byte) error {
184 | l := len(dAtA)
185 | iNdEx := 0
186 | for iNdEx < l {
187 | preIndex := iNdEx
188 | var wire uint64
189 | for shift := uint(0); ; shift += 7 {
190 | if shift >= 64 {
191 | return ErrIntOverflowUpdatePlayer
192 | }
193 | if iNdEx >= l {
194 | return io.ErrUnexpectedEOF
195 | }
196 | b := dAtA[iNdEx]
197 | iNdEx++
198 | wire |= (uint64(b) & 0x7F) << shift
199 | if b < 0x80 {
200 | break
201 | }
202 | }
203 | fieldNum := int32(wire >> 3)
204 | wireType := int(wire & 0x7)
205 | if wireType == 4 {
206 | return fmt.Errorf("proto: UpdatePlayer: wiretype end group for non-group")
207 | }
208 | if fieldNum <= 0 {
209 | return fmt.Errorf("proto: UpdatePlayer: illegal tag %d (wire type %d)", fieldNum, wire)
210 | }
211 | switch fieldNum {
212 | case 1:
213 | if wireType != 0 {
214 | return fmt.Errorf("proto: wrong wireType = %d for field ClientSlot", wireType)
215 | }
216 | m.ClientSlot = 0
217 | for shift := uint(0); ; shift += 7 {
218 | if shift >= 64 {
219 | return ErrIntOverflowUpdatePlayer
220 | }
221 | if iNdEx >= l {
222 | return io.ErrUnexpectedEOF
223 | }
224 | b := dAtA[iNdEx]
225 | iNdEx++
226 | m.ClientSlot |= (int32(b) & 0x7F) << shift
227 | if b < 0x80 {
228 | break
229 | }
230 | }
231 | case 2:
232 | if wireType != 1 {
233 | return fmt.Errorf("proto: wrong wireType = %d for field X", wireType)
234 | }
235 | var v uint64
236 | if (iNdEx + 8) > l {
237 | return io.ErrUnexpectedEOF
238 | }
239 | v = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))
240 | iNdEx += 8
241 | m.X = float64(math.Float64frombits(v))
242 | case 3:
243 | if wireType != 1 {
244 | return fmt.Errorf("proto: wrong wireType = %d for field Y", wireType)
245 | }
246 | var v uint64
247 | if (iNdEx + 8) > l {
248 | return io.ErrUnexpectedEOF
249 | }
250 | v = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))
251 | iNdEx += 8
252 | m.Y = float64(math.Float64frombits(v))
253 | case 4:
254 | if wireType != 0 {
255 | return fmt.Errorf("proto: wrong wireType = %d for field IsKeyLeftPressed", wireType)
256 | }
257 | var v int
258 | for shift := uint(0); ; shift += 7 {
259 | if shift >= 64 {
260 | return ErrIntOverflowUpdatePlayer
261 | }
262 | if iNdEx >= l {
263 | return io.ErrUnexpectedEOF
264 | }
265 | b := dAtA[iNdEx]
266 | iNdEx++
267 | v |= (int(b) & 0x7F) << shift
268 | if b < 0x80 {
269 | break
270 | }
271 | }
272 | m.IsKeyLeftPressed = bool(v != 0)
273 | case 5:
274 | if wireType != 0 {
275 | return fmt.Errorf("proto: wrong wireType = %d for field IsKeyRightPressed", wireType)
276 | }
277 | var v int
278 | for shift := uint(0); ; shift += 7 {
279 | if shift >= 64 {
280 | return ErrIntOverflowUpdatePlayer
281 | }
282 | if iNdEx >= l {
283 | return io.ErrUnexpectedEOF
284 | }
285 | b := dAtA[iNdEx]
286 | iNdEx++
287 | v |= (int(b) & 0x7F) << shift
288 | if b < 0x80 {
289 | break
290 | }
291 | }
292 | m.IsKeyRightPressed = bool(v != 0)
293 | default:
294 | iNdEx = preIndex
295 | skippy, err := skipUpdatePlayer(dAtA[iNdEx:])
296 | if err != nil {
297 | return err
298 | }
299 | if skippy < 0 {
300 | return ErrInvalidLengthUpdatePlayer
301 | }
302 | if (iNdEx + skippy) > l {
303 | return io.ErrUnexpectedEOF
304 | }
305 | iNdEx += skippy
306 | }
307 | }
308 |
309 | if iNdEx > l {
310 | return io.ErrUnexpectedEOF
311 | }
312 | return nil
313 | }
314 | func skipUpdatePlayer(dAtA []byte) (n int, err error) {
315 | l := len(dAtA)
316 | iNdEx := 0
317 | for iNdEx < l {
318 | var wire uint64
319 | for shift := uint(0); ; shift += 7 {
320 | if shift >= 64 {
321 | return 0, ErrIntOverflowUpdatePlayer
322 | }
323 | if iNdEx >= l {
324 | return 0, io.ErrUnexpectedEOF
325 | }
326 | b := dAtA[iNdEx]
327 | iNdEx++
328 | wire |= (uint64(b) & 0x7F) << shift
329 | if b < 0x80 {
330 | break
331 | }
332 | }
333 | wireType := int(wire & 0x7)
334 | switch wireType {
335 | case 0:
336 | for shift := uint(0); ; shift += 7 {
337 | if shift >= 64 {
338 | return 0, ErrIntOverflowUpdatePlayer
339 | }
340 | if iNdEx >= l {
341 | return 0, io.ErrUnexpectedEOF
342 | }
343 | iNdEx++
344 | if dAtA[iNdEx-1] < 0x80 {
345 | break
346 | }
347 | }
348 | return iNdEx, nil
349 | case 1:
350 | iNdEx += 8
351 | return iNdEx, nil
352 | case 2:
353 | var length int
354 | for shift := uint(0); ; shift += 7 {
355 | if shift >= 64 {
356 | return 0, ErrIntOverflowUpdatePlayer
357 | }
358 | if iNdEx >= l {
359 | return 0, io.ErrUnexpectedEOF
360 | }
361 | b := dAtA[iNdEx]
362 | iNdEx++
363 | length |= (int(b) & 0x7F) << shift
364 | if b < 0x80 {
365 | break
366 | }
367 | }
368 | iNdEx += length
369 | if length < 0 {
370 | return 0, ErrInvalidLengthUpdatePlayer
371 | }
372 | return iNdEx, nil
373 | case 3:
374 | for {
375 | var innerWire uint64
376 | var start int = iNdEx
377 | for shift := uint(0); ; shift += 7 {
378 | if shift >= 64 {
379 | return 0, ErrIntOverflowUpdatePlayer
380 | }
381 | if iNdEx >= l {
382 | return 0, io.ErrUnexpectedEOF
383 | }
384 | b := dAtA[iNdEx]
385 | iNdEx++
386 | innerWire |= (uint64(b) & 0x7F) << shift
387 | if b < 0x80 {
388 | break
389 | }
390 | }
391 | innerWireType := int(innerWire & 0x7)
392 | if innerWireType == 4 {
393 | break
394 | }
395 | next, err := skipUpdatePlayer(dAtA[start:])
396 | if err != nil {
397 | return 0, err
398 | }
399 | iNdEx = start + next
400 | }
401 | return iNdEx, nil
402 | case 4:
403 | return iNdEx, nil
404 | case 5:
405 | iNdEx += 4
406 | return iNdEx, nil
407 | default:
408 | return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
409 | }
410 | }
411 | panic("unreachable")
412 | }
413 |
414 | var (
415 | ErrInvalidLengthUpdatePlayer = fmt.Errorf("proto: negative length found during unmarshaling")
416 | ErrIntOverflowUpdatePlayer = fmt.Errorf("proto: integer overflow")
417 | )
418 |
419 | func init() { proto.RegisterFile("update_player.proto", fileDescriptorUpdatePlayer) }
420 |
421 | var fileDescriptorUpdatePlayer = []byte{
422 | // 179 bytes of a gzipped FileDescriptorProto
423 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2e, 0x2d, 0x48, 0x49,
424 | 0x2c, 0x49, 0x8d, 0x2f, 0xc8, 0x49, 0xac, 0x4c, 0x2d, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17,
425 | 0x62, 0xcb, 0x4b, 0x2d, 0xc9, 0x2d, 0x4e, 0x57, 0x5a, 0xc2, 0xc8, 0xc5, 0x13, 0x0a, 0x96, 0x0f,
426 | 0x00, 0x4b, 0x0b, 0xc9, 0x71, 0x71, 0x39, 0xe7, 0x64, 0xa6, 0xe6, 0x95, 0x04, 0xe7, 0xe4, 0x97,
427 | 0x48, 0x30, 0x2a, 0x30, 0x6a, 0xb0, 0x06, 0x21, 0x89, 0x08, 0xf1, 0x70, 0x31, 0x46, 0x48, 0x30,
428 | 0x29, 0x30, 0x6a, 0x30, 0x06, 0x31, 0x46, 0x80, 0x78, 0x91, 0x12, 0xcc, 0x10, 0x5e, 0xa4, 0x90,
429 | 0x16, 0x97, 0x80, 0x67, 0xb1, 0x77, 0x6a, 0xa5, 0x4f, 0x6a, 0x5a, 0x49, 0x40, 0x51, 0x6a, 0x71,
430 | 0x71, 0x6a, 0x8a, 0x04, 0x8b, 0x02, 0xa3, 0x06, 0x47, 0x10, 0x86, 0xb8, 0x90, 0x0e, 0x97, 0x20,
431 | 0x58, 0x2c, 0x28, 0x33, 0x3d, 0x03, 0xae, 0x98, 0x15, 0xac, 0x18, 0x53, 0xc2, 0x49, 0xe0, 0xc4,
432 | 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf1, 0x58, 0x8e, 0x21,
433 | 0x89, 0x0d, 0xec, 0x0f, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xba, 0x88, 0x27, 0xa6, 0xde,
434 | 0x00, 0x00, 0x00,
435 | }
436 |
--------------------------------------------------------------------------------