1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-09 17:30:43 +00:00
OpenDiablo2/d2networking/d2client/d2localclient/local_client_connection.go
Ian Ling 3936e01afb Networking bugfixes and cleanup
Make sure connections close properly, without weird error messages
Remove player map entity when a player disconnects from a multiplayer game
Close server properly when host disconnects, handle ServerClose on remote clients
Don't mix JSON decoders and raw TCP writes
Actually handle incoming packets from remote clients
General code cleanup for simplicity and consistency
2020-12-28 13:33:17 -08:00

122 lines
3.7 KiB
Go

package d2localclient
import (
"github.com/google/uuid"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
"github.com/OpenDiablo2/OpenDiablo2/d2networking"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2server"
)
// LocalClientConnection is the implementation of ClientConnection
// for a local client.
type LocalClientConnection struct {
asset *d2asset.AssetManager
heroState *d2hero.HeroStateFactory
clientListener d2networking.ClientListener // The game client
uniqueID string // Unique ID generated on construction
openNetworkServer bool // True if this is a server
playerState *d2hero.HeroState // Local player state
gameServer *d2server.GameServer // Game Server
logLevel d2util.LogLevel
}
// GetUniqueID returns LocalClientConnection.uniqueID.
func (l *LocalClientConnection) GetUniqueID() string {
return l.uniqueID
}
// GetConnectionType returns an enum representing the connection type.
// See: d2clientconnectiontype
func (l *LocalClientConnection) GetConnectionType() d2clientconnectiontype.ClientConnectionType {
return d2clientconnectiontype.Local
}
// SendPacketToClient passes a packet to the game client for processing.
func (l *LocalClientConnection) SendPacketToClient(packet d2netpacket.NetPacket) error {
return l.clientListener.OnPacketReceived(packet)
}
// Create constructs a new LocalClientConnection and returns
// a pointer to it.
func Create(
asset *d2asset.AssetManager,
l d2util.LogLevel,
openNetworkServer bool) (*LocalClientConnection, error) {
heroStateFactory, err := d2hero.NewHeroStateFactory(asset)
if err != nil {
return nil, err
}
result := &LocalClientConnection{
heroState: heroStateFactory,
asset: asset,
uniqueID: uuid.New().String(),
openNetworkServer: openNetworkServer,
logLevel: l,
}
return result, nil
}
// Open creates a new GameServer, runs the server and connects this client to it.
func (l *LocalClientConnection) Open(_, saveFilePath string) error {
var err error
l.SetPlayerState(l.heroState.LoadHeroState(saveFilePath))
l.gameServer, err = d2server.NewGameServer(l.asset, l.openNetworkServer, l.logLevel, 30)
if err != nil {
return err
}
if err := l.gameServer.Start(); err != nil {
return err
}
l.gameServer.OnClientConnected(l)
return nil
}
// Close disconnects from the server and destroys it.
func (l *LocalClientConnection) Close() error {
disconnectRequest, err := d2netpacket.CreatePlayerDisconnectRequestPacket(l.uniqueID)
if err != nil {
return err
}
err = l.SendPacketToServer(disconnectRequest)
if err != nil {
return err
}
return nil
}
// SendPacketToServer calls d2server.OnPacketReceived with the given packet.
func (l *LocalClientConnection) SendPacketToServer(packet d2netpacket.NetPacket) error {
return l.gameServer.OnPacketReceived(l, packet)
}
// SetClientListener sets LocalClientConnection.clientListener to the given value.
func (l *LocalClientConnection) SetClientListener(listener d2networking.ClientListener) {
l.clientListener = listener
}
// GetPlayerState returns LocalClientConnection.playerState.
func (l *LocalClientConnection) GetPlayerState() *d2hero.HeroState {
return l.playerState
}
// SetPlayerState sets LocalClientConnection.playerState to the given value.
func (l *LocalClientConnection) SetPlayerState(playerState *d2hero.HeroState) {
l.playerState = playerState
}