diff --git a/d2networking/d2client/d2localclient/local_client_connection.go b/d2networking/d2client/d2localclient/local_client_connection.go index 4ae4276e..b3cbb65d 100644 --- a/d2networking/d2client/d2localclient/local_client_connection.go +++ b/d2networking/d2client/d2localclient/local_client_connection.go @@ -2,6 +2,8 @@ package d2localclient import ( + "log" + "github.com/OpenDiablo2/OpenDiablo2/d2game/d2player" "github.com/OpenDiablo2/OpenDiablo2/d2networking" "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype" @@ -47,7 +49,7 @@ func Create(openNetworkServer bool) *LocalClientConnection { } // 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(_ string, saveFilePath string) error { l.SetPlayerState(d2player.LoadPlayerState(saveFilePath)) d2server.Create(l.openNetworkServer) go d2server.Run() @@ -57,7 +59,10 @@ func (l *LocalClientConnection) Open(connectionString string, saveFilePath strin // Close disconnects from the server and destroys it. func (l *LocalClientConnection) Close() error { - l.SendPacketToServer(d2netpacket.CreateServerClosedPacket()) + err := l.SendPacketToServer(d2netpacket.CreateServerClosedPacket()) + if err != nil { + log.Printf("LocalClientConnection: error sending ServerClosedPacket to server: %s", err) + } d2server.OnClientDisconnected(l) d2server.Destroy() return nil diff --git a/d2networking/d2client/d2remoteclient/remote_client_connection.go b/d2networking/d2client/d2remoteclient/remote_client_connection.go index f6c0ae3d..1f1abbd8 100644 --- a/d2networking/d2client/d2remoteclient/remote_client_connection.go +++ b/d2networking/d2client/d2remoteclient/remote_client_connection.go @@ -5,6 +5,7 @@ import ( "bytes" "compress/gzip" "encoding/json" + "errors" "fmt" "io" "log" @@ -82,7 +83,11 @@ func (l *RemoteClientConnection) Open(connectionString string, saveFilePath stri log.Printf("Connected to server at %s", l.udpConnection.RemoteAddr().String()) gameState := d2player.LoadPlayerState(saveFilePath) - l.SendPacketToServer(d2netpacket.CreatePlayerConnectionRequestPacket(l.GetUniqueId(), gameState)) + err = l.SendPacketToServer(d2netpacket.CreatePlayerConnectionRequestPacket(l.GetUniqueId(), gameState)) + if err != nil { + log.Print("RemoteClientConnection: error sending PlayerConnectionRequestPacket to server.") + return err + } return nil } @@ -91,7 +96,10 @@ func (l *RemoteClientConnection) Open(connectionString string, saveFilePath stri // RemoteClientConnection.active to false. func (l *RemoteClientConnection) Close() error { l.active = false - l.SendPacketToServer(d2netpacket.CreatePlayerDisconnectRequestPacket(l.GetUniqueId())) + err := l.SendPacketToServer(d2netpacket.CreatePlayerDisconnectRequestPacket(l.GetUniqueId())) + if err != nil { + return err + } return nil } @@ -106,8 +114,15 @@ func (l *RemoteClientConnection) SendPacketToServer(packet d2netpacket.NetPacket var buff bytes.Buffer buff.WriteByte(byte(packet.PacketType)) writer, _ := gzip.NewWriterLevel(&buff, gzip.BestCompression) - writer.Write(data) - writer.Close() + + if written, err := writer.Write(data); err != nil { + return err + } else if written == 0 { + return errors.New(fmt.Sprintf("RemoteClientConnection: attempted to send empty %v packet body.", packet.PacketType)) + } + if err = writer.Close(); err != nil { + return err + } if _, err = l.udpConnection.Write(buff.Bytes()); err != nil { return err } @@ -137,42 +152,87 @@ func (l *RemoteClientConnection) serverListener() { packetType := d2netpackettype.NetPacketType(packetTypeId) reader, err := gzip.NewReader(buff) sb := new(strings.Builder) - io.Copy(sb, reader) + written, err := io.Copy(sb, reader) + if err != nil { + log.Printf("RemoteClientConnection: error copying bytes from %v packet: %s", packetType, err) + // TODO: All packets coming from the client seem to be throwing an error + //continue + } + if written == 0 { + log.Printf("RemoteClientConnection: empty packet %v packet received", packetType) + continue + } + stringData := sb.String() switch packetType { case d2netpackettype.GenerateMap: var packet d2netpacket.GenerateMapPacket - json.Unmarshal([]byte(stringData), &packet) - l.SendPacketToClient(d2netpacket.NetPacket{ + err := json.Unmarshal([]byte(stringData), &packet) + if err != nil { + log.Printf("GameServer: error unmarshalling %T: %s", packet, err) + continue + } + err = l.SendPacketToClient(d2netpacket.NetPacket{ PacketType: packetType, PacketData: packet, }) + if err != nil { + log.Printf("RemoteClientConnection: error processing packet %v: %s", packetType, err) + } case d2netpackettype.MovePlayer: var packet d2netpacket.MovePlayerPacket - json.Unmarshal([]byte(stringData), &packet) - l.SendPacketToClient(d2netpacket.NetPacket{ + err := json.Unmarshal([]byte(stringData), &packet) + if err != nil { + log.Printf("GameServer: error unmarshalling %T: %s", packet, err) + continue + } + err = l.SendPacketToClient(d2netpacket.NetPacket{ PacketType: packetType, PacketData: packet, }) + if err != nil { + log.Printf("RemoteClientConnection: error processing packet %v: %s", packetType, err) + } case d2netpackettype.UpdateServerInfo: var packet d2netpacket.UpdateServerInfoPacket - json.Unmarshal([]byte(stringData), &packet) - l.SendPacketToClient(d2netpacket.NetPacket{ + err := json.Unmarshal([]byte(stringData), &packet) + if err != nil { + log.Printf("GameServer: error unmarshalling %T: %s", packet, err) + continue + } + err = l.SendPacketToClient(d2netpacket.NetPacket{ PacketType: packetType, PacketData: packet, }) + if err != nil { + log.Printf("RemoteClientConnection: error processing packet %v: %s", packetType, err) + } case d2netpackettype.AddPlayer: var packet d2netpacket.AddPlayerPacket - json.Unmarshal([]byte(stringData), &packet) - l.SendPacketToClient(d2netpacket.NetPacket{ + err := json.Unmarshal([]byte(stringData), &packet) + if err != nil { + log.Printf("GameServer: error unmarshalling %T: %s", packet, err) + continue + } + err = l.SendPacketToClient(d2netpacket.NetPacket{ PacketType: packetType, PacketData: packet, }) + if err != nil { + log.Printf("RemoteClientConnection: error processing packet %v: %s", packetType, err) + } case d2netpackettype.Ping: - l.SendPacketToServer(d2netpacket.CreatePongPacket(l.uniqueId)) + err := l.SendPacketToServer(d2netpacket.CreatePongPacket(l.uniqueId)) + if err != nil { + log.Printf("RemoteClientConnection: error responding to server ping: %s", err) + } case d2netpackettype.PlayerDisconnectionNotification: var packet d2netpacket.PlayerDisconnectRequestPacket - json.Unmarshal([]byte(stringData), &packet) + err := json.Unmarshal([]byte(stringData), &packet) + if err != nil { + log.Printf("GameServer: error unmarshalling %T: %s", packet, err) + continue + } log.Printf("Received disconnect: %s", packet.Id) default: fmt.Printf("Unknown packet type %d\n", packetType) diff --git a/d2networking/d2client/game_client.go b/d2networking/d2client/game_client.go index 71b25a0d..98a71309 100644 --- a/d2networking/d2client/game_client.go +++ b/d2networking/d2client/game_client.go @@ -114,7 +114,10 @@ func (g *GameClient) OnPacketReceived(packet d2netpacket.NetPacket) error { } else { player.SetIsInTown(false) } - player.SetAnimationMode(player.GetAnimationMode().String()) + err := player.SetAnimationMode(player.GetAnimationMode().String()) + if err != nil { + log.Printf("GameClient: error setting animation mode for player %s: %s", player.Id, err) + } }) } case d2netpackettype.CastSkill: @@ -145,7 +148,11 @@ func (g *GameClient) OnPacketReceived(packet d2netpacket.NetPacket) error { g.MapEngine.AddEntity(missile) case d2netpackettype.Ping: - g.clientConnection.SendPacketToServer(d2netpacket.CreatePongPacket(g.PlayerId)) + err := g.clientConnection.SendPacketToServer(d2netpacket.CreatePongPacket(g.PlayerId)) + if err != nil { + log.Printf("GameClient: error responding to server ping: %s", err) + } + case d2netpackettype.ServerClosed: // TODO: Need to be tied into a character save and exit log.Print("Server has been closed") diff --git a/d2networking/d2netpacket/d2netpackettype/message_type.go b/d2networking/d2netpacket/d2netpackettype/message_type.go index e23fbc36..a15ecb78 100644 --- a/d2networking/d2netpacket/d2netpackettype/message_type.go +++ b/d2networking/d2netpacket/d2netpackettype/message_type.go @@ -5,7 +5,7 @@ package d2netpackettype // d2netpacket. type NetPacketType uint32 -//(Except NetPacket which declares a NetPacketType to specify the packet body +// (Except NetPacket which declares a NetPacketType to specify the packet body // type. See d2netpackettype.NetPacket.) // // Warning @@ -26,3 +26,20 @@ const ( ServerClosed // Sent by the local host when it has closed the server CastSkill // Sent by client or server, indicates entity casting skill ) + +func (n NetPacketType) String() string { + strings := map[NetPacketType]string{ + UpdateServerInfo: "UpdateServerInfo", + GenerateMap: "GenerateMap", + AddPlayer: "AddPlayer", + MovePlayer: "MovePlayer", + PlayerConnectionRequest: "PlayerConnectionRequest", + PlayerDisconnectionNotification: "PlayerDisconnectionNotification", + Ping: "Ping", + Pong: "Pong", + ServerClosed: "ServerClosed", + CastSkill: "CastSkill", + } + + return strings[n] +} diff --git a/d2networking/d2server/connection_manager.go b/d2networking/d2server/connection_manager.go index e20ec953..76b9d03c 100644 --- a/d2networking/d2server/connection_manager.go +++ b/d2networking/d2server/connection_manager.go @@ -85,7 +85,10 @@ func (c *ConnectionManager) Shutdown() { // Things can be done more cleanly once we have graceful exits however we still need to account for other OS Signals log.Print("Notifying clients server is shutting down...") for _, connection := range c.gameServer.clientConnections { - connection.SendPacketToClient(d2netpacket.CreateServerClosedPacket()) + err := connection.SendPacketToClient(d2netpacket.CreateServerClosedPacket()) + if err != nil { + log.Printf("ConnectionManager: error sending ServerClosedPacket to client ID %s: %s", connection.GetUniqueId(), err) + } } Stop() } diff --git a/d2networking/d2server/d2udpclientconnection/udp_client_connection.go b/d2networking/d2server/d2udpclientconnection/udp_client_connection.go index 95a65d47..e76e4546 100644 --- a/d2networking/d2server/d2udpclientconnection/udp_client_connection.go +++ b/d2networking/d2server/d2udpclientconnection/udp_client_connection.go @@ -5,6 +5,8 @@ import ( "bytes" "compress/gzip" "encoding/json" + "errors" + "fmt" "net" "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype" @@ -57,10 +59,16 @@ func (u *UDPClientConnection) SendPacketToClient(packet d2netpacket.NetPacket) e var buff bytes.Buffer buff.WriteByte(byte(packet.PacketType)) writer, _ := gzip.NewWriterLevel(&buff, gzip.BestCompression) - writer.Write(data) - writer.Close() - _, err = u.udpConnection.WriteToUDP(buff.Bytes(), u.address) - if err != nil { + + if written, err := writer.Write(data); err != nil { + return err + } else if written == 0 { + return errors.New(fmt.Sprintf("RemoteClientConnection: attempted to send empty %v packet body.", packet.PacketType)) + } + if err = writer.Close(); err != nil { + return err + } + if _, err = u.udpConnection.WriteToUDP(buff.Bytes(), u.address); err != nil { return err } diff --git a/d2networking/d2server/game_server.go b/d2networking/d2server/game_server.go index 1520dd6e..5a6aba87 100644 --- a/d2networking/d2server/game_server.go +++ b/d2networking/d2server/game_server.go @@ -89,7 +89,10 @@ func createNetworkServer() { if err != nil { panic(err) } - singletonServer.udpConnection.SetReadBuffer(4096) + err = singletonServer.udpConnection.SetReadBuffer(4096) + if err != nil { + log.Print("GameServer: error setting UDP read buffer:", err) + } } // runNetworkServer runs a while loop, reading from the GameServer's UDP @@ -107,35 +110,63 @@ func runNetworkServer() { packetType := d2netpackettype.NetPacketType(packetTypeId) reader, err := gzip.NewReader(buff) sb := new(strings.Builder) - io.Copy(sb, reader) + written, err := io.Copy(sb, reader) + if err != nil { + log.Printf("GameServer: error copying bytes from %v packet: %s", packetType, err) + continue + } + if written == 0 { + log.Printf("GameServer: empty packet %v packet received", packetType) + continue + } + stringData := sb.String() switch packetType { case d2netpackettype.PlayerConnectionRequest: packetData := d2netpacket.PlayerConnectionRequestPacket{} - json.Unmarshal([]byte(stringData), &packetData) + err := json.Unmarshal([]byte(stringData), &packetData) + if err != nil { + log.Printf("GameServer: error unmarshalling packet of type %T: %s", packetData, err) + continue + } clientConnection := d2udpclientconnection.CreateUDPClientConnection(singletonServer.udpConnection, packetData.Id, addr) clientConnection.SetPlayerState(packetData.PlayerState) OnClientConnected(clientConnection) case d2netpackettype.MovePlayer: packetData := d2netpacket.MovePlayerPacket{} - json.Unmarshal([]byte(stringData), &packetData) + err := json.Unmarshal([]byte(stringData), &packetData) + if err != nil { + log.Printf("GameServer: error unmarshalling %T: %s", packetData, err) + continue + } netPacket := d2netpacket.NetPacket{ PacketType: packetType, PacketData: packetData, } for _, player := range singletonServer.clientConnections { - player.SendPacketToClient(netPacket) + err = player.SendPacketToClient(netPacket) + if err != nil { + log.Printf("GameServer: error sending %T to client %s: %s", packetData, player.GetUniqueId(), err) + } } case d2netpackettype.Pong: packetData := d2netpacket.PlayerConnectionRequestPacket{} - json.Unmarshal([]byte(stringData), &packetData) + err := json.Unmarshal([]byte(stringData), &packetData) + if err != nil { + log.Printf("GameServer: error unmarshalling packet of type %T: %s", packetData, err) + continue + } singletonServer.manager.Recv(packetData.Id) case d2netpackettype.ServerClosed: singletonServer.manager.Shutdown() case d2netpackettype.PlayerDisconnectionNotification: var packet d2netpacket.PlayerDisconnectRequestPacket - json.Unmarshal([]byte(stringData), &packet) + err := json.Unmarshal([]byte(stringData), &packet) + if err != nil { + log.Printf("GameServer: error unmarshalling packet of type %T: %s", packet, err) + continue + } log.Printf("Received disconnect: %s", packet.Id) } } @@ -146,7 +177,10 @@ func runNetworkServer() { func Run() { log.Print("Starting GameServer") singletonServer.running = true - singletonServer.scriptEngine.RunScript("scripts/server/server.js") + _, err := singletonServer.scriptEngine.RunScript("scripts/server/server.js") + if err != nil { + log.Printf("GameServer: error initializing debug script: %s", err) + } if singletonServer.udpConnection != nil { go runNetworkServer() } @@ -159,7 +193,10 @@ func Stop() { log.Print("Stopping GameServer") singletonServer.running = false if singletonServer.udpConnection != nil { - singletonServer.udpConnection.Close() + err := singletonServer.udpConnection.Close() + if err != nil { + log.Printf("GameServer: error when trying to close UDP connection: %s", err) + } } } @@ -190,21 +227,33 @@ func OnClientConnected(client ClientConnection) { log.Printf("Client connected with an id of %s", client.GetUniqueId()) singletonServer.clientConnections[client.GetUniqueId()] = client - client.SendPacketToClient(d2netpacket.CreateUpdateServerInfoPacket(singletonServer.seed, client.GetUniqueId())) - client.SendPacketToClient(d2netpacket.CreateGenerateMapPacket(d2enum.RegionAct1Town)) + err := client.SendPacketToClient(d2netpacket.CreateUpdateServerInfoPacket(singletonServer.seed, client.GetUniqueId())) + if err != nil { + log.Printf("GameServer: error sending UpdateServerInfoPacket to client %s: %s", client.GetUniqueId(), err) + } + err = client.SendPacketToClient(d2netpacket.CreateGenerateMapPacket(d2enum.RegionAct1Town)) + if err != nil { + log.Printf("GameServer: error sending GenerateMapPacket to client %s: %s", client.GetUniqueId(), err) + } playerState := client.GetPlayerState() createPlayerPacket := d2netpacket.CreateAddPlayerPacket(client.GetUniqueId(), playerState.HeroName, int(sx*5)+3, int(sy*5)+3, playerState.HeroType, *playerState.Stats, playerState.Equipment) for _, connection := range singletonServer.clientConnections { - connection.SendPacketToClient(createPlayerPacket) + err := connection.SendPacketToClient(createPlayerPacket) + if err != nil { + log.Printf("GameServer: error sending %T to client %s: %s", createPlayerPacket, connection.GetUniqueId(), err) + } if connection.GetUniqueId() == client.GetUniqueId() { continue } conPlayerState := connection.GetPlayerState() - client.SendPacketToClient(d2netpacket.CreateAddPlayerPacket(connection.GetUniqueId(), conPlayerState.HeroName, + err = client.SendPacketToClient(d2netpacket.CreateAddPlayerPacket(connection.GetUniqueId(), conPlayerState.HeroName, int(conPlayerState.X*5)+3, int(conPlayerState.Y*5)+3, conPlayerState.HeroType, *conPlayerState.Stats, conPlayerState.Equipment)) + if err != nil { + log.Printf("GameServer: error sending CreateAddPlayerPacket to client %s: %s", connection.GetUniqueId(), err) + } } } @@ -228,11 +277,17 @@ func OnPacketReceived(client ClientConnection, packet d2netpacket.NetPacket) err playerState.Y = packet.PacketData.(d2netpacket.MovePlayerPacket).DestY // ---------------------------------------------------------------- for _, player := range singletonServer.clientConnections { - player.SendPacketToClient(packet) + err := player.SendPacketToClient(packet) + if err != nil { + log.Printf("GameServer: error sending %T to client %s: %s", packet, player.GetUniqueId(), err) + } } case d2netpackettype.CastSkill: for _, player := range singletonServer.clientConnections { - player.SendPacketToClient(packet) + err := player.SendPacketToClient(packet) + if err != nil { + log.Printf("GameServer: error sending %T to client %s: %s", packet, player.GetUniqueId(), err) + } } } return nil