mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-04 23:56:40 -05:00
Initial work to separate client and server logic (#330)
* Switched to json formatted characters * Added infrastructure for networking * Minor updates. * more updates for map engine/rendering * More map engine changes and fixes
This commit is contained in:
parent
515b66736d
commit
52f8cd6d0c
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,3 +8,4 @@
|
||||
/OpenDiablo2.exe
|
||||
/OpenDiablo2
|
||||
**/*.pprof
|
||||
tags
|
||||
|
@ -1,6 +1,7 @@
|
||||
package d2gamestate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
@ -9,33 +10,19 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2inventory"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
)
|
||||
|
||||
/*
|
||||
File Spec
|
||||
--------------------------------------------
|
||||
UINT32 GameState Version
|
||||
INT64 Game Seed
|
||||
BYTE Hero Type
|
||||
BYTE Hero Level
|
||||
BYTE Act
|
||||
BYTE Hero Name Length
|
||||
BYTE[] Hero Name
|
||||
--------------------------------------------
|
||||
*/
|
||||
|
||||
type GameState struct {
|
||||
Seed int64
|
||||
HeroName string
|
||||
HeroType d2enum.Hero
|
||||
HeroLevel int
|
||||
Act int
|
||||
FilePath string
|
||||
Equipment d2inventory.CharacterEquipment
|
||||
Seed int64 `json:"seed"` // TODO: Seed needs to be regenerated every time the game starts
|
||||
HeroName string `json:"heroName"`
|
||||
HeroType d2enum.Hero `json:"heroType"`
|
||||
HeroLevel int `json:"heroLevel"`
|
||||
Act int `json:"act"`
|
||||
FilePath string `json:"-"`
|
||||
Equipment d2inventory.CharacterEquipment `json:"equipment"`
|
||||
}
|
||||
|
||||
const GameStateVersion = uint32(2) // Update this when you make breaking changes
|
||||
@ -47,7 +34,6 @@ func HasGameStates() bool {
|
||||
}
|
||||
|
||||
func GetAllGameStates() []*GameState {
|
||||
// TODO: Make this not crash tf out on bad files
|
||||
basePath, _ := getGameBaseSavePath()
|
||||
files, _ := ioutil.ReadDir(basePath)
|
||||
result := make([]*GameState, 0)
|
||||
@ -74,41 +60,31 @@ func CreateTestGameState() *GameState {
|
||||
}
|
||||
|
||||
func LoadGameState(path string) *GameState {
|
||||
strData, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := &GameState{
|
||||
FilePath: path,
|
||||
}
|
||||
f, err := os.Open(path)
|
||||
err = json.Unmarshal(strData, result)
|
||||
if err != nil {
|
||||
log.Panicf(err.Error())
|
||||
}
|
||||
bytes, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
log.Panicf(err.Error())
|
||||
}
|
||||
defer f.Close()
|
||||
sr := d2common.CreateStreamReader(bytes)
|
||||
if sr.GetUInt32() != GameStateVersion {
|
||||
// Unknown game version
|
||||
return nil
|
||||
}
|
||||
result.Seed = sr.GetInt64()
|
||||
result.HeroType = d2enum.Hero(sr.GetByte())
|
||||
result.HeroLevel = int(sr.GetByte())
|
||||
result.Act = int(sr.GetByte())
|
||||
heroNameLen := sr.GetByte()
|
||||
heroName, _ := sr.ReadBytes(int(heroNameLen))
|
||||
result.HeroName = string(heroName)
|
||||
return result
|
||||
}
|
||||
|
||||
func CreateGameState(heroName string, hero d2enum.Hero, hardcore bool) *GameState {
|
||||
result := &GameState{
|
||||
HeroName: heroName,
|
||||
HeroType: hero,
|
||||
Act: 1,
|
||||
Seed: time.Now().UnixNano(),
|
||||
FilePath: "",
|
||||
HeroName: heroName,
|
||||
HeroType: hero,
|
||||
Act: 1,
|
||||
Seed: time.Now().UnixNano(),
|
||||
Equipment: d2inventory.HeroObjects[hero],
|
||||
FilePath: "",
|
||||
}
|
||||
|
||||
result.Save()
|
||||
return result
|
||||
}
|
||||
@ -141,22 +117,6 @@ func (v *GameState) Save() {
|
||||
if err := os.MkdirAll(path.Dir(v.FilePath), 0755); err != nil {
|
||||
log.Panic(err.Error())
|
||||
}
|
||||
f, err := os.Create(v.FilePath)
|
||||
if err != nil {
|
||||
log.Panicf(err.Error())
|
||||
}
|
||||
defer f.Close()
|
||||
sr := d2common.CreateStreamWriter()
|
||||
sr.PushUint32(GameStateVersion)
|
||||
sr.PushInt64(v.Seed)
|
||||
sr.PushByte(byte(v.HeroType))
|
||||
sr.PushByte(byte(v.HeroLevel))
|
||||
sr.PushByte(byte(v.Act))
|
||||
sr.PushByte(byte(len(v.HeroName)))
|
||||
for _, ch := range v.HeroName {
|
||||
sr.PushByte(byte(ch))
|
||||
}
|
||||
if _, err := f.Write(sr.GetBytes()); err != nil {
|
||||
log.Panicf(err.Error())
|
||||
}
|
||||
fileJson, _ := json.MarshalIndent(v, "", " ")
|
||||
ioutil.WriteFile(v.FilePath, fileJson, 0644)
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
package d2inventory
|
||||
|
||||
type CharacterEquipment struct {
|
||||
Head *InventoryItemArmor // Head
|
||||
Torso *InventoryItemArmor // TR
|
||||
Legs *InventoryItemArmor // Legs
|
||||
RightArm *InventoryItemArmor // RA
|
||||
LeftArm *InventoryItemArmor // LA
|
||||
LeftHand *InventoryItemWeapon // LH
|
||||
RightHand *InventoryItemWeapon // RH
|
||||
Shield *InventoryItemArmor // SH
|
||||
Head *InventoryItemArmor `json:"head"` // Head
|
||||
Torso *InventoryItemArmor `json:"torso"` // TR
|
||||
Legs *InventoryItemArmor `json:"legs"` // Legs
|
||||
RightArm *InventoryItemArmor `json:"rightArm"` // RA
|
||||
LeftArm *InventoryItemArmor `json:"leftArm"` // LA
|
||||
LeftHand *InventoryItemWeapon `json:"leftHand"` // LH
|
||||
RightHand *InventoryItemWeapon `json:"rightHand"` // RH
|
||||
Shield *InventoryItemArmor `json:"shield"` // SH
|
||||
// S1-S8?
|
||||
}
|
||||
|
@ -8,13 +8,13 @@ import (
|
||||
)
|
||||
|
||||
type InventoryItemArmor struct {
|
||||
inventorySizeX int
|
||||
inventorySizeY int
|
||||
inventorySlotX int
|
||||
inventorySlotY int
|
||||
itemName string
|
||||
itemCode string
|
||||
armorClass string
|
||||
InventorySizeX int `json:"inventorySizeX"`
|
||||
InventorySizeY int `json:"inventorySizeY"`
|
||||
InventorySlotX int `json:"inventorySlotX"`
|
||||
InventorySlotY int `json:"inventorySlotY"`
|
||||
ItemName string `json:"itemName"`
|
||||
ItemCode string `json:"itemCode"`
|
||||
ArmorClass string `json:"armorClass"`
|
||||
}
|
||||
|
||||
func GetArmorItemByCode(code string) *InventoryItemArmor {
|
||||
@ -23,19 +23,19 @@ func GetArmorItemByCode(code string) *InventoryItemArmor {
|
||||
log.Fatalf("Could not find armor entry for code '%s'", code)
|
||||
}
|
||||
return &InventoryItemArmor{
|
||||
inventorySizeX: result.InventoryWidth,
|
||||
inventorySizeY: result.InventoryHeight,
|
||||
itemName: result.Name,
|
||||
itemCode: result.Code,
|
||||
armorClass: "lit", // TODO: Where does this come from?
|
||||
InventorySizeX: result.InventoryWidth,
|
||||
InventorySizeY: result.InventoryHeight,
|
||||
ItemName: result.Name,
|
||||
ItemCode: result.Code,
|
||||
ArmorClass: "lit", // TODO: Where does this come from?
|
||||
}
|
||||
}
|
||||
|
||||
func (v *InventoryItemArmor) ArmorClass() string {
|
||||
if v == nil || v.itemCode == "" {
|
||||
func (v *InventoryItemArmor) GetArmorClass() string {
|
||||
if v == nil || v.ItemCode == "" {
|
||||
return "lit"
|
||||
}
|
||||
return v.armorClass
|
||||
return v.ArmorClass
|
||||
}
|
||||
|
||||
func (v *InventoryItemArmor) InventoryItemName() string {
|
||||
@ -43,7 +43,7 @@ func (v *InventoryItemArmor) InventoryItemName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
return v.itemName
|
||||
return v.ItemName
|
||||
}
|
||||
|
||||
func (v *InventoryItemArmor) InventoryItemType() d2enum.InventoryItemType {
|
||||
@ -51,25 +51,25 @@ func (v *InventoryItemArmor) InventoryItemType() d2enum.InventoryItemType {
|
||||
}
|
||||
|
||||
func (v *InventoryItemArmor) InventoryGridSize() (int, int) {
|
||||
return v.inventorySizeX, v.inventorySizeY
|
||||
return v.InventorySizeX, v.InventorySizeY
|
||||
}
|
||||
|
||||
func (v *InventoryItemArmor) InventoryGridSlot() (int, int) {
|
||||
return v.inventorySlotX, v.inventorySlotY
|
||||
return v.InventorySlotX, v.InventorySlotY
|
||||
}
|
||||
|
||||
func (v *InventoryItemArmor) SetInventoryGridSlot(x int, y int) {
|
||||
v.inventorySlotX, v.inventorySlotY = x, y
|
||||
v.InventorySlotX, v.InventorySlotY = x, y
|
||||
}
|
||||
|
||||
func (v *InventoryItemArmor) Serialize() []byte {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
func (v *InventoryItemArmor) ItemCode() string {
|
||||
func (v *InventoryItemArmor) GetItemCode() string {
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return v.itemCode
|
||||
return v.ItemCode
|
||||
}
|
||||
|
@ -8,14 +8,14 @@ import (
|
||||
)
|
||||
|
||||
type InventoryItemWeapon struct {
|
||||
inventorySizeX int
|
||||
inventorySizeY int
|
||||
inventorySlotX int
|
||||
inventorySlotY int
|
||||
itemName string
|
||||
itemCode string
|
||||
weaponClass string
|
||||
weaponClassOffHand string
|
||||
InventorySizeX int `json:"inventorySizeX"`
|
||||
InventorySizeY int `json:"inventorySizeY"`
|
||||
InventorySlotX int `json:"inventorySlotX"`
|
||||
InventorySlotY int `json:"inventorySlotY"`
|
||||
ItemName string `json:"itemName"`
|
||||
ItemCode string `json:"itemCode"`
|
||||
WeaponClass string `json:"weaponClass"`
|
||||
WeaponClassOffHand string `json:"weaponClassOffHand"`
|
||||
}
|
||||
|
||||
func GetWeaponItemByCode(code string) *InventoryItemWeapon {
|
||||
@ -25,34 +25,34 @@ func GetWeaponItemByCode(code string) *InventoryItemWeapon {
|
||||
log.Fatalf("Could not find weapon entry for code '%s'", code)
|
||||
}
|
||||
return &InventoryItemWeapon{
|
||||
inventorySizeX: result.InventoryWidth,
|
||||
inventorySizeY: result.InventoryHeight,
|
||||
itemName: result.Name,
|
||||
itemCode: result.Code,
|
||||
weaponClass: result.WeaponClass,
|
||||
weaponClassOffHand: result.WeaponClass2Hand,
|
||||
InventorySizeX: result.InventoryWidth,
|
||||
InventorySizeY: result.InventoryHeight,
|
||||
ItemName: result.Name,
|
||||
ItemCode: result.Code,
|
||||
WeaponClass: result.WeaponClass,
|
||||
WeaponClassOffHand: result.WeaponClass2Hand,
|
||||
}
|
||||
}
|
||||
|
||||
func (v *InventoryItemWeapon) WeaponClass() string {
|
||||
if v == nil || v.itemCode == "" {
|
||||
func (v *InventoryItemWeapon) GetWeaponClass() string {
|
||||
if v == nil || v.ItemCode == "" {
|
||||
return "hth"
|
||||
}
|
||||
return v.weaponClass
|
||||
return v.WeaponClass
|
||||
}
|
||||
|
||||
func (v *InventoryItemWeapon) WeaponClassOffHand() string {
|
||||
if v == nil || v.itemCode == "" {
|
||||
func (v *InventoryItemWeapon) GetWeaponClassOffHand() string {
|
||||
if v == nil || v.ItemCode == "" {
|
||||
return ""
|
||||
}
|
||||
return v.weaponClassOffHand
|
||||
return v.WeaponClassOffHand
|
||||
}
|
||||
|
||||
func (v *InventoryItemWeapon) InventoryItemName() string {
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
return v.itemName
|
||||
return v.ItemName
|
||||
}
|
||||
|
||||
func (v *InventoryItemWeapon) InventoryItemType() d2enum.InventoryItemType {
|
||||
@ -60,24 +60,24 @@ func (v *InventoryItemWeapon) InventoryItemType() d2enum.InventoryItemType {
|
||||
}
|
||||
|
||||
func (v *InventoryItemWeapon) InventoryGridSize() (int, int) {
|
||||
return v.inventorySizeX, v.inventorySizeY
|
||||
return v.InventorySizeX, v.InventorySizeY
|
||||
}
|
||||
|
||||
func (v *InventoryItemWeapon) InventoryGridSlot() (int, int) {
|
||||
return v.inventorySlotX, v.inventorySlotY
|
||||
return v.InventorySlotX, v.InventorySlotY
|
||||
}
|
||||
|
||||
func (v *InventoryItemWeapon) SetInventoryGridSlot(x int, y int) {
|
||||
v.inventorySlotX, v.inventorySlotY = x, y
|
||||
v.InventorySlotX, v.InventorySlotY = x, y
|
||||
}
|
||||
|
||||
func (v *InventoryItemWeapon) Serialize() []byte {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
func (v *InventoryItemWeapon) ItemCode() string {
|
||||
func (v *InventoryItemWeapon) GetItemCode() string {
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
return v.itemCode
|
||||
return v.ItemCode
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package d2map
|
||||
|
||||
import (
|
||||
"log"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
@ -8,10 +9,7 @@ import (
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2term"
|
||||
)
|
||||
|
||||
type MapEntity interface {
|
||||
@ -21,31 +19,25 @@ type MapEntity interface {
|
||||
}
|
||||
|
||||
type MapEngine struct {
|
||||
gameState *d2gamestate.GameState
|
||||
|
||||
debugVisLevel int
|
||||
|
||||
seed int64
|
||||
regions []*MapRegion
|
||||
entities MapEntitiesSearcher
|
||||
viewport *Viewport
|
||||
camera Camera
|
||||
}
|
||||
|
||||
func CreateMapEngine(gameState *d2gamestate.GameState) *MapEngine {
|
||||
func CreateMapEngine() *MapEngine {
|
||||
engine := &MapEngine{
|
||||
gameState: gameState,
|
||||
viewport: NewViewport(0, 0, 800, 600),
|
||||
entities: NewRangeSearcher(),
|
||||
seed: 0,
|
||||
entities: NewRangeSearcher(),
|
||||
}
|
||||
|
||||
d2term.BindAction("mapdebugvis", "set map debug visualization level", func(level int) {
|
||||
engine.debugVisLevel = level
|
||||
})
|
||||
|
||||
engine.viewport.SetCamera(&engine.camera)
|
||||
return engine
|
||||
}
|
||||
|
||||
func (m *MapEngine) SetSeed(seed int64) {
|
||||
log.Printf("Setting map engine seed to %d", seed)
|
||||
m.seed = seed
|
||||
}
|
||||
|
||||
func (m *MapEngine) GetStartPosition() (float64, float64) {
|
||||
var startX, startY float64
|
||||
if len(m.regions) > 0 {
|
||||
@ -67,45 +59,25 @@ func (m *MapEngine) GetCenterPosition() (float64, float64) {
|
||||
return centerX, centerY
|
||||
}
|
||||
|
||||
func (m *MapEngine) MoveCameraTo(x, y float64) {
|
||||
m.camera.MoveTo(x, y)
|
||||
}
|
||||
|
||||
func (m *MapEngine) MoveCameraBy(x, y float64) {
|
||||
m.camera.MoveBy(x, y)
|
||||
}
|
||||
|
||||
func (m *MapEngine) ScreenToWorld(x, y int) (float64, float64) {
|
||||
return m.viewport.ScreenToWorld(x, y)
|
||||
}
|
||||
|
||||
func (m *MapEngine) ScreenToOrtho(x, y int) (float64, float64) {
|
||||
return m.viewport.ScreenToOrtho(x, y)
|
||||
}
|
||||
|
||||
func (m *MapEngine) WorldToOrtho(x, y float64) (float64, float64) {
|
||||
return m.viewport.WorldToOrtho(x, y)
|
||||
}
|
||||
|
||||
func (m *MapEngine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int, fileIndex int) {
|
||||
region, entities := loadRegion(m.gameState.Seed, 0, 0, regionType, levelPreset, fileIndex)
|
||||
func (m *MapEngine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int, fileIndex int, cacheTiles bool) {
|
||||
region, entities := loadRegion(m.seed, 0, 0, regionType, levelPreset, fileIndex, cacheTiles)
|
||||
m.regions = append(m.regions, region)
|
||||
m.entities.Add(entities...)
|
||||
}
|
||||
|
||||
func (m *MapEngine) GenerateAct1Overworld() {
|
||||
d2audio.PlayBGM("/data/global/music/Act1/town1.wav") // TODO: Temp stuff here
|
||||
func (m *MapEngine) GenerateAct1Overworld(cacheTiles bool) {
|
||||
//d2audio.PlayBGM("/data/global/music/Act1/town1.wav") // TODO: Temp stuff here
|
||||
|
||||
region, entities := loadRegion(m.gameState.Seed, 0, 0, d2enum.RegionAct1Town, 1, -1)
|
||||
region, entities := loadRegion(m.seed, 0, 0, d2enum.RegionAct1Town, 1, -1, cacheTiles)
|
||||
m.regions = append(m.regions, region)
|
||||
m.entities.Add(entities...)
|
||||
|
||||
if strings.Contains(region.regionPath, "E1") {
|
||||
region, entities := loadRegion(m.gameState.Seed, region.tileRect.Width-1, 0, d2enum.RegionAct1Town, 2, -1)
|
||||
region, entities := loadRegion(m.seed, region.tileRect.Width-1, 0, d2enum.RegionAct1Town, 2, -1, cacheTiles)
|
||||
m.AppendRegion(region)
|
||||
m.entities.Add(entities...)
|
||||
} else if strings.Contains(region.regionPath, "S1") {
|
||||
region, entities := loadRegion(m.gameState.Seed, 0, region.tileRect.Height-1, d2enum.RegionAct1Town, 3, -1)
|
||||
region, entities := loadRegion(m.seed, 0, region.tileRect.Height-1, d2enum.RegionAct1Town, 3, -1, cacheTiles)
|
||||
m.AppendRegion(region)
|
||||
m.entities.Add(entities...)
|
||||
}
|
||||
@ -140,9 +112,9 @@ func (m *MapEngine) RemoveEntity(entity MapEntity) {
|
||||
|
||||
func (m *MapEngine) Advance(tickTime float64) {
|
||||
for _, region := range m.regions {
|
||||
if region.isVisbile(m.viewport) {
|
||||
region.advance(tickTime)
|
||||
}
|
||||
//if region.isVisbile(m.viewport) {
|
||||
region.advance(tickTime)
|
||||
//}
|
||||
}
|
||||
|
||||
for _, entity := range m.entities.All() {
|
||||
@ -152,17 +124,6 @@ func (m *MapEngine) Advance(tickTime float64) {
|
||||
m.entities.Update()
|
||||
}
|
||||
|
||||
func (m *MapEngine) Render(target d2render.Surface) {
|
||||
for _, region := range m.regions {
|
||||
if region.isVisbile(m.viewport) {
|
||||
region.renderPass1(m.viewport, target)
|
||||
region.renderDebug(m.debugVisLevel, m.viewport, target)
|
||||
region.renderPass2(m.entities, m.viewport, target)
|
||||
region.renderPass3(m.viewport, target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MapEngine) PathFind(startX, startY, endX, endY float64) (path []astar.Pather, distance float64, found bool) {
|
||||
startTileX := int(math.Floor(startX))
|
||||
startTileY := int(math.Floor(startY))
|
||||
|
@ -8,28 +8,29 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
|
||||
)
|
||||
|
||||
type Hero struct {
|
||||
type Player struct {
|
||||
*AnimatedComposite
|
||||
Equipment d2inventory.CharacterEquipment
|
||||
Id string
|
||||
mode d2enum.AnimationMode
|
||||
direction int
|
||||
}
|
||||
|
||||
func CreateHero(x, y int, direction int, heroType d2enum.Hero, equipment d2inventory.CharacterEquipment) *Hero {
|
||||
func CreatePlayer(id string, x, y int, direction int, heroType d2enum.Hero, equipment d2inventory.CharacterEquipment) *Player {
|
||||
object := &d2datadict.ObjectLookupRecord{
|
||||
Mode: d2enum.AnimationModePlayerNeutral.String(),
|
||||
Base: "/data/global/chars",
|
||||
Token: heroType.GetToken(),
|
||||
Class: equipment.RightHand.WeaponClass(),
|
||||
SH: equipment.Shield.ItemCode(),
|
||||
Class: equipment.RightHand.GetWeaponClass(),
|
||||
SH: equipment.Shield.GetItemCode(),
|
||||
// TODO: Offhand class?
|
||||
HD: equipment.Head.ArmorClass(),
|
||||
TR: equipment.Torso.ArmorClass(),
|
||||
LG: equipment.Legs.ArmorClass(),
|
||||
RA: equipment.RightArm.ArmorClass(),
|
||||
LA: equipment.LeftArm.ArmorClass(),
|
||||
RH: equipment.RightHand.ItemCode(),
|
||||
LH: equipment.LeftHand.ItemCode(),
|
||||
HD: equipment.Head.GetArmorClass(),
|
||||
TR: equipment.Torso.GetArmorClass(),
|
||||
LG: equipment.Legs.GetArmorClass(),
|
||||
RA: equipment.RightArm.GetArmorClass(),
|
||||
LA: equipment.LeftArm.GetArmorClass(),
|
||||
RH: equipment.RightHand.GetItemCode(),
|
||||
LH: equipment.LeftHand.GetItemCode(),
|
||||
}
|
||||
|
||||
entity, err := CreateAnimatedComposite(x, y, object, d2resource.PaletteUnits)
|
||||
@ -37,25 +38,26 @@ func CreateHero(x, y int, direction int, heroType d2enum.Hero, equipment d2inven
|
||||
panic(err)
|
||||
}
|
||||
|
||||
result := &Hero{
|
||||
result := &Player{
|
||||
Id: id,
|
||||
AnimatedComposite: entity,
|
||||
Equipment: equipment,
|
||||
mode: d2enum.AnimationModePlayerTownNeutral,
|
||||
direction: direction,
|
||||
}
|
||||
result.SetMode(result.mode.String(), equipment.RightHand.WeaponClass(), direction)
|
||||
result.SetMode(result.mode.String(), equipment.RightHand.GetWeaponClass(), direction)
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *Hero) Advance(tickTime float64) {
|
||||
func (v *Player) Advance(tickTime float64) {
|
||||
v.Step(tickTime)
|
||||
v.AnimatedComposite.Advance(tickTime)
|
||||
}
|
||||
|
||||
func (v *Hero) Render(target d2render.Surface) {
|
||||
func (v *Player) Render(target d2render.Surface) {
|
||||
v.AnimatedComposite.Render(target)
|
||||
}
|
||||
|
||||
func (v *Hero) GetPosition() (float64, float64) {
|
||||
func (v *Player) GetPosition() (float64, float64) {
|
||||
return v.AnimatedComposite.GetPosition()
|
||||
}
|
@ -92,7 +92,7 @@ type MapRegion struct {
|
||||
walkableArea [][]PathTile
|
||||
}
|
||||
|
||||
func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.RegionIdType, levelPreset int, fileIndex int) (*MapRegion, []MapEntity) {
|
||||
func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.RegionIdType, levelPreset int, fileIndex int, cacheTiles bool) (*MapRegion, []MapEntity) {
|
||||
region := &MapRegion{
|
||||
levelType: d2datadict.LevelTypes[levelType],
|
||||
levelPreset: d2datadict.LevelPresets[levelPreset],
|
||||
@ -145,8 +145,11 @@ func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.Regio
|
||||
|
||||
entities := region.loadEntities()
|
||||
region.loadSpecials()
|
||||
region.generateTileCache()
|
||||
region.generateWalkableMatrix()
|
||||
|
||||
if cacheTiles {
|
||||
region.generateTileCache()
|
||||
}
|
||||
return region, entities
|
||||
}
|
||||
|
||||
|
60
d2core/d2map/renderer.go
Normal file
60
d2core/d2map/renderer.go
Normal file
@ -0,0 +1,60 @@
|
||||
package d2map
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2term"
|
||||
)
|
||||
|
||||
type MapRenderer struct {
|
||||
mapEngine *MapEngine
|
||||
viewport *Viewport
|
||||
camera Camera
|
||||
debugVisLevel int
|
||||
}
|
||||
|
||||
func CreateMapRenderer(mapEngine *MapEngine) *MapRenderer {
|
||||
result := &MapRenderer{
|
||||
mapEngine: mapEngine,
|
||||
viewport: NewViewport(0, 0, 800, 600),
|
||||
}
|
||||
result.viewport.SetCamera(&result.camera)
|
||||
d2term.BindAction("mapdebugvis", "set map debug visualization level", func(level int) {
|
||||
result.debugVisLevel = level
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
func (m *MapRenderer) SetMapEngine(mapEngine *MapEngine) {
|
||||
m.mapEngine = mapEngine
|
||||
}
|
||||
|
||||
func (m *MapRenderer) Render(target d2render.Surface) {
|
||||
for _, region := range m.mapEngine.regions {
|
||||
if region.isVisbile(m.viewport) {
|
||||
region.renderPass1(m.viewport, target)
|
||||
region.renderDebug(m.debugVisLevel, m.viewport, target)
|
||||
region.renderPass2(m.mapEngine.entities, m.viewport, target)
|
||||
region.renderPass3(m.viewport, target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MapRenderer) MoveCameraTo(x, y float64) {
|
||||
m.camera.MoveTo(x, y)
|
||||
}
|
||||
|
||||
func (m *MapRenderer) MoveCameraBy(x, y float64) {
|
||||
m.camera.MoveBy(x, y)
|
||||
}
|
||||
|
||||
func (m *MapRenderer) ScreenToWorld(x, y int) (float64, float64) {
|
||||
return m.viewport.ScreenToWorld(x, y)
|
||||
}
|
||||
|
||||
func (m *MapRenderer) ScreenToOrtho(x, y int) (float64, float64) {
|
||||
return m.viewport.ScreenToOrtho(x, y)
|
||||
}
|
||||
|
||||
func (m *MapRenderer) WorldToOrtho(x, y float64) (float64, float64) {
|
||||
return m.viewport.WorldToOrtho(x, y)
|
||||
}
|
@ -6,6 +6,9 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
||||
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
@ -39,7 +42,7 @@ type CharacterSelect struct {
|
||||
characterNameLabel [8]d2ui.Label
|
||||
characterStatsLabel [8]d2ui.Label
|
||||
characterExpLabel [8]d2ui.Label
|
||||
characterImage [8]*d2map.Hero
|
||||
characterImage [8]*d2map.Player
|
||||
gameStates []*d2gamestate.GameState
|
||||
selectedCharacter int
|
||||
mouseButtonPressed bool
|
||||
@ -155,10 +158,7 @@ func (v *CharacterSelect) updateCharacterBoxes() {
|
||||
v.characterStatsLabel[i].SetText("Level 1 " + v.gameStates[idx].HeroType.String())
|
||||
v.characterExpLabel[i].SetText(expText)
|
||||
// TODO: Generate or load the object from the actual player data...
|
||||
v.characterImage[i] = d2map.CreateHero(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
v.characterImage[i] = d2map.CreatePlayer("", 0, 0, 0,
|
||||
v.gameStates[idx].HeroType,
|
||||
d2inventory.HeroObjects[v.gameStates[idx].HeroType],
|
||||
)
|
||||
@ -293,5 +293,7 @@ func (v *CharacterSelect) refreshGameStates() {
|
||||
}
|
||||
|
||||
func (v *CharacterSelect) onOkButtonClicked() {
|
||||
d2scene.SetNextScene(CreateGame(v.gameStates[v.selectedCharacter]))
|
||||
gameClient, _ := d2client.Create(d2clientconnectiontype.Local)
|
||||
gameClient.Open(v.gameStates[v.selectedCharacter].FilePath)
|
||||
d2scene.SetNextScene(CreateGame(gameClient))
|
||||
}
|
||||
|
@ -3,86 +3,108 @@ package d2gamescene
|
||||
import (
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
gameState *d2gamestate.GameState
|
||||
pentSpinLeft *d2ui.Sprite
|
||||
pentSpinRight *d2ui.Sprite
|
||||
testLabel d2ui.Label
|
||||
mapEngine *d2map.MapEngine
|
||||
hero *d2map.Hero
|
||||
gameControls *d2player.GameControls
|
||||
//pentSpinLeft *d2ui.Sprite
|
||||
//pentSpinRight *d2ui.Sprite
|
||||
//testLabel d2ui.Label
|
||||
gameClient *d2client.GameClient
|
||||
mapRenderer *d2map.MapRenderer
|
||||
gameControls *d2player.GameControls // TODO: Hack
|
||||
localPlayer *d2map.Player
|
||||
}
|
||||
|
||||
func CreateGame(gameState *d2gamestate.GameState) *Game {
|
||||
return &Game{gameState: gameState}
|
||||
func CreateGame(gameClient *d2client.GameClient) *Game {
|
||||
return &Game{
|
||||
gameClient: gameClient,
|
||||
gameControls: nil,
|
||||
localPlayer: nil,
|
||||
mapRenderer: d2map.CreateMapRenderer(gameClient.MapEngine),
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Game) OnLoad() error {
|
||||
animation, _ := d2asset.LoadAnimation(d2resource.PentSpin, d2resource.PaletteSky)
|
||||
v.pentSpinLeft, _ = d2ui.LoadSprite(animation)
|
||||
v.pentSpinLeft.PlayBackward()
|
||||
v.pentSpinLeft.SetPlayLengthMs(475)
|
||||
v.pentSpinLeft.SetPosition(100, 300)
|
||||
//animation, _ := d2asset.LoadAnimation(d2resource.PentSpin, d2resource.PaletteSky)
|
||||
//v.pentSpinLeft, _ = d2ui.LoadSprite(animation)
|
||||
//v.pentSpinLeft.PlayBackward()
|
||||
//v.pentSpinLeft.SetPlayLengthMs(475)
|
||||
//v.pentSpinLeft.SetPosition(100, 300)
|
||||
//
|
||||
//animation, _ = d2asset.LoadAnimation(d2resource.PentSpin, d2resource.PaletteSky)
|
||||
//v.pentSpinRight, _ = d2ui.LoadSprite(animation)
|
||||
//v.pentSpinRight.PlayForward()
|
||||
//v.pentSpinRight.SetPlayLengthMs(475)
|
||||
//v.pentSpinRight.SetPosition(650, 300)
|
||||
//
|
||||
//v.testLabel = d2ui.CreateLabel(d2resource.Font42, d2resource.PaletteUnits)
|
||||
//v.testLabel.Alignment = d2ui.LabelAlignCenter
|
||||
//v.testLabel.SetText("Soon :tm:")
|
||||
//v.testLabel.SetPosition(400, 250)
|
||||
|
||||
animation, _ = d2asset.LoadAnimation(d2resource.PentSpin, d2resource.PaletteSky)
|
||||
v.pentSpinRight, _ = d2ui.LoadSprite(animation)
|
||||
v.pentSpinRight.PlayForward()
|
||||
v.pentSpinRight.SetPlayLengthMs(475)
|
||||
v.pentSpinRight.SetPosition(650, 300)
|
||||
/*
|
||||
startX, startY := v.mapEngine.GetStartPosition()
|
||||
v.hero = d2map.CreateHero(
|
||||
int(startX*5)+3,
|
||||
int(startY*5)+3,
|
||||
0,
|
||||
v.gameState.HeroType,
|
||||
v.gameState.Equipment,
|
||||
)
|
||||
v.mapEngine.AddEntity(v.hero)
|
||||
|
||||
v.testLabel = d2ui.CreateLabel(d2resource.Font42, d2resource.PaletteUnits)
|
||||
v.testLabel.Alignment = d2ui.LabelAlignCenter
|
||||
v.testLabel.SetText("Soon :tm:")
|
||||
v.testLabel.SetPosition(400, 250)
|
||||
|
||||
v.mapEngine = d2map.CreateMapEngine(v.gameState)
|
||||
v.mapEngine.GenerateMap(d2enum.RegionAct1Town, 1, 0)
|
||||
|
||||
startX, startY := v.mapEngine.GetStartPosition()
|
||||
v.hero = d2map.CreateHero(
|
||||
int(startX*5)+3,
|
||||
int(startY*5)+3,
|
||||
0,
|
||||
v.gameState.HeroType,
|
||||
v.gameState.Equipment,
|
||||
)
|
||||
v.mapEngine.AddEntity(v.hero)
|
||||
|
||||
v.gameControls = d2player.NewGameControls(v.hero, v.mapEngine)
|
||||
v.gameControls.Load()
|
||||
d2input.BindHandler(v.gameControls)
|
||||
v.gameControls = d2player.NewGameControls(v.hero, v.mapEngine)
|
||||
v.gameControls.Load()
|
||||
d2input.BindHandler(v.gameControls)
|
||||
*/
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Game) OnUnload() error {
|
||||
d2input.UnbindHandler(v.gameControls)
|
||||
d2input.UnbindHandler(v.gameControls) // TODO: hack
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Game) Render(screen d2render.Surface) error {
|
||||
screen.Clear(color.Black)
|
||||
v.mapEngine.Render(screen)
|
||||
v.gameControls.Render(screen)
|
||||
v.mapRenderer.Render(screen)
|
||||
if v.gameControls != nil {
|
||||
v.gameControls.Render(screen)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Game) Advance(tickTime float64) error {
|
||||
v.mapEngine.Advance(tickTime)
|
||||
v.gameClient.MapEngine.Advance(tickTime) // TODO: Hack
|
||||
|
||||
rx, ry := v.mapEngine.WorldToOrtho(v.hero.AnimatedComposite.LocationX/5, v.hero.AnimatedComposite.LocationY/5)
|
||||
v.mapEngine.MoveCameraTo(rx, ry)
|
||||
// Bind the game controls to the player once it exists
|
||||
if v.gameControls == nil {
|
||||
for _, player := range v.gameClient.Players {
|
||||
if player.Id != v.gameClient.PlayerId {
|
||||
continue
|
||||
}
|
||||
v.localPlayer = player
|
||||
v.gameControls = d2player.NewGameControls(player, v.gameClient.MapEngine, v.mapRenderer, v.gameClient)
|
||||
v.gameControls.Load()
|
||||
d2input.BindHandler(v.gameControls)
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Update the camera to focus on the player
|
||||
if v.localPlayer != nil {
|
||||
rx, ry := v.mapRenderer.WorldToOrtho(v.localPlayer.AnimatedComposite.LocationX/5, v.localPlayer.AnimatedComposite.LocationY/5)
|
||||
v.mapRenderer.MoveCameraTo(rx, ry)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -76,8 +76,9 @@ var regions = []RegionSpec{
|
||||
}
|
||||
|
||||
type MapEngineTest struct {
|
||||
gameState *d2gamestate.GameState
|
||||
mapEngine *d2map.MapEngine
|
||||
gameState *d2gamestate.GameState
|
||||
mapEngine *d2map.MapEngine
|
||||
mapRenderer *d2map.MapRenderer
|
||||
|
||||
//TODO: this is region specific properties, should be refactored for multi-region rendering
|
||||
currentRegion int
|
||||
@ -125,20 +126,22 @@ func (met *MapEngineTest) LoadRegionByIndex(n int, levelPreset, fileIndex int) {
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
met.mapEngine.GenerateAct1Overworld()
|
||||
met.mapEngine.GenerateAct1Overworld(true)
|
||||
} else {
|
||||
met.mapEngine = d2map.CreateMapEngine(met.gameState) // necessary for map name update
|
||||
met.mapEngine.GenerateMap(d2enum.RegionIdType(n), levelPreset, fileIndex)
|
||||
met.mapEngine = d2map.CreateMapEngine() // necessary for map name update
|
||||
met.mapEngine.GenerateMap(d2enum.RegionIdType(n), levelPreset, fileIndex, true)
|
||||
met.mapRenderer.SetMapEngine(met.mapEngine)
|
||||
}
|
||||
|
||||
met.mapEngine.MoveCameraTo(met.mapEngine.WorldToOrtho(met.mapEngine.GetCenterPosition()))
|
||||
met.mapRenderer.MoveCameraTo(met.mapRenderer.WorldToOrtho(met.mapEngine.GetCenterPosition()))
|
||||
}
|
||||
|
||||
func (met *MapEngineTest) OnLoad() error {
|
||||
// TODO: Game seed comes from the game state object
|
||||
d2input.BindHandler(met)
|
||||
|
||||
met.mapEngine = d2map.CreateMapEngine(met.gameState)
|
||||
met.mapEngine = d2map.CreateMapEngine()
|
||||
met.mapRenderer = d2map.CreateMapRenderer(met.mapEngine)
|
||||
met.LoadRegionByIndex(met.currentRegion, met.levelPreset, met.fileIndex)
|
||||
|
||||
return nil
|
||||
@ -150,10 +153,10 @@ func (met *MapEngineTest) OnUnload() error {
|
||||
}
|
||||
|
||||
func (met *MapEngineTest) Render(screen d2render.Surface) error {
|
||||
met.mapEngine.Render(screen)
|
||||
met.mapRenderer.Render(screen)
|
||||
|
||||
screenX, screenY := d2render.GetCursorPos()
|
||||
worldX, worldY := met.mapEngine.ScreenToWorld(screenX, screenY)
|
||||
worldX, worldY := met.mapRenderer.ScreenToWorld(screenX, screenY)
|
||||
//subtileX := int(math.Ceil(math.Mod(worldX*10, 10))) / 2
|
||||
//subtileY := int(math.Ceil(math.Mod(worldY*10, 10))) / 2
|
||||
|
||||
@ -277,22 +280,22 @@ func (met *MapEngineTest) OnKeyRepeat(event d2input.KeyEvent) bool {
|
||||
}
|
||||
|
||||
if event.Key == d2input.KeyDown {
|
||||
met.mapEngine.MoveCameraBy(0, moveSpeed)
|
||||
met.mapRenderer.MoveCameraBy(0, moveSpeed)
|
||||
return true
|
||||
}
|
||||
|
||||
if event.Key == d2input.KeyUp {
|
||||
met.mapEngine.MoveCameraBy(0, -moveSpeed)
|
||||
met.mapRenderer.MoveCameraBy(0, -moveSpeed)
|
||||
return true
|
||||
}
|
||||
|
||||
if event.Key == d2input.KeyRight {
|
||||
met.mapEngine.MoveCameraBy(moveSpeed, 0)
|
||||
met.mapRenderer.MoveCameraBy(moveSpeed, 0)
|
||||
return true
|
||||
}
|
||||
|
||||
if event.Key == d2input.KeyLeft {
|
||||
met.mapEngine.MoveCameraBy(-moveSpeed, 0)
|
||||
met.mapRenderer.MoveCameraBy(-moveSpeed, 0)
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,9 @@ import (
|
||||
"image"
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
dh "github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
@ -422,7 +425,9 @@ func (v SelectHeroClass) onExitButtonClicked() {
|
||||
|
||||
func (v SelectHeroClass) onOkButtonClicked() {
|
||||
gameState := d2gamestate.CreateGameState(v.heroNameTextbox.GetText(), v.selectedHero, v.hardcoreCheckbox.GetCheckState())
|
||||
d2scene.SetNextScene(CreateGame(gameState))
|
||||
gameClient, _ := d2client.Create(d2clientconnectiontype.Local)
|
||||
gameClient.Open(gameState.FilePath)
|
||||
d2scene.SetNextScene(CreateGame(gameClient))
|
||||
}
|
||||
|
||||
func (v *SelectHeroClass) Render(screen d2render.Surface) error {
|
||||
|
@ -3,7 +3,6 @@ package d2player
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
|
||||
@ -11,6 +10,8 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2term"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
)
|
||||
|
||||
type Panel interface {
|
||||
@ -24,10 +25,12 @@ type Panel interface {
|
||||
var missileID = 59
|
||||
|
||||
type GameControls struct {
|
||||
hero *d2map.Hero
|
||||
mapEngine *d2map.MapEngine
|
||||
inventory *Inventory
|
||||
heroStats *HeroStats
|
||||
hero *d2map.Player
|
||||
mapEngine *d2map.MapEngine
|
||||
mapRenderer *d2map.MapRenderer
|
||||
inventory *Inventory
|
||||
heroStats *HeroStats
|
||||
gameClient *d2client.GameClient
|
||||
|
||||
// UI
|
||||
globeSprite *d2ui.Sprite
|
||||
@ -36,16 +39,19 @@ type GameControls struct {
|
||||
skillIcon *d2ui.Sprite
|
||||
}
|
||||
|
||||
func NewGameControls(hero *d2map.Hero, mapEngine *d2map.MapEngine) *GameControls {
|
||||
func NewGameControls(hero *d2map.Player, mapEngine *d2map.MapEngine, mapRenderer *d2map.MapRenderer,
|
||||
gameClient *d2client.GameClient) *GameControls {
|
||||
d2term.BindAction("setmissile", "set missile id to summon on right click", func(id int) {
|
||||
missileID = id
|
||||
})
|
||||
|
||||
return &GameControls{
|
||||
hero: hero,
|
||||
mapEngine: mapEngine,
|
||||
inventory: NewInventory(),
|
||||
heroStats: NewHeroStats(),
|
||||
hero: hero,
|
||||
mapEngine: mapEngine,
|
||||
gameClient: gameClient,
|
||||
mapRenderer: mapRenderer,
|
||||
inventory: NewInventory(),
|
||||
heroStats: NewHeroStats(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,21 +69,22 @@ func (g *GameControls) OnKeyDown(event d2input.KeyEvent) bool {
|
||||
}
|
||||
|
||||
func (g *GameControls) OnMouseButtonDown(event d2input.MouseEvent) bool {
|
||||
px, py := g.mapEngine.ScreenToWorld(event.X, event.Y)
|
||||
px, py := g.mapRenderer.ScreenToWorld(event.X, event.Y)
|
||||
px = float64(int(px*10)) / 10.0
|
||||
py = float64(int(py*10)) / 10.0
|
||||
heroPosX := g.hero.AnimatedComposite.LocationX / 5.0
|
||||
heroPosY := g.hero.AnimatedComposite.LocationY / 5.0
|
||||
|
||||
if event.Button == d2input.MouseButtonLeft {
|
||||
path, _, found := g.mapEngine.PathFind(heroPosX, heroPosY, px, py)
|
||||
if found {
|
||||
g.hero.AnimatedComposite.SetPath(path, func() {
|
||||
g.hero.AnimatedComposite.SetAnimationMode(
|
||||
d2enum.AnimationModeObjectNeutral.String(),
|
||||
)
|
||||
})
|
||||
}
|
||||
g.gameClient.SendPacketToServer(d2netpacket.CreateMovePlayerPacket(g.gameClient.PlayerId, heroPosX, heroPosY, px, py))
|
||||
//path, _, found := g.mapEngine.PathFind(heroPosX, heroPosY, px, py)
|
||||
//if found {
|
||||
// g.hero.AnimatedComposite.SetPath(path, func() {
|
||||
// g.hero.AnimatedComposite.SetAnimationMode(
|
||||
// d2enum.AnimationModeObjectNeutral.String(),
|
||||
// )
|
||||
// })
|
||||
//}
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
|
||||
type InventoryItem interface {
|
||||
InventoryGridSize() (width int, height int)
|
||||
ItemCode() string
|
||||
GetItemCode() string
|
||||
InventoryGridSlot() (x int, y int)
|
||||
SetInventoryGridSlot(x int, y int)
|
||||
}
|
||||
@ -94,23 +94,23 @@ func (g *ItemGrid) Load(items ...InventoryItem) {
|
||||
var itemSprite *d2ui.Sprite
|
||||
|
||||
for _, item := range items {
|
||||
if _, exists := g.sprites[item.ItemCode()]; exists {
|
||||
if _, exists := g.sprites[item.GetItemCode()]; exists {
|
||||
// Already loaded, don't reload.
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: Put the pattern into D2Shared
|
||||
animation, err := d2asset.LoadAnimation(
|
||||
fmt.Sprintf("/data/global/items/inv%s.dc6", item.ItemCode()),
|
||||
fmt.Sprintf("/data/global/items/inv%s.dc6", item.GetItemCode()),
|
||||
d2resource.PaletteSky,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("failed to load sprite for item (%s): %v", item.ItemCode(), err)
|
||||
log.Printf("failed to load sprite for item (%s): %v", item.GetItemCode(), err)
|
||||
continue
|
||||
}
|
||||
itemSprite, err = d2ui.LoadSprite(animation)
|
||||
|
||||
g.sprites[item.ItemCode()] = itemSprite
|
||||
g.sprites[item.GetItemCode()] = itemSprite
|
||||
}
|
||||
|
||||
}
|
||||
@ -156,7 +156,7 @@ func (g *ItemGrid) canFit(x int, y int, item InventoryItem) bool {
|
||||
|
||||
func (g *ItemGrid) Set(x int, y int, item InventoryItem) error {
|
||||
if !g.canFit(x, y, item) {
|
||||
return fmt.Errorf("can not set item (%s) to position (%v, %v)", item.ItemCode(), x, y)
|
||||
return fmt.Errorf("can not set item (%s) to position (%v, %v)", item.GetItemCode(), x, y)
|
||||
}
|
||||
g.set(x, y, item)
|
||||
return nil
|
||||
@ -189,7 +189,7 @@ func (g *ItemGrid) Render(target d2render.Surface) {
|
||||
continue
|
||||
}
|
||||
|
||||
itemSprite := g.sprites[item.ItemCode()]
|
||||
itemSprite := g.sprites[item.GetItemCode()]
|
||||
if itemSprite == nil {
|
||||
// In case it failed to load.
|
||||
// TODO: fallback to something
|
||||
|
@ -17,7 +17,7 @@ func (t *TestItem) InventoryGridSize() (int, int) {
|
||||
return t.width, t.height
|
||||
}
|
||||
|
||||
func (t *TestItem) ItemCode() string {
|
||||
func (t *TestItem) GetItemCode() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
7
d2networking/client_listener.go
Normal file
7
d2networking/client_listener.go
Normal file
@ -0,0 +1,7 @@
|
||||
package d2networking
|
||||
|
||||
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
|
||||
type ClientListener interface {
|
||||
OnPacketReceived(packet d2netpacket.NetPacket) error
|
||||
}
|
13
d2networking/d2client/client_connection.go
Normal file
13
d2networking/d2client/client_connection.go
Normal file
@ -0,0 +1,13 @@
|
||||
package d2client
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
)
|
||||
|
||||
type ClientConnection interface {
|
||||
Open(connectionString string) error
|
||||
Close() error
|
||||
SendPacketToServer(packet d2netpacket.NetPacket) error
|
||||
SetClientListener(listener d2networking.ClientListener)
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package d2clientconnectiontype
|
||||
|
||||
type ClientConnectionType int
|
||||
|
||||
const (
|
||||
Local ClientConnectionType = 1
|
||||
)
|
@ -0,0 +1,55 @@
|
||||
package d2localclient
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2server"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
type LocalClientConnection struct {
|
||||
clientListener d2networking.ClientListener
|
||||
uniqueId string
|
||||
}
|
||||
|
||||
func (l LocalClientConnection) GetUniqueId() string {
|
||||
return l.uniqueId
|
||||
}
|
||||
|
||||
func (l LocalClientConnection) GetConnectionType() string {
|
||||
return "Local Client"
|
||||
}
|
||||
|
||||
func (l *LocalClientConnection) SendPacketToClient(packet d2netpacket.NetPacket) error {
|
||||
return l.clientListener.OnPacketReceived(packet)
|
||||
}
|
||||
|
||||
func Create() *LocalClientConnection {
|
||||
result := &LocalClientConnection{
|
||||
uniqueId: uuid.NewV4().String(),
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (l *LocalClientConnection) Open(gameStatePath string) error {
|
||||
d2server.Create(gameStatePath)
|
||||
go d2server.Run()
|
||||
d2server.OnClientConnected(l)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LocalClientConnection) Close() error {
|
||||
d2server.OnClientDisconnected(l)
|
||||
d2server.Destroy()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LocalClientConnection) SendPacketToServer(packet d2netpacket.NetPacket) error {
|
||||
// TODO: This is going to blow up if the server has ceased to be.
|
||||
return d2server.OnPacketReceived(l, packet)
|
||||
}
|
||||
|
||||
func (l *LocalClientConnection) SetClientListener(listener d2networking.ClientListener) {
|
||||
l.clientListener = listener
|
||||
}
|
94
d2networking/d2client/game_client.go
Normal file
94
d2networking/d2client/game_client.go
Normal file
@ -0,0 +1,94 @@
|
||||
package d2client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2localclient"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||
)
|
||||
|
||||
type GameClient struct {
|
||||
clientConnection ClientConnection
|
||||
GameState *d2gamestate.GameState
|
||||
MapEngine *d2map.MapEngine
|
||||
PlayerId string
|
||||
Players map[string]*d2map.Player
|
||||
}
|
||||
|
||||
func Create(connectionType d2clientconnectiontype.ClientConnectionType) (*GameClient, error) {
|
||||
result := &GameClient{
|
||||
MapEngine: d2map.CreateMapEngine(),
|
||||
Players: make(map[string]*d2map.Player, 0),
|
||||
}
|
||||
|
||||
switch connectionType {
|
||||
case d2clientconnectiontype.Local:
|
||||
result.clientConnection = d2localclient.Create()
|
||||
result.clientConnection.SetClientListener(result)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown client connection type specified: %d", connectionType)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (g *GameClient) Open(connectionString string) error {
|
||||
return g.clientConnection.Open(connectionString)
|
||||
}
|
||||
|
||||
func (g *GameClient) Close() error {
|
||||
return g.clientConnection.Close()
|
||||
}
|
||||
|
||||
func (g *GameClient) Destroy() error {
|
||||
return g.clientConnection.Close()
|
||||
}
|
||||
|
||||
func (g *GameClient) OnPacketReceived(packet d2netpacket.NetPacket) error {
|
||||
switch packet.PacketType {
|
||||
case d2netpackettype.GenerateMap:
|
||||
mapData := packet.PacketData.(d2netpacket.GenerateMapPacket)
|
||||
g.MapEngine.GenerateMap(mapData.RegionType, mapData.LevelPreset, mapData.FileIndex, true)
|
||||
break
|
||||
case d2netpackettype.UpdateServerInfo:
|
||||
serverInfo := packet.PacketData.(d2netpacket.UpdateServerInfoPacket)
|
||||
g.MapEngine.SetSeed(serverInfo.Seed)
|
||||
g.PlayerId = serverInfo.PlayerId
|
||||
log.Printf("Player id set to %s", serverInfo.PlayerId)
|
||||
break
|
||||
case d2netpackettype.AddPlayer:
|
||||
player := packet.PacketData.(d2netpacket.AddPlayerPacket)
|
||||
newPlayer := d2map.CreatePlayer(player.Id, player.X, player.Y, 0, player.HeroType, player.Equipment)
|
||||
g.Players[newPlayer.Id] = newPlayer
|
||||
g.MapEngine.AddEntity(newPlayer)
|
||||
break
|
||||
case d2netpackettype.MovePlayer:
|
||||
movePlayer := packet.PacketData.(d2netpacket.MovePlayerPacket)
|
||||
player := g.Players[movePlayer.PlayerId]
|
||||
path, _, found := g.MapEngine.PathFind(movePlayer.StartX, movePlayer.StartY, movePlayer.DestX, movePlayer.DestY)
|
||||
if found {
|
||||
player.AnimatedComposite.SetPath(path, func() {
|
||||
player.AnimatedComposite.SetAnimationMode(
|
||||
d2enum.AnimationModeObjectNeutral.String(),
|
||||
)
|
||||
})
|
||||
}
|
||||
break
|
||||
default:
|
||||
log.Fatalf("Invalid packet type: %d", packet.PacketType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GameClient) SendPacketToServer(packet d2netpacket.NetPacket) error {
|
||||
return g.clientConnection.SendPacketToServer(packet)
|
||||
}
|
12
d2networking/d2netpacket/d2netpackettype/message_type.go
Normal file
12
d2networking/d2netpacket/d2netpackettype/message_type.go
Normal file
@ -0,0 +1,12 @@
|
||||
package d2netpackettype
|
||||
|
||||
type NetPacketType uint32
|
||||
|
||||
// Warning: Do NOT re-arrange the order of these packet values unless you want to
|
||||
// break compatibility between clients of slightly different versions.
|
||||
const (
|
||||
UpdateServerInfo NetPacketType = iota
|
||||
GenerateMap
|
||||
AddPlayer
|
||||
MovePlayer
|
||||
)
|
8
d2networking/d2netpacket/net_packet.go
Normal file
8
d2networking/d2netpacket/net_packet.go
Normal file
@ -0,0 +1,8 @@
|
||||
package d2netpacket
|
||||
|
||||
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||
|
||||
type NetPacket struct {
|
||||
PacketType d2netpackettype.NetPacketType `json:"packetType"`
|
||||
PacketData interface{} `json:"packetData"`
|
||||
}
|
28
d2networking/d2netpacket/packet_add_player.go
Normal file
28
d2networking/d2netpacket/packet_add_player.go
Normal file
@ -0,0 +1,28 @@
|
||||
package d2netpacket
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2inventory"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||
)
|
||||
|
||||
type AddPlayerPacket struct {
|
||||
Id string `json:"id"`
|
||||
X int `json:"x"`
|
||||
Y int `json:"y"`
|
||||
HeroType d2enum.Hero `json:"hero"`
|
||||
Equipment d2inventory.CharacterEquipment `json:"equipment"`
|
||||
}
|
||||
|
||||
func CreateAddPlayerPacket(id string, x, y int, heroType d2enum.Hero, equipment d2inventory.CharacterEquipment) NetPacket {
|
||||
return NetPacket{
|
||||
PacketType: d2netpackettype.AddPlayer,
|
||||
PacketData: AddPlayerPacket{
|
||||
Id: id,
|
||||
X: x,
|
||||
Y: y,
|
||||
HeroType: heroType,
|
||||
Equipment: equipment,
|
||||
},
|
||||
}
|
||||
}
|
24
d2networking/d2netpacket/packet_generate_map.go
Normal file
24
d2networking/d2netpacket/packet_generate_map.go
Normal file
@ -0,0 +1,24 @@
|
||||
package d2netpacket
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||
)
|
||||
|
||||
type GenerateMapPacket struct {
|
||||
RegionType d2enum.RegionIdType `json:"regionType"`
|
||||
LevelPreset int `json:"levelPreset"`
|
||||
FileIndex int `json:"fileIndex"`
|
||||
}
|
||||
|
||||
func CreateGenerateMapPacket(regionType d2enum.RegionIdType, levelPreset int, fileIndex int) NetPacket {
|
||||
return NetPacket{
|
||||
PacketType: d2netpackettype.GenerateMap,
|
||||
PacketData: GenerateMapPacket{
|
||||
RegionType: regionType,
|
||||
LevelPreset: levelPreset,
|
||||
FileIndex: fileIndex,
|
||||
},
|
||||
}
|
||||
|
||||
}
|
26
d2networking/d2netpacket/packet_move_player.go
Normal file
26
d2networking/d2netpacket/packet_move_player.go
Normal file
@ -0,0 +1,26 @@
|
||||
package d2netpacket
|
||||
|
||||
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||
|
||||
// TODO: Need to handle being on different maps
|
||||
|
||||
type MovePlayerPacket struct {
|
||||
PlayerId string `json:"playerId"`
|
||||
StartX float64 `json:"startX"`
|
||||
StartY float64 `json:"startY"`
|
||||
DestX float64 `json:"destX"`
|
||||
DestY float64 `json:"destY"`
|
||||
}
|
||||
|
||||
func CreateMovePlayerPacket(playerId string, startX, startY, destX, destY float64) NetPacket {
|
||||
return NetPacket{
|
||||
PacketType: d2netpackettype.MovePlayer,
|
||||
PacketData: MovePlayerPacket{
|
||||
PlayerId: playerId,
|
||||
StartX: startX,
|
||||
StartY: startY,
|
||||
DestX: destX,
|
||||
DestY: destY,
|
||||
},
|
||||
}
|
||||
}
|
18
d2networking/d2netpacket/packet_update_server_info.go
Normal file
18
d2networking/d2netpacket/packet_update_server_info.go
Normal file
@ -0,0 +1,18 @@
|
||||
package d2netpacket
|
||||
|
||||
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||
|
||||
type UpdateServerInfoPacket struct {
|
||||
Seed int64 `json:"seed"`
|
||||
PlayerId string `json:"playerId"`
|
||||
}
|
||||
|
||||
func CreateUpdateServerInfoPacket(seed int64, playerId string) NetPacket {
|
||||
return NetPacket{
|
||||
PacketType: d2netpackettype.UpdateServerInfo,
|
||||
PacketData: UpdateServerInfoPacket{
|
||||
Seed: seed,
|
||||
PlayerId: playerId,
|
||||
},
|
||||
}
|
||||
}
|
9
d2networking/d2server/client_connection.go
Normal file
9
d2networking/d2server/client_connection.go
Normal file
@ -0,0 +1,9 @@
|
||||
package d2server
|
||||
|
||||
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
|
||||
type ClientConnection interface {
|
||||
GetUniqueId() string
|
||||
GetConnectionType() string
|
||||
SendPacketToClient(packet d2netpacket.NetPacket) error
|
||||
}
|
88
d2networking/d2server/game_server.go
Normal file
88
d2networking/d2server/game_server.go
Normal file
@ -0,0 +1,88 @@
|
||||
package d2server
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
)
|
||||
|
||||
type GameServer struct {
|
||||
gameState *d2gamestate.GameState
|
||||
clientConnections map[string]ClientConnection
|
||||
mapEngines []*d2map.MapEngine
|
||||
}
|
||||
|
||||
var singletonServer *GameServer
|
||||
|
||||
func Create(gameStatePath string) {
|
||||
log.Print("Creating GameServer")
|
||||
if singletonServer != nil {
|
||||
return
|
||||
}
|
||||
|
||||
singletonServer = &GameServer{
|
||||
clientConnections: make(map[string]ClientConnection),
|
||||
mapEngines: make([]*d2map.MapEngine, 0),
|
||||
gameState: d2gamestate.LoadGameState(gameStatePath),
|
||||
}
|
||||
|
||||
mapEngine := d2map.CreateMapEngine()
|
||||
mapEngine.GenerateMap(d2enum.RegionAct1Town, 1, 0, false)
|
||||
singletonServer.mapEngines = append(singletonServer.mapEngines, mapEngine)
|
||||
}
|
||||
|
||||
func Run() {
|
||||
log.Print("Starting GameServer")
|
||||
}
|
||||
|
||||
func Stop() {
|
||||
log.Print("Stopping GameServer")
|
||||
}
|
||||
|
||||
func Destroy() {
|
||||
if singletonServer == nil {
|
||||
return
|
||||
}
|
||||
log.Print("Destroying GameServer")
|
||||
Stop()
|
||||
}
|
||||
|
||||
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.gameState.Seed, client.GetUniqueId()))
|
||||
client.SendPacketToClient(d2netpacket.CreateGenerateMapPacket(d2enum.RegionAct1Town, 1, 0))
|
||||
|
||||
// TODO: This needs to use a real method of loading characters instead of cloning the 'save file character'
|
||||
sx, sy := singletonServer.mapEngines[0].GetStartPosition() // TODO: Another temporary hack
|
||||
createPlayerPacket := d2netpacket.CreateAddPlayerPacket(client.GetUniqueId(), int(sx*5)+3, int(sy*5)+3,
|
||||
singletonServer.gameState.HeroType, singletonServer.gameState.Equipment)
|
||||
for _, connection := range singletonServer.clientConnections {
|
||||
connection.SendPacketToClient(createPlayerPacket)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func OnClientDisconnected(client ClientConnection) {
|
||||
log.Printf("Client disconnected with an id of %s", client.GetUniqueId())
|
||||
delete(singletonServer.clientConnections, client.GetUniqueId())
|
||||
}
|
||||
|
||||
func OnPacketReceived(client ClientConnection, packet d2netpacket.NetPacket) error {
|
||||
switch packet.PacketType {
|
||||
case d2netpackettype.MovePlayer:
|
||||
// TODO: This needs to be verified on the server (here) before sending to other clients....
|
||||
for _, player := range singletonServer.clientConnections {
|
||||
player.SendPacketToClient(packet)
|
||||
}
|
||||
break
|
||||
}
|
||||
return nil
|
||||
}
|
3
go.mod
3
go.mod
@ -9,6 +9,9 @@ require (
|
||||
github.com/beefsack/go-astar v0.0.0-20171024231011-f324bbb0d6f7
|
||||
github.com/go-restruct/restruct v0.0.0-20191227155143-5734170a48a1
|
||||
github.com/hajimehoshi/ebiten v1.11.0-alpha.2.0.20200102072751-e66f1fb71e2e
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
||||
github.com/pebbe/zmq4 v1.2.1 // indirect
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/stretchr/testify v1.4.0
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 // indirect
|
||||
golang.org/x/mobile v0.0.0-20191115022231-f0c40035f2ba // indirect
|
||||
|
7
go.sum
7
go.sum
@ -34,11 +34,18 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-sqlite3 v1.13.0 h1:LnJI81JidiW9r7pS/hXe6cFeO5EXNq7KbfvoJLRI69c=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/pebbe/zmq4 v1.2.1 h1:jrXQW3mD8Si2mcSY/8VBs2nNkK/sKCOEM0rHAfxyc8c=
|
||||
github.com/pebbe/zmq4 v1.2.1/go.mod h1:7N4y5R18zBiu3l0vajMUWQgZyjv464prE8RCyBcmnZM=
|
||||
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
|
4
main.go
4
main.go
@ -13,6 +13,8 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2inventory"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
@ -182,6 +184,8 @@ func initialize() error {
|
||||
return err
|
||||
}
|
||||
|
||||
d2inventory.LoadHeroObjects()
|
||||
|
||||
d2ui.Initialize()
|
||||
|
||||
return nil
|
||||
|
Loading…
Reference in New Issue
Block a user