~sircmpwn/cells

ref: a0c7f20043108cdef497538b2b4b0ce6724d69eb cells/conn.go -rw-r--r-- 2.8 KiB
a0c7f200Drew DeVault Implement map storage and updates 8 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package main

import (
	"encoding/json"
	"log"
	"math/rand"
	"sync"
	"sync/atomic"

	"github.com/gorilla/websocket"
)

var (
	conns  sync.Map
	nextId int64
)

type Connection struct {
	Conn   *websocket.Conn
	Player Player
}

func (c *Connection) Run() {
	conns.Store(c, nil)
	c.Player.Id = atomic.AddInt64(&nextId, 1)

	c.Conn.WriteJSON(&SpawnSelfMessage{
		Message: Message{"spawn_self"},
		Self:    c.Player,
	})

	conns.Range(func(key interface{}, _ interface{}) bool {
		peer, _ := key.(*Connection)
		if peer == c {
			return true
		}
		// TODO: Only spawn proximate peers
		c.Conn.WriteJSON(&SpawnPeerMessage{
			Message: Message{"spawn_peer"},
			Peer:    peer.Player,
		})
		peer.Conn.WriteJSON(&SpawnPeerMessage{
			Message: Message{"spawn_peer"},
			Peer:    c.Player,
		})
		return true
	})

	// TODO: Only send proximate chunks
	for coords, chunk := range Map {
		c.Conn.WriteJSON(&ChunkDataMessage{
			Message: Message{"chunk_data"},
			Coords:  coords,
			Cells:   *chunk,
		})
	}

	for {
		_, data, err := c.Conn.ReadMessage()
		if err != nil {
			log.Println("read:", err)
			break
		}
		var msg Message
		err = json.Unmarshal(data, &msg)
		if err != nil {
			log.Println("json.Unmarshal:", err)
			break
		}
		switch msg.Type {
		case "ping":
			var ping PingMessage
			json.Unmarshal(data, &ping)
			ping.Color = c.Player.Color
			c.SendToPeers(&ping)
		case "player_motion":
			// TODO: Throttle motion messages
			var motion PlayerMotionMessage
			json.Unmarshal(data, &motion)
			// TODO: Prevent teleportation
			c.Player.Position = motion.Position
			motion.PlayerId = c.Player.Id
			c.SendToPeers(&motion)
		case "set_cell":
			// TODO: Enforce reach distance
			var setCell SetCellMessage
			json.Unmarshal(data, &setCell)
			SetCell(setCell.Coords, c.Player.Color)
			setCell.Color = c.Player.Color
			c.SendToPeers(&setCell)
			break;
		}
	}

	c.SendToPeers(&DespawnPeerMessage{
		Message: Message{"despawn_peer"},
		PeerId: c.Player.Id,
	})
	conns.Delete(c)
}

func SendToEveryone(msg interface{}) {
	conns.Range(func(key interface{}, _ interface{}) bool {
		conn, _ := key.(*Connection)
		conn.Conn.WriteJSON(msg)
		return true
	})
}

func (c *Connection) SendToPeers(msg interface{}) {
	conns.Range(func(key interface{}, _ interface{}) bool {
		conn, _ := key.(*Connection)
		if conn == c {
			return true
		}
		conn.Conn.WriteJSON(msg)
		return true
	})
}

func assignColor() Color {
	colors := Colors
	rand.Shuffle(len(colors), func(i, j int) {
		colors[i], colors[j] = colors[j], colors[i]
	})
	for _, color := range colors {
		inUse := false
		conns.Range(func(key interface{}, _ interface{}) bool {
			conn, _ := key.(*Connection)
			if Color(conn.Player.Color).EqualTo(color) {
				inUse = true
				return false
			}
			return true
		})
		if !inUse {
			return color
		}
	}
	// TODO: Select randomly
	return Colors[0]
}