/
GoWorldConnection.go
486 lines (430 loc) · 17.3 KB
/
GoWorldConnection.go
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
package proto
import (
"net"
"time"
"github.com/xiaonanln/go-xnsyncutil/xnsyncutil"
"github.com/xiaonanln/goworld/engine/common"
"github.com/xiaonanln/goworld/engine/consts"
"github.com/xiaonanln/goworld/engine/gwlog"
"github.com/xiaonanln/goworld/engine/netutil"
"github.com/xiaonanln/goworld/engine/netutil/compress"
)
// GoWorldConnection is the network protocol implementation of GoWorld components (dispatcher, gate, game)
type GoWorldConnection struct {
packetConn *netutil.PacketConnection
closed xnsyncutil.AtomicBool
autoFlushing bool
}
// NewGoWorldConnection creates a GoWorldConnection using network connection
func NewGoWorldConnection(conn netutil.Connection, compressConnection bool, compressFormat string) *GoWorldConnection {
var compressor compress.Compressor
if compressConnection {
compressor = compress.NewCompressor(compressFormat)
}
return &GoWorldConnection{
packetConn: netutil.NewPacketConnection(conn, compressor),
}
}
// SendSetGameID sends MT_SET_GAME_ID message
func (gwc *GoWorldConnection) SendSetGameID(id uint16, isReconnect bool, isRestore bool, isBanBootEntity bool,
eids []common.EntityID) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_SET_GAME_ID)
packet.AppendUint16(id)
packet.AppendBool(isReconnect)
packet.AppendBool(isRestore)
packet.AppendBool(isBanBootEntity)
// put all entity IDs to the packet
packet.AppendUint32(uint32(len(eids)))
for _, eid := range eids {
packet.AppendEntityID(eid)
}
return gwc.SendPacketRelease(packet)
}
// SendSetGateID sends MT_SET_GATE_ID message
func (gwc *GoWorldConnection) SendSetGateID(id uint16) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_SET_GATE_ID)
packet.AppendUint16(id)
return gwc.SendPacketRelease(packet)
}
// SendNotifyCreateEntity sends MT_NOTIFY_CREATE_ENTITY message
func (gwc *GoWorldConnection) SendNotifyCreateEntity(id common.EntityID) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_NOTIFY_CREATE_ENTITY)
packet.AppendEntityID(id)
return gwc.SendPacketRelease(packet)
}
// SendNotifyDestroyEntity sends MT_NOTIFY_DESTROY_ENTITY message
func (gwc *GoWorldConnection) SendNotifyDestroyEntity(id common.EntityID) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_NOTIFY_DESTROY_ENTITY)
packet.AppendEntityID(id)
return gwc.SendPacketRelease(packet)
}
// SendNotifyClientConnected sends MT_NOTIFY_CLIENT_CONNECTED message
func (gwc *GoWorldConnection) SendNotifyClientConnected(id common.ClientID, bootEid common.EntityID) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_NOTIFY_CLIENT_CONNECTED)
packet.AppendClientID(id)
packet.AppendEntityID(bootEid)
return gwc.SendPacketRelease(packet)
}
// SendNotifyClientDisconnected sends MT_NOTIFY_CLIENT_DISCONNECTED message
func (gwc *GoWorldConnection) SendNotifyClientDisconnected(id common.ClientID, ownerEntityID common.EntityID) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_NOTIFY_CLIENT_DISCONNECTED)
packet.AppendEntityID(ownerEntityID)
packet.AppendClientID(id)
return gwc.SendPacketRelease(packet)
}
// SendCreateEntitySomewhere sends MT_CREATE_ENTITY_SOMEWHERE message
func (gwc *GoWorldConnection) SendCreateEntitySomewhere(gameid uint16, entityid common.EntityID, typeName string, data map[string]interface{}) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_CREATE_ENTITY_SOMEWHERE)
packet.AppendUint16(gameid)
packet.AppendEntityID(entityid)
packet.AppendVarStr(typeName)
packet.AppendData(data)
return gwc.SendPacketRelease(packet)
}
// SendLoadEntitySomewhere sends MT_LOAD_ENTITY_SOMEWHERE message
func (gwc *GoWorldConnection) SendLoadEntitySomewhere(typeName string, entityID common.EntityID, gameid uint16) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_LOAD_ENTITY_SOMEWHERE)
packet.AppendUint16(gameid)
packet.AppendEntityID(entityID)
packet.AppendVarStr(typeName)
return gwc.SendPacketRelease(packet)
}
// SendSrvdisRegister
func (gwc *GoWorldConnection) SendSrvdisRegister(srvid string, info string, force bool) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_SRVDIS_REGISTER)
packet.AppendVarStr(srvid)
packet.AppendVarStr(info)
packet.AppendBool(force)
return gwc.SendPacketRelease(packet)
}
// SendCallEntityMethod sends MT_CALL_ENTITY_METHOD message
func (gwc *GoWorldConnection) SendCallEntityMethod(id common.EntityID, method string, args []interface{}) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_CALL_ENTITY_METHOD)
packet.AppendEntityID(id)
packet.AppendVarStr(method)
packet.AppendArgs(args)
return gwc.SendPacketRelease(packet)
}
// SendCallEntityMethodFromClient sends MT_CALL_ENTITY_METHOD_FROM_CLIENT message
func (gwc *GoWorldConnection) SendCallEntityMethodFromClient(id common.EntityID, method string, args []interface{}) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_CALL_ENTITY_METHOD_FROM_CLIENT)
packet.AppendEntityID(id)
packet.AppendVarStr(method)
packet.AppendArgs(args)
return gwc.SendPacketRelease(packet)
}
// SendCreateEntityOnClient sends MT_CREATE_ENTITY_ON_CLIENT message
func (gwc *GoWorldConnection) SendCreateEntityOnClient(gameid uint16, clientid common.ClientID, typeName string, entityid common.EntityID,
isPlayer bool, clientData map[string]interface{}, x, y, z float32, yaw float32) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_CREATE_ENTITY_ON_CLIENT)
packet.AppendUint16(gameid)
packet.AppendClientID(clientid)
packet.AppendBool(isPlayer)
packet.AppendEntityID(entityid)
packet.AppendVarStr(typeName)
packet.AppendFloat32(x)
packet.AppendFloat32(y)
packet.AppendFloat32(z)
packet.AppendFloat32(yaw)
packet.AppendData(clientData)
return gwc.SendPacketRelease(packet)
}
// SendSyncPositionYawFromClient sends MT_SYNC_POSITION_YAW_FROM_CLIENT message
func (gwc *GoWorldConnection) SendSyncPositionYawFromClient(entityID common.EntityID, x, y, z float32, yaw float32) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_SYNC_POSITION_YAW_FROM_CLIENT)
packet.AppendEntityID(entityID)
packet.AppendFloat32(x)
packet.AppendFloat32(y)
packet.AppendFloat32(z)
packet.AppendFloat32(yaw)
return gwc.SendPacketRelease(packet)
}
//func (gwc *GoWorldConnection) SendSetClientClientID(clientid common.ClientID) error {
// packet := gwc.packetConn.NewPacket()
// packet.AppendUint16(MT_SET_CLIENT_CLIENTID)
// packet.AppendClientID(clientid)
// return gwc.SendPacketRelease(packet)
//}
func (gwc *GoWorldConnection) SetHeartbeatFromClient() error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_HEARTBEAT_FROM_CLIENT)
return gwc.SendPacketRelease(packet)
}
// SendDestroyEntityOnClient sends MT_DESTROY_ENTITY_ON_CLIENT message
func (gwc *GoWorldConnection) SendDestroyEntityOnClient(gateid uint16, clientid common.ClientID, typeName string, entityid common.EntityID) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_DESTROY_ENTITY_ON_CLIENT)
packet.AppendUint16(gateid)
packet.AppendClientID(clientid)
packet.AppendVarStr(typeName)
packet.AppendEntityID(entityid)
return gwc.SendPacketRelease(packet)
}
// SendNotifyMapAttrChangeOnClient sends MT_NOTIFY_MAP_ATTR_CHANGE_ON_CLIENT message
func (gwc *GoWorldConnection) SendNotifyMapAttrChangeOnClient(gateid uint16, clientid common.ClientID, entityid common.EntityID, path []interface{}, key string, val interface{}) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_NOTIFY_MAP_ATTR_CHANGE_ON_CLIENT)
packet.AppendUint16(gateid)
packet.AppendClientID(clientid)
packet.AppendEntityID(entityid)
packet.AppendData(path)
packet.AppendVarStr(key)
packet.AppendData(val)
return gwc.SendPacketRelease(packet)
}
// SendNotifyMapAttrDelOnClient sends MT_NOTIFY_MAP_ATTR_DEL_ON_CLIENT message
func (gwc *GoWorldConnection) SendNotifyMapAttrDelOnClient(gateid uint16, clientid common.ClientID, entityid common.EntityID, path []interface{}, key string) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_NOTIFY_MAP_ATTR_DEL_ON_CLIENT)
packet.AppendUint16(gateid)
packet.AppendClientID(clientid)
packet.AppendEntityID(entityid)
packet.AppendData(path)
packet.AppendVarStr(key)
return gwc.SendPacketRelease(packet)
}
// SendNotifyMapAttrClearOnClient sends MT_NOTIFY_MAP_ATTR_CLEAR_ON_CLIENT message
func (gwc *GoWorldConnection) SendNotifyMapAttrClearOnClient(gateid uint16, clientid common.ClientID, entityid common.EntityID, path []interface{}) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_NOTIFY_MAP_ATTR_CLEAR_ON_CLIENT)
packet.AppendUint16(gateid)
packet.AppendClientID(clientid)
packet.AppendEntityID(entityid)
packet.AppendData(path)
return gwc.SendPacketRelease(packet)
}
// SendNotifyListAttrChangeOnClient sends MT_NOTIFY_LIST_ATTR_CHANGE_ON_CLIENT message
func (gwc *GoWorldConnection) SendNotifyListAttrChangeOnClient(gateid uint16, clientid common.ClientID, entityid common.EntityID, path []interface{}, index uint32, val interface{}) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_NOTIFY_LIST_ATTR_CHANGE_ON_CLIENT)
packet.AppendUint16(gateid)
packet.AppendClientID(clientid)
packet.AppendEntityID(entityid)
packet.AppendData(path)
packet.AppendUint32(index)
packet.AppendData(val)
return gwc.SendPacketRelease(packet)
}
// SendNotifyListAttrPopOnClient sends MT_NOTIFY_LIST_ATTR_POP_ON_CLIENT message
func (gwc *GoWorldConnection) SendNotifyListAttrPopOnClient(gateid uint16, clientid common.ClientID, entityid common.EntityID, path []interface{}) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_NOTIFY_LIST_ATTR_POP_ON_CLIENT)
packet.AppendUint16(gateid)
packet.AppendClientID(clientid)
packet.AppendEntityID(entityid)
packet.AppendData(path)
return gwc.SendPacketRelease(packet)
}
// SendNotifyListAttrAppendOnClient sends MT_NOTIFY_LIST_ATTR_APPEND_ON_CLIENT message
func (gwc *GoWorldConnection) SendNotifyListAttrAppendOnClient(gateid uint16, clientid common.ClientID, entityid common.EntityID, path []interface{}, val interface{}) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_NOTIFY_LIST_ATTR_APPEND_ON_CLIENT)
packet.AppendUint16(gateid)
packet.AppendClientID(clientid)
packet.AppendEntityID(entityid)
packet.AppendData(path)
packet.AppendData(val)
return gwc.SendPacketRelease(packet)
}
// SendCallEntityMethodOnClient sends MT_CALL_ENTITY_METHOD_ON_CLIENT message
func (gwc *GoWorldConnection) SendCallEntityMethodOnClient(gateid uint16, clientid common.ClientID, entityID common.EntityID, method string, args []interface{}) (err error) {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_CALL_ENTITY_METHOD_ON_CLIENT)
packet.AppendUint16(gateid)
packet.AppendClientID(clientid)
packet.AppendEntityID(entityID)
packet.AppendVarStr(method)
packet.AppendArgs(args)
return gwc.SendPacketRelease(packet)
}
// SendSetClientFilterProp sends MT_SET_CLIENTPROXY_FILTER_PROP message
func (gwc *GoWorldConnection) SendSetClientFilterProp(gateid uint16, clientid common.ClientID, key, val string) (err error) {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_SET_CLIENTPROXY_FILTER_PROP)
packet.AppendUint16(gateid)
packet.AppendClientID(clientid)
packet.AppendVarStr(key)
packet.AppendVarStr(val)
return gwc.SendPacketRelease(packet)
}
// SendClearClientFilterProp sends MT_CLEAR_CLIENTPROXY_FILTER_PROPS message
func (gwc *GoWorldConnection) SendClearClientFilterProp(gateid uint16, clientid common.ClientID) (err error) {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_CLEAR_CLIENTPROXY_FILTER_PROPS)
packet.AppendUint16(gateid)
packet.AppendClientID(clientid)
return gwc.SendPacketRelease(packet)
}
// SendCallFilterClientProxies sends MT_CALL_FILTERED_CLIENTS message
func AllocCallFilterClientProxiesPacket(op FilterClientsOpType, key, val string, method string, args []interface{}) *netutil.Packet {
packet := netutil.NewPacket()
packet.AppendUint16(MT_CALL_FILTERED_CLIENTS)
packet.AppendByte(byte(op))
packet.AppendVarStr(key)
packet.AppendVarStr(val)
packet.AppendVarStr(method)
packet.AppendArgs(args)
return packet
}
func AllocCallNilSpacesPacket(exceptGameID uint16, method string, args []interface{}) *netutil.Packet {
// construct one packet for multiple sending
packet := netutil.NewPacket()
packet.AppendUint16(MT_CALL_NIL_SPACES)
packet.AppendUint16(exceptGameID)
packet.AppendVarStr(method)
packet.AppendArgs(args)
return packet
}
func AllocGameLBCInfoPacket(lbcinfo GameLBCInfo) *netutil.Packet {
packet := netutil.NewPacket()
packet.AppendUint16(MT_GAME_LBC_INFO)
packet.AppendData(lbcinfo)
return packet
}
// SendQuerySpaceGameIDForMigrate sends MT_QUERY_SPACE_GAMEID_FOR_MIGRATE message
func (gwc *GoWorldConnection) SendQuerySpaceGameIDForMigrate(spaceid common.EntityID, entityid common.EntityID) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_QUERY_SPACE_GAMEID_FOR_MIGRATE)
packet.AppendEntityID(spaceid)
packet.AppendEntityID(entityid)
return gwc.SendPacketRelease(packet)
}
// SendMigrateRequest sends MT_MIGRATE_REQUEST message
func (gwc *GoWorldConnection) SendMigrateRequest(entityID common.EntityID, spaceID common.EntityID, spaceGameID uint16) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_MIGRATE_REQUEST)
packet.AppendEntityID(entityID)
packet.AppendEntityID(spaceID)
packet.AppendUint16(spaceGameID)
return gwc.SendPacketRelease(packet)
}
// SendCancelMigrate sends MT_CANCEL_MIGRATE message to dispatcher to unblock the entity
func (gwc *GoWorldConnection) SendCancelMigrate(entityid common.EntityID) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_CANCEL_MIGRATE)
packet.AppendEntityID(entityid)
return gwc.SendPacketRelease(packet)
}
// SendRealMigrate sends MT_REAL_MIGRATE message
func (gwc *GoWorldConnection) SendRealMigrate(eid common.EntityID, targetGame uint16, data []byte) error {
packet := gwc.packetConn.NewPacket()
packet.AppendUint16(MT_REAL_MIGRATE)
packet.AppendEntityID(eid)
packet.AppendUint16(targetGame)
packet.AppendVarBytes(data)
return gwc.SendPacketRelease(packet)
}
//// SendStartFreezeGame sends MT_START_FREEZE_GAME message
//func (gwc *GoWorldConnection) SendStartFreezeGame(gameid uint16) error {
// packet := gwc.packetConn.NewPacket()
// packet.AppendUint16(MT_START_FREEZE_GAME)
// return gwc.SendPacketRelease(packet)
//}
func AllocStartFreezeGamePacket() *netutil.Packet {
packet := netutil.NewPacket()
packet.AppendUint16(MT_START_FREEZE_GAME)
return packet
}
func MakeNotifyGameConnectedPacket(gameid uint16) *netutil.Packet {
pkt := netutil.NewPacket()
pkt.AppendUint16(MT_NOTIFY_GAME_CONNECTED)
pkt.AppendUint16(gameid)
return pkt
}
func (gwc *GoWorldConnection) SendSetGameIDAck(dispid uint16, connectedGameIDs []uint16, rejectEntities []common.EntityID, srvdisRegisterMap map[string]string) error {
pkt := netutil.NewPacket()
pkt.AppendUint16(MT_SET_GAME_ID_ACK)
pkt.AppendUint16(dispid)
pkt.AppendUint16(uint16(len(connectedGameIDs)))
for _, gameid := range connectedGameIDs {
pkt.AppendUint16(gameid)
}
// put rejected entity IDs to the packet
pkt.AppendUint32(uint32(len(rejectEntities)))
for _, eid := range rejectEntities {
pkt.AppendEntityID(eid)
}
// put all services to the packet
pkt.AppendMapStringString(srvdisRegisterMap)
return gwc.SendPacketRelease(pkt)
}
// SendPacket send a packet to remote
func (gwc *GoWorldConnection) SendPacket(packet *netutil.Packet) error {
return gwc.packetConn.SendPacket(packet)
}
// SendPacketRelease send a packet to remote and then release the packet
func (gwc *GoWorldConnection) SendPacketRelease(packet *netutil.Packet) error {
err := gwc.packetConn.SendPacket(packet)
packet.Release()
return err
}
// Flush connection writes
func (gwc *GoWorldConnection) Flush(reason string) error {
return gwc.packetConn.Flush(reason)
}
// SetAutoFlush starts a goroutine to flush connection writes at some specified interval
func (gwc *GoWorldConnection) SetAutoFlush(interval time.Duration) {
if gwc.autoFlushing {
gwlog.Panicf("%s.SetAutoFlush: already auto flushing!", gwc)
}
gwc.autoFlushing = true
go func() {
//defer gwlog.Debugf("%s: auto flush routine quited", gwc)
for !gwc.IsClosed() {
time.Sleep(interval)
err := gwc.Flush("AutoFlush")
if err != nil {
break
}
}
}()
}
// Recv receives the next packet and retrive the message type
func (gwc *GoWorldConnection) Recv(msgtype *MsgType) (*netutil.Packet, error) {
pkt, err := gwc.packetConn.RecvPacket()
if err != nil {
return nil, err
}
*msgtype = MsgType(pkt.ReadUint16())
if consts.DEBUG_PACKETS {
gwlog.Infof("%s: Recv msgtype=%v, payload size=%d", gwc, *msgtype, pkt.GetPayloadLen())
}
return pkt, nil
}
// SetRecvDeadline set receive deadline
func (gwc *GoWorldConnection) SetRecvDeadline(deadline time.Time) error {
return gwc.packetConn.SetRecvDeadline(deadline)
}
// Close this connection
func (gwc *GoWorldConnection) Close() error {
gwc.closed.Store(true)
return gwc.packetConn.Close()
}
// IsClosed returns if the connection is closed
func (gwc *GoWorldConnection) IsClosed() bool {
return gwc.closed.Load()
}
// RemoteAddr returns the remote address
func (gwc *GoWorldConnection) RemoteAddr() net.Addr {
return gwc.packetConn.RemoteAddr()
}
// LocalAddr returns the local address
func (gwc *GoWorldConnection) LocalAddr() net.Addr {
return gwc.packetConn.LocalAddr()
}
func (gwc *GoWorldConnection) String() string {
return gwc.packetConn.String()
}