mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-11-18 02:16:23 -05:00
D2networking resolve lint issues (#492)
* Added automap.go stub * Handle errors in original AutoMap.txt file * Completed AutoMapRecord struct and comments * AutoMap loader implemented * Update from base repo * Comments added to d2netpacket and d2netpackettype. Note, the Overview for d2netpacket is in net_packet.go. It could be placed in a doc.go file but net_packet.go seemed appropriate in this case. * Comments added to d2server * client_connection.go missed from previous commit * Comments added to d2client * Doc.go added to d2networking and other corrections
This commit is contained in:
parent
aae565d528
commit
5ea6ada452
@ -2,6 +2,8 @@ package d2networking
|
|||||||
|
|
||||||
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||||
|
|
||||||
|
// ClientListener is an interface used to pass packet data from
|
||||||
|
// ClientConnections to GameServer and GameClient.
|
||||||
type ClientListener interface {
|
type ClientListener interface {
|
||||||
OnPacketReceived(packet d2netpacket.NetPacket) error
|
OnPacketReceived(packet d2netpacket.NetPacket) error
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ClientConnection is an interface for abstracting local and
|
||||||
|
// remote server connections.
|
||||||
type ClientConnection interface {
|
type ClientConnection interface {
|
||||||
Open(connectionString string, saveFilePath string) error
|
Open(connectionString string, saveFilePath string) error
|
||||||
Close() error
|
Close() error
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package d2clientconnectiontype
|
package d2clientconnectiontype
|
||||||
|
|
||||||
|
// ClientConnectionType is an enum referring to types implementing
|
||||||
|
// d2server.ClientConnection and d2client.ClientConnection.
|
||||||
type ClientConnectionType int
|
type ClientConnectionType int
|
||||||
|
|
||||||
|
//
|
||||||
const (
|
const (
|
||||||
Local ClientConnectionType = iota
|
Local ClientConnectionType = iota // Local client
|
||||||
LANServer
|
LANServer // Server
|
||||||
LANClient
|
LANClient // Remote client
|
||||||
)
|
)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// Package d2localclient facilitates communication between a local client and server.
|
||||||
package d2localclient
|
package d2localclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -9,25 +10,33 @@ import (
|
|||||||
uuid "github.com/satori/go.uuid"
|
uuid "github.com/satori/go.uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// LocalClientConnection is the implementation of ClientConnection
|
||||||
|
// for a local client.
|
||||||
type LocalClientConnection struct {
|
type LocalClientConnection struct {
|
||||||
clientListener d2networking.ClientListener
|
clientListener d2networking.ClientListener // The game client
|
||||||
uniqueId string
|
uniqueId string // Unique ID generated on construction
|
||||||
openNetworkServer bool
|
openNetworkServer bool // True if this is a server
|
||||||
playerState *d2player.PlayerState
|
playerState *d2player.PlayerState // Local player state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUniqueId returns LocalClientConnection.uniqueId.
|
||||||
func (l LocalClientConnection) GetUniqueId() string {
|
func (l LocalClientConnection) GetUniqueId() string {
|
||||||
return l.uniqueId
|
return l.uniqueId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetConnectionType returns an enum representing the connection type.
|
||||||
|
// See: d2clientconnectiontype
|
||||||
func (l LocalClientConnection) GetConnectionType() d2clientconnectiontype.ClientConnectionType {
|
func (l LocalClientConnection) GetConnectionType() d2clientconnectiontype.ClientConnectionType {
|
||||||
return d2clientconnectiontype.Local
|
return d2clientconnectiontype.Local
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendPacketToClient passes a packet to the game client for processing.
|
||||||
func (l *LocalClientConnection) SendPacketToClient(packet d2netpacket.NetPacket) error {
|
func (l *LocalClientConnection) SendPacketToClient(packet d2netpacket.NetPacket) error {
|
||||||
return l.clientListener.OnPacketReceived(packet)
|
return l.clientListener.OnPacketReceived(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create constructs a new LocalClientConnection and returns
|
||||||
|
// a pointer to it.
|
||||||
func Create(openNetworkServer bool) *LocalClientConnection {
|
func Create(openNetworkServer bool) *LocalClientConnection {
|
||||||
result := &LocalClientConnection{
|
result := &LocalClientConnection{
|
||||||
uniqueId: uuid.NewV4().String(),
|
uniqueId: uuid.NewV4().String(),
|
||||||
@ -37,6 +46,7 @@ func Create(openNetworkServer bool) *LocalClientConnection {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open creates a new GameServer, runs the server and connects this client to it.
|
||||||
func (l *LocalClientConnection) Open(connectionString string, saveFilePath string) error {
|
func (l *LocalClientConnection) Open(connectionString string, saveFilePath string) error {
|
||||||
l.SetPlayerState(d2player.LoadPlayerState(saveFilePath))
|
l.SetPlayerState(d2player.LoadPlayerState(saveFilePath))
|
||||||
d2server.Create(l.openNetworkServer)
|
d2server.Create(l.openNetworkServer)
|
||||||
@ -45,6 +55,7 @@ func (l *LocalClientConnection) Open(connectionString string, saveFilePath strin
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close disconnects from the server and destroys it.
|
||||||
func (l *LocalClientConnection) Close() error {
|
func (l *LocalClientConnection) Close() error {
|
||||||
l.SendPacketToServer(d2netpacket.CreateServerClosedPacket())
|
l.SendPacketToServer(d2netpacket.CreateServerClosedPacket())
|
||||||
d2server.OnClientDisconnected(l)
|
d2server.OnClientDisconnected(l)
|
||||||
@ -52,19 +63,23 @@ func (l *LocalClientConnection) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendPacketToServer calls d2server.OnPacketReceived with the given packet.
|
||||||
func (l *LocalClientConnection) SendPacketToServer(packet d2netpacket.NetPacket) error {
|
func (l *LocalClientConnection) SendPacketToServer(packet d2netpacket.NetPacket) error {
|
||||||
// TODO: This is going to blow up if the server has ceased to be.
|
// TODO: This is going to blow up if the server has ceased to be.
|
||||||
return d2server.OnPacketReceived(l, packet)
|
return d2server.OnPacketReceived(l, packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetClientListener sets LocalClientConnection.clientListener to the given value.
|
||||||
func (l *LocalClientConnection) SetClientListener(listener d2networking.ClientListener) {
|
func (l *LocalClientConnection) SetClientListener(listener d2networking.ClientListener) {
|
||||||
l.clientListener = listener
|
l.clientListener = listener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPlayerState returns LocalClientConnection.playerState.
|
||||||
func (l *LocalClientConnection) GetPlayerState() *d2player.PlayerState {
|
func (l *LocalClientConnection) GetPlayerState() *d2player.PlayerState {
|
||||||
return l.playerState
|
return l.playerState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetPlayerState sets LocalClientConnection.playerState to the given value.
|
||||||
func (l *LocalClientConnection) SetPlayerState(playerState *d2player.PlayerState) {
|
func (l *LocalClientConnection) SetPlayerState(playerState *d2player.PlayerState) {
|
||||||
l.playerState = playerState
|
l.playerState = playerState
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// Package d2remoteclient facilitates communication between a remote client and server.
|
||||||
package d2remoteclient
|
package d2remoteclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -5,12 +6,13 @@ import (
|
|||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking"
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking"
|
||||||
@ -19,25 +21,33 @@ import (
|
|||||||
uuid "github.com/satori/go.uuid"
|
uuid "github.com/satori/go.uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// RemoteClientConnection is the implementation of ClientConnection
|
||||||
|
// for a remote client.
|
||||||
type RemoteClientConnection struct {
|
type RemoteClientConnection struct {
|
||||||
clientListener d2networking.ClientListener
|
clientListener d2networking.ClientListener // The GameClient
|
||||||
uniqueId string
|
uniqueId string // Unique ID generated on construction
|
||||||
udpConnection *net.UDPConn
|
udpConnection *net.UDPConn // UDP connection to the server
|
||||||
active bool
|
active bool // The connection is currently open
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUniqueId returns RemoteClientConnection.uniqueId.
|
||||||
func (l RemoteClientConnection) GetUniqueId() string {
|
func (l RemoteClientConnection) GetUniqueId() string {
|
||||||
return l.uniqueId
|
return l.uniqueId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetConnectionType returns an enum representing the connection type.
|
||||||
|
// See: d2clientconnectiontype
|
||||||
func (l RemoteClientConnection) GetConnectionType() d2clientconnectiontype.ClientConnectionType {
|
func (l RemoteClientConnection) GetConnectionType() d2clientconnectiontype.ClientConnectionType {
|
||||||
return d2clientconnectiontype.LANClient
|
return d2clientconnectiontype.LANClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *RemoteClientConnection) SendPacketToClient(packet d2netpacket.NetPacket) error { // WHAT IS THIS
|
// SendPacketToClient passes a packet to the game client for processing.
|
||||||
|
func (l *RemoteClientConnection) SendPacketToClient(packet d2netpacket.NetPacket) error {
|
||||||
return l.clientListener.OnPacketReceived(packet)
|
return l.clientListener.OnPacketReceived(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create constructs a new RemoteClientConnection
|
||||||
|
// and returns a pointer to it.
|
||||||
func Create() *RemoteClientConnection {
|
func Create() *RemoteClientConnection {
|
||||||
result := &RemoteClientConnection{
|
result := &RemoteClientConnection{
|
||||||
uniqueId: uuid.NewV4().String(),
|
uniqueId: uuid.NewV4().String(),
|
||||||
@ -46,6 +56,8 @@ func Create() *RemoteClientConnection {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open runs serverListener() in a goroutine to continuously read UDP packets.
|
||||||
|
// It also sends a PlayerConnectionRequestPacket packet to the server (see d2netpacket).
|
||||||
func (l *RemoteClientConnection) Open(connectionString string, saveFilePath string) error {
|
func (l *RemoteClientConnection) Open(connectionString string, saveFilePath string) error {
|
||||||
if !strings.Contains(connectionString, ":") {
|
if !strings.Contains(connectionString, ":") {
|
||||||
connectionString += ":6669"
|
connectionString += ":6669"
|
||||||
@ -75,6 +87,8 @@ func (l *RemoteClientConnection) Open(connectionString string, saveFilePath stri
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close informs the server that this client has disconnected and sets
|
||||||
|
// RemoteClientConnection.active to false.
|
||||||
func (l *RemoteClientConnection) Close() error {
|
func (l *RemoteClientConnection) Close() error {
|
||||||
l.active = false
|
l.active = false
|
||||||
l.SendPacketToServer(d2netpacket.CreatePlayerDisconnectRequestPacket(l.GetUniqueId()))
|
l.SendPacketToServer(d2netpacket.CreatePlayerDisconnectRequestPacket(l.GetUniqueId()))
|
||||||
@ -82,6 +96,8 @@ func (l *RemoteClientConnection) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendPacketToServer compresses the JSON encoding of a NetPacket and
|
||||||
|
// sends it to the server.
|
||||||
func (l *RemoteClientConnection) SendPacketToServer(packet d2netpacket.NetPacket) error {
|
func (l *RemoteClientConnection) SendPacketToServer(packet d2netpacket.NetPacket) error {
|
||||||
data, err := json.Marshal(packet.PacketData)
|
data, err := json.Marshal(packet.PacketData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -98,10 +114,13 @@ func (l *RemoteClientConnection) SendPacketToServer(packet d2netpacket.NetPacket
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetClientListener sets RemoteClientConnection.clientListener to the given value.
|
||||||
func (l *RemoteClientConnection) SetClientListener(listener d2networking.ClientListener) {
|
func (l *RemoteClientConnection) SetClientListener(listener d2networking.ClientListener) {
|
||||||
l.clientListener = listener
|
l.clientListener = listener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// serverListener runs a while loop, reading from the GameServer's UDP
|
||||||
|
// connection.
|
||||||
func (l *RemoteClientConnection) serverListener() {
|
func (l *RemoteClientConnection) serverListener() {
|
||||||
buffer := make([]byte, 4096)
|
buffer := make([]byte, 4096)
|
||||||
for l.active {
|
for l.active {
|
||||||
|
7
d2networking/d2client/doc.go
Normal file
7
d2networking/d2client/doc.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// Package d2client provides client side connection, map and entity
|
||||||
|
// management.
|
||||||
|
/*
|
||||||
|
GameClient declares the ClientConnection interface to interact with
|
||||||
|
local and remote servers. LocalClientConnection is the host and
|
||||||
|
creates the game server (see d2server).*/
|
||||||
|
package d2client
|
@ -22,17 +22,20 @@ import (
|
|||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GameClient manages a connection to d2server.GameServer
|
||||||
|
// and keeps a synchronised copy of the map and entities.
|
||||||
type GameClient struct {
|
type GameClient struct {
|
||||||
clientConnection ClientConnection
|
clientConnection ClientConnection // Abstract local/remote connection
|
||||||
connectionType d2clientconnectiontype.ClientConnectionType
|
connectionType d2clientconnectiontype.ClientConnectionType // Type of connection (local or remote)
|
||||||
GameState *d2player.PlayerState
|
GameState *d2player.PlayerState // local player state
|
||||||
MapEngine *d2mapengine.MapEngine
|
MapEngine *d2mapengine.MapEngine // Map and entities
|
||||||
PlayerId string
|
PlayerId string // ID of the local player
|
||||||
Players map[string]*d2mapentity.Player
|
Players map[string]*d2mapentity.Player // IDs of the other players
|
||||||
Seed int64
|
Seed int64 // Map seed
|
||||||
RegenMap bool
|
RegenMap bool // Regenerate tile cache on render (map has changed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create constructs a new GameClient and returns a pointer to it.
|
||||||
func Create(connectionType d2clientconnectiontype.ClientConnectionType) (*GameClient, error) {
|
func Create(connectionType d2clientconnectiontype.ClientConnectionType) (*GameClient, error) {
|
||||||
result := &GameClient{
|
result := &GameClient{
|
||||||
MapEngine: d2mapengine.CreateMapEngine(), // TODO: Mapgen - Needs levels.txt stuff
|
MapEngine: d2mapengine.CreateMapEngine(), // TODO: Mapgen - Needs levels.txt stuff
|
||||||
@ -54,18 +57,26 @@ func Create(connectionType d2clientconnectiontype.ClientConnectionType) (*GameCl
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open creates the server and connects to it if the client is local.
|
||||||
|
// If the client is remote it sends a PlayerConnectionRequestPacket to the
|
||||||
|
// server (see d2netpacket).
|
||||||
func (g *GameClient) Open(connectionString string, saveFilePath string) error {
|
func (g *GameClient) Open(connectionString string, saveFilePath string) error {
|
||||||
return g.clientConnection.Open(connectionString, saveFilePath)
|
return g.clientConnection.Open(connectionString, saveFilePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close destroys the server if the client is local. For remote clients
|
||||||
|
// it sends a DisconnectRequestPacket (see d2netpacket).
|
||||||
func (g *GameClient) Close() error {
|
func (g *GameClient) Close() error {
|
||||||
return g.clientConnection.Close()
|
return g.clientConnection.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Destroy does the same thing as Close.
|
||||||
func (g *GameClient) Destroy() error {
|
func (g *GameClient) Destroy() error {
|
||||||
return g.clientConnection.Close()
|
return g.clientConnection.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnPacketReceived is called by the ClientConection and processes incoming
|
||||||
|
// packets.
|
||||||
func (g *GameClient) OnPacketReceived(packet d2netpacket.NetPacket) error {
|
func (g *GameClient) OnPacketReceived(packet d2netpacket.NetPacket) error {
|
||||||
switch packet.PacketType {
|
switch packet.PacketType {
|
||||||
case d2netpackettype.GenerateMap:
|
case d2netpackettype.GenerateMap:
|
||||||
@ -145,6 +156,8 @@ func (g *GameClient) OnPacketReceived(packet d2netpacket.NetPacket) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendPacketToServer calls server.OnPacketReceived if the client is local.
|
||||||
|
// If it is remote the NetPacket sent over a UDP connection to the server.
|
||||||
func (g *GameClient) SendPacketToServer(packet d2netpacket.NetPacket) error {
|
func (g *GameClient) SendPacketToServer(packet d2netpacket.NetPacket) error {
|
||||||
return g.clientConnection.SendPacketToServer(packet)
|
return g.clientConnection.SendPacketToServer(packet)
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,28 @@
|
|||||||
|
// Package d2netpackettype defines the enumerable NetPacketType.
|
||||||
package d2netpackettype
|
package d2netpackettype
|
||||||
|
|
||||||
|
// NetPacketType is an enum referring to all packet types in package
|
||||||
|
// d2netpacket.
|
||||||
type NetPacketType uint32
|
type NetPacketType uint32
|
||||||
|
|
||||||
// Warning: Do NOT re-arrange the order of these packet values unless you want to
|
//(Except NetPacket which declares a NetPacketType to specify the packet body
|
||||||
// break compatibility between clients of slightly different versions.
|
// type. See d2netpackettype.NetPacket.)
|
||||||
// Also note that the packet id is a byte, so if we use more than 256
|
//
|
||||||
// of these then we are doing something very wrong.
|
// Warning
|
||||||
|
//
|
||||||
|
// Do NOT re-arrange the order of these packet values unless you want to
|
||||||
|
// break compatibility between clients of slightly different versions.
|
||||||
|
// Also note that the packet id is a byte, so if we use more than 256 of
|
||||||
|
// these then we are doing something very wrong.
|
||||||
const (
|
const (
|
||||||
UpdateServerInfo NetPacketType = iota
|
UpdateServerInfo NetPacketType = iota // Sent by the server, client sets the given player ID and map seed
|
||||||
GenerateMap // Sent by the server to generate a map
|
GenerateMap // Sent by the server, client generates a map
|
||||||
AddPlayer // Server sends to the client to add a player
|
AddPlayer // Sent by the server, client adds a player
|
||||||
MovePlayer // Sent to the client or server to indicate player movement
|
MovePlayer // Sent by client or server, moves a player entity
|
||||||
PlayerConnectionRequest // Client sends to server to request a connection
|
PlayerConnectionRequest // Sent by the remote client when connecting
|
||||||
PlayerDisconnectionNotification // Client notifies the server that it is disconnecting
|
PlayerDisconnectionNotification // Sent by the remote client when disconnecting
|
||||||
Ping // Ping message type
|
Ping // Requests a Pong packet
|
||||||
Pong // Pong message type
|
Pong // Responds to a Ping packet
|
||||||
ServerClosed // Local host has closed the server
|
ServerClosed // Sent by the local host when it has closed the server
|
||||||
CastSkill // Sent to the client or server to indicate entity casting skill
|
CastSkill // Sent by client or server, indicates entity casting skill
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,22 @@
|
|||||||
|
// Package d2netpacket defines types which are encoded to JSON and sent in network
|
||||||
|
// packet payloads.
|
||||||
|
/*
|
||||||
|
Package d2netpacket/d2netpackettype defines a uint32 enumerable representing each
|
||||||
|
packet type.
|
||||||
|
|
||||||
|
A struct is defined for each packet type. Each struct comes with a function which
|
||||||
|
returns a NetPacket declaring the type enum (header) followed by the associated
|
||||||
|
struct (body). The NetPacket is marshalled to JSON for transport. On receipt of
|
||||||
|
the packet, the enum is read as a single byte then the remaining data (the struct)
|
||||||
|
is unmarshalled to the type associated with the type enum.*/
|
||||||
package d2netpacket
|
package d2netpacket
|
||||||
|
|
||||||
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||||
|
|
||||||
|
// NetPacket is used to wrap and send all packet types under d2netpacket.
|
||||||
|
// When decoding a packet: First the PacketType byte is read, then the
|
||||||
|
// PacketData is unmarshalled to a struct of the type associated with
|
||||||
|
// PacketType.
|
||||||
type NetPacket struct {
|
type NetPacket struct {
|
||||||
PacketType d2netpackettype.NetPacketType `json:"packetType"`
|
PacketType d2netpackettype.NetPacketType `json:"packetType"`
|
||||||
PacketData interface{} `json:"packetData"`
|
PacketData interface{} `json:"packetData"`
|
||||||
|
@ -7,6 +7,9 @@ import (
|
|||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AddPlayerPacket contains the data required to create a Player entity.
|
||||||
|
// It is sent by the server to create the entity for a newly connected
|
||||||
|
// player on a client.
|
||||||
type AddPlayerPacket struct {
|
type AddPlayerPacket struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@ -14,9 +17,11 @@ type AddPlayerPacket struct {
|
|||||||
Y int `json:"y"`
|
Y int `json:"y"`
|
||||||
HeroType d2enum.Hero `json:"hero"`
|
HeroType d2enum.Hero `json:"hero"`
|
||||||
Equipment d2inventory.CharacterEquipment `json:"equipment"`
|
Equipment d2inventory.CharacterEquipment `json:"equipment"`
|
||||||
Stats d2hero.HeroStatsState `json:"heroStats"`
|
Stats d2hero.HeroStatsState `json:"heroStats"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateAddPlayerPacket returns a NetPacket which declares an
|
||||||
|
// AddPlayerPacket with the data in given parameters.
|
||||||
func CreateAddPlayerPacket(id, name string, x, y int, heroType d2enum.Hero, stats d2hero.HeroStatsState, equipment d2inventory.CharacterEquipment) NetPacket {
|
func CreateAddPlayerPacket(id, name string, x, y int, heroType d2enum.Hero, stats d2hero.HeroStatsState, equipment d2inventory.CharacterEquipment) NetPacket {
|
||||||
return NetPacket{
|
return NetPacket{
|
||||||
PacketType: d2netpackettype.AddPlayer,
|
PacketType: d2netpackettype.AddPlayer,
|
||||||
@ -27,7 +32,7 @@ func CreateAddPlayerPacket(id, name string, x, y int, heroType d2enum.Hero, stat
|
|||||||
Y: y,
|
Y: y,
|
||||||
HeroType: heroType,
|
HeroType: heroType,
|
||||||
Equipment: equipment,
|
Equipment: equipment,
|
||||||
Stats: stats,
|
Stats: stats,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,15 @@ import (
|
|||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GenerateMapPacket contains an enumerable representing a region. It
|
||||||
|
// is sent by the server to generate the map for the given region on
|
||||||
|
// a client.
|
||||||
type GenerateMapPacket struct {
|
type GenerateMapPacket struct {
|
||||||
RegionType d2enum.RegionIdType `json:"regionType"`
|
RegionType d2enum.RegionIdType `json:"regionType"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateGenerateMapPacket returns a NetPacket which declares a
|
||||||
|
// GenerateMapPacket with the given regionType.
|
||||||
func CreateGenerateMapPacket(regionType d2enum.RegionIdType) NetPacket {
|
func CreateGenerateMapPacket(regionType d2enum.RegionIdType) NetPacket {
|
||||||
return NetPacket{
|
return NetPacket{
|
||||||
PacketType: d2netpackettype.GenerateMap,
|
PacketType: d2netpackettype.GenerateMap,
|
||||||
|
@ -2,8 +2,9 @@ package d2netpacket
|
|||||||
|
|
||||||
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||||
|
|
||||||
|
// MovePlayerPacket contains a movement command for a specific player entity.
|
||||||
|
// It is sent by the server to move a player entity on a client.
|
||||||
// TODO: Need to handle being on different maps
|
// TODO: Need to handle being on different maps
|
||||||
|
|
||||||
type MovePlayerPacket struct {
|
type MovePlayerPacket struct {
|
||||||
PlayerId string `json:"playerId"`
|
PlayerId string `json:"playerId"`
|
||||||
StartX float64 `json:"startX"`
|
StartX float64 `json:"startX"`
|
||||||
@ -12,6 +13,8 @@ type MovePlayerPacket struct {
|
|||||||
DestY float64 `json:"destY"`
|
DestY float64 `json:"destY"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateMovePlayerPacket returns a NetPacket which declares a MovePlayerPacket
|
||||||
|
// with the given ID and movement command.
|
||||||
func CreateMovePlayerPacket(playerId string, startX, startY, destX, destY float64) NetPacket {
|
func CreateMovePlayerPacket(playerId string, startX, startY, destX, destY float64) NetPacket {
|
||||||
return NetPacket{
|
return NetPacket{
|
||||||
PacketType: d2netpackettype.MovePlayer,
|
PacketType: d2netpackettype.MovePlayer,
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
package d2netpacket
|
package d2netpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PingPacket contains the time at which it was sent. It is sent by the
|
||||||
|
// server and instructs the client to respond with a Pong packet.
|
||||||
type PingPacket struct {
|
type PingPacket struct {
|
||||||
TS time.Time `json:"ts"`
|
TS time.Time `json:"ts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreatePingPacket returns a NetPacket which declares a GenerateMapPacket
|
||||||
|
// with the the current time.
|
||||||
func CreatePingPacket() NetPacket {
|
func CreatePingPacket() NetPacket {
|
||||||
return NetPacket{
|
return NetPacket{
|
||||||
PacketType: d2netpackettype.Ping,
|
PacketType: d2netpackettype.Ping,
|
||||||
|
@ -2,8 +2,10 @@ package d2netpacket
|
|||||||
|
|
||||||
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||||
|
|
||||||
|
// CastPacket contains a cast command for an entity. It is sent by the server
|
||||||
|
// and instructs the client to trigger the use of the given skill on the given
|
||||||
|
// entity.
|
||||||
// TODO: Need to handle being on different maps
|
// TODO: Need to handle being on different maps
|
||||||
|
|
||||||
type CastPacket struct {
|
type CastPacket struct {
|
||||||
SourceEntityID string `json:"sourceEntityId"`
|
SourceEntityID string `json:"sourceEntityId"`
|
||||||
SkillID int `json:"skillId"`
|
SkillID int `json:"skillId"`
|
||||||
@ -12,6 +14,8 @@ type CastPacket struct {
|
|||||||
TargetEntityID string `json:"targetEntityId"`
|
TargetEntityID string `json:"targetEntityId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateCastPacket returns a NetPacket which declares a CastPacket with the
|
||||||
|
// given skill command.
|
||||||
func CreateCastPacket(entityID string, skillID int, targetX, targetY float64) NetPacket {
|
func CreateCastPacket(entityID string, skillID int, targetX, targetY float64) NetPacket {
|
||||||
return NetPacket{
|
return NetPacket{
|
||||||
PacketType: d2netpackettype.CastSkill,
|
PacketType: d2netpackettype.CastSkill,
|
||||||
|
@ -5,11 +5,15 @@ import (
|
|||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PlayerConnectionRequestPacket contains a player ID and game state.
|
||||||
|
// It is sent by a remote client to initiate a connection (join a game).
|
||||||
type PlayerConnectionRequestPacket struct {
|
type PlayerConnectionRequestPacket struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
PlayerState *d2player.PlayerState `json:"gameState"`
|
PlayerState *d2player.PlayerState `json:"gameState"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreatePlayerConnectionRequestPacket returns a NetPacket which defines a
|
||||||
|
// PlayerConnectionRequestPacket with the given ID and game state.
|
||||||
func CreatePlayerConnectionRequestPacket(id string, playerState *d2player.PlayerState) NetPacket {
|
func CreatePlayerConnectionRequestPacket(id string, playerState *d2player.PlayerState) NetPacket {
|
||||||
return NetPacket{
|
return NetPacket{
|
||||||
PacketType: d2netpackettype.PlayerConnectionRequest,
|
PacketType: d2netpackettype.PlayerConnectionRequest,
|
||||||
|
@ -5,11 +5,15 @@ import (
|
|||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PlayerDisconnectRequestPacket contains a player ID and game state.
|
||||||
|
// It is sent by a remote client to close the connection (leave a game).
|
||||||
type PlayerDisconnectRequestPacket struct {
|
type PlayerDisconnectRequestPacket struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
PlayerState *d2player.PlayerState `json:"gameState"`
|
PlayerState *d2player.PlayerState `json:"gameState"` // TODO: remove this? It isn't used.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreatePlayerDisconnectRequestPacket returns a NetPacket which defines a
|
||||||
|
// PlayerDisconnectRequestPacket with the given ID.
|
||||||
func CreatePlayerDisconnectRequestPacket(id string) NetPacket {
|
func CreatePlayerDisconnectRequestPacket(id string) NetPacket {
|
||||||
return NetPacket{
|
return NetPacket{
|
||||||
PacketType: d2netpackettype.PlayerDisconnectionNotification,
|
PacketType: d2netpackettype.PlayerDisconnectionNotification,
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
package d2netpacket
|
package d2netpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PongPacket contains the time at which it was sent and the ID of the
|
||||||
|
// client. It is sent by the client in response to a Pong packet.
|
||||||
type PongPacket struct {
|
type PongPacket struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
TS time.Time `json:"ts"`
|
TS time.Time `json:"ts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreatePongPacket returns a NetPacket which declares a PongPacket with
|
||||||
|
// the current time and given ID.
|
||||||
func CreatePongPacket(id string) NetPacket {
|
func CreatePongPacket(id string) NetPacket {
|
||||||
return NetPacket{
|
return NetPacket{
|
||||||
PacketType: d2netpackettype.Pong,
|
PacketType: d2netpackettype.Pong,
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
package d2netpacket
|
package d2netpacket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ServerClosedPacket contains the current time. It is sent by the server
|
||||||
|
// to inform a client that the server has shut down.
|
||||||
type ServerClosedPacket struct {
|
type ServerClosedPacket struct {
|
||||||
TS time.Time `json:"ts"`
|
TS time.Time `json:"ts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateServerClosedPacket returns a NetPacket which declares a
|
||||||
|
// ServerClosedPacket with the current time.
|
||||||
func CreateServerClosedPacket() NetPacket {
|
func CreateServerClosedPacket() NetPacket {
|
||||||
return NetPacket{
|
return NetPacket{
|
||||||
PacketType: d2netpackettype.ServerClosed,
|
PacketType: d2netpackettype.ServerClosed,
|
||||||
|
@ -2,11 +2,15 @@ package d2netpacket
|
|||||||
|
|
||||||
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||||
|
|
||||||
|
// UpdateServerInfoPacket contains the ID for a player and the map seed.
|
||||||
|
// It is sent by the server to synchronise these values on the client.
|
||||||
type UpdateServerInfoPacket struct {
|
type UpdateServerInfoPacket struct {
|
||||||
Seed int64 `json:"seed"`
|
Seed int64 `json:"seed"`
|
||||||
PlayerId string `json:"playerId"`
|
PlayerId string `json:"playerId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateUpdateServerInfoPacket returns a NetPacket which declares an
|
||||||
|
// UpdateServerInfoPacket with the given player ID and map seed.
|
||||||
func CreateUpdateServerInfoPacket(seed int64, playerId string) NetPacket {
|
func CreateUpdateServerInfoPacket(seed int64, playerId string) NetPacket {
|
||||||
return NetPacket{
|
return NetPacket{
|
||||||
PacketType: d2netpackettype.UpdateServerInfo,
|
PacketType: d2netpackettype.UpdateServerInfo,
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ClientConnection is an interface for abstracting local and remote
|
||||||
|
// clients.
|
||||||
type ClientConnection interface {
|
type ClientConnection interface {
|
||||||
GetUniqueId() string
|
GetUniqueId() string
|
||||||
GetConnectionType() d2clientconnectiontype.ClientConnectionType
|
GetConnectionType() d2clientconnectiontype.ClientConnectionType
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
package d2server
|
package d2server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConnectionManager is responsible for cleanup up connections accepted by the game server. As the server communicates over
|
// ConnectionManager is responsible for cleanup up connections accepted by the game server.
|
||||||
// UDP and is stateless we need to implement some loose state management via a ping/pong system. ConnectionManager also handles
|
// As the server communicates over UDP and is stateless we need to implement some loose state
|
||||||
// communication for graceful shutdowns.
|
// management via a ping/pong system. ConnectionManager also handles communication for
|
||||||
//
|
// graceful shutdowns.
|
||||||
// retries: # of attempts before the dropping the client
|
|
||||||
// interval: How long to wait before each ping/pong test
|
|
||||||
// gameServer: The *GameServer is argument provided for the connection manager to watch over
|
|
||||||
// status: map of inflight ping/pong requests
|
|
||||||
type ConnectionManager struct {
|
type ConnectionManager struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
retries int
|
retries int // Number of attempts before the dropping the client
|
||||||
interval time.Duration
|
interval time.Duration // How long to wait before each ping/pong test
|
||||||
gameServer *GameServer
|
gameServer *GameServer // The GameServer with the connections being managed
|
||||||
status map[string]int
|
status map[string]int // Map of inflight ping/pong requests
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateConnectionManager constructs a new ConnectionManager and calls
|
||||||
|
// ConnectionManager.Run() in a goroutine before retuning a pointer to
|
||||||
|
// the new ConnectionManager.
|
||||||
func CreateConnectionManager(gameServer *GameServer) *ConnectionManager {
|
func CreateConnectionManager(gameServer *GameServer) *ConnectionManager {
|
||||||
manager := &ConnectionManager{
|
manager := &ConnectionManager{
|
||||||
retries: 3,
|
retries: 3,
|
||||||
|
@ -1,24 +1,31 @@
|
|||||||
|
// Package d2udpclientconnection provides an implementation of a UDP client connection with a game state.
|
||||||
package d2udpclientconnection
|
package d2udpclientconnection
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// UDPClientConnection is the implementation of the
|
||||||
|
// d2server.ClientConnection interface to represent remote client from the
|
||||||
|
// server perspective.
|
||||||
type UDPClientConnection struct {
|
type UDPClientConnection struct {
|
||||||
id string
|
id string // ID of the associated RemoteClientConnection
|
||||||
address *net.UDPAddr
|
address *net.UDPAddr // IP address of the associated RemoteClientConnection
|
||||||
udpConnection *net.UDPConn
|
udpConnection *net.UDPConn // Server's UDP Connection
|
||||||
playerState *d2player.PlayerState
|
playerState *d2player.PlayerState // Client's game state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateUDPClientConnection constructs a new UDPClientConnection and
|
||||||
|
// returns a pointer to it.
|
||||||
func CreateUDPClientConnection(udpConnection *net.UDPConn, id string, address *net.UDPAddr) *UDPClientConnection {
|
func CreateUDPClientConnection(udpConnection *net.UDPConn, id string, address *net.UDPAddr) *UDPClientConnection {
|
||||||
result := &UDPClientConnection{
|
result := &UDPClientConnection{
|
||||||
id: id,
|
id: id,
|
||||||
@ -29,14 +36,19 @@ func CreateUDPClientConnection(udpConnection *net.UDPConn, id string, address *n
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUniqueId returns UDPClientConnection.id
|
||||||
func (u UDPClientConnection) GetUniqueId() string {
|
func (u UDPClientConnection) GetUniqueId() string {
|
||||||
return u.id
|
return u.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetConnectionType returns an enum representing the connection type.
|
||||||
|
// See: d2clientconnectiontype.
|
||||||
func (u UDPClientConnection) GetConnectionType() d2clientconnectiontype.ClientConnectionType {
|
func (u UDPClientConnection) GetConnectionType() d2clientconnectiontype.ClientConnectionType {
|
||||||
return d2clientconnectiontype.LANClient
|
return d2clientconnectiontype.LANClient
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendPacketToClient compresses the JSON encoding of a NetPacket and
|
||||||
|
// sends it to the client.
|
||||||
func (u *UDPClientConnection) SendPacketToClient(packet d2netpacket.NetPacket) error {
|
func (u *UDPClientConnection) SendPacketToClient(packet d2netpacket.NetPacket) error {
|
||||||
data, err := json.Marshal(packet.PacketData)
|
data, err := json.Marshal(packet.PacketData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -55,10 +67,12 @@ func (u *UDPClientConnection) SendPacketToClient(packet d2netpacket.NetPacket) e
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetPlayerState sets UDP.playerState to the given value.
|
||||||
func (u *UDPClientConnection) SetPlayerState(playerState *d2player.PlayerState) {
|
func (u *UDPClientConnection) SetPlayerState(playerState *d2player.PlayerState) {
|
||||||
u.playerState = playerState
|
u.playerState = playerState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPlayerState returns UDPClientConnection.playerState.
|
||||||
func (u *UDPClientConnection) GetPlayerState() *d2player.PlayerState {
|
func (u *UDPClientConnection) GetPlayerState() *d2player.PlayerState {
|
||||||
return u.playerState
|
return u.playerState
|
||||||
}
|
}
|
||||||
|
5
d2networking/d2server/doc.go
Normal file
5
d2networking/d2server/doc.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// Package d2server provides connection management and client synchronisation.
|
||||||
|
/*
|
||||||
|
Data is encoded to JSON and compressed using gzip. Transport is over UDP.
|
||||||
|
The server is authoritative for both local and remote clients.*/
|
||||||
|
package d2server
|
@ -24,6 +24,9 @@ import (
|
|||||||
"github.com/robertkrimen/otto"
|
"github.com/robertkrimen/otto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GameServer owns the authoritative copy of the map and entities
|
||||||
|
// It accepts incoming connections from local (host) and remote
|
||||||
|
// clients.
|
||||||
type GameServer struct {
|
type GameServer struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
clientConnections map[string]ClientConnection
|
clientConnections map[string]ClientConnection
|
||||||
@ -37,6 +40,11 @@ type GameServer struct {
|
|||||||
|
|
||||||
var singletonServer *GameServer
|
var singletonServer *GameServer
|
||||||
|
|
||||||
|
// Create constructs a new GameServer and assigns it as a singleton. It
|
||||||
|
// also generates the initial map and entities for the server.
|
||||||
|
//
|
||||||
|
// If openNetworkServer is true, the GameServer starts listening for UDP
|
||||||
|
// packets.
|
||||||
func Create(openNetworkServer bool) {
|
func Create(openNetworkServer bool) {
|
||||||
log.Print("Creating GameServer")
|
log.Print("Creating GameServer")
|
||||||
if singletonServer != nil {
|
if singletonServer != nil {
|
||||||
@ -84,6 +92,8 @@ func createNetworkServer() {
|
|||||||
singletonServer.udpConnection.SetReadBuffer(4096)
|
singletonServer.udpConnection.SetReadBuffer(4096)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// runNetworkServer runs a while loop, reading from the GameServer's UDP
|
||||||
|
// connection.
|
||||||
func runNetworkServer() {
|
func runNetworkServer() {
|
||||||
buffer := make([]byte, 4096)
|
buffer := make([]byte, 4096)
|
||||||
for singletonServer.running {
|
for singletonServer.running {
|
||||||
@ -131,6 +141,8 @@ func runNetworkServer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run sets GameServer.running to true and call runNetworkServer
|
||||||
|
// in a goroutine.
|
||||||
func Run() {
|
func Run() {
|
||||||
log.Print("Starting GameServer")
|
log.Print("Starting GameServer")
|
||||||
singletonServer.running = true
|
singletonServer.running = true
|
||||||
@ -141,6 +153,8 @@ func Run() {
|
|||||||
log.Print("Network server has been started")
|
log.Print("Network server has been started")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop sets GameServer.running to false and closes the
|
||||||
|
// GameServer's UDP connection.
|
||||||
func Stop() {
|
func Stop() {
|
||||||
log.Print("Stopping GameServer")
|
log.Print("Stopping GameServer")
|
||||||
singletonServer.running = false
|
singletonServer.running = false
|
||||||
@ -149,6 +163,7 @@ func Stop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Destroy calls Stop() if the server exists.
|
||||||
func Destroy() {
|
func Destroy() {
|
||||||
if singletonServer == nil {
|
if singletonServer == nil {
|
||||||
return
|
return
|
||||||
@ -157,6 +172,14 @@ func Destroy() {
|
|||||||
Stop()
|
Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnClientConnected initializes the given ClientConnection. It sends the
|
||||||
|
// following packets to the newly connected client: UpdateServerInfoPacket,
|
||||||
|
// GenerateMapPacket, AddPlayerPacket.
|
||||||
|
//
|
||||||
|
// It also sends AddPlayerPackets for each other player entity to the new
|
||||||
|
// player and vice versa, so all player entities exist on all clients.
|
||||||
|
//
|
||||||
|
// For more information, see d2networking.d2netpacket.
|
||||||
func OnClientConnected(client ClientConnection) {
|
func OnClientConnected(client ClientConnection) {
|
||||||
// Temporary position hack --------------------------------------------
|
// Temporary position hack --------------------------------------------
|
||||||
sx, sy := singletonServer.mapEngines[0].GetStartPosition() // TODO: Another temporary hack
|
sx, sy := singletonServer.mapEngines[0].GetStartPosition() // TODO: Another temporary hack
|
||||||
@ -186,11 +209,14 @@ func OnClientConnected(client ClientConnection) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnClientDisconnected removes the given client from the list
|
||||||
|
// of client connections.
|
||||||
func OnClientDisconnected(client ClientConnection) {
|
func OnClientDisconnected(client ClientConnection) {
|
||||||
log.Printf("Client disconnected with an id of %s", client.GetUniqueId())
|
log.Printf("Client disconnected with an id of %s", client.GetUniqueId())
|
||||||
delete(singletonServer.clientConnections, client.GetUniqueId())
|
delete(singletonServer.clientConnections, client.GetUniqueId())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnPacketReceived is called by the local client to 'send' a packet to the server.
|
||||||
func OnPacketReceived(client ClientConnection, packet d2netpacket.NetPacket) error {
|
func OnPacketReceived(client ClientConnection, packet d2netpacket.NetPacket) error {
|
||||||
switch packet.PacketType {
|
switch packet.PacketType {
|
||||||
case d2netpackettype.MovePlayer:
|
case d2netpackettype.MovePlayer:
|
||||||
|
4
d2networking/doc.go
Normal file
4
d2networking/doc.go
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// Package d2networking provides client and server implementations for OpenDiablo2.
|
||||||
|
/*
|
||||||
|
The server is authoritative and communicates with local and remote clients over UDP.*/
|
||||||
|
package d2networking
|
Loading…
Reference in New Issue
Block a user