2020-06-13 22:32:09 +00:00
|
|
|
package d2client
|
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
2020-06-23 00:31:42 +00:00
|
|
|
"os"
|
2020-06-13 22:32:09 +00:00
|
|
|
|
2020-06-26 20:50:24 +00:00
|
|
|
// "github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapgen"
|
2020-06-21 22:40:37 +00:00
|
|
|
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
|
2020-06-26 20:50:24 +00:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2maprenderer"
|
2020-06-13 22:32:09 +00:00
|
|
|
|
2020-06-18 18:11:04 +00:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
2020-06-21 22:40:37 +00:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
2020-06-26 20:50:24 +00:00
|
|
|
d2cct "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
2020-06-13 22:32:09 +00:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
|
|
|
)
|
|
|
|
|
|
|
|
type GameClient struct {
|
|
|
|
clientConnection ClientConnection
|
2020-06-26 20:50:24 +00:00
|
|
|
connectionType d2cct.ClientConnectionType
|
2020-06-18 18:11:04 +00:00
|
|
|
GameState *d2player.PlayerState
|
2020-06-21 22:40:37 +00:00
|
|
|
MapEngine *d2mapengine.MapEngine
|
2020-06-26 20:50:24 +00:00
|
|
|
MapRenderer *d2maprenderer.MapRenderer
|
|
|
|
realm *d2mapengine.MapRealm
|
2020-06-13 22:32:09 +00:00
|
|
|
PlayerId string
|
2020-06-21 22:40:37 +00:00
|
|
|
Players map[string]*d2mapentity.Player
|
2020-06-19 06:19:27 +00:00
|
|
|
Seed int64
|
2020-06-21 22:40:37 +00:00
|
|
|
RegenMap bool
|
2020-06-13 22:32:09 +00:00
|
|
|
}
|
|
|
|
|
2020-06-26 20:50:24 +00:00
|
|
|
// Using the `clientConnection`, opens a connection and passes the savefile path
|
2020-06-18 18:11:04 +00:00
|
|
|
func (g *GameClient) Open(connectionString string, saveFilePath string) error {
|
|
|
|
return g.clientConnection.Open(connectionString, saveFilePath)
|
2020-06-13 22:32:09 +00:00
|
|
|
}
|
|
|
|
|
2020-06-26 20:50:24 +00:00
|
|
|
// Closes the `clientConnection`
|
2020-06-13 22:32:09 +00:00
|
|
|
func (g *GameClient) Close() error {
|
|
|
|
return g.clientConnection.Close()
|
|
|
|
}
|
|
|
|
|
2020-06-26 20:50:24 +00:00
|
|
|
// Closes the `clientConnection`
|
2020-06-13 22:32:09 +00:00
|
|
|
func (g *GameClient) Destroy() error {
|
|
|
|
return g.clientConnection.Close()
|
|
|
|
}
|
|
|
|
|
2020-06-26 20:50:24 +00:00
|
|
|
// Routes the incoming packets to the packet handlers
|
2020-06-13 22:32:09 +00:00
|
|
|
func (g *GameClient) OnPacketReceived(packet d2netpacket.NetPacket) error {
|
|
|
|
switch packet.PacketType {
|
2020-06-26 20:50:24 +00:00
|
|
|
|
|
|
|
// UNSURE: should we be bubbling up errors from these handler calls?
|
2020-06-13 22:32:09 +00:00
|
|
|
case d2netpackettype.UpdateServerInfo:
|
2020-06-26 20:50:24 +00:00
|
|
|
g.handleUpdateServerInfo(packet)
|
|
|
|
|
2020-06-13 22:32:09 +00:00
|
|
|
case d2netpackettype.AddPlayer:
|
2020-06-26 20:50:24 +00:00
|
|
|
g.handleAddPlayer(packet)
|
|
|
|
|
|
|
|
case d2netpackettype.GenerateMap:
|
|
|
|
g.handleGenerateMap(packet)
|
|
|
|
|
2020-06-13 22:32:09 +00:00
|
|
|
case d2netpackettype.MovePlayer:
|
2020-06-26 20:50:24 +00:00
|
|
|
g.handleMovePlayer(packet)
|
|
|
|
|
2020-06-23 00:31:42 +00:00
|
|
|
case d2netpackettype.Ping:
|
2020-06-26 20:50:24 +00:00
|
|
|
g.handlePong(packet)
|
|
|
|
|
2020-06-23 00:31:42 +00:00
|
|
|
case d2netpackettype.ServerClosed:
|
2020-06-26 20:50:24 +00:00
|
|
|
g.handleServerClosed(packet)
|
|
|
|
|
2020-06-13 22:32:09 +00:00
|
|
|
default:
|
|
|
|
log.Fatalf("Invalid packet type: %d", packet.PacketType)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-06-26 20:50:24 +00:00
|
|
|
// Using the `clientConnection`, sends a packet to the server
|
2020-06-13 22:32:09 +00:00
|
|
|
func (g *GameClient) SendPacketToServer(packet d2netpacket.NetPacket) error {
|
|
|
|
return g.clientConnection.SendPacketToServer(packet)
|
|
|
|
}
|
2020-06-26 20:50:24 +00:00
|
|
|
|
|
|
|
func (g *GameClient) handleUpdateServerInfo(p d2netpacket.NetPacket) {
|
|
|
|
serverInfo := p.PacketData.(d2netpacket.UpdateServerInfoPacket)
|
|
|
|
seed := serverInfo.Seed
|
|
|
|
playerId := serverInfo.PlayerId
|
|
|
|
|
|
|
|
g.Seed = seed
|
|
|
|
g.realm.Init(seed)
|
|
|
|
g.PlayerId = playerId
|
|
|
|
|
|
|
|
log.Printf("Player id set to %s", playerId)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameClient) handleAddPlayer(p d2netpacket.NetPacket) {
|
|
|
|
player := p.PacketData.(d2netpacket.AddPlayerPacket)
|
|
|
|
levelId := g.realm.GetFirstActLevelId(player.Act)
|
|
|
|
g.MapEngine = g.realm.GetMapEngine(player.Act, levelId)
|
|
|
|
|
|
|
|
pId := player.Id
|
|
|
|
pName := player.Name
|
|
|
|
pAct := player.Act
|
|
|
|
pLvlId := levelId
|
|
|
|
pX := player.X
|
|
|
|
pY := player.Y
|
|
|
|
pDir := 0
|
|
|
|
pHero := player.HeroType
|
|
|
|
pStat := player.Stats
|
|
|
|
pEquip := player.Equipment
|
|
|
|
|
|
|
|
// UNSURE: maybe we should be passing a struct instead of all the vars?
|
|
|
|
newPlayer := d2mapentity.CreatePlayer(
|
|
|
|
pId, pName, pAct, pLvlId, pX, pY, pDir, pHero, pStat, pEquip,
|
|
|
|
)
|
|
|
|
|
|
|
|
g.Players[newPlayer.Id] = newPlayer
|
|
|
|
g.realm.AddPlayer(pId, pAct)
|
|
|
|
g.MapEngine.AddEntity(newPlayer)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameClient) handleGenerateMap(p d2netpacket.NetPacket) {
|
|
|
|
mapData := p.PacketData.(d2netpacket.GenerateMapPacket)
|
|
|
|
g.realm.GenerateMap(mapData.ActId, mapData.LevelId)
|
|
|
|
engine := g.realm.GetMapEngine(mapData.ActId, mapData.LevelId)
|
|
|
|
g.MapRenderer = d2maprenderer.CreateMapRenderer(engine)
|
|
|
|
g.RegenMap = true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameClient) handleMovePlayer(p d2netpacket.NetPacket) {
|
|
|
|
movePlayer := p.PacketData.(d2netpacket.MovePlayerPacket)
|
|
|
|
|
|
|
|
player := g.Players[movePlayer.PlayerId]
|
|
|
|
x1, y1 := movePlayer.StartX, movePlayer.StartY
|
|
|
|
x2, y2 := movePlayer.DestX, movePlayer.DestY
|
|
|
|
|
|
|
|
path, _, _ := g.MapEngine.PathFind(x1, y1, x2, y2)
|
|
|
|
|
|
|
|
if len(path) > 0 {
|
|
|
|
player.SetPath(path, func() {
|
|
|
|
tile := g.MapEngine.TileAt(player.TileX, player.TileY)
|
|
|
|
if tile == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
regionType := tile.RegionType
|
|
|
|
if regionType == d2enum.RegionAct1Town {
|
|
|
|
player.SetIsInTown(true)
|
|
|
|
} else {
|
|
|
|
player.SetIsInTown(false)
|
|
|
|
}
|
|
|
|
player.SetAnimationMode(player.GetAnimationMode().String())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameClient) handlePong(p d2netpacket.NetPacket) {
|
|
|
|
pong := d2netpacket.CreatePongPacket(g.PlayerId)
|
|
|
|
g.clientConnection.SendPacketToServer(pong)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GameClient) handleServerClosed(p d2netpacket.NetPacket) {
|
|
|
|
// TODO: Need to be tied into a character save and exit
|
|
|
|
log.Print("Server has been closed")
|
|
|
|
os.Exit(0)
|
|
|
|
}
|