Compare commits

..

13 Commits

Author SHA1 Message Date
899b95b4e6 SelectWithTimeout && WaitWithTImeout now use time.Duration 2023-12-01 20:23:27 -06:00
e33b7c0556 util: added test 2023-12-01 20:13:53 -06:00
3445b852fd util: added SelectWithTimeout && WaitWithTImeout 2023-12-01 20:13:42 -06:00
557117f093 moved internal/protocol -> cnet/protocol 2023-12-01 19:56:23 -06:00
b07e9ddbcb merged internal/service -> cnet/service 2023-12-01 19:22:49 -06:00
af867ccff2 renamed cnet.CNPeer -> cnet.Peer 2023-12-01 19:15:00 -06:00
c60017f78f rename cnpeer package to cnet 2023-12-01 17:11:41 -06:00
e1804a1042 merged entity/chunk && entity/chunkposition 2023-12-01 17:03:46 -06:00
bcc999db38 moved internal/entity to shard/entity 2023-12-01 16:56:55 -06:00
e355af19ab moved internal/protocol/cnpeer to cnpeer
also started a util package
2023-12-01 15:29:19 -06:00
0ed19ad6c5 tests workflow: add timeout
some of the tests can fail in really bad, slow ways. make sure we don't
spin our wheels waiting for a failed test to never fail.
2023-12-01 14:10:45 -06:00
66fe3c9738 TestService: minor refactor; clearer waitgroup Add 2023-12-01 14:08:17 -06:00
72dbfe2541 TestService: wait for OnConnect && OnDisconnect 2023-12-01 13:58:57 -06:00
30 changed files with 299 additions and 250 deletions

View File

@ -23,4 +23,4 @@ jobs:
with: with:
go-version: '1.21.x' go-version: '1.21.x'
- name: Test with the Go CLI - name: Test with the Go CLI
run: go test -v ./... run: go test -timeout 10s -v ./...

View File

@ -1,4 +1,4 @@
package protocol package cnet
import ( import (
"bytes" "bytes"
@ -8,7 +8,8 @@ import (
"io" "io"
"net" "net"
"sync/atomic" "sync/atomic"
"time"
"github.com/CPunch/gopenfusion/cnet/protocol"
) )
const ( const (
@ -22,8 +23,8 @@ type PacketEvent struct {
PktID uint32 PktID uint32
} }
// CNPeer is a simple wrapper for net.Conn connections to send/recv packets over the Fusionfall packet protocol. // Peer is a simple wrapper for net.Conn connections to send/recv packets over the Fusionfall packet protocol.
type CNPeer struct { type Peer struct {
uData interface{} uData interface{}
conn net.Conn conn net.Conn
ctx context.Context ctx context.Context
@ -37,42 +38,38 @@ type CNPeer struct {
FE_key []byte FE_key []byte
} }
func GetTime() uint64 { func NewPeer(ctx context.Context, conn net.Conn) *Peer {
return uint64(time.Now().UnixMilli()) p := &Peer{
}
func NewCNPeer(ctx context.Context, conn net.Conn) *CNPeer {
p := &CNPeer{
conn: conn, conn: conn,
ctx: ctx, ctx: ctx,
whichKey: USE_E, whichKey: USE_E,
alive: &atomic.Bool{}, alive: &atomic.Bool{},
E_key: []byte(DEFAULT_KEY), E_key: []byte(protocol.DEFAULT_KEY),
FE_key: nil, FE_key: nil,
} }
return p return p
} }
func (peer *CNPeer) SetUserData(uData interface{}) { func (peer *Peer) SetUserData(uData interface{}) {
peer.uData = uData peer.uData = uData
} }
func (peer *CNPeer) UserData() interface{} { func (peer *Peer) UserData() interface{} {
return peer.uData return peer.uData
} }
func (peer *CNPeer) Send(typeID uint32, data ...interface{}) error { func (peer *Peer) Send(typeID uint32, data ...interface{}) error {
// grab buffer from pool // grab buffer from pool
buf := GetBuffer() buf := protocol.GetBuffer()
defer PutBuffer(buf) defer protocol.PutBuffer(buf)
// allocate space for packet size // allocate space for packet size
buf.Write(make([]byte, 4)) buf.Write(make([]byte, 4))
// body start // body start
pkt := NewPacket(buf) pkt := protocol.NewPacket(buf)
// encode type id // encode type id
if err := pkt.Encode(typeID); err != nil { if err := pkt.Encode(typeID); err != nil {
@ -97,7 +94,7 @@ func (peer *CNPeer) Send(typeID uint32, data ...interface{}) error {
case USE_FE: case USE_FE:
key = peer.FE_key key = peer.FE_key
} }
EncryptData(buf.Bytes()[4:], key) protocol.EncryptData(buf.Bytes()[4:], key)
// send full packet // send full packet
// log.Printf("Sending %#v, sizeof: %d, buffer: %v", data, buf.Len(), buf.Bytes()) // log.Printf("Sending %#v, sizeof: %d, buffer: %v", data, buf.Len(), buf.Bytes())
@ -107,11 +104,11 @@ func (peer *CNPeer) Send(typeID uint32, data ...interface{}) error {
return nil return nil
} }
func (peer *CNPeer) SetActiveKey(whichKey int) { func (peer *Peer) SetActiveKey(whichKey int) {
peer.whichKey = whichKey peer.whichKey = whichKey
} }
func (peer *CNPeer) Kill() { func (peer *Peer) Kill() {
// de-bounce: only kill if alive // de-bounce: only kill if alive
if !peer.alive.CompareAndSwap(true, false) { if !peer.alive.CompareAndSwap(true, false) {
return return
@ -121,7 +118,7 @@ func (peer *CNPeer) Kill() {
} }
// meant to be invoked as a goroutine // meant to be invoked as a goroutine
func (peer *CNPeer) Handler(eRecv chan<- *PacketEvent) error { func (peer *Peer) Handler(eRecv chan<- *PacketEvent) error {
defer func() { defer func() {
close(eRecv) close(eRecv)
peer.Kill() peer.Kill()
@ -140,19 +137,19 @@ func (peer *CNPeer) Handler(eRecv chan<- *PacketEvent) error {
} }
// client should never send a packet size outside of this range // client should never send a packet size outside of this range
if sz > CN_PACKET_BUFFER_SIZE || sz < 4 { if sz > protocol.CN_PACKET_BUFFER_SIZE || sz < 4 {
return fmt.Errorf("invalid packet size: %d", sz) return fmt.Errorf("invalid packet size: %d", sz)
} }
// grab buffer && read packet body // grab buffer && read packet body
buf := GetBuffer() buf := protocol.GetBuffer()
if _, err := buf.ReadFrom(io.LimitReader(peer.conn, int64(sz))); err != nil { if _, err := buf.ReadFrom(io.LimitReader(peer.conn, int64(sz))); err != nil {
return fmt.Errorf("failed to read packet body: %v", err) return fmt.Errorf("failed to read packet body: %v", err)
} }
// decrypt // decrypt
DecryptData(buf.Bytes(), peer.E_key) protocol.DecryptData(buf.Bytes(), peer.E_key)
pkt := NewPacket(buf) pkt := protocol.NewPacket(buf)
// create packet && read pktID // create packet && read pktID
var pktID uint32 var pktID uint32

View File

@ -4,7 +4,7 @@ import (
"bytes" "bytes"
"testing" "testing"
"github.com/CPunch/gopenfusion/internal/protocol" "github.com/CPunch/gopenfusion/cnet/protocol"
"github.com/matryer/is" "github.com/matryer/is"
) )

View File

@ -1,4 +1,4 @@
package service package cnet
import ( import (
"context" "context"
@ -10,13 +10,13 @@ import (
"strconv" "strconv"
"sync" "sync"
"github.com/CPunch/gopenfusion/cnet/protocol"
"github.com/CPunch/gopenfusion/config" "github.com/CPunch/gopenfusion/config"
"github.com/CPunch/gopenfusion/internal/protocol"
) )
type PacketHandler func(peer *protocol.CNPeer, pkt protocol.Packet) error type PacketHandler func(peer *Peer, pkt protocol.Packet) error
func StubbedPacket(_ *protocol.CNPeer, _ protocol.Packet) error { func StubbedPacket(_ *Peer, _ protocol.Packet) error {
return nil return nil
} }
@ -28,18 +28,18 @@ type Service struct {
started chan struct{} started chan struct{}
stopped chan struct{} stopped chan struct{}
packetHandlers map[uint32]PacketHandler packetHandlers map[uint32]PacketHandler
peers map[chan *protocol.PacketEvent]*protocol.CNPeer peers map[chan *PacketEvent]*Peer
stateLock sync.Mutex stateLock sync.Mutex
// OnDisconnect is called when a peer disconnects from the service. // OnDisconnect is called when a peer disconnects from the service.
// uData is the stored value of the key/value pair in the peer map. // uData is the stored value of the key/value pair in the peer map.
// It may not be set while the service is running. (eg. srvc.Start() has been called) // It may not be set while the service is running. (eg. srvc.Start() has been called)
OnDisconnect func(peer *protocol.CNPeer) OnDisconnect func(peer *Peer)
// OnConnect is called when a peer connects to the service. // OnConnect is called when a peer connects to the service.
// return value is used as the value in the peer map. // return value is used as the value in the peer map.
// It may not be set while the service is running. (eg. srvc.Start() has been called) // It may not be set while the service is running. (eg. srvc.Start() has been called)
OnConnect func(peer *protocol.CNPeer) OnConnect func(peer *Peer)
} }
func RandomPort() (int, error) { func RandomPort() (int, error) {
@ -69,7 +69,7 @@ func NewService(ctx context.Context, name string, port int) *Service {
func (srvc *Service) Reset(ctx context.Context) { func (srvc *Service) Reset(ctx context.Context) {
srvc.ctx = ctx srvc.ctx = ctx
srvc.packetHandlers = make(map[uint32]PacketHandler) srvc.packetHandlers = make(map[uint32]PacketHandler)
srvc.peers = make(map[chan *protocol.PacketEvent]*protocol.CNPeer) srvc.peers = make(map[chan *PacketEvent]*Peer)
srvc.started = make(chan struct{}) srvc.started = make(chan struct{})
srvc.stopped = make(chan struct{}) srvc.stopped = make(chan struct{})
} }
@ -80,8 +80,8 @@ func (srvc *Service) AddPacketHandler(pktID uint32, handler PacketHandler) {
} }
type newPeerConnection struct { type newPeerConnection struct {
peer *protocol.CNPeer peer *Peer
channel chan *protocol.PacketEvent channel chan *PacketEvent
} }
func (srvc *Service) Start() error { func (srvc *Service) Start() error {
@ -112,22 +112,22 @@ func (srvc *Service) Start() error {
} }
// create a new peer and pass it to the event loop // create a new peer and pass it to the event loop
peer := protocol.NewCNPeer(srvc.ctx, conn) peer := NewPeer(srvc.ctx, conn)
eRecv := make(chan *protocol.PacketEvent) eRecv := make(chan *PacketEvent)
peerConnections <- newPeerConnection{channel: eRecv, peer: peer} peerConnections <- newPeerConnection{channel: eRecv, peer: peer}
go peer.Handler(eRecv) go peer.Handler(eRecv)
} }
} }
func (srvc *Service) getPeer(channel chan *protocol.PacketEvent) *protocol.CNPeer { func (srvc *Service) getPeer(channel chan *PacketEvent) *Peer {
return srvc.peers[channel] return srvc.peers[channel]
} }
func (srvc *Service) setPeer(channel chan *protocol.PacketEvent, peer *protocol.CNPeer) { func (srvc *Service) setPeer(channel chan *PacketEvent, peer *Peer) {
srvc.peers[channel] = peer srvc.peers[channel] = peer
} }
func (srvc *Service) removePeer(channel chan *protocol.PacketEvent) { func (srvc *Service) removePeer(channel chan *PacketEvent) {
delete(srvc.peers, channel) delete(srvc.peers, channel)
} }
@ -147,7 +147,7 @@ func (srvc *Service) Stopped() <-chan struct{} {
// if f returns false, the iteration is stopped. // if f returns false, the iteration is stopped.
// NOTE: the peer map is not locked while iterating, if you're calling this // NOTE: the peer map is not locked while iterating, if you're calling this
// outside of the service's event loop, you'll need to lock the peer map yourself. // outside of the service's event loop, you'll need to lock the peer map yourself.
func (srvc *Service) RangePeers(f func(peer *protocol.CNPeer) bool) { func (srvc *Service) RangePeers(f func(peer *Peer) bool) {
for _, peer := range srvc.peers { for _, peer := range srvc.peers {
if !f(peer) { if !f(peer) {
break break
@ -167,7 +167,7 @@ func (srvc *Service) Unlock() {
func (srvc *Service) stop() { func (srvc *Service) stop() {
// OnDisconnect handler might need to do something important // OnDisconnect handler might need to do something important
srvc.RangePeers(func(peer *protocol.CNPeer) bool { srvc.RangePeers(func(peer *Peer) bool {
peer.Kill() peer.Kill()
if srvc.OnDisconnect != nil { if srvc.OnDisconnect != nil {
srvc.OnDisconnect(peer) srvc.OnDisconnect(peer)
@ -196,7 +196,7 @@ func (srvc *Service) handleEvents(peerPipe <-chan newPeerConnection) {
Chan: reflect.ValueOf(peerPipe), Chan: reflect.ValueOf(peerPipe),
}) })
addPoll := func(channel chan *protocol.PacketEvent) { addPoll := func(channel chan *PacketEvent) {
poll = append(poll, reflect.SelectCase{ poll = append(poll, reflect.SelectCase{
Dir: reflect.SelectRecv, Dir: reflect.SelectRecv,
Chan: reflect.ValueOf(channel), Chan: reflect.ValueOf(channel),
@ -221,7 +221,7 @@ func (srvc *Service) handleEvents(peerPipe <-chan newPeerConnection) {
addPoll(evnt.channel) addPoll(evnt.channel)
srvc.connect(evnt.channel, evnt.peer) srvc.connect(evnt.channel, evnt.peer)
default: // peer event default: // peer event
channel := poll[chosen].Chan.Interface().(chan *protocol.PacketEvent) channel := poll[chosen].Chan.Interface().(chan *PacketEvent)
peer := srvc.getPeer(channel) peer := srvc.getPeer(channel)
if peer == nil { if peer == nil {
log.Printf("Unknown peer event: %v", value) log.Printf("Unknown peer event: %v", value)
@ -229,7 +229,7 @@ func (srvc *Service) handleEvents(peerPipe <-chan newPeerConnection) {
continue continue
} }
evnt, ok := value.Interface().(*protocol.PacketEvent) evnt, ok := value.Interface().(*PacketEvent)
if !recvOK || !ok || evnt == nil { if !recvOK || !ok || evnt == nil {
// peer disconnected, remove it from our poll queue // peer disconnected, remove it from our poll queue
removePoll(chosen) removePoll(chosen)
@ -250,7 +250,7 @@ func (srvc *Service) handleEvents(peerPipe <-chan newPeerConnection) {
} }
} }
func (srvc *Service) handlePacket(peer *protocol.CNPeer, typeID uint32, pkt protocol.Packet) error { func (srvc *Service) handlePacket(peer *Peer, typeID uint32, pkt protocol.Packet) error {
if hndlr, ok := srvc.packetHandlers[typeID]; ok { if hndlr, ok := srvc.packetHandlers[typeID]; ok {
// fmt.Printf("Handling packet %x\n", typeID) // fmt.Printf("Handling packet %x\n", typeID)
if err := hndlr(peer, pkt); err != nil { if err := hndlr(peer, pkt); err != nil {
@ -263,7 +263,7 @@ func (srvc *Service) handlePacket(peer *protocol.CNPeer, typeID uint32, pkt prot
return nil return nil
} }
func (srvc *Service) disconnect(channel chan *protocol.PacketEvent, peer *protocol.CNPeer) { func (srvc *Service) disconnect(channel chan *PacketEvent, peer *Peer) {
log.Printf("Peer %p disconnected from %s\n", peer, srvc.Name) log.Printf("Peer %p disconnected from %s\n", peer, srvc.Name)
if srvc.OnDisconnect != nil { if srvc.OnDisconnect != nil {
srvc.OnDisconnect(peer) srvc.OnDisconnect(peer)
@ -272,7 +272,7 @@ func (srvc *Service) disconnect(channel chan *protocol.PacketEvent, peer *protoc
srvc.removePeer(channel) srvc.removePeer(channel)
} }
func (srvc *Service) connect(channel chan *protocol.PacketEvent, peer *protocol.CNPeer) { func (srvc *Service) connect(channel chan *PacketEvent, peer *Peer) {
log.Printf("New peer %p connected to %s\n", peer, srvc.Name) log.Printf("New peer %p connected to %s\n", peer, srvc.Name)
if srvc.OnConnect != nil { if srvc.OnConnect != nil {
srvc.OnConnect(peer) srvc.OnConnect(peer)

97
cnet/service_test.go Normal file
View File

@ -0,0 +1,97 @@
package cnet_test
import (
"context"
"fmt"
"log"
"net"
"os"
"sync"
"testing"
"time"
"github.com/CPunch/gopenfusion/cnet"
"github.com/CPunch/gopenfusion/cnet/protocol"
"github.com/CPunch/gopenfusion/util"
"github.com/matryer/is"
)
var (
srvcPort int
)
const (
timeout = 2 * time.Second
maxDummyPeers = 5
)
func TestMain(m *testing.M) {
var err error
srvcPort, err = cnet.RandomPort()
if err != nil {
panic(err)
}
os.Exit(m.Run())
}
func TestService(t *testing.T) {
is := is.New(t)
ctx, cancel := context.WithCancel(context.Background())
srvc := cnet.NewService(ctx, "TEST", srvcPort)
wg := sync.WaitGroup{}
// shutdown service when test is done
defer func() {
cancel()
is.True(util.SelectWithTimeout(srvc.Stopped(), timeout)) // wait for service to stop with timeout
}()
// our dummy packet handler
wg.Add(maxDummyPeers)
srvc.AddPacketHandler(0x1234, func(peer *cnet.Peer, pkt protocol.Packet) error {
log.Printf("Received packet %#v", pkt)
wg.Done()
return nil
})
// wait for all dummy peers to connect and disconnect
wg.Add(maxDummyPeers)
srvc.OnConnect = func(peer *cnet.Peer) {
wg.Done()
}
wg.Add(maxDummyPeers)
srvc.OnDisconnect = func(peer *cnet.Peer) {
wg.Done()
}
// run service
go func() { is.NoErr(srvc.Start()) }() // srvc.Start error
is.True(util.SelectWithTimeout(srvc.Started(), timeout)) // wait for service to start with timeout
wg.Add(maxDummyPeers * 2) // 2 wg.Done() per peer for receiving packets
for i := 0; i < maxDummyPeers; i++ {
go func() {
// make dummy client
conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", srvcPort))
is.NoErr(err) // net.Dial error
peer := cnet.NewPeer(ctx, conn)
go func() {
defer peer.Kill()
// send dummy packets
for i := 0; i < 2; i++ {
is.NoErr(peer.Send(0x1234)) // peer.Send error
}
}()
// we wait until Handler gracefully exits (peer was killed)
peer.Handler(make(chan *cnet.PacketEvent))
wg.Done()
}()
}
is.True(util.WaitWithTimeout(&wg, timeout)) // wait for all dummy peers to be done with timeout
}

View File

@ -6,7 +6,7 @@ import (
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"github.com/CPunch/gopenfusion/internal/protocol" "github.com/CPunch/gopenfusion/cnet/protocol"
"github.com/georgysavva/scany/v2/sqlscan" "github.com/georgysavva/scany/v2/sqlscan"
) )

View File

@ -8,8 +8,8 @@ import (
"github.com/matryer/is" "github.com/matryer/is"
"github.com/CPunch/gopenfusion/cnet/protocol"
"github.com/CPunch/gopenfusion/internal/db" "github.com/CPunch/gopenfusion/internal/db"
"github.com/CPunch/gopenfusion/internal/protocol"
"github.com/bitcomplete/sqltestutil" "github.com/bitcomplete/sqltestutil"
) )

View File

@ -3,7 +3,7 @@ package db
import ( import (
"database/sql" "database/sql"
"github.com/CPunch/gopenfusion/internal/protocol" "github.com/CPunch/gopenfusion/cnet/protocol"
) )
type Inventory struct { type Inventory struct {

View File

@ -3,8 +3,8 @@ package db
import ( import (
"database/sql" "database/sql"
"github.com/CPunch/gopenfusion/cnet/protocol"
"github.com/CPunch/gopenfusion/config" "github.com/CPunch/gopenfusion/config"
"github.com/CPunch/gopenfusion/internal/protocol"
"github.com/blockloop/scan" "github.com/blockloop/scan"
) )

View File

@ -1,15 +0,0 @@
package entity
import "github.com/CPunch/gopenfusion/config"
type ChunkPosition struct {
X int
Y int
}
func MakeChunkPosition(x, y int) ChunkPosition {
return ChunkPosition{
X: x / (config.VIEW_DISTANCE / 3),
Y: y / (config.VIEW_DISTANCE / 3),
}
}

View File

@ -1,117 +0,0 @@
package service_test
import (
"context"
"fmt"
"log"
"net"
"os"
"sync"
"testing"
"time"
"github.com/CPunch/gopenfusion/internal/protocol"
"github.com/CPunch/gopenfusion/internal/service"
"github.com/matryer/is"
)
var (
srvcPort int
)
const (
timeout = 2
maxDummyPeers = 5
)
func selectWithTimeout(ch <-chan struct{}, seconds int) bool {
select {
case <-ch:
return true
case <-time.After(time.Duration(seconds) * time.Second):
return false
}
}
func waitWithTimeout(wg *sync.WaitGroup, seconds int) bool {
done := make(chan struct{})
go func() {
defer close(done)
wg.Wait()
}()
return selectWithTimeout(done, seconds)
}
func TestMain(m *testing.M) {
var err error
srvcPort, err = service.RandomPort()
if err != nil {
panic(err)
}
os.Exit(m.Run())
}
func TestService(t *testing.T) {
is := is.New(t)
ctx, cancel := context.WithCancel(context.Background())
srvc := service.NewService(ctx, "TEST", srvcPort)
wg := sync.WaitGroup{}
// shutdown service when test is done
defer func() {
cancel()
is.True(selectWithTimeout(srvc.Stopped(), timeout)) // wait for service to stop with timeout
}()
// our dummy packet handler
srvc.AddPacketHandler(0x1234, func(peer *protocol.CNPeer, pkt protocol.Packet) error {
log.Printf("Received packet %#v", pkt)
wg.Done()
return nil
})
// wait for all dummy peers to connect and disconnect
wg.Add(maxDummyPeers)
srvc.OnConnect = func(peer *protocol.CNPeer) {
wg.Done()
}
wg.Add(maxDummyPeers)
srvc.OnDisconnect = func(peer *protocol.CNPeer) {
wg.Done()
}
// run service
go func() {
is.NoErr(srvc.Start()) // srvc.Start error
}()
is.True(selectWithTimeout(srvc.Started(), timeout)) // wait for service to start with timeout
wg.Add(maxDummyPeers * 3) // 3 wg.Done() calls per dummy peer. 2 per peer for receiving packets, 1 for Handler() exit
for i := 0; i < maxDummyPeers; i++ {
go func() {
// make dummy client
conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", srvcPort))
is.NoErr(err) // net.Dial error
peer := protocol.NewCNPeer(ctx, conn)
go func() {
defer peer.Kill()
// send dummy packets
for i := 0; i < 2; i++ {
is.NoErr(peer.Send(0x1234)) // peer.Send error
}
}()
// we wait until Handler gracefully exits (peer was killed)
peer.Handler(make(chan *protocol.PacketEvent))
wg.Done()
}()
}
is.True(waitWithTimeout(&wg, timeout)) // wait for all dummy peers to be done with timeout
}

View File

@ -7,10 +7,12 @@ import (
"log" "log"
"math/rand" "math/rand"
"github.com/CPunch/gopenfusion/cnet"
"github.com/CPunch/gopenfusion/cnet/protocol"
"github.com/CPunch/gopenfusion/config" "github.com/CPunch/gopenfusion/config"
"github.com/CPunch/gopenfusion/internal/db" "github.com/CPunch/gopenfusion/internal/db"
"github.com/CPunch/gopenfusion/internal/protocol"
"github.com/CPunch/gopenfusion/internal/redis" "github.com/CPunch/gopenfusion/internal/redis"
"github.com/CPunch/gopenfusion/util"
) )
const ( const (
@ -25,14 +27,14 @@ const (
LOGIN_UPDATED_EUALA_REQUIRED = 9 LOGIN_UPDATED_EUALA_REQUIRED = 9
) )
func (server *LoginServer) AcceptLogin(peer *protocol.CNPeer, SzID string, IClientVerC int32, ISlotNum int8, data []protocol.SP_LS2CL_REP_CHAR_INFO) error { func (server *LoginServer) AcceptLogin(peer *cnet.Peer, SzID string, IClientVerC int32, ISlotNum int8, data []protocol.SP_LS2CL_REP_CHAR_INFO) error {
resp := protocol.SP_LS2CL_REP_LOGIN_SUCC{ resp := protocol.SP_LS2CL_REP_LOGIN_SUCC{
SzID: SzID, SzID: SzID,
ICharCount: int8(len(data)), ICharCount: int8(len(data)),
ISlotNum: ISlotNum, ISlotNum: ISlotNum,
IPaymentFlag: 1, IPaymentFlag: 1,
IOpenBetaFlag: 0, IOpenBetaFlag: 0,
UiSvrTime: protocol.GetTime(), UiSvrTime: util.GetTime(),
} }
if err := peer.Send(protocol.P_LS2CL_REP_LOGIN_SUCC, resp); err != nil { if err := peer.Send(protocol.P_LS2CL_REP_LOGIN_SUCC, resp); err != nil {
@ -61,7 +63,7 @@ func (server *LoginServer) AcceptLogin(peer *protocol.CNPeer, SzID string, IClie
return nil return nil
} }
func (server *LoginServer) Login(peer *protocol.CNPeer, pkt protocol.Packet) error { func (server *LoginServer) Login(peer *cnet.Peer, pkt protocol.Packet) error {
var loginPkt protocol.SP_CL2LS_REQ_LOGIN var loginPkt protocol.SP_CL2LS_REQ_LOGIN
pkt.Decode(&loginPkt) pkt.Decode(&loginPkt)
@ -137,7 +139,7 @@ func (server *LoginServer) Login(peer *protocol.CNPeer, pkt protocol.Packet) err
return server.AcceptLogin(peer, loginPkt.SzID, loginPkt.IClientVerC, 1, charInfo[:len(plrs)]) return server.AcceptLogin(peer, loginPkt.SzID, loginPkt.IClientVerC, 1, charInfo[:len(plrs)])
} }
func (server *LoginServer) CheckCharacterName(peer *protocol.CNPeer, pkt protocol.Packet) error { func (server *LoginServer) CheckCharacterName(peer *cnet.Peer, pkt protocol.Packet) error {
var charPkt protocol.SP_CL2LS_REQ_CHECK_CHAR_NAME var charPkt protocol.SP_CL2LS_REQ_CHECK_CHAR_NAME
pkt.Decode(&charPkt) pkt.Decode(&charPkt)
@ -148,7 +150,7 @@ func (server *LoginServer) CheckCharacterName(peer *protocol.CNPeer, pkt protoco
}) })
} }
func (server *LoginServer) SaveCharacterName(peer *protocol.CNPeer, pkt protocol.Packet) error { func (server *LoginServer) SaveCharacterName(peer *cnet.Peer, pkt protocol.Packet) error {
var charPkt protocol.SP_CL2LS_REQ_SAVE_CHAR_NAME var charPkt protocol.SP_CL2LS_REQ_SAVE_CHAR_NAME
pkt.Decode(&charPkt) pkt.Decode(&charPkt)
@ -201,7 +203,7 @@ func validateCharacterCreation(character *protocol.SP_CL2LS_REQ_CHAR_CREATE) boo
return true return true
} }
func SendFail(peer *protocol.CNPeer) error { func SendFail(peer *cnet.Peer) error {
if err := peer.Send(protocol.P_LS2CL_REP_SHARD_SELECT_FAIL, protocol.SP_LS2CL_REP_SHARD_SELECT_FAIL{ if err := peer.Send(protocol.P_LS2CL_REP_SHARD_SELECT_FAIL, protocol.SP_LS2CL_REP_SHARD_SELECT_FAIL{
IErrorCode: 2, IErrorCode: 2,
}); err != nil { }); err != nil {
@ -211,7 +213,7 @@ func SendFail(peer *protocol.CNPeer) error {
return nil return nil
} }
func (server *LoginServer) CharacterCreate(peer *protocol.CNPeer, pkt protocol.Packet) error { func (server *LoginServer) CharacterCreate(peer *cnet.Peer, pkt protocol.Packet) error {
var charPkt protocol.SP_CL2LS_REQ_CHAR_CREATE var charPkt protocol.SP_CL2LS_REQ_CHAR_CREATE
pkt.Decode(&charPkt) pkt.Decode(&charPkt)
@ -244,7 +246,7 @@ func (server *LoginServer) CharacterCreate(peer *protocol.CNPeer, pkt protocol.P
}) })
} }
func (server *LoginServer) CharacterDelete(peer *protocol.CNPeer, pkt protocol.Packet) error { func (server *LoginServer) CharacterDelete(peer *cnet.Peer, pkt protocol.Packet) error {
var charPkt protocol.SP_CL2LS_REQ_CHAR_DELETE var charPkt protocol.SP_CL2LS_REQ_CHAR_DELETE
pkt.Decode(&charPkt) pkt.Decode(&charPkt)
@ -263,7 +265,7 @@ func (server *LoginServer) CharacterDelete(peer *protocol.CNPeer, pkt protocol.P
}) })
} }
func (server *LoginServer) ShardSelect(peer *protocol.CNPeer, pkt protocol.Packet) error { func (server *LoginServer) ShardSelect(peer *cnet.Peer, pkt protocol.Packet) error {
var selection protocol.SP_CL2LS_REQ_CHAR_SELECT var selection protocol.SP_CL2LS_REQ_CHAR_SELECT
pkt.Decode(&selection) pkt.Decode(&selection)
@ -319,7 +321,7 @@ func (server *LoginServer) ShardSelect(peer *protocol.CNPeer, pkt protocol.Packe
return peer.Send(protocol.P_LS2CL_REP_SHARD_SELECT_SUCC, resp) return peer.Send(protocol.P_LS2CL_REP_SHARD_SELECT_SUCC, resp)
} }
func (server *LoginServer) FinishTutorial(peer *protocol.CNPeer, pkt protocol.Packet) error { func (server *LoginServer) FinishTutorial(peer *cnet.Peer, pkt protocol.Packet) error {
var charPkt protocol.SP_CL2LS_REQ_SAVE_CHAR_TUTOR var charPkt protocol.SP_CL2LS_REQ_SAVE_CHAR_TUTOR
pkt.Decode(&charPkt) pkt.Decode(&charPkt)

View File

@ -3,20 +3,20 @@ package login
import ( import (
"context" "context"
"github.com/CPunch/gopenfusion/cnet"
"github.com/CPunch/gopenfusion/cnet/protocol"
"github.com/CPunch/gopenfusion/internal/db" "github.com/CPunch/gopenfusion/internal/db"
"github.com/CPunch/gopenfusion/internal/protocol"
"github.com/CPunch/gopenfusion/internal/redis" "github.com/CPunch/gopenfusion/internal/redis"
"github.com/CPunch/gopenfusion/internal/service"
) )
type LoginServer struct { type LoginServer struct {
service *service.Service service *cnet.Service
dbHndlr *db.DBHandler dbHndlr *db.DBHandler
redisHndlr *redis.RedisHandler redisHndlr *redis.RedisHandler
} }
func NewLoginServer(ctx context.Context, dbHndlr *db.DBHandler, redisHndlr *redis.RedisHandler, port int) (*LoginServer, error) { func NewLoginServer(ctx context.Context, dbHndlr *db.DBHandler, redisHndlr *redis.RedisHandler, port int) (*LoginServer, error) {
srvc := service.NewService(ctx, "LOGIN", port) srvc := cnet.NewService(ctx, "LOGIN", port)
server := &LoginServer{ server := &LoginServer{
service: srvc, service: srvc,
@ -30,14 +30,14 @@ func NewLoginServer(ctx context.Context, dbHndlr *db.DBHandler, redisHndlr *redi
srvc.AddPacketHandler(protocol.P_CL2LS_REQ_CHAR_CREATE, server.CharacterCreate) srvc.AddPacketHandler(protocol.P_CL2LS_REQ_CHAR_CREATE, server.CharacterCreate)
srvc.AddPacketHandler(protocol.P_CL2LS_REQ_CHAR_SELECT, server.ShardSelect) srvc.AddPacketHandler(protocol.P_CL2LS_REQ_CHAR_SELECT, server.ShardSelect)
srvc.AddPacketHandler(protocol.P_CL2LS_REQ_CHAR_DELETE, server.CharacterDelete) srvc.AddPacketHandler(protocol.P_CL2LS_REQ_CHAR_DELETE, server.CharacterDelete)
srvc.AddPacketHandler(protocol.P_CL2LS_REQ_SHARD_SELECT, service.StubbedPacket) srvc.AddPacketHandler(protocol.P_CL2LS_REQ_SHARD_SELECT, cnet.StubbedPacket)
srvc.AddPacketHandler(protocol.P_CL2LS_REQ_SHARD_LIST_INFO, service.StubbedPacket) srvc.AddPacketHandler(protocol.P_CL2LS_REQ_SHARD_LIST_INFO, cnet.StubbedPacket)
srvc.AddPacketHandler(protocol.P_CL2LS_CHECK_NAME_LIST, service.StubbedPacket) srvc.AddPacketHandler(protocol.P_CL2LS_CHECK_NAME_LIST, cnet.StubbedPacket)
srvc.AddPacketHandler(protocol.P_CL2LS_REQ_SAVE_CHAR_TUTOR, server.FinishTutorial) srvc.AddPacketHandler(protocol.P_CL2LS_REQ_SAVE_CHAR_TUTOR, server.FinishTutorial)
srvc.AddPacketHandler(protocol.P_CL2LS_REQ_PC_EXIT_DUPLICATE, service.StubbedPacket) srvc.AddPacketHandler(protocol.P_CL2LS_REQ_PC_EXIT_DUPLICATE, cnet.StubbedPacket)
srvc.AddPacketHandler(protocol.P_CL2LS_REP_LIVE_CHECK, service.StubbedPacket) srvc.AddPacketHandler(protocol.P_CL2LS_REP_LIVE_CHECK, cnet.StubbedPacket)
srvc.AddPacketHandler(protocol.P_CL2LS_REQ_CHANGE_CHAR_NAME, service.StubbedPacket) srvc.AddPacketHandler(protocol.P_CL2LS_REQ_CHANGE_CHAR_NAME, cnet.StubbedPacket)
srvc.AddPacketHandler(protocol.P_CL2LS_REQ_SERVER_SELECT, service.StubbedPacket) srvc.AddPacketHandler(protocol.P_CL2LS_REQ_SERVER_SELECT, cnet.StubbedPacket)
return server, nil return server, nil
} }

View File

@ -3,11 +3,12 @@ package shard
import ( import (
"fmt" "fmt"
"github.com/CPunch/gopenfusion/internal/entity" "github.com/CPunch/gopenfusion/cnet"
"github.com/CPunch/gopenfusion/internal/protocol" "github.com/CPunch/gopenfusion/cnet/protocol"
"github.com/CPunch/gopenfusion/shard/entity"
) )
func (server *ShardServer) freeChat(peer *protocol.CNPeer, pkt protocol.Packet) error { func (server *ShardServer) freeChat(peer *cnet.Peer, pkt protocol.Packet) error {
var chat protocol.SP_CL2FE_REQ_SEND_FREECHAT_MESSAGE var chat protocol.SP_CL2FE_REQ_SEND_FREECHAT_MESSAGE
pkt.Decode(&chat) pkt.Decode(&chat)
@ -24,7 +25,7 @@ func (server *ShardServer) freeChat(peer *protocol.CNPeer, pkt protocol.Packet)
}) })
} }
func (server *ShardServer) menuChat(peer *protocol.CNPeer, pkt protocol.Packet) error { func (server *ShardServer) menuChat(peer *cnet.Peer, pkt protocol.Packet) error {
var chat protocol.SP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE var chat protocol.SP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE
pkt.Decode(&chat) pkt.Decode(&chat)
@ -41,7 +42,7 @@ func (server *ShardServer) menuChat(peer *protocol.CNPeer, pkt protocol.Packet)
}) })
} }
func (server *ShardServer) emoteChat(peer *protocol.CNPeer, pkt protocol.Packet) error { func (server *ShardServer) emoteChat(peer *cnet.Peer, pkt protocol.Packet) error {
var chat protocol.SP_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT var chat protocol.SP_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT
pkt.Decode(&chat) pkt.Decode(&chat)

View File

@ -3,8 +3,22 @@ package entity
import ( import (
"log" "log"
"sync" "sync"
"github.com/CPunch/gopenfusion/config"
) )
type ChunkPosition struct {
X int
Y int
}
func MakeChunkPosition(x, y int) ChunkPosition {
return ChunkPosition{
X: x / (config.VIEW_DISTANCE / 3),
Y: y / (config.VIEW_DISTANCE / 3),
}
}
type Chunk struct { type Chunk struct {
Position ChunkPosition Position ChunkPosition
entities map[Entity]struct{} entities map[Entity]struct{}

View File

@ -1,6 +1,6 @@
package entity package entity
import "github.com/CPunch/gopenfusion/internal/protocol" import "github.com/CPunch/gopenfusion/cnet"
type EntityKind int type EntityKind int
@ -20,6 +20,6 @@ type Entity interface {
SetPosition(x, y, z int) SetPosition(x, y, z int)
SetAngle(angle int) SetAngle(angle int)
DisappearFromViewOf(peer *protocol.CNPeer) DisappearFromViewOf(peer *cnet.Peer)
EnterIntoViewOf(peer *protocol.CNPeer) EnterIntoViewOf(peer *cnet.Peer)
} }

View File

@ -3,7 +3,7 @@ package entity_test
import ( import (
"testing" "testing"
"github.com/CPunch/gopenfusion/internal/entity" "github.com/CPunch/gopenfusion/shard/entity"
"github.com/matryer/is" "github.com/matryer/is"
) )

View File

@ -3,7 +3,8 @@ package entity
import ( import (
"sync/atomic" "sync/atomic"
"github.com/CPunch/gopenfusion/internal/protocol" "github.com/CPunch/gopenfusion/cnet"
"github.com/CPunch/gopenfusion/cnet/protocol"
) )
type NPC struct { type NPC struct {
@ -62,13 +63,13 @@ func (npc *NPC) SetAngle(angle int) {
npc.Angle = angle npc.Angle = angle
} }
func (npc *NPC) DisappearFromViewOf(peer *protocol.CNPeer) { func (npc *NPC) DisappearFromViewOf(peer *cnet.Peer) {
peer.Send(protocol.P_FE2CL_NPC_EXIT, protocol.SP_FE2CL_NPC_EXIT{ peer.Send(protocol.P_FE2CL_NPC_EXIT, protocol.SP_FE2CL_NPC_EXIT{
INPC_ID: int32(npc.ID), INPC_ID: int32(npc.ID),
}) })
} }
func (npc *NPC) EnterIntoViewOf(peer *protocol.CNPeer) { func (npc *NPC) EnterIntoViewOf(peer *cnet.Peer) {
peer.Send(protocol.P_FE2CL_NPC_NEW, protocol.SP_FE2CL_NPC_NEW{ peer.Send(protocol.P_FE2CL_NPC_NEW, protocol.SP_FE2CL_NPC_NEW{
NPCAppearanceData: npc.GetAppearanceData(), NPCAppearanceData: npc.GetAppearanceData(),
}) })

View File

@ -1,17 +1,18 @@
package entity package entity
import ( import (
"github.com/CPunch/gopenfusion/cnet"
"github.com/CPunch/gopenfusion/cnet/protocol"
"github.com/CPunch/gopenfusion/internal/db" "github.com/CPunch/gopenfusion/internal/db"
"github.com/CPunch/gopenfusion/internal/protocol"
) )
type Player struct { type Player struct {
db.Player db.Player
Peer *protocol.CNPeer Peer *cnet.Peer
Chunk ChunkPosition Chunk ChunkPosition
} }
func NewPlayer(peer *protocol.CNPeer, player *db.Player) *Player { func NewPlayer(peer *cnet.Peer, player *db.Player) *Player {
return &Player{ return &Player{
Player: *player, Player: *player,
Peer: peer, Peer: peer,
@ -51,13 +52,13 @@ func (plr *Player) SetAngle(angle int) {
plr.Angle = angle plr.Angle = angle
} }
func (plr *Player) DisappearFromViewOf(peer *protocol.CNPeer) { func (plr *Player) DisappearFromViewOf(peer *cnet.Peer) {
peer.Send(protocol.P_FE2CL_PC_EXIT, protocol.SP_FE2CL_PC_EXIT{ peer.Send(protocol.P_FE2CL_PC_EXIT, protocol.SP_FE2CL_PC_EXIT{
IID: int32(plr.PlayerID), IID: int32(plr.PlayerID),
}) })
} }
func (plr *Player) EnterIntoViewOf(peer *protocol.CNPeer) { func (plr *Player) EnterIntoViewOf(peer *cnet.Peer) {
peer.Send(protocol.P_FE2CL_PC_NEW, protocol.SP_FE2CL_PC_NEW{ peer.Send(protocol.P_FE2CL_PC_NEW, protocol.SP_FE2CL_PC_NEW{
PCAppearanceData: plr.GetAppearanceData(), PCAppearanceData: plr.GetAppearanceData(),
}) })

View File

@ -1,7 +1,7 @@
package shard package shard
import ( import (
"github.com/CPunch/gopenfusion/internal/entity" "github.com/CPunch/gopenfusion/shard/entity"
) )
func (server *ShardServer) addEntity(e entity.Entity) { func (server *ShardServer) addEntity(e entity.Entity) {

View File

@ -4,12 +4,14 @@ import (
"fmt" "fmt"
"log" "log"
"github.com/CPunch/gopenfusion/internal/entity" "github.com/CPunch/gopenfusion/cnet"
"github.com/CPunch/gopenfusion/internal/protocol" "github.com/CPunch/gopenfusion/cnet/protocol"
"github.com/CPunch/gopenfusion/internal/redis" "github.com/CPunch/gopenfusion/internal/redis"
"github.com/CPunch/gopenfusion/shard/entity"
"github.com/CPunch/gopenfusion/util"
) )
func (server *ShardServer) attachPlayer(peer *protocol.CNPeer, meta redis.LoginMetadata) (*entity.Player, error) { func (server *ShardServer) attachPlayer(peer *cnet.Peer, meta redis.LoginMetadata) (*entity.Player, error) {
dbPlr, err := server.dbHndlr.GetPlayer(int(meta.PlayerID)) dbPlr, err := server.dbHndlr.GetPlayer(int(meta.PlayerID))
if err != nil { if err != nil {
return nil, err return nil, err
@ -24,7 +26,7 @@ func (server *ShardServer) attachPlayer(peer *protocol.CNPeer, meta redis.LoginM
return plr, nil return plr, nil
} }
func (server *ShardServer) RequestEnter(peer *protocol.CNPeer, pkt protocol.Packet) error { func (server *ShardServer) RequestEnter(peer *cnet.Peer, pkt protocol.Packet) error {
var enter protocol.SP_CL2FE_REQ_PC_ENTER var enter protocol.SP_CL2FE_REQ_PC_ENTER
pkt.Decode(&enter) pkt.Decode(&enter)
@ -49,13 +51,13 @@ func (server *ShardServer) RequestEnter(peer *protocol.CNPeer, pkt protocol.Pack
resp := &protocol.SP_FE2CL_REP_PC_ENTER_SUCC{ resp := &protocol.SP_FE2CL_REP_PC_ENTER_SUCC{
IID: int32(plr.PlayerID), IID: int32(plr.PlayerID),
PCLoadData2CL: plr.ToPCLoadData2CL(), PCLoadData2CL: plr.ToPCLoadData2CL(),
UiSvrTime: protocol.GetTime(), UiSvrTime: util.GetTime(),
} }
// setup peer // setup peer
peer.E_key = protocol.CreateNewKey(resp.UiSvrTime, uint64(resp.IID+1), uint64(resp.PCLoadData2CL.IFusionMatter+1)) peer.E_key = protocol.CreateNewKey(resp.UiSvrTime, uint64(resp.IID+1), uint64(resp.PCLoadData2CL.IFusionMatter+1))
peer.FE_key = loginData.FEKey peer.FE_key = loginData.FEKey
peer.SetActiveKey(protocol.USE_FE) peer.SetActiveKey(cnet.USE_FE)
log.Printf("Player %d (AccountID %d) entered\n", resp.IID, loginData.AccountID) log.Printf("Player %d (AccountID %d) entered\n", resp.IID, loginData.AccountID)
if err := peer.Send(protocol.P_FE2CL_REP_PC_ENTER_SUCC, resp); err != nil { if err := peer.Send(protocol.P_FE2CL_REP_PC_ENTER_SUCC, resp); err != nil {
@ -65,7 +67,7 @@ func (server *ShardServer) RequestEnter(peer *protocol.CNPeer, pkt protocol.Pack
return nil return nil
} }
func (server *ShardServer) LoadingComplete(peer *protocol.CNPeer, pkt protocol.Packet) error { func (server *ShardServer) LoadingComplete(peer *cnet.Peer, pkt protocol.Packet) error {
var loadComplete protocol.SP_CL2FE_REQ_PC_LOADING_COMPLETE var loadComplete protocol.SP_CL2FE_REQ_PC_LOADING_COMPLETE
pkt.Decode(&loadComplete) pkt.Decode(&loadComplete)

View File

@ -3,8 +3,10 @@ package shard
import ( import (
"fmt" "fmt"
"github.com/CPunch/gopenfusion/internal/entity" "github.com/CPunch/gopenfusion/cnet"
"github.com/CPunch/gopenfusion/internal/protocol" "github.com/CPunch/gopenfusion/cnet/protocol"
"github.com/CPunch/gopenfusion/shard/entity"
"github.com/CPunch/gopenfusion/util"
) )
func (server *ShardServer) updatePlayerPosition(plr *entity.Player, X, Y, Z, Angle int) { func (server *ShardServer) updatePlayerPosition(plr *entity.Player, X, Y, Z, Angle int) {
@ -15,7 +17,7 @@ func (server *ShardServer) updatePlayerPosition(plr *entity.Player, X, Y, Z, Ang
server.updateEntityChunk(plr, plr.GetChunkPos(), entity.MakeChunkPosition(X, Y)) server.updateEntityChunk(plr, plr.GetChunkPos(), entity.MakeChunkPosition(X, Y))
} }
func (server *ShardServer) playerMove(peer *protocol.CNPeer, pkt protocol.Packet) error { func (server *ShardServer) playerMove(peer *cnet.Peer, pkt protocol.Packet) error {
var move protocol.SP_CL2FE_REQ_PC_MOVE var move protocol.SP_CL2FE_REQ_PC_MOVE
pkt.Decode(&move) pkt.Decode(&move)
@ -39,11 +41,11 @@ func (server *ShardServer) playerMove(peer *protocol.CNPeer, pkt protocol.Packet
CKeyValue: move.CKeyValue, CKeyValue: move.CKeyValue,
ISpeed: move.ISpeed, ISpeed: move.ISpeed,
IID: int32(plr.PlayerID), IID: int32(plr.PlayerID),
ISvrTime: protocol.GetTime(), ISvrTime: util.GetTime(),
}) })
} }
func (server *ShardServer) playerStop(peer *protocol.CNPeer, pkt protocol.Packet) error { func (server *ShardServer) playerStop(peer *cnet.Peer, pkt protocol.Packet) error {
var stop protocol.SP_CL2FE_REQ_PC_STOP var stop protocol.SP_CL2FE_REQ_PC_STOP
pkt.Decode(&stop) pkt.Decode(&stop)
@ -61,11 +63,11 @@ func (server *ShardServer) playerStop(peer *protocol.CNPeer, pkt protocol.Packet
IY: stop.IY, IY: stop.IY,
IZ: stop.IZ, IZ: stop.IZ,
IID: int32(plr.PlayerID), IID: int32(plr.PlayerID),
ISvrTime: protocol.GetTime(), ISvrTime: util.GetTime(),
}) })
} }
func (server *ShardServer) playerJump(peer *protocol.CNPeer, pkt protocol.Packet) error { func (server *ShardServer) playerJump(peer *cnet.Peer, pkt protocol.Packet) error {
var jump protocol.SP_CL2FE_REQ_PC_JUMP var jump protocol.SP_CL2FE_REQ_PC_JUMP
pkt.Decode(&jump) pkt.Decode(&jump)
@ -89,6 +91,6 @@ func (server *ShardServer) playerJump(peer *protocol.CNPeer, pkt protocol.Packet
CKeyValue: jump.CKeyValue, CKeyValue: jump.CKeyValue,
ISpeed: jump.ISpeed, ISpeed: jump.ISpeed,
IID: int32(plr.PlayerID), IID: int32(plr.PlayerID),
ISvrTime: protocol.GetTime(), ISvrTime: util.GetTime(),
}) })
} }

View File

@ -6,7 +6,7 @@ import (
"os" "os"
"github.com/CPunch/gopenfusion/config" "github.com/CPunch/gopenfusion/config"
"github.com/CPunch/gopenfusion/internal/entity" "github.com/CPunch/gopenfusion/shard/entity"
) )
type NPCData struct { type NPCData struct {

View File

@ -3,25 +3,25 @@ package shard
import ( import (
"context" "context"
"github.com/CPunch/gopenfusion/cnet"
"github.com/CPunch/gopenfusion/cnet/protocol"
"github.com/CPunch/gopenfusion/config" "github.com/CPunch/gopenfusion/config"
"github.com/CPunch/gopenfusion/internal/db" "github.com/CPunch/gopenfusion/internal/db"
"github.com/CPunch/gopenfusion/internal/entity"
"github.com/CPunch/gopenfusion/internal/protocol"
"github.com/CPunch/gopenfusion/internal/redis" "github.com/CPunch/gopenfusion/internal/redis"
"github.com/CPunch/gopenfusion/internal/service" "github.com/CPunch/gopenfusion/shard/entity"
) )
type PacketHandler func(peer *protocol.CNPeer, pkt protocol.Packet) error type PacketHandler func(peer *cnet.Peer, pkt protocol.Packet) error
type ShardServer struct { type ShardServer struct {
service *service.Service service *cnet.Service
dbHndlr *db.DBHandler dbHndlr *db.DBHandler
redisHndlr *redis.RedisHandler redisHndlr *redis.RedisHandler
chunks map[entity.ChunkPosition]*entity.Chunk chunks map[entity.ChunkPosition]*entity.Chunk
} }
func NewShardServer(ctx context.Context, dbHndlr *db.DBHandler, redisHndlr *redis.RedisHandler, port int) (*ShardServer, error) { func NewShardServer(ctx context.Context, dbHndlr *db.DBHandler, redisHndlr *redis.RedisHandler, port int) (*ShardServer, error) {
srvc := service.NewService(ctx, "SHARD", port) srvc := cnet.NewService(ctx, "SHARD", port)
server := &ShardServer{ server := &ShardServer{
service: srvc, service: srvc,
@ -55,7 +55,7 @@ func (server *ShardServer) Start() {
server.service.Start() server.service.Start()
} }
func (server *ShardServer) onDisconnect(peer *protocol.CNPeer) { func (server *ShardServer) onDisconnect(peer *cnet.Peer) {
// remove from chunks // remove from chunks
plr, ok := peer.UserData().(*entity.Player) plr, ok := peer.UserData().(*entity.Player)
if ok && plr != nil { if ok && plr != nil {
@ -63,6 +63,6 @@ func (server *ShardServer) onDisconnect(peer *protocol.CNPeer) {
} }
} }
func (server *ShardServer) onConnect(peer *protocol.CNPeer) { func (server *ShardServer) onConnect(peer *cnet.Peer) {
} }

29
util/util.go Normal file
View File

@ -0,0 +1,29 @@
package util
import (
"sync"
"time"
)
func GetTime() uint64 {
return uint64(time.Now().UnixMilli())
}
func SelectWithTimeout(ch <-chan struct{}, timeout time.Duration) bool {
select {
case <-ch:
return true
case <-time.After(timeout):
return false
}
}
func WaitWithTimeout(wg *sync.WaitGroup, timeout time.Duration) bool {
done := make(chan struct{})
go func() {
defer close(done)
wg.Wait()
}()
return SelectWithTimeout(done, timeout)
}

35
util/util_test.go Normal file
View File

@ -0,0 +1,35 @@
package util_test
import (
"sync"
"testing"
"time"
"github.com/CPunch/gopenfusion/util"
"github.com/matryer/is"
)
func TestWaitWithTimeout(t *testing.T) {
is := is.New(t)
wg := &sync.WaitGroup{}
go func() {
time.Sleep(1 * time.Second)
wg.Done()
}()
wg.Add(1)
is.True(!util.WaitWithTimeout(wg, 500*time.Millisecond)) // timeout should occur
is.True(util.WaitWithTimeout(wg, 750*time.Millisecond)) // timeout shouldn't occur
}
func TestSelectWithTimeout(t *testing.T) {
is := is.New(t)
ch := make(chan struct{})
go func() {
time.Sleep(1 * time.Second)
close(ch)
}()
is.True(!util.SelectWithTimeout(ch, 500*time.Millisecond)) // timeout should occur
is.True(util.SelectWithTimeout(ch, 750*time.Millisecond)) // timeout shouldn't occur
}