1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-26 17:15:24 +00:00

D2core logger (#934)

* logger for d2audio & d2map

* logger for d2ui e.t.c

* d2inventory now passes on error messages

* no more importing log in d2core

* implemented #925

* added logger to part of d2networking & fixed "need to be changed" comments

* fixed lints

* fixed errors

Co-authored-by: M. Sz <mszeptuch@protonmail.com>
This commit is contained in:
gucio321 2020-11-21 11:33:22 +01:00 committed by GitHub
parent 34f9538afb
commit 9ffbf1320c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 471 additions and 255 deletions

View File

@ -138,7 +138,7 @@ func (a *App) startDedicatedServer() error {
srvChanIn := make(chan int)
srvChanLog := make(chan string)
srvErr := d2networking.StartDedicatedServer(a.asset, srvChanIn, srvChanLog, maxPlayers)
srvErr := d2networking.StartDedicatedServer(a.asset, srvChanIn, srvChanLog, a.config.LogLevel, maxPlayers)
if srvErr != nil {
return srvErr
}
@ -179,7 +179,7 @@ func (a *App) loadEngine() error {
a.asset.SetLogLevel(logLevel)
audio := ebiten2.CreateAudio(a.asset)
audio := ebiten2.CreateAudio(a.config.LogLevel, a.asset)
inputManager := d2input.NewInputManager()
@ -195,7 +195,7 @@ func (a *App) loadEngine() error {
scriptEngine := d2script.CreateScriptEngine()
uiManager := d2ui.NewUIManager(a.asset, renderer, inputManager, audio)
uiManager := d2ui.NewUIManager(a.asset, renderer, inputManager, a.config.LogLevel, audio)
a.inputManager = inputManager
a.terminal = term
@ -409,14 +409,14 @@ func (a *App) initialize() error {
}
}
gui, err := d2gui.CreateGuiManager(a.asset, a.inputManager)
gui, err := d2gui.CreateGuiManager(a.asset, a.config.LogLevel, a.inputManager)
if err != nil {
return err
}
a.guiManager = gui
a.screen = d2screen.NewScreenManager(a.ui, a.guiManager)
a.screen = d2screen.NewScreenManager(a.ui, a.config.LogLevel, a.guiManager)
a.audio.SetVolumes(a.config.BgmVolume, a.config.SfxVolume)
@ -931,7 +931,7 @@ func (a *App) ToSelectHero(connType d2clientconnectiontype.ClientConnectionType,
// ToCreateGame forces the game to transition to the Create Game screen
func (a *App) ToCreateGame(filePath string, connType d2clientconnectiontype.ClientConnectionType, host string) {
gameClient, err := d2client.Create(connType, a.asset, a.scriptEngine)
gameClient, err := d2client.Create(connType, a.asset, a.config.LogLevel, a.scriptEngine)
if err != nil {
a.logger.Error(err.Error())
}

View File

@ -3,9 +3,9 @@ package ebiten
import (
"io"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/hajimehoshi/ebiten/v2/audio"
@ -14,14 +14,20 @@ import (
const sampleRate = 44100
const logPrefix = "Ebiten Audio Provider"
var _ d2interface.AudioProvider = &AudioProvider{} // Static check to confirm struct conforms to interface
// CreateAudio creates an instance of ebiten's audio provider
func CreateAudio(am *d2asset.AssetManager) *AudioProvider {
func CreateAudio(l d2util.LogLevel, am *d2asset.AssetManager) *AudioProvider {
result := &AudioProvider{
asset: am,
}
result.Logger = d2util.NewLogger()
result.Logger.SetLevel(l)
result.Logger.SetPrefix(logPrefix)
result.audioContext = audio.NewContext(sampleRate)
return result
@ -36,6 +42,8 @@ type AudioProvider struct {
lastBgm string
sfxVolume float64
bgmVolume float64
*d2util.Logger
}
// PlayBGM loads an audio stream and plays it in the background
@ -55,7 +63,7 @@ func (eap *AudioProvider) PlayBGM(song string) {
err := eap.bgmAudio.Close()
if err != nil {
log.Panic(err)
eap.Fatal(err.Error())
}
}
@ -66,20 +74,20 @@ func (eap *AudioProvider) PlayBGM(song string) {
}
if _, err = audioStream.Seek(0, io.SeekStart); err != nil {
log.Fatal(err)
eap.Fatal(err.Error())
}
eap.bgmStream, err = wav.Decode(eap.audioContext, audioStream)
if err != nil {
log.Fatal(err)
eap.Fatal(err.Error())
}
s := audio.NewInfiniteLoop(eap.bgmStream, eap.bgmStream.Length())
eap.bgmAudio, err = audio.NewPlayer(eap.audioContext, s)
if err != nil {
log.Fatal(err)
eap.Fatal(err.Error())
}
eap.bgmAudio.SetVolume(eap.bgmVolume)
@ -142,7 +150,7 @@ func (eap *AudioProvider) createSoundEffect(sfx string, context *audio.Context,
d, err := wav.Decode(context, audioData)
if err != nil {
log.Fatal(err)
eap.Fatal(err.Error())
}
var player *audio.Player
@ -157,7 +165,7 @@ func (eap *AudioProvider) createSoundEffect(sfx string, context *audio.Context,
}
if err != nil {
log.Fatal(err)
eap.Fatal(err.Error())
}
result.player = player

View File

@ -1,7 +1,7 @@
package d2audio
import (
"log"
"fmt"
"math/rand"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
@ -9,10 +9,15 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2records"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
)
type envState int
const (
logPrefix = "Sound Engine"
)
const (
envAttack = 0
envSustain = 1
@ -32,6 +37,8 @@ type Sound struct {
vRate float64
state envState
// panning float64 // lets forget about this for now
*d2util.Logger
}
func (s *Sound) update(elapsed float64) {
@ -66,7 +73,7 @@ func (s *Sound) SetPan(pan float64) {
// Play the sound
func (s *Sound) Play() {
log.Println("starting sound", s.entry.Handle)
s.Info("starting sound" + s.entry.Handle)
s.effect.Play()
if s.entry.FadeIn != 0 {
@ -103,11 +110,13 @@ type SoundEngine struct {
timer float64
accTime float64
sounds map[*Sound]struct{}
*d2util.Logger
}
// NewSoundEngine creates a new sound engine
func NewSoundEngine(provider d2interface.AudioProvider,
asset *d2asset.AssetManager, term d2interface.Terminal) *SoundEngine {
asset *d2asset.AssetManager, l d2util.LogLevel, term d2interface.Terminal) *SoundEngine {
r := SoundEngine{
asset: asset,
provider: provider,
@ -115,11 +124,15 @@ func NewSoundEngine(provider d2interface.AudioProvider,
timer: 1,
}
r.Logger = d2util.NewLogger()
r.Logger.SetPrefix(logPrefix)
r.Logger.SetLevel(l)
err := term.BindAction("playsoundid", "plays the sound for a given id", func(id int) {
r.PlaySoundID(id)
})
if err != nil {
log.Print(err)
r.Error(err.Error())
return nil
}
@ -127,25 +140,25 @@ func NewSoundEngine(provider d2interface.AudioProvider,
r.PlaySoundHandle(handle)
})
if err != nil {
log.Print(err)
r.Error(err.Error())
return nil
}
err = term.BindAction("activesounds", "list currently active sounds", func() {
for s := range r.sounds {
if err != nil {
log.Print(err)
r.Error(err.Error())
return
}
log.Println(s)
r.Info(fmt.Sprint(s))
}
})
err = term.BindAction("killsounds", "kill active sounds", func() {
for s := range r.sounds {
if err != nil {
log.Print(err)
r.Error(err.Error())
return
}
@ -207,13 +220,14 @@ func (s *SoundEngine) PlaySoundID(id int) *Sound {
effect, err := s.provider.LoadSound(entry.FileName, entry.Loop, entry.MusicVol)
if err != nil {
log.Print(err)
s.Error(err.Error())
return nil
}
snd := Sound{
entry: entry,
effect: effect,
Logger: s.Logger,
}
s.sounds[&snd] = struct{}{}

View File

@ -1,8 +1,6 @@
package d2gui
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
@ -66,6 +64,8 @@ type Box struct {
disableBorder bool
isOpen bool
title string
*d2util.Logger
}
// NewBox return a new Box instance
@ -76,9 +76,10 @@ func NewBox(
contentLayout *Layout,
width, height int,
x, y int,
l d2util.LogLevel,
title string,
) *Box {
return &Box{
box := &Box{
asset: asset,
renderer: renderer,
uiManager: ui,
@ -90,6 +91,12 @@ func NewBox(
x: x,
y: y,
}
box.Logger = d2util.NewLogger()
box.Logger.SetLevel(l)
box.Logger.SetPrefix(logPrefix)
return box
}
// GetLayout returns the box layout
@ -145,12 +152,12 @@ func (box *Box) setupTopBorder(offsetY int) {
for _, frameIndex := range topEdgePiece {
f, err := box.uiManager.NewSprite(d2resource.BoxPieces, d2resource.PaletteSky)
if err != nil {
log.Print(err)
box.Error(err.Error())
}
err = f.SetCurrentFrame(frameIndex)
if err != nil {
log.Print(err)
box.Error(err.Error())
}
f.SetPosition(currentX, currentY)
@ -187,12 +194,12 @@ func (box *Box) setupBottomBorder(offsetY int) {
for _, frameIndex := range bottomEdgePiece {
f, err := box.uiManager.NewSprite(d2resource.BoxPieces, d2resource.PaletteSky)
if err != nil {
log.Print(err)
box.Error(err.Error())
}
err = f.SetCurrentFrame(frameIndex)
if err != nil {
log.Print(err)
box.Error(err.Error())
}
f.SetPosition(currentX, currentY)
@ -227,12 +234,12 @@ func (box *Box) setupLeftBorder() {
for _, frameIndex := range leftBorderPiece {
f, err := box.uiManager.NewSprite(d2resource.BoxPieces, d2resource.PaletteSky)
if err != nil {
log.Print(err)
box.Error(err.Error())
}
err = f.SetCurrentFrame(frameIndex)
if err != nil {
log.Print(err)
box.Error(err.Error())
}
f.SetPosition(currentX, currentY)
@ -266,12 +273,12 @@ func (box *Box) setupRightBorder() {
for _, frameIndex := range rightBorderPiece {
f, err := box.uiManager.NewSprite(d2resource.BoxPieces, d2resource.PaletteSky)
if err != nil {
log.Print(err)
box.Error(err.Error())
}
err = f.SetCurrentFrame(frameIndex)
if err != nil {
log.Print(err)
box.Error(err.Error())
}
f.SetPosition(currentX, currentY)
@ -302,12 +309,12 @@ func (box *Box) setupCorners() {
for _, frameIndex := range cornersFrames {
f, err := box.uiManager.NewSprite(d2resource.BoxPieces, d2resource.PaletteSky)
if err != nil {
log.Print(err)
box.Error(err.Error())
}
err = f.SetCurrentFrame(frameIndex)
if err != nil {
log.Print(err)
box.Error(err.Error())
}
switch frameIndex {

View File

@ -2,14 +2,18 @@ package d2gui
import (
"image/color"
"log"
"math"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
)
const (
logPrefix = "GUI Manager"
)
// GuiManager is a GUI widget manager that handles dynamic layout/positioning of widgets
type GuiManager struct {
asset *d2asset.AssetManager
@ -20,10 +24,12 @@ type GuiManager struct {
loadingAnim d2interface.Animation
cursorVisible bool
loading bool
*d2util.Logger
}
// CreateGuiManager creates an instance of the GuiManager
func CreateGuiManager(asset *d2asset.AssetManager, inputManager d2interface.InputManager) (*GuiManager, error) {
func CreateGuiManager(asset *d2asset.AssetManager, l d2util.LogLevel, inputManager d2interface.InputManager) (*GuiManager, error) {
cursorAnim, err := asset.LoadAnimation(d2resource.CursorDefault, d2resource.PaletteUnits)
if err != nil {
return nil, err
@ -41,6 +47,10 @@ func CreateGuiManager(asset *d2asset.AssetManager, inputManager d2interface.Inpu
cursorVisible: true,
}
manager.Logger = d2util.NewLogger()
manager.Logger.SetPrefix(logPrefix)
manager.Logger.SetLevel(l)
manager.clear()
if err := inputManager.BindHandler(manager); err != nil {
@ -159,7 +169,7 @@ func (m *GuiManager) ShowLoadScreen(progress float64) {
err := animation.SetCurrentFrame(int(float64(frameCount-1) * progress))
if err != nil {
log.Print(err)
m.Error(err.Error())
}
m.loading = true

View File

@ -2,7 +2,6 @@ package d2gui
import (
"image/color"
"log"
"time"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
@ -36,7 +35,7 @@ type Label struct {
blinkTimer time.Time
}
func createLabel(renderer d2interface.Renderer, text string, font *d2asset.Font, col color.RGBA) *Label {
func createLabel(renderer d2interface.Renderer, text string, font *d2asset.Font, col color.RGBA) (*Label, error) {
label := &Label{
font: font,
renderer: renderer,
@ -46,13 +45,12 @@ func createLabel(renderer d2interface.Renderer, text string, font *d2asset.Font,
err := label.setText(text)
if err != nil {
log.Print(err)
return nil
return nil, err
}
label.SetVisible(true)
return label
return label, nil
}
// SetHoverColor will set the value of hoverColor

View File

@ -2,7 +2,6 @@ package d2gui
import (
"image/color"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
@ -19,11 +18,13 @@ type LabelButton struct {
isHovered bool
layout *Layout
x, y int
*d2util.Logger
}
// NewLabelButton generates a new instance of LabelButton
func NewLabelButton(x, y int, text string, col color.RGBA, callback func()) *LabelButton {
return &LabelButton{
func NewLabelButton(x, y int, text string, col color.RGBA, l d2util.LogLevel, callback func()) *LabelButton {
lb := &LabelButton{
x: x,
y: y,
hoverColor: col,
@ -31,6 +32,12 @@ func NewLabelButton(x, y int, text string, col color.RGBA, callback func()) *Lab
callback: callback,
canHover: true,
}
lb.Logger = d2util.NewLogger()
lb.Logger.SetLevel(l)
lb.Logger.SetPrefix(logPrefix)
return lb
}
// IsInRect checks if the given point is within the overlay layout rectangle
@ -60,13 +67,13 @@ func (lb *LabelButton) Load(renderer d2interface.Renderer, asset *d2asset.AssetM
mainLayout.SetMouseEnterHandler(func(event d2interface.MouseMoveEvent) {
if err := l.SetIsHovered(true); err != nil {
log.Printf("could not change label to hover state: %v", err)
lb.Errorf("could not change label to hover state: %v", err)
}
})
mainLayout.SetMouseLeaveHandler(func(event d2interface.MouseMoveEvent) {
if err := l.SetIsHovered(false); err != nil {
log.Printf("could not change label to hover state: %v", err)
lb.Errorf("could not change label to hover state: %v", err)
}
})

View File

@ -167,7 +167,10 @@ func (l *Layout) AddLabel(text string, fontStyle FontStyle) (*Label, error) {
return nil, err
}
label := createLabel(l.renderer, text, font, d2util.Color(ColorWhite))
label, err := createLabel(l.renderer, text, font, d2util.Color(ColorWhite))
if err != nil {
return nil, err
}
l.entries = append(l.entries, &layoutEntry{widget: label})
@ -181,7 +184,10 @@ func (l *Layout) AddLabelWithColor(text string, fontStyle FontStyle, col color.R
return nil, err
}
label := createLabel(l.renderer, text, font, col)
label, err := createLabel(l.renderer, text, font, col)
if err != nil {
return nil, err
}
l.entries = append(l.entries, &layoutEntry{widget: label})

View File

@ -2,7 +2,6 @@ package d2hero
import (
"encoding/json"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2records"
)
@ -27,10 +26,10 @@ func (hs *HeroSkill) MarshalJSON() ([]byte, error) {
// only serialize the Shallow object instead of the SkillRecord & SkillDescriptionRecord
bytes, err := json.Marshal(hs.Shallow)
if err != nil {
log.Fatalln(err)
return nil, err
}
return bytes, err
return bytes, nil
}
// UnmarshalJSON overrides the default logic used when the HeroSkill is deserialized from a byte array.

View File

@ -1,7 +1,7 @@
package d2inventory
import (
"log"
"fmt"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
@ -11,7 +11,10 @@ import (
func NewInventoryItemFactory(asset *d2asset.AssetManager) (*InventoryItemFactory, error) {
factory := &InventoryItemFactory{asset: asset}
factory.loadHeroObjects()
err := factory.loadHeroObjects()
if err != nil {
return nil, err
}
return factory, nil
}
@ -23,46 +26,88 @@ type InventoryItemFactory struct {
}
// LoadHeroObjects loads the equipment objects of the hero
func (f *InventoryItemFactory) loadHeroObjects() {
func (f *InventoryItemFactory) loadHeroObjects() error {
// https://github.com/OpenDiablo2/OpenDiablo2/issues/795
//Mode: d2enum.AnimationModePlayerNeutral.String(),
//Base: "/data/global/chars",
shield, err := f.GetArmorItemByCode("buc")
if err != nil {
return err
}
rhhex, err := f.GetWeaponItemByCode("hax")
if err != nil {
return err
}
rhwnd, err := f.GetWeaponItemByCode("wnd")
if err != nil {
return err
}
rhssd, err := f.GetWeaponItemByCode("ssd")
if err != nil {
return err
}
rhktr, err := f.GetWeaponItemByCode("ktr")
if err != nil {
return err
}
rhsst, err := f.GetWeaponItemByCode("sst")
if err != nil {
return err
}
rhjav, err := f.GetWeaponItemByCode("jav")
if err != nil {
return err
}
rhclb, err := f.GetWeaponItemByCode("clb")
if err != nil {
return err
}
f.DefaultHeroItems = map[d2enum.Hero]CharacterEquipment{
d2enum.HeroBarbarian: {
RightHand: f.GetWeaponItemByCode("hax"),
Shield: f.GetArmorItemByCode("buc"),
RightHand: rhhex,
Shield: shield,
},
d2enum.HeroNecromancer: {
RightHand: f.GetWeaponItemByCode("wnd"),
RightHand: rhwnd,
},
d2enum.HeroPaladin: {
RightHand: f.GetWeaponItemByCode("ssd"),
Shield: f.GetArmorItemByCode("buc"),
RightHand: rhssd,
Shield: shield,
},
d2enum.HeroAssassin: {
RightHand: f.GetWeaponItemByCode("ktr"),
Shield: f.GetArmorItemByCode("buc"),
RightHand: rhktr,
Shield: shield,
},
d2enum.HeroSorceress: {
RightHand: f.GetWeaponItemByCode("sst"),
LeftHand: f.GetWeaponItemByCode("sst"),
RightHand: rhsst,
LeftHand: rhsst,
},
d2enum.HeroAmazon: {
RightHand: f.GetWeaponItemByCode("jav"),
Shield: f.GetArmorItemByCode("buc"),
RightHand: rhjav,
Shield: shield,
},
d2enum.HeroDruid: {
RightHand: f.GetWeaponItemByCode("clb"),
Shield: f.GetArmorItemByCode("buc"),
RightHand: rhclb,
Shield: shield,
},
}
return nil
}
// GetArmorItemByCode returns the armor item for the given code
func (f *InventoryItemFactory) GetArmorItemByCode(code string) *InventoryItemArmor {
func (f *InventoryItemFactory) GetArmorItemByCode(code string) (*InventoryItemArmor, error) {
result := f.asset.Records.Item.Armors[code]
if result == nil {
log.Fatalf("Could not find armor entry for code '%s'", code)
return nil, fmt.Errorf("could not find armor entry for code '%s'", code)
}
return &InventoryItemArmor{
@ -71,14 +116,14 @@ func (f *InventoryItemFactory) GetArmorItemByCode(code string) *InventoryItemArm
ItemName: result.Name,
ItemCode: result.Code,
ArmorClass: d2enum.ArmorClassLite, // comes from ArmType.txt
}
}, nil
}
// GetMiscItemByCode returns the miscellaneous item for the given code
func (f *InventoryItemFactory) GetMiscItemByCode(code string) *InventoryItemMisc {
func (f *InventoryItemFactory) GetMiscItemByCode(code string) (*InventoryItemMisc, error) {
result := f.asset.Records.Item.Misc[code]
if result == nil {
log.Fatalf("Could not find misc item entry for code '%s'", code)
return nil, fmt.Errorf("could not find misc item entry for code '%s'", code)
}
return &InventoryItemMisc{
@ -86,15 +131,15 @@ func (f *InventoryItemFactory) GetMiscItemByCode(code string) *InventoryItemMisc
InventorySizeY: result.InventoryHeight,
ItemName: result.Name,
ItemCode: result.Code,
}
}, nil
}
// GetWeaponItemByCode returns the weapon item for the given code
func (f *InventoryItemFactory) GetWeaponItemByCode(code string) *InventoryItemWeapon {
func (f *InventoryItemFactory) GetWeaponItemByCode(code string) (*InventoryItemWeapon, error) {
// https://github.com/OpenDiablo2/OpenDiablo2/issues/796
result := f.asset.Records.Item.Weapons[code]
if result == nil {
log.Fatalf("Could not find weapon entry for code '%s'", code)
return nil, fmt.Errorf("could not find weapon entry for code '%s'", code)
}
return &InventoryItemWeapon{
@ -104,5 +149,5 @@ func (f *InventoryItemFactory) GetWeaponItemByCode(code string) *InventoryItemWe
ItemCode: result.Code,
WeaponClass: result.WeaponClass,
WeaponClassOffHand: result.WeaponClass2Hand,
}
}, nil
}

View File

@ -1,7 +1,6 @@
package d2mapengine
import (
"log"
"strings"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2records"
@ -13,10 +12,15 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2geom"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapstamp"
)
const (
logPrefix = "Map Engine"
)
// MapEngine loads the tiles which make up the isometric map and the entities
type MapEngine struct {
asset *d2asset.AssetManager
@ -34,6 +38,8 @@ type MapEngine struct {
// https://github.com/OpenDiablo2/OpenDiablo2/issues/789
IsLoading bool // (temp) Whether we have processed the GenerateMapPacket(only for remote client)
*d2util.Logger
}
const (
@ -41,9 +47,9 @@ const (
)
// CreateMapEngine creates a new instance of the map engine and returns a pointer to it.
func CreateMapEngine(asset *d2asset.AssetManager) *MapEngine {
func CreateMapEngine(l d2util.LogLevel, asset *d2asset.AssetManager) *MapEngine {
entity, _ := d2mapentity.NewMapEntityFactory(asset)
stamp := d2mapstamp.NewStampFactory(asset, entity)
stamp := d2mapstamp.NewStampFactory(asset, l, entity)
engine := &MapEngine{
asset: asset,
@ -53,6 +59,10 @@ func CreateMapEngine(asset *d2asset.AssetManager) *MapEngine {
IsLoading: false,
}
engine.Logger = d2util.NewLogger()
engine.Logger.SetLevel(l)
engine.Logger.SetPrefix(logPrefix)
return engine
}
@ -89,14 +99,13 @@ func (m *MapEngine) addDT1(fileName string) {
fileData, err := m.asset.LoadFile("/data/global/tiles/" + fileName)
if err != nil {
log.Printf("Could not load /data/global/tiles/%s", fileName)
// panic(err)
m.Fatalf("Could not load /data/global/tiles/%s", fileName)
return
}
dt1, err := d2dt1.LoadDT1(fileData)
if err != nil {
log.Print(err)
m.Error(err.Error())
}
m.dt1TileData = append(m.dt1TileData, dt1.Tiles...)
@ -118,7 +127,7 @@ func (m *MapEngine) AddDS1(fileName string) {
ds1, err := d2ds1.LoadDS1(fileData)
if err != nil {
log.Print(err)
m.Error(err.Error())
}
for idx := range ds1.Files {
@ -138,7 +147,7 @@ func (m *MapEngine) LevelType() d2records.LevelTypeRecord {
// SetSeed sets the seed of the map for generation.
func (m *MapEngine) SetSeed(seed int64) {
log.Printf("Setting map engine seed to %d", seed)
m.Infof("Setting map engine seed to %d", seed)
m.seed = seed
}
@ -259,7 +268,7 @@ func (m *MapEngine) GetTiles(style, sequence int, tileType d2enum.TileType) []d2
}
if len(tiles) == 0 {
log.Printf("Unknown tile ID [%d %d %d]\n", style, sequence, tileType)
m.Warningf("Unknown tile ID [%d %d %d]", style, sequence, tileType)
return nil
}

View File

@ -4,7 +4,6 @@ package d2mapgen
// is experiemental, and mapgen will likely change dramatically in the future.
import (
"log"
"math/rand"
"strings"
@ -49,7 +48,7 @@ func (g *MapGenerator) GenerateAct1Overworld() {
townStamp.RegionPath()
townSize := townStamp.Size()
log.Printf("Region Path: %s", townStamp.RegionPath())
g.Infof("Region Path: %s", townStamp.RegionPath())
switch {
case strings.Contains(townStamp.RegionPath(), "E1"):

View File

@ -5,17 +5,26 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2geom"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapstamp"
)
const (
logPrefix = "Map Generator"
)
// NewMapGenerator creates a map generator instance
func NewMapGenerator(a *d2asset.AssetManager, e *d2mapengine.MapEngine) (*MapGenerator, error) {
func NewMapGenerator(a *d2asset.AssetManager, l d2util.LogLevel, e *d2mapengine.MapEngine) (*MapGenerator, error) {
generator := &MapGenerator{
asset: a,
engine: e,
}
generator.Logger = d2util.NewLogger()
generator.Logger.SetLevel(l)
generator.Logger.SetPrefix(logPrefix)
return generator, nil
}
@ -23,6 +32,8 @@ func NewMapGenerator(a *d2asset.AssetManager, e *d2mapengine.MapEngine) (*MapGen
type MapGenerator struct {
asset *d2asset.AssetManager
engine *d2mapengine.MapEngine
*d2util.Logger
}
func (g *MapGenerator) loadPreset(id, index int) *d2mapstamp.Stamp {

View File

@ -2,9 +2,7 @@ package d2maprenderer
import (
"errors"
"fmt"
"image/color"
"log"
"math"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
@ -17,6 +15,10 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
)
const (
logPrefix = "Map Renderer"
)
const (
screenMiddleX = 400
two = 2
@ -59,12 +61,14 @@ type MapRenderer struct {
entityDebugVisLevel int // Entity Debug visibility index (0=none, 1=vectors)
lastFrameTime float64 // The last time the map was rendered
currentFrame int // Current render frame (for animations)
*d2util.Logger
}
// CreateMapRenderer creates a new MapRenderer, sets the required fields and returns a pointer to it.
func CreateMapRenderer(asset *d2asset.AssetManager, renderer d2interface.Renderer,
mapEngine *d2mapengine.MapEngine,
term d2interface.Terminal, startX, startY float64) *MapRenderer {
term d2interface.Terminal, l d2util.LogLevel, startX, startY float64) *MapRenderer {
result := &MapRenderer{
asset: asset,
renderer: renderer,
@ -72,6 +76,10 @@ func CreateMapRenderer(asset *d2asset.AssetManager, renderer d2interface.Rendere
viewport: NewViewport(0, 0, 800, 600),
}
result.Logger = d2util.NewLogger()
result.Logger.SetPrefix(logPrefix)
result.Logger.SetLevel(l)
result.Camera = Camera{}
rx, ry := result.WorldToOrtho(startX, startY)
startPosition := d2vector.NewPosition(rx, ry)
@ -84,7 +92,7 @@ func CreateMapRenderer(asset *d2asset.AssetManager, renderer d2interface.Rendere
})
if err != nil {
fmt.Printf("could not bind the mapdebugvis action, err: %v\n", err)
result.Errorf("could not bind the mapdebugvis action, err: %v", err)
}
err = term.BindAction("entitydebugvis", "set entity debug visualization level", func(level int) {
@ -92,7 +100,7 @@ func CreateMapRenderer(asset *d2asset.AssetManager, renderer d2interface.Rendere
})
if err != nil {
fmt.Printf("could not bind the entitydebugvis action, err: %v\n", err)
result.Errorf("could not bind the entitydebugvis action, err: %v", err)
}
if mapEngine.LevelType().ID != 0 {
@ -363,7 +371,7 @@ func (mr *MapRenderer) renderFloor(tile d2ds1.FloorShadowRecord, target d2interf
}
if img == nil {
log.Printf("Render called on uncached floor {%v,%v}", tile.Style, tile.Sequence)
mr.Warningf("Render called on uncached floor {%v,%v}", tile.Style, tile.Sequence)
return
}
@ -379,7 +387,7 @@ func (mr *MapRenderer) renderFloor(tile d2ds1.FloorShadowRecord, target d2interf
func (mr *MapRenderer) renderWall(tile d2ds1.WallRecord, viewport *Viewport, target d2interface.Surface) {
img := mr.getImageCacheRecord(tile.Style, tile.Sequence, tile.Type, tile.RandomIndex)
if img == nil {
log.Printf("Render called on uncached wall {%v,%v,%v}", tile.Style, tile.Sequence, tile.Type)
mr.Warningf("Render called on uncached wall {%v,%v,%v}", tile.Style, tile.Sequence, tile.Type)
return
}
@ -395,7 +403,7 @@ func (mr *MapRenderer) renderWall(tile d2ds1.WallRecord, viewport *Viewport, tar
func (mr *MapRenderer) renderShadow(tile d2ds1.FloorShadowRecord, target d2interface.Surface) {
img := mr.getImageCacheRecord(tile.Style, tile.Sequence, 13, tile.RandomIndex)
if img == nil {
log.Printf("Render called on uncached shadow {%v,%v}", tile.Style, tile.Sequence)
mr.Warningf("Render called on uncached shadow {%v,%v}", tile.Style, tile.Sequence)
return
}

View File

@ -1,8 +1,6 @@
package d2maprenderer
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1"
@ -28,7 +26,7 @@ func (mr *MapRenderer) generateTileCache() {
mr.palette, err = mr.loadPaletteForAct(d2enum.RegionIdType(mr.mapEngine.LevelType().ID))
if err != nil {
log.Print(err)
mr.Error(err.Error())
}
tiles := *mr.mapEngine.Tiles()
@ -61,7 +59,7 @@ func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord) {
var tileData []*d2dt1.Tile
if tileOptions == nil {
log.Printf("Could not locate tile Style:%d, Seq: %d, Type: %d\n", tile.Style, tile.Sequence, 0)
mr.Errorf("Could not locate tile Style:%d, Seq: %d, Type: %d", tile.Style, tile.Sequence, 0)
tileData = append(tileData, &d2dt1.Tile{})
tileData[0].Width = defaultFloorTileWidth
@ -205,7 +203,7 @@ func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord) {
}
if realHeight == 0 {
log.Printf("Invalid 0 height for wall tile")
mr.Error("Invalid 0 height for wall tile")
return
}

View File

@ -1,7 +1,6 @@
package d2mapstamp
import (
"log"
"math"
"math/rand"
@ -10,12 +9,24 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
)
const logPrefix = "Map Stamp"
// NewStampFactory creates a MapStamp factory instance
func NewStampFactory(asset *d2asset.AssetManager, entity *d2mapentity.MapEntityFactory) *StampFactory {
return &StampFactory{asset, entity}
func NewStampFactory(asset *d2asset.AssetManager, l d2util.LogLevel, entity *d2mapentity.MapEntityFactory) *StampFactory {
result := &StampFactory{
asset: asset,
entity: entity,
}
result.Logger = d2util.NewLogger()
result.Logger.SetLevel(l)
result.Logger.SetPrefix(logPrefix)
return result
}
// StampFactory is responsible for loading map stamps. A stamp can be thought of like a
@ -23,6 +34,8 @@ func NewStampFactory(asset *d2asset.AssetManager, entity *d2mapentity.MapEntityF
type StampFactory struct {
asset *d2asset.AssetManager
entity *d2mapentity.MapEntityFactory
*d2util.Logger
}
// LoadStamp loads the Stamp data from file, using the given level type, level preset index, and
@ -48,7 +61,7 @@ func (f *StampFactory) LoadStamp(levelType d2enum.RegionIdType, levelPreset, fil
dt1, err := d2dt1.LoadDT1(fileData)
if err != nil {
log.Print(err)
f.Error(err.Error())
return nil
}
@ -82,7 +95,7 @@ func (f *StampFactory) LoadStamp(levelType d2enum.RegionIdType, levelPreset, fil
stamp.ds1, err = d2ds1.LoadDS1(fileData)
if err != nil {
log.Print(err)
f.Error(err.Error())
return nil
}

View File

@ -1,7 +1,7 @@
package d2records
import (
"log"
"fmt"
"strconv"
"strings"
@ -24,6 +24,11 @@ func cubeRecipeLoader(r *RecordManager, d *d2txt.DataDictionary) error {
var inputFields = []string{"input 1", "input 2", "input 3", "input 4", "input 5", "input 6", "input 7"}
for d.Next() {
class, err := classFieldToEnum(d.String("class"))
if err != nil {
return err
}
record := &CubeRecipeRecord{
Description: d.String("description"),
@ -37,7 +42,7 @@ func cubeRecipeLoader(r *RecordManager, d *d2txt.DataDictionary) error {
ReqOperation: d.Number("op"),
ReqValue: d.Number("value"),
Class: classFieldToEnum(d.String("class")),
Class: class,
NumInputs: d.Number("numinputs"),
}
@ -45,17 +50,25 @@ func cubeRecipeLoader(r *RecordManager, d *d2txt.DataDictionary) error {
// Create inputs - input 1-7
record.Inputs = make([]CubeRecipeItem, len(inputFields))
for i := range inputFields {
record.Inputs[i] = newCubeRecipeItem(
record.Inputs[i], err = newCubeRecipeItem(
d.String(inputFields[i]))
if err != nil {
return err
}
}
// Create outputs - output "", b, c
record.Outputs = make([]CubeRecipeResult, len(outputLabels))
for o, outLabel := range outputLabels {
record.Outputs[o] = CubeRecipeResult{
Item: newCubeRecipeItem(
d.String(outputFields[o])),
for o, outLabel := range outputLabels {
item, err := newCubeRecipeItem(
d.String(outputFields[o]))
if err != nil {
return err
}
record.Outputs[o] = CubeRecipeResult{
Item: item,
Level: d.Number(outLabel + "lvl"),
ILevel: d.Number(outLabel + "plvl"),
PLevel: d.Number(outLabel + "ilvl"),
@ -94,7 +107,7 @@ func cubeRecipeLoader(r *RecordManager, d *d2txt.DataDictionary) error {
// arguments. arguments include at least an item and sometimes
// parameters and/or a count (qty parameter). For example:
// "weap,sock,mag,qty=10"
func newCubeRecipeItem(f string) CubeRecipeItem {
func newCubeRecipeItem(f string) (CubeRecipeItem, error) {
args := splitFieldValue(f)
item := CubeRecipeItem{
@ -115,7 +128,8 @@ func newCubeRecipeItem(f string) CubeRecipeItem {
count, err := strconv.Atoi(strings.Split(arg, "=")[1])
if err != nil {
log.Fatal("Error parsing item count:", err)
// need to be verified
return item, fmt.Errorf("error parsing item count %e", err)
}
item.Count = count
@ -132,7 +146,7 @@ func newCubeRecipeItem(f string) CubeRecipeItem {
// No other arguments were provided
if len(args) == 0 {
return item
return item, nil
}
// Record the argument strings
@ -141,11 +155,11 @@ func newCubeRecipeItem(f string) CubeRecipeItem {
item.Params[idx] = arg
}
return item
return item, nil
}
// classFieldToEnum converts class tokens to s2enum.Hero.
func classFieldToEnum(f string) []d2enum.Hero {
func classFieldToEnum(f string) ([]d2enum.Hero, error) {
split := splitFieldValue(f)
enums := make([]d2enum.Hero, len(split))
@ -170,11 +184,11 @@ func classFieldToEnum(f string) []d2enum.Hero {
case "dru":
enums[idx] = d2enum.HeroDruid
default:
log.Fatalf("Unknown hero token: '%s'", class)
return nil, fmt.Errorf("unknown hero token: '%s'", class)
}
}
return enums
return enums, nil
}
// splitFieldValue splits a string array from the following format:

View File

@ -1,7 +1,7 @@
package d2records
import (
"log"
"fmt"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2txt"
@ -13,6 +13,11 @@ func monsterStats2Loader(r *RecordManager, d *d2txt.DataDictionary) error {
records := make(MonStats2)
for d.Next() {
resurrectMode, err := monsterAnimationModeFromString(d.String("ResurrectMode"))
if err != nil {
return err
}
record := &MonStats2Record{
Key: d.String("Id"),
Height: d.Number("Height"),
@ -145,7 +150,7 @@ func monsterStats2Loader(r *RecordManager, d *d2txt.DataDictionary) error {
InfernoLen: d.Number("InfernoLen"),
InfernoAnim: d.Number("InfernoAnim"),
InfernoRollback: d.Number("InfernoRollback"),
ResurrectMode: monsterAnimationModeFromString(d.String("ResurrectMode")),
ResurrectMode: resurrectMode,
ResurrectSkill: d.String("ResurrectSkill"),
}
@ -170,12 +175,11 @@ var monsterAnimationModeLookup = map[string]d2enum.MonsterAnimationMode{
d2enum.MonsterAnimationModeSequence.String(): d2enum.MonsterAnimationModeSequence,
}
func monsterAnimationModeFromString(s string) d2enum.MonsterAnimationMode {
func monsterAnimationModeFromString(s string) (d2enum.MonsterAnimationMode, error) {
v, ok := monsterAnimationModeLookup[s]
if !ok {
log.Fatalf("unhandled MonsterAnimationMode %q", s)
return d2enum.MonsterAnimationModeNeutral
return d2enum.MonsterAnimationModeNeutral, fmt.Errorf("unhandled MonsterAnimationMode %q", s)
}
return v
return v, nil
}

View File

@ -1,7 +1,6 @@
package d2records
import (
"log"
"testing"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
@ -17,7 +16,7 @@ func TestIndexObjects(t *testing.T) {
r, err := NewRecordManager(d2util.LogLevelDefault)
if err != nil {
log.Print(err)
t.Error(err)
}
testObjects := []ObjectLookupRecord{

View File

@ -2,7 +2,6 @@ package d2records
import (
"fmt"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
@ -37,7 +36,7 @@ func NewRecordManager(l d2util.LogLevel) (*RecordManager, error) {
// RecordManager stores all of the records loaded from txt files
type RecordManager struct {
Logger *d2util.Logger
*d2util.Logger
boundLoaders map[string][]recordLoader // there can be more than one loader bound for a file
Animation struct {
Data d2data.AnimationData
@ -411,7 +410,7 @@ func (r *RecordManager) initObjectRecords(lookups []ObjectLookupRecord) {
func (r *RecordManager) LookupObject(act, typ, id int) *ObjectLookupRecord {
object := r.lookupObject(act, typ, id)
if object == nil {
log.Panicf("Failed to look up object Act: %d, Type: %d, ID: %d", act, typ, id)
r.Fatalf("Failed to look up object Act: %d, Type: %d, ID: %d", act, typ, id)
}
return object

View File

@ -1,7 +1,7 @@
package d2records
import (
"log"
"fmt"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2calculation/d2parser"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
@ -19,6 +19,11 @@ func skillDetailsLoader(r *RecordManager, d *d2txt.DataDictionary) error {
name := d.String("skill")
parser.SetCurrentReference("skill", name)
anim, err := animToEnum(d.String("anim"))
if err != nil {
return err
}
record := &SkillRecord{
Skill: d.String("skill"),
ID: d.Number("Id"),
@ -141,7 +146,7 @@ func skillDetailsLoader(r *RecordManager, d *d2txt.DataDictionary) error {
Itypeb3: d.String("itypeb3"),
Etypeb1: d.String("etypeb1"),
Etypeb2: d.String("etypeb2"),
Anim: animToEnum(d.String("anim")),
Anim: anim,
Seqtrans: d.String("seqtrans"),
Monanim: d.String("monanim"),
Seqnum: d.Number("seqnum"),
@ -277,45 +282,42 @@ func skillDetailsLoader(r *RecordManager, d *d2txt.DataDictionary) error {
return nil
}
func animToEnum(anim string) d2enum.PlayerAnimationMode {
func animToEnum(anim string) (d2enum.PlayerAnimationMode, error) {
switch anim {
case "SC":
return d2enum.PlayerAnimationModeCast
return d2enum.PlayerAnimationModeCast, nil
case "TH":
return d2enum.PlayerAnimationModeThrow
return d2enum.PlayerAnimationModeThrow, nil
case "KK":
return d2enum.PlayerAnimationModeKick
return d2enum.PlayerAnimationModeKick, nil
case "SQ":
return d2enum.PlayerAnimationModeSequence
return d2enum.PlayerAnimationModeSequence, nil
case "S1":
return d2enum.PlayerAnimationModeSkill1
return d2enum.PlayerAnimationModeSkill1, nil
case "S2":
return d2enum.PlayerAnimationModeSkill2
return d2enum.PlayerAnimationModeSkill2, nil
case "S3":
return d2enum.PlayerAnimationModeSkill3
return d2enum.PlayerAnimationModeSkill3, nil
case "S4":
return d2enum.PlayerAnimationModeSkill4
return d2enum.PlayerAnimationModeSkill4, nil
case "A1":
return d2enum.PlayerAnimationModeAttack1
return d2enum.PlayerAnimationModeAttack1, nil
case "A2":
return d2enum.PlayerAnimationModeAttack2
return d2enum.PlayerAnimationModeAttack2, nil
case "":
return d2enum.PlayerAnimationModeNone
default:
log.Fatalf("Unknown skill anim value [%s]", anim)
return d2enum.PlayerAnimationModeNone, nil
}
// should not be reached
return d2enum.PlayerAnimationModeNone
return d2enum.PlayerAnimationModeNone, fmt.Errorf("unknown skill anim value [%s]", anim)
}

View File

@ -1,13 +1,16 @@
package d2screen
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
const (
logPrefix = "Screen Manager"
)
// ScreenManager manages game screens (main menu, credits, character select, game, etc)
type ScreenManager struct {
uiManager *d2ui.UIManager
@ -16,11 +19,22 @@ type ScreenManager struct {
loadingState LoadingState
currentScreen Screen
guiManager *d2gui.GuiManager
*d2util.Logger
}
// NewScreenManager creates a screen manager
func NewScreenManager(ui *d2ui.UIManager, guiManager *d2gui.GuiManager) *ScreenManager {
return &ScreenManager{uiManager: ui, guiManager: guiManager}
func NewScreenManager(ui *d2ui.UIManager, l d2util.LogLevel, guiManager *d2gui.GuiManager) *ScreenManager {
sm := &ScreenManager{
uiManager: ui,
guiManager: guiManager,
}
sm.Logger = d2util.NewLogger()
sm.Logger.SetPrefix(logPrefix)
sm.Logger.SetLevel(l)
return sm
}
// SetNextScreen is about to set a given screen as next
@ -35,11 +49,11 @@ func (sm *ScreenManager) Advance(elapsed float64) error {
// this call blocks execution and could lead to deadlock if a screen implements OnLoad incorreclty
load, ok := <-sm.loadingState.updates
if !ok {
log.Println("loadingState chan should not be closed while in a loading screen")
sm.Warning("loadingState chan should not be closed while in a loading screen")
}
if load.err != nil {
log.Printf("PROBLEM LOADING THE SCREEN: %v", load.err)
sm.Errorf("PROBLEM LOADING THE SCREEN: %v", load.err)
return load.err
}

View File

@ -445,7 +445,7 @@ func (ui *UIManager) NewButton(buttonType ButtonType, text string) *Button {
buttonSprite, err := ui.NewSprite(buttonLayout.ResourceName, buttonLayout.PaletteName)
if err != nil {
log.Print(err)
ui.Error(err.Error())
return nil
}
@ -455,7 +455,7 @@ func (ui *UIManager) NewButton(buttonType ButtonType, text string) *Button {
for i := 0; i < buttonLayout.XSegments; i++ {
w, _, frameSizeErr := buttonSprite.GetFrameSize(i)
if frameSizeErr != nil {
log.Print(frameSizeErr)
ui.Error(frameSizeErr.Error())
return nil
}
@ -469,7 +469,7 @@ func (ui *UIManager) NewButton(buttonType ButtonType, text string) *Button {
for i := 0; i < buttonLayout.YSegments; i++ {
_, h, frameSizeErr := buttonSprite.GetFrameSize(i * buttonLayout.YSegments)
if frameSizeErr != nil {
log.Print(frameSizeErr)
ui.Error(frameSizeErr.Error())
return nil
}

View File

@ -1,8 +1,6 @@
package d2ui
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
@ -35,13 +33,13 @@ func (ui *UIManager) NewCheckbox(checkState bool) *Checkbox {
checkboxSprite, err := ui.NewSprite(d2resource.Checkbox, d2resource.PaletteFechar)
if err != nil {
log.Print(err)
ui.Error(err.Error())
return nil
}
result.width, result.height, err = checkboxSprite.GetFrameSize(0)
if err != nil {
log.Print(err)
ui.Error(err.Error())
return nil
}

View File

@ -2,12 +2,17 @@ package d2ui
import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
)
// CursorButton represents a mouse button
type CursorButton uint8
const (
logPrefix = "UI Manager"
)
const (
// CursorButtonLeft represents the left mouse button
CursorButtonLeft CursorButton = 1
@ -30,6 +35,7 @@ func NewUIManager(
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
input d2interface.InputManager,
l d2util.LogLevel,
audio d2interface.AudioProvider,
) *UIManager {
ui := &UIManager{
@ -39,5 +45,9 @@ func NewUIManager(
audio: audio,
}
ui.Logger = d2util.NewLogger()
ui.Logger.SetPrefix(logPrefix)
ui.Logger.SetLevel(l)
return ui
}

View File

@ -1,8 +1,6 @@
package d2ui
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
@ -69,6 +67,8 @@ func NewUIFrame(
}
frame.Load()
frame.asset.Logger.SetPrefix(logPrefix) // workaround
return frame
}
@ -76,7 +76,7 @@ func NewUIFrame(
func (u *UIFrame) Load() {
sprite, err := u.manager.NewSprite(d2resource.Frame, d2resource.PaletteSky)
if err != nil {
log.Print(err)
u.asset.Logger.Error(err.Error())
}
u.frame = sprite
@ -111,7 +111,7 @@ func (u *UIFrame) calculateSize() {
for i := range framesWidth {
w, _, err := u.frame.GetFrameSize(framesWidth[i])
if err != nil {
log.Print(err)
u.asset.Logger.Error(err.Error())
}
u.width += w
@ -120,7 +120,7 @@ func (u *UIFrame) calculateSize() {
for i := range framesHeight {
_, h, err := u.frame.GetFrameSize(framesHeight[i])
if err != nil {
log.Print(err)
u.asset.Logger.Error(err.Error())
}
u.height += h
@ -132,11 +132,11 @@ func (u *UIFrame) Render(target d2interface.Surface) {
switch u.frameOrientation {
case FrameLeft:
if err := u.renderLeft(target); err != nil {
log.Printf("Render error %e", err)
u.asset.Logger.Error("Render error" + err.Error())
}
case FrameRight:
if err := u.renderRight(target); err != nil {
log.Printf("Render error %e", err)
u.asset.Logger.Error("Render error" + err.Error())
}
}
}

View File

@ -2,7 +2,6 @@ package d2ui
import (
"image/color"
"log"
"regexp"
"strings"
@ -20,13 +19,15 @@ type Label struct {
font *d2asset.Font
Color map[int]color.Color
backgroundColor color.Color
*d2util.Logger
}
// NewLabel creates a new instance of a UI label
func (ui *UIManager) NewLabel(fontPath, palettePath string) *Label {
font, err := ui.asset.LoadFont(fontPath+".tbl", fontPath+".dc6", palettePath)
if err != nil {
log.Print(err)
ui.Error(err.Error())
return nil
}
@ -37,6 +38,7 @@ func (ui *UIManager) NewLabel(fontPath, palettePath string) *Label {
Alignment: HorizontalAlignLeft,
Color: map[int]color.Color{0: color.White},
font: font,
Logger: ui.Logger,
}
result.bindManager(ui)
@ -75,7 +77,7 @@ func (v *Label) Render(target d2interface.Surface) {
err := v.font.RenderText(character, target)
if err != nil {
log.Print(err)
v.Error(err.Error())
}
target.PushTranslation(charWidth, 0)
@ -160,7 +162,7 @@ func (v *Label) getAlignOffset(textWidth int) int {
case HorizontalAlignRight:
return -textWidth
default:
log.Fatal("Invalid Alignment")
v.Fatal("Invalid Alignment")
return 0
}
}

View File

@ -1,8 +1,6 @@
package d2ui
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
)
@ -33,7 +31,7 @@ type Scrollbar struct {
func (ui *UIManager) NewScrollbar(x, y, height int) *Scrollbar {
scrollbarSprite, err := ui.NewSprite(d2resource.Scrollbar, d2resource.PaletteSky)
if err != nil {
log.Print(err)
ui.Error(err.Error())
return nil
}

View File

@ -4,17 +4,19 @@ import (
"fmt"
"image"
"image/color"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
)
// Sprite is a positioned visual object.
type Sprite struct {
*BaseWidget
animation d2interface.Animation
*d2util.Logger
}
const (
@ -34,7 +36,9 @@ func (ui *UIManager) NewSprite(animationPath, palettePath string) (*Sprite, erro
return &Sprite{
BaseWidget: base,
animation: animation}, nil
animation: animation,
Logger: ui.Logger,
}, nil
}
// Render renders the sprite on the given surface
@ -70,7 +74,7 @@ func (s *Sprite) RenderSegmented(target d2interface.Surface, segmentsX, segments
for x := 0; x < segmentsX; x++ {
idx := x + y*segmentsX + frameOffset*segmentsX*segmentsY
if err := s.animation.SetCurrentFrame(idx); err != nil {
log.Printf("SetCurrentFrame error %e", err)
s.Error("SetCurrentFrame error" + err.Error())
}
target.PushTranslation(s.x+currentX, s.y+currentY)
@ -150,7 +154,7 @@ func (s *Sprite) SetCurrentFrame(frameIndex int) error {
func (s *Sprite) Rewind() {
err := s.animation.SetCurrentFrame(0)
if err != nil {
log.Print(err)
s.Error(err.Error())
}
}

View File

@ -1,7 +1,6 @@
package d2ui
import (
"log"
"strings"
"time"
@ -29,7 +28,7 @@ type TextBox struct {
func (ui *UIManager) NewTextbox() *TextBox {
bgSprite, err := ui.NewSprite(d2resource.TextBox2, d2resource.PaletteUnits)
if err != nil {
log.Print(err)
ui.Error(err.Error())
return nil
}

View File

@ -1,7 +1,6 @@
package d2ui
import (
"log"
"sort"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
@ -9,6 +8,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
)
// UIManager manages a collection of UI elements (buttons, textboxes, labels)
@ -25,6 +25,8 @@ type UIManager struct {
CursorY int
pressedWidget ClickableWidget
clickSfx d2interface.SoundEffect
*d2util.Logger
}
// Note: methods for creating buttons and stuff are in their respective files
@ -34,13 +36,13 @@ type UIManager struct {
func (ui *UIManager) Initialize() {
sfx, err := ui.audio.LoadSound(d2resource.SFXButtonClick, false, false)
if err != nil {
log.Fatalf("failed to initialize ui: %v", err)
ui.Fatalf("failed to initialize ui: %v", err)
}
ui.clickSfx = sfx
if err := ui.inputManager.BindHandler(ui); err != nil {
log.Fatalf("failed to initialize ui: %v", err)
ui.Fatalf("failed to initialize ui: %v", err)
}
}
@ -64,7 +66,7 @@ func (ui *UIManager) addWidgetGroup(group *WidgetGroup) {
func (ui *UIManager) addWidget(widget Widget) {
err := ui.inputManager.BindHandler(widget)
if err != nil {
log.Print(err)
ui.Error(err.Error())
}
clickable, ok := widget.(ClickableWidget)
@ -159,7 +161,7 @@ func (ui *UIManager) Advance(elapsed float64) {
if widget.GetVisible() {
err := widget.Advance(elapsed)
if err != nil {
log.Print(err)
ui.Error(err.Error())
}
}
}

View File

@ -72,13 +72,13 @@ func CreateGame(
lastRegionType: d2enum.RegionNone,
ticksSinceLevelCheck: 0,
mapRenderer: d2maprenderer.CreateMapRenderer(asset, renderer,
gameClient.MapEngine, term, startX, startY),
gameClient.MapEngine, term, l, startX, startY),
escapeMenu: d2player.NewEscapeMenu(navigator, renderer, audioProvider, ui, guiManager, asset, l, keyMap),
inputManager: inputManager,
audioProvider: audioProvider,
renderer: renderer,
terminal: term,
soundEngine: d2audio.NewSoundEngine(audioProvider, asset, term),
soundEngine: d2audio.NewSoundEngine(audioProvider, asset, l, term),
uiManager: ui,
guiManager: guiManager,
keyMap: keyMap,

View File

@ -116,6 +116,7 @@ func CreateMapEngineTest(currentRegion,
audioProvider: audioProvider,
screen: screen,
playerStateFactory: heroStateFactory,
logLevel: l,
}
mapEngineTest.playerState = heroStateFactory.CreateTestGameState()
@ -152,7 +153,8 @@ type MapEngineTest struct {
regionSpec regionSpec
filesCount int
logger *d2util.Logger
logger *d2util.Logger
logLevel d2util.LogLevel
}
func (met *MapEngineTest) loadRegionByIndex(n, levelPreset, fileIndex int) {
@ -187,14 +189,14 @@ func (met *MapEngineTest) loadRegionByIndex(n, levelPreset, fileIndex int) {
met.levelPreset = levelPreset
}
mapGen, _ := d2mapgen.NewMapGenerator(met.asset, met.mapEngine)
mapGen, _ := d2mapgen.NewMapGenerator(met.asset, met.logLevel, met.mapEngine)
met.mapGen = mapGen
if n == 0 {
met.mapEngine.SetSeed(time.Now().UnixNano())
met.mapGen.GenerateAct1Overworld()
} else {
met.mapEngine = d2mapengine.CreateMapEngine(met.asset) // necessary for map name update
met.mapEngine = d2mapengine.CreateMapEngine(met.logLevel, met.asset) // necessary for map name update
met.mapEngine.SetSeed(time.Now().UnixNano())
met.mapEngine.GenerateMap(d2enum.RegionIdType(n), levelPreset, fileIndex)
}
@ -216,12 +218,12 @@ func (met *MapEngineTest) OnLoad(loading d2screen.LoadingState) {
loading.Progress(twentyPercent)
met.mapEngine = d2mapengine.CreateMapEngine(met.asset)
met.mapEngine = d2mapengine.CreateMapEngine(met.logLevel, met.asset)
loading.Progress(fiftyPercent)
met.mapRenderer = d2maprenderer.CreateMapRenderer(met.asset, met.renderer, met.mapEngine,
met.terminal, 0.0, 0.0)
met.terminal, met.logLevel, 0.0, 0.0)
loading.Progress(seventyPercent)
met.loadRegionByIndex(met.currentRegion, met.levelPreset, met.fileIndex)

View File

@ -77,23 +77,23 @@ func NewKeyBindingMenu(
ret.Box = d2gui.NewBox(
asset, renderer, ui, ret.mainLayout,
keyBindingMenuWidth, keyBindingMenuHeight,
keyBindingMenuX, keyBindingMenuY, "",
keyBindingMenuX, keyBindingMenuY, l, "",
)
ret.Box.SetPadding(keyBindingMenuPaddingX, keyBindingSettingPaddingY)
ret.Box.SetOptions([]*d2gui.LabelButton{
d2gui.NewLabelButton(0, 0, "Cancel", d2util.Color(d2gui.ColorRed), func() {
d2gui.NewLabelButton(0, 0, "Cancel", d2util.Color(d2gui.ColorRed), d2util.LogLevelDefault, func() {
if err := ret.onCancelClicked(); err != nil {
ret.logger.Error("error while clicking option Cancel: %v" + err.Error())
}
}),
d2gui.NewLabelButton(0, 0, "Default", d2util.Color(d2gui.ColorBlue), func() {
d2gui.NewLabelButton(0, 0, "Default", d2util.Color(d2gui.ColorBlue), d2util.LogLevelDefault, func() {
if err := ret.onDefaultClicked(); err != nil {
ret.logger.Error("error while clicking option Default: %v" + err.Error())
}
}),
d2gui.NewLabelButton(0, 0, "Accept", d2util.Color(d2gui.ColorGreen), func() {
d2gui.NewLabelButton(0, 0, "Accept", d2util.Color(d2gui.ColorGreen), d2util.LogLevelDefault, func() {
if err := ret.onAcceptClicked(); err != nil {
ret.logger.Error("error while clicking option Accept: %v" + err.Error())
}

View File

@ -3,6 +3,7 @@ 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"
@ -22,16 +23,18 @@ type LocalClientConnection struct {
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 {
func (l *LocalClientConnection) GetUniqueID() string {
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
}
@ -42,7 +45,10 @@ func (l *LocalClientConnection) SendPacketToClient(packet d2netpacket.NetPacket)
// Create constructs a new LocalClientConnection and returns
// a pointer to it.
func Create(asset *d2asset.AssetManager, openNetworkServer bool) (*LocalClientConnection, error) {
func Create(
asset *d2asset.AssetManager,
l d2util.LogLevel,
openNetworkServer bool) (*LocalClientConnection, error) {
heroStateFactory, err := d2hero.NewHeroStateFactory(asset)
if err != nil {
return nil, err
@ -53,6 +59,7 @@ func Create(asset *d2asset.AssetManager, openNetworkServer bool) (*LocalClientCo
asset: asset,
uniqueID: uuid.New().String(),
openNetworkServer: openNetworkServer,
logLevel: l,
}
return result, nil
@ -64,7 +71,7 @@ func (l *LocalClientConnection) Open(_, saveFilePath string) error {
l.SetPlayerState(l.heroState.LoadHeroState(saveFilePath))
l.gameServer, err = d2server.NewGameServer(l.asset, l.openNetworkServer, 30)
l.gameServer, err = d2server.NewGameServer(l.asset, l.openNetworkServer, l.logLevel, 30)
if err != nil {
return err
}

View File

@ -3,12 +3,12 @@ package d2remoteclient
import (
"encoding/json"
"fmt"
"log"
"net"
"strings"
"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"
@ -17,6 +17,8 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
)
const logPrefix = "Remote Client"
// RemoteClientConnection is the implementation of ClientConnection
// for a remote client.
type RemoteClientConnection struct {
@ -26,11 +28,13 @@ type RemoteClientConnection struct {
uniqueID string // Unique ID generated on construction
tcpConnection *net.TCPConn // UDP connection to the server
active bool // The connection is currently open
*d2util.Logger
}
// Create constructs a new RemoteClientConnection
// and returns a pointer to it.
func Create(asset *d2asset.AssetManager) (*RemoteClientConnection, error) {
func Create(l d2util.LogLevel, asset *d2asset.AssetManager) (*RemoteClientConnection, error) {
heroStateFactory, err := d2hero.NewHeroStateFactory(asset)
if err != nil {
return nil, err
@ -42,6 +46,10 @@ func Create(asset *d2asset.AssetManager) (*RemoteClientConnection, error) {
uniqueID: uuid.New().String(),
}
result.Logger = d2util.NewLogger()
result.Logger.SetPrefix(logPrefix)
result.Logger.SetLevel(l)
return result, nil
}
@ -66,14 +74,14 @@ func (r *RemoteClientConnection) Open(connectionString, saveFilePath string) err
r.active = true
go r.serverListener()
log.Printf("Connected to server at %s", r.tcpConnection.RemoteAddr().String())
r.Infof("Connected to server at %s", r.tcpConnection.RemoteAddr().String())
gameState := r.heroState.LoadHeroState(saveFilePath)
packet := d2netpacket.CreatePlayerConnectionRequestPacket(r.GetUniqueID(), gameState)
err = r.SendPacketToServer(packet)
if err != nil {
log.Print("RemoteClientConnection: error sending PlayerConnectionRequestPacket to server.")
r.Errorf("RemoteClientConnection: error sending PlayerConnectionRequestPacket to server.")
return err
}
@ -134,18 +142,18 @@ func (r *RemoteClientConnection) serverListener() {
for {
err := decoder.Decode(&packet)
if err != nil {
log.Printf("failed to decode the packet, err: %v\n", err)
r.Errorf("failed to decode the packet, err: %v\n", err)
return
}
p, err := r.decodeToPacket(packet.PacketType, string(packet.PacketData))
if err != nil {
log.Println(packet.PacketType, err)
r.Error(fmt.Sprintln(packet.PacketType, err))
}
err = r.clientListener.OnPacketReceived(p)
if err != nil {
log.Println(packet.PacketType, err)
r.Error(fmt.Sprintln(packet.PacketType, err))
}
}
}

View File

@ -2,7 +2,6 @@ package d2client
import (
"fmt"
"log"
"os"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
@ -15,6 +14,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2records"
@ -26,6 +26,8 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2script"
)
const logPrefix = "Game Client"
const (
numSubtilesPerTile = 5
)
@ -44,24 +46,32 @@ type GameClient struct {
Players map[string]*d2mapentity.Player // IDs of the other players
Seed int64 // Map seed
RegenMap bool // Regenerate tile cache on render (map has changed)
*d2util.Logger
}
// Create constructs a new GameClient and returns a pointer to it.
func Create(connectionType d2clientconnectiontype.ClientConnectionType,
asset *d2asset.AssetManager, scriptEngine *d2script.ScriptEngine) (*GameClient, error) {
asset *d2asset.AssetManager,
l d2util.LogLevel,
scriptEngine *d2script.ScriptEngine) (*GameClient, error) {
result := &GameClient{
asset: asset,
MapEngine: d2mapengine.CreateMapEngine(asset),
MapEngine: d2mapengine.CreateMapEngine(l, asset),
Players: make(map[string]*d2mapentity.Player),
connectionType: connectionType,
scriptEngine: scriptEngine,
}
result.Logger = d2util.NewLogger()
result.Logger.SetPrefix(logPrefix)
result.Logger.SetLevel(l)
// for a remote client connection, set loading to true - wait until we process the GenerateMapPacket
// before we start updating map entites
result.MapEngine.IsLoading = connectionType == d2clientconnectiontype.LANClient
mapGen, err := d2mapgen.NewMapGenerator(asset, result.MapEngine)
mapGen, err := d2mapgen.NewMapGenerator(asset, l, result.MapEngine)
if err != nil {
return nil, err
}
@ -70,11 +80,11 @@ func Create(connectionType d2clientconnectiontype.ClientConnectionType,
switch connectionType {
case d2clientconnectiontype.LANClient:
result.clientConnection, err = d2remoteclient.Create(asset)
result.clientConnection, err = d2remoteclient.Create(l, asset)
case d2clientconnectiontype.LANServer:
result.clientConnection, err = d2localclient.Create(asset, true)
result.clientConnection, err = d2localclient.Create(asset, l, true)
case d2clientconnectiontype.Local:
result.clientConnection, err = d2localclient.Create(asset, false)
result.clientConnection, err = d2localclient.Create(asset, l, false)
default:
err = fmt.Errorf("unknown client connection type specified: %d", connectionType)
}
@ -147,20 +157,20 @@ func (g *GameClient) OnPacketReceived(packet d2netpacket.NetPacket) error {
}
case d2netpackettype.Ping:
if err := g.handlePingPacket(); err != nil {
log.Printf("GameClient: error responding to server ping: %s", err)
g.Errorf("GameClient: error responding to server ping: %s", err)
}
case d2netpackettype.PlayerDisconnectionNotification:
// Not implemented
log.Printf("RemoteClientConnection: received disconnect: %s", packet.PacketData)
g.Infof("RemoteClientConnection: received disconnect: %s", packet.PacketData)
case d2netpackettype.ServerClosed:
// https://github.com/OpenDiablo2/OpenDiablo2/issues/802
log.Print("Server has been closed")
g.Infof("Server has been closed")
os.Exit(0)
case d2netpackettype.ServerFull:
log.Println("Server is full")
g.Infof("Server is full") // need to be verified
os.Exit(0)
default:
log.Fatalf("Invalid packet type: %d", packet.PacketType)
g.Fatalf("Invalid packet type: %d", packet.PacketType)
}
return nil
@ -196,7 +206,7 @@ func (g *GameClient) handleUpdateServerInfoPacket(packet d2netpacket.NetPacket)
g.MapEngine.SetSeed(serverInfo.Seed)
g.PlayerID = serverInfo.PlayerID
g.Seed = serverInfo.Seed
log.Printf("Player id set to %s", serverInfo.PlayerID)
g.Infof("Player id set to %s", serverInfo.PlayerID)
return nil
}
@ -259,7 +269,7 @@ func (g *GameClient) handleMovePlayerPacket(packet d2netpacket.NetPacket) error
if err != nil {
fmtStr := "GameClient: error setting animation mode for player %s: %s"
log.Printf(fmtStr, player.ID(), err)
g.Errorf(fmtStr, player.ID(), err)
}
})
}

View File

@ -5,7 +5,6 @@ import (
"encoding/json"
"errors"
"fmt"
"log"
"net"
"sync"
"time"
@ -13,6 +12,7 @@ import (
"github.com/robertkrimen/otto"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
@ -23,6 +23,8 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2script"
)
const logPrefix = "Game Server"
const (
port = "6669"
chunkSize int = 4096 // nolint:deadcode,unused,varcheck // WIP
@ -51,6 +53,8 @@ type GameServer struct {
maxConnections int
packetManagerChan chan []byte
heroStateFactory *d2hero.HeroStateFactory
*d2util.Logger
}
// NewGameServer builds a new GameServer that can be started
@ -58,7 +62,9 @@ type GameServer struct {
// ctx: required context item
// networkServer: true = 0.0.0.0 | false = 127.0.0.1
// maxConnections (default: 8): maximum number of TCP connections allowed open
func NewGameServer(asset *d2asset.AssetManager, networkServer bool,
func NewGameServer(asset *d2asset.AssetManager,
networkServer bool,
l d2util.LogLevel,
maxConnections ...int) (*GameServer,
error) {
if len(maxConnections) == 0 {
@ -86,11 +92,15 @@ func NewGameServer(asset *d2asset.AssetManager, networkServer bool,
heroStateFactory: heroStateFactory,
}
mapEngine := d2mapengine.CreateMapEngine(asset)
gameServer.Logger = d2util.NewLogger()
gameServer.Logger.SetPrefix(logPrefix)
gameServer.Logger.SetLevel(l)
mapEngine := d2mapengine.CreateMapEngine(l, asset)
mapEngine.SetSeed(gameServer.seed)
mapEngine.ResetMap(d2enum.RegionAct1Town, 100, 100)
mapGen, err := d2mapgen.NewMapGenerator(asset, mapEngine)
mapGen, err := d2mapgen.NewMapGenerator(asset, l, mapEngine)
if err != nil {
return nil, err
}
@ -118,7 +128,7 @@ func (g *GameServer) Start() error {
listenerAddress = "0.0.0.0:" + port
}
log.Printf("Starting Game Server @ %s\n", listenerAddress)
g.Infof("Starting Game Server @ %s\n", listenerAddress)
l, err := net.Listen("tcp4", listenerAddress)
if err != nil {
@ -133,7 +143,7 @@ func (g *GameServer) Start() error {
for {
c, err := g.listener.Accept()
if err != nil {
log.Printf("Unable to accept connection: %s\n", err)
g.Errorf("Unable to accept connection: %s", err)
return
}
@ -150,7 +160,7 @@ func (g *GameServer) Stop() {
g.cancel()
if err := g.listener.Close(); err != nil {
log.Printf("failed to close the listener %s, err: %v\n", g.listener.Addr(), err)
g.Errorf("failed to close the listener %s, err: %v\n", g.listener.Addr(), err)
}
}
@ -168,14 +178,14 @@ func (g *GameServer) packetManager() {
case d2netpackettype.PlayerConnectionRequest:
player, err := d2netpacket.UnmarshalNetPacket(p)
if err != nil {
log.Printf("Unable to unmarshal PlayerConnectionRequestPacket: %s\n", err)
g.Errorf("Unable to unmarshal PlayerConnectionRequestPacket: %s\n", err)
}
g.sendPacketToClients(player)
case d2netpackettype.MovePlayer:
move, err := d2netpacket.UnmarshalNetPacket(p)
if err != nil {
log.Println(err)
g.Error(err.Error())
continue
}
@ -183,7 +193,7 @@ func (g *GameServer) packetManager() {
case d2netpackettype.CastSkill:
castSkill, err := d2netpacket.UnmarshalNetPacket(p)
if err != nil {
log.Println(err)
g.Error(err.Error())
continue
}
@ -191,7 +201,7 @@ func (g *GameServer) packetManager() {
case d2netpackettype.SpawnItem:
item, err := d2netpacket.UnmarshalNetPacket(p)
if err != nil {
log.Println(err)
g.Error(err.Error())
continue
}
@ -206,7 +216,7 @@ func (g *GameServer) packetManager() {
func (g *GameServer) sendPacketToClients(packet d2netpacket.NetPacket) {
for _, c := range g.connections {
if err := c.SendPacketToClient(packet); err != nil {
log.Printf("GameServer: error sending packet: %s to client %s: %s", packet.PacketType, c.GetUniqueID(), err)
g.Errorf("GameServer: error sending packet: %s to client %s: %s", packet.PacketType, c.GetUniqueID(), err)
}
}
}
@ -218,11 +228,11 @@ func (g *GameServer) handleConnection(conn net.Conn) {
var packet d2netpacket.NetPacket
log.Printf("Accepting connection: %s\n", conn.RemoteAddr().String())
g.Infof("Accepting connection: %s\n", conn.RemoteAddr().String())
defer func() {
if err := conn.Close(); err != nil {
log.Printf("failed to close the connection: %s\n", conn.RemoteAddr())
g.Errorf("failed to close the connection: %s\n", conn.RemoteAddr())
}
}()
@ -231,7 +241,7 @@ func (g *GameServer) handleConnection(conn net.Conn) {
for {
err := decoder.Decode(&packet)
if err != nil {
log.Println(err)
g.Error(err.Error())
return // exit this connection as we could not read the first packet
}
@ -240,16 +250,16 @@ func (g *GameServer) handleConnection(conn net.Conn) {
// to.
if connected == 0 {
if packet.PacketType != d2netpackettype.PlayerConnectionRequest {
log.Printf("Closing connection with %s: did not receive new player connection request...\n", conn.RemoteAddr().String())
g.Infof("Closing connection with %s: did not receive new player connection request...", conn.RemoteAddr().String())
}
if err := g.registerConnection(packet.PacketData, conn); err != nil {
switch err {
case errServerFull: // Server is currently full and not accepting new connections.
_, errServerFullPacket := conn.Write(d2netpacket.MarshalPacket(d2netpacket.CreateServerFullPacket()))
log.Println(errServerFullPacket)
g.Error(fmt.Sprintln(errServerFullPacket))
case errPlayerAlreadyExists: // Player is already registered and did not disconnection correctly.
log.Println(err)
g.Error(fmt.Sprintln(err))
}
return
@ -283,7 +293,7 @@ func (g *GameServer) registerConnection(b []byte, conn net.Conn) error {
// if it is not full, unmarshal the playerConnectionRequest
packet, err := d2netpacket.UnmarshalPlayerConnectionRequest(b)
if err != nil {
log.Printf("Failed to unmarshal PlayerConnectionRequest: %s\n", err)
g.Errorf("Failed to unmarshal PlayerConnectionRequest: %s\n", err)
}
// check to see if the player is already registered
@ -294,7 +304,7 @@ func (g *GameServer) registerConnection(b []byte, conn net.Conn) error {
// Client a new TCP Client Connection and add it to the connections map
client := d2tcpclientconnection.CreateTCPClientConnection(conn, packet.ID)
client.SetPlayerState(packet.PlayerState)
log.Printf("Client connected with an id of %s", client.GetUniqueID())
g.Infof("Client connected with an id of %s", client.GetUniqueID())
g.connections[client.GetUniqueID()] = client
// Temporary position hack --------------------------------------------
@ -330,7 +340,7 @@ func (g *GameServer) OnClientConnected(client ClientConnection) {
clientPlayerState.Y = sy
// --------------------------------------------------------------------
log.Printf("Client connected with an id of %s", client.GetUniqueID())
g.Infof("Client connected with an id of %s", client.GetUniqueID())
g.connections[client.GetUniqueID()] = client
g.handleClientConnection(client, sx, sy)
@ -339,12 +349,12 @@ func (g *GameServer) OnClientConnected(client ClientConnection) {
func (g *GameServer) handleClientConnection(client ClientConnection, x, y float64) {
err := client.SendPacketToClient(d2netpacket.CreateUpdateServerInfoPacket(g.seed, client.GetUniqueID()))
if err != nil {
log.Printf("GameServer: error sending UpdateServerInfoPacket to client %s: %s", client.GetUniqueID(), err)
g.Errorf("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)
g.Errorf("GameServer: error sending GenerateMapPacket to client %s: %s", client.GetUniqueID(), err)
}
playerState := client.GetPlayerState()
@ -371,7 +381,7 @@ func (g *GameServer) handleClientConnection(client ClientConnection, x, y float6
for _, connection := range g.connections {
err := connection.SendPacketToClient(createPlayerPacket)
if err != nil {
log.Printf("GameServer: error sending %T to client %s: %s", createPlayerPacket, connection.GetUniqueID(), err)
g.Errorf("GameServer: error sending %T to client %s: %s", createPlayerPacket, connection.GetUniqueID(), err)
}
if connection.GetUniqueID() == client.GetUniqueID() {
@ -397,7 +407,7 @@ func (g *GameServer) handleClientConnection(client ClientConnection, x, y float6
)
if err != nil {
log.Printf("GameServer: error sending CreateAddPlayerPacket to client %s: %s", connection.GetUniqueID(), err)
g.Errorf("GameServer: error sending CreateAddPlayerPacket to client %s: %s", connection.GetUniqueID(), err)
}
}
}
@ -405,7 +415,7 @@ func (g *GameServer) handleClientConnection(client ClientConnection, x, y float6
// OnClientDisconnected removes the given client from the list
// of client connections.
func (g *GameServer) OnClientDisconnected(client ClientConnection) {
log.Printf("Client disconnected with an id of %s", client.GetUniqueID())
g.Infof("Client disconnected with an id of %s", client.GetUniqueID())
delete(g.connections, client.GetUniqueID())
}
@ -443,10 +453,10 @@ func (g *GameServer) OnPacketReceived(client ClientConnection, packet d2netpacke
err = g.heroStateFactory.Save(playerState)
if err != nil {
log.Printf("GameServer: error saving saving Player: %s", err)
g.Errorf("GameServer: error saving saving Player: %s", err)
}
default:
log.Printf("GameServer: received unknown packet %T", packet)
g.Warningf("GameServer: received unknown packet %T", packet)
}
return nil

View File

@ -3,6 +3,7 @@ package d2networking
import (
"os"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2server"
)
@ -33,9 +34,10 @@ func StartDedicatedServer(
manager *d2asset.AssetManager,
in chan int,
log chan string,
l d2util.LogLevel,
maxPlayers int,
) error {
server, err := d2server.NewGameServer(manager, true, maxPlayers)
server, err := d2server.NewGameServer(manager, true, l, maxPlayers)
if err != nil {
return err
}