battlemap - socket_broadcast.go
1 package battlemap
2
3 import (
4 "encoding/json"
5 "sync/atomic"
6 )
7
8 const (
9 broadcastIsAdmin = -1 - iota
10 broadcastCurrentUserMap
11 broadcastCurrentUserMapData
12
13 broadcastMapDataSet
14 broadcastMapDataRemove
15 broadcastMapStartChange
16
17 broadcastImageItemAdd
18 broadcastAudioItemAdd
19 broadcastCharacterItemAdd
20 broadcastMapItemAdd
21
22 broadcastImageItemMove
23 broadcastAudioItemMove
24 broadcastCharacterItemMove
25 broadcastMapItemMove
26
27 broadcastImageItemRemove
28 broadcastAudioItemRemove
29 broadcastCharacterItemRemove
30 broadcastMapItemRemove
31
32 broadcastImageItemCopy
33 broadcastAudioItemCopy
34 broadcastCharacterItemCopy
35 broadcastMapItemCopy
36
37 broadcastImageFolderAdd
38 broadcastAudioFolderAdd
39 broadcastCharacterFolderAdd
40 broadcastMapFolderAdd
41
42 broadcastImageFolderMove
43 broadcastAudioFolderMove
44 broadcastCharacterFolderMove
45 broadcastMapFolderMove
46
47 broadcastImageFolderRemove
48 broadcastAudioFolderRemove
49 broadcastCharacterFolderRemove
50 broadcastMapFolderRemove
51
52 broadcastMapItemChange
53
54 broadcastCharacterDataChange
55
56 broadcastLayerAdd
57 broadcastLayerFolderAdd
58 broadcastLayerMove
59 broadcastLayerRename
60 broadcastLayerRemove
61
62 broadcastGridDistanceChange
63 broadcastGridDiagonalChange
64 broadcastMapLightChange
65
66 broadcastLayerShow
67 broadcastLayerHide
68 broadcastLayerLock
69 broadcastLayerUnlock
70 broadcastMaskAdd
71 broadcastMaskRemove
72 broadcastMaskSet
73
74 broadcastTokenAdd
75 broadcastTokenRemove
76 broadcastTokenMoveLayerPos
77 broadcastTokenSet
78 broadcastTokenSetMulti
79 broadcastLayerShift
80
81 broadcastWallAdd
82 broadcastWallRemove
83 broadcastWallModify
84 broadcastWallMoveLayer
85
86 broadcastMusicPackAdd
87 broadcastMusicPackRename
88 broadcastMusicPackRemove
89 broadcastMusicPackCopy
90 broadcastMusicPackVolume
91 broadcastMusicPackPlay
92 broadcastMusicPackStop
93 broadcastMusicPackStopAll
94 broadcastMusicPackTrackAdd
95 broadcastMusicPackTrackRemove
96 broadcastMusicPackTrackVolume
97 broadcastMusicPackTrackRepeat
98
99 broadcastPluginChange
100 broadcastPluginSettingChange
101
102 broadcastWindow
103
104 broadcastSignalMeasure
105 broadcastSignalPosition
106 broadcastSignalMovePosition
107 broadcastAny
108 )
109
110 func (s *socket) KickAdmins(except ID) {
111 s.mu.RLock()
112 for c := range s.conns {
113 id := c.ID
114 if id > 0 && id != except {
115 go c.kickAdmin()
116 }
117 }
118 s.mu.RUnlock()
119 }
120
121 func (c *conn) kickAdmin() {
122 atomic.StoreUint64((*uint64)(&c.ID), 0)
123 c.rpc.SendData(loggedOut)
124 }
125
126 const broadcastStart = "{\"id\": -0,\"result\":"
127
128 func buildBroadcast(id int, data json.RawMessage) []byte {
129 l := len(broadcastStart) + len(data) + 1
130 dat := make([]byte, l)
131 copy(dat, broadcastStart)
132 copy(dat[len(broadcastStart):], data)
133 id = -id
134 if id > 9 {
135 dat[6] = '-'
136 dat[7] = byte('0' + id/10)
137 }
138 dat[8] = byte('0' + id%10)
139 dat[l-1] = '}'
140 return dat
141 }
142
143 func (s *socket) SetCurrentUserMap(currentUserMap uint64, data, mData json.RawMessage, except ID) {
144 s.mu.RLock()
145 var dat, mdat json.RawMessage
146 for c := range s.conns {
147 id := c.ID
148 if c.IsAdmin() {
149 if except != id {
150 if len(dat) == 0 {
151 dat = buildBroadcast(broadcastCurrentUserMap, data)
152 }
153 go c.rpc.SendData(dat)
154 }
155 } else {
156 if len(mdat) == 0 {
157 mdat = buildBroadcast(broadcastCurrentUserMapData, mData)
158 }
159 atomic.StoreUint64(&c.CurrentMap, currentUserMap)
160 go c.rpc.SendData(mdat)
161 }
162 }
163 s.mu.RUnlock()
164 }
165
166 type userStatus uint8
167
168 const (
169 userAny userStatus = iota
170 userAdmin
171 userNotAdmin
172 )
173
174 func (s *socket) broadcastMapChange(cd ConnData, id int, data json.RawMessage, user userStatus) {
175 s.mu.RLock()
176 var dat json.RawMessage
177 for c := range s.conns {
178 currentMap := atomic.LoadUint64(&c.CurrentMap)
179 if c.ID != cd.ID && (currentMap == cd.CurrentMap || cd.CurrentMap == 0) && (user == userAny || ((user == userAdmin) && c.IsAdmin()) || ((user == userNotAdmin) && !c.IsAdmin())) {
180 if len(dat) == 0 {
181 dat = buildBroadcast(id, data)
182 }
183 go c.rpc.SendData(dat)
184 }
185 }
186 s.mu.RUnlock()
187 }
188
189 func (s *socket) broadcastAdminChange(id int, data json.RawMessage, except ID) {
190 s.mu.RLock()
191 var dat json.RawMessage
192 for c := range s.conns {
193 if c.IsAdmin() && c.ID != except {
194 if len(dat) == 0 {
195 dat = buildBroadcast(id, data)
196 }
197 go c.rpc.SendData(dat)
198 }
199 }
200 s.mu.RUnlock()
201 }
202
203 type idName struct {
204 ID uint64 `json:"id"`
205 Name string `json:"name"`
206 }
207