1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-29 10:35:23 +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) srvChanIn := make(chan int)
srvChanLog := make(chan string) 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 { if srvErr != nil {
return srvErr return srvErr
} }
@ -179,7 +179,7 @@ func (a *App) loadEngine() error {
a.asset.SetLogLevel(logLevel) a.asset.SetLogLevel(logLevel)
audio := ebiten2.CreateAudio(a.asset) audio := ebiten2.CreateAudio(a.config.LogLevel, a.asset)
inputManager := d2input.NewInputManager() inputManager := d2input.NewInputManager()
@ -195,7 +195,7 @@ func (a *App) loadEngine() error {
scriptEngine := d2script.CreateScriptEngine() 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.inputManager = inputManager
a.terminal = term 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 { if err != nil {
return err return err
} }
a.guiManager = gui 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) 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 // ToCreateGame forces the game to transition to the Create Game screen
func (a *App) ToCreateGame(filePath string, connType d2clientconnectiontype.ClientConnectionType, host string) { 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 { if err != nil {
a.logger.Error(err.Error()) a.logger.Error(err.Error())
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,7 +2,6 @@ package d2gui
import ( import (
"image/color" "image/color"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
@ -19,11 +18,13 @@ type LabelButton struct {
isHovered bool isHovered bool
layout *Layout layout *Layout
x, y int x, y int
*d2util.Logger
} }
// NewLabelButton generates a new instance of LabelButton // NewLabelButton generates a new instance of LabelButton
func NewLabelButton(x, y int, text string, col color.RGBA, callback func()) *LabelButton { func NewLabelButton(x, y int, text string, col color.RGBA, l d2util.LogLevel, callback func()) *LabelButton {
return &LabelButton{ lb := &LabelButton{
x: x, x: x,
y: y, y: y,
hoverColor: col, hoverColor: col,
@ -31,6 +32,12 @@ func NewLabelButton(x, y int, text string, col color.RGBA, callback func()) *Lab
callback: callback, callback: callback,
canHover: true, 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 // 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) { mainLayout.SetMouseEnterHandler(func(event d2interface.MouseMoveEvent) {
if err := l.SetIsHovered(true); err != nil { 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) { mainLayout.SetMouseLeaveHandler(func(event d2interface.MouseMoveEvent) {
if err := l.SetIsHovered(false); err != nil { 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 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}) 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 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}) l.entries = append(l.entries, &layoutEntry{widget: label})

View File

@ -2,7 +2,6 @@ package d2hero
import ( import (
"encoding/json" "encoding/json"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2records" "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 // only serialize the Shallow object instead of the SkillRecord & SkillDescriptionRecord
bytes, err := json.Marshal(hs.Shallow) bytes, err := json.Marshal(hs.Shallow)
if err != nil { 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. // UnmarshalJSON overrides the default logic used when the HeroSkill is deserialized from a byte array.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,8 +1,6 @@
package d2maprenderer package d2maprenderer
import ( import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1" "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)) mr.palette, err = mr.loadPaletteForAct(d2enum.RegionIdType(mr.mapEngine.LevelType().ID))
if err != nil { if err != nil {
log.Print(err) mr.Error(err.Error())
} }
tiles := *mr.mapEngine.Tiles() tiles := *mr.mapEngine.Tiles()
@ -61,7 +59,7 @@ func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord) {
var tileData []*d2dt1.Tile var tileData []*d2dt1.Tile
if tileOptions == nil { 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 = append(tileData, &d2dt1.Tile{})
tileData[0].Width = defaultFloorTileWidth tileData[0].Width = defaultFloorTileWidth
@ -205,7 +203,7 @@ func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord) {
} }
if realHeight == 0 { if realHeight == 0 {
log.Printf("Invalid 0 height for wall tile") mr.Error("Invalid 0 height for wall tile")
return return
} }

View File

@ -1,7 +1,6 @@
package d2mapstamp package d2mapstamp
import ( import (
"log"
"math" "math"
"math/rand" "math/rand"
@ -10,12 +9,24 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
) )
const logPrefix = "Map Stamp"
// NewStampFactory creates a MapStamp factory instance // NewStampFactory creates a MapStamp factory instance
func NewStampFactory(asset *d2asset.AssetManager, entity *d2mapentity.MapEntityFactory) *StampFactory { func NewStampFactory(asset *d2asset.AssetManager, l d2util.LogLevel, entity *d2mapentity.MapEntityFactory) *StampFactory {
return &StampFactory{asset, entity} 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 // 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 { type StampFactory struct {
asset *d2asset.AssetManager asset *d2asset.AssetManager
entity *d2mapentity.MapEntityFactory entity *d2mapentity.MapEntityFactory
*d2util.Logger
} }
// LoadStamp loads the Stamp data from file, using the given level type, level preset index, and // 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) dt1, err := d2dt1.LoadDT1(fileData)
if err != nil { if err != nil {
log.Print(err) f.Error(err.Error())
return nil return nil
} }
@ -82,7 +95,7 @@ func (f *StampFactory) LoadStamp(levelType d2enum.RegionIdType, levelPreset, fil
stamp.ds1, err = d2ds1.LoadDS1(fileData) stamp.ds1, err = d2ds1.LoadDS1(fileData)
if err != nil { if err != nil {
log.Print(err) f.Error(err.Error())
return nil return nil
} }

View File

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

View File

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

View File

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

View File

@ -2,7 +2,6 @@ package d2records
import ( import (
"fmt" "fmt"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util" "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 // RecordManager stores all of the records loaded from txt files
type RecordManager struct { type RecordManager struct {
Logger *d2util.Logger *d2util.Logger
boundLoaders map[string][]recordLoader // there can be more than one loader bound for a file boundLoaders map[string][]recordLoader // there can be more than one loader bound for a file
Animation struct { Animation struct {
Data d2data.AnimationData Data d2data.AnimationData
@ -411,7 +410,7 @@ func (r *RecordManager) initObjectRecords(lookups []ObjectLookupRecord) {
func (r *RecordManager) LookupObject(act, typ, id int) *ObjectLookupRecord { func (r *RecordManager) LookupObject(act, typ, id int) *ObjectLookupRecord {
object := r.lookupObject(act, typ, id) object := r.lookupObject(act, typ, id)
if object == nil { 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 return object

View File

@ -1,7 +1,7 @@
package d2records package d2records
import ( import (
"log" "fmt"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2calculation/d2parser" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2calculation/d2parser"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
@ -19,6 +19,11 @@ func skillDetailsLoader(r *RecordManager, d *d2txt.DataDictionary) error {
name := d.String("skill") name := d.String("skill")
parser.SetCurrentReference("skill", name) parser.SetCurrentReference("skill", name)
anim, err := animToEnum(d.String("anim"))
if err != nil {
return err
}
record := &SkillRecord{ record := &SkillRecord{
Skill: d.String("skill"), Skill: d.String("skill"),
ID: d.Number("Id"), ID: d.Number("Id"),
@ -141,7 +146,7 @@ func skillDetailsLoader(r *RecordManager, d *d2txt.DataDictionary) error {
Itypeb3: d.String("itypeb3"), Itypeb3: d.String("itypeb3"),
Etypeb1: d.String("etypeb1"), Etypeb1: d.String("etypeb1"),
Etypeb2: d.String("etypeb2"), Etypeb2: d.String("etypeb2"),
Anim: animToEnum(d.String("anim")), Anim: anim,
Seqtrans: d.String("seqtrans"), Seqtrans: d.String("seqtrans"),
Monanim: d.String("monanim"), Monanim: d.String("monanim"),
Seqnum: d.Number("seqnum"), Seqnum: d.Number("seqnum"),
@ -277,45 +282,42 @@ func skillDetailsLoader(r *RecordManager, d *d2txt.DataDictionary) error {
return nil return nil
} }
func animToEnum(anim string) d2enum.PlayerAnimationMode { func animToEnum(anim string) (d2enum.PlayerAnimationMode, error) {
switch anim { switch anim {
case "SC": case "SC":
return d2enum.PlayerAnimationModeCast return d2enum.PlayerAnimationModeCast, nil
case "TH": case "TH":
return d2enum.PlayerAnimationModeThrow return d2enum.PlayerAnimationModeThrow, nil
case "KK": case "KK":
return d2enum.PlayerAnimationModeKick return d2enum.PlayerAnimationModeKick, nil
case "SQ": case "SQ":
return d2enum.PlayerAnimationModeSequence return d2enum.PlayerAnimationModeSequence, nil
case "S1": case "S1":
return d2enum.PlayerAnimationModeSkill1 return d2enum.PlayerAnimationModeSkill1, nil
case "S2": case "S2":
return d2enum.PlayerAnimationModeSkill2 return d2enum.PlayerAnimationModeSkill2, nil
case "S3": case "S3":
return d2enum.PlayerAnimationModeSkill3 return d2enum.PlayerAnimationModeSkill3, nil
case "S4": case "S4":
return d2enum.PlayerAnimationModeSkill4 return d2enum.PlayerAnimationModeSkill4, nil
case "A1": case "A1":
return d2enum.PlayerAnimationModeAttack1 return d2enum.PlayerAnimationModeAttack1, nil
case "A2": case "A2":
return d2enum.PlayerAnimationModeAttack2 return d2enum.PlayerAnimationModeAttack2, nil
case "": case "":
return d2enum.PlayerAnimationModeNone return d2enum.PlayerAnimationModeNone, nil
default:
log.Fatalf("Unknown skill anim value [%s]", anim)
} }
// should not be reached // 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 package d2screen
import ( import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
) )
const (
logPrefix = "Screen Manager"
)
// ScreenManager manages game screens (main menu, credits, character select, game, etc) // ScreenManager manages game screens (main menu, credits, character select, game, etc)
type ScreenManager struct { type ScreenManager struct {
uiManager *d2ui.UIManager uiManager *d2ui.UIManager
@ -16,11 +19,22 @@ type ScreenManager struct {
loadingState LoadingState loadingState LoadingState
currentScreen Screen currentScreen Screen
guiManager *d2gui.GuiManager guiManager *d2gui.GuiManager
*d2util.Logger
} }
// NewScreenManager creates a screen manager // NewScreenManager creates a screen manager
func NewScreenManager(ui *d2ui.UIManager, guiManager *d2gui.GuiManager) *ScreenManager { func NewScreenManager(ui *d2ui.UIManager, l d2util.LogLevel, guiManager *d2gui.GuiManager) *ScreenManager {
return &ScreenManager{uiManager: ui, guiManager: guiManager} 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 // 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 // this call blocks execution and could lead to deadlock if a screen implements OnLoad incorreclty
load, ok := <-sm.loadingState.updates load, ok := <-sm.loadingState.updates
if !ok { 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 { 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 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) buttonSprite, err := ui.NewSprite(buttonLayout.ResourceName, buttonLayout.PaletteName)
if err != nil { if err != nil {
log.Print(err) ui.Error(err.Error())
return nil return nil
} }
@ -455,7 +455,7 @@ func (ui *UIManager) NewButton(buttonType ButtonType, text string) *Button {
for i := 0; i < buttonLayout.XSegments; i++ { for i := 0; i < buttonLayout.XSegments; i++ {
w, _, frameSizeErr := buttonSprite.GetFrameSize(i) w, _, frameSizeErr := buttonSprite.GetFrameSize(i)
if frameSizeErr != nil { if frameSizeErr != nil {
log.Print(frameSizeErr) ui.Error(frameSizeErr.Error())
return nil return nil
} }
@ -469,7 +469,7 @@ func (ui *UIManager) NewButton(buttonType ButtonType, text string) *Button {
for i := 0; i < buttonLayout.YSegments; i++ { for i := 0; i < buttonLayout.YSegments; i++ {
_, h, frameSizeErr := buttonSprite.GetFrameSize(i * buttonLayout.YSegments) _, h, frameSizeErr := buttonSprite.GetFrameSize(i * buttonLayout.YSegments)
if frameSizeErr != nil { if frameSizeErr != nil {
log.Print(frameSizeErr) ui.Error(frameSizeErr.Error())
return nil return nil
} }

View File

@ -1,8 +1,6 @@
package d2ui package d2ui
import ( import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "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) checkboxSprite, err := ui.NewSprite(d2resource.Checkbox, d2resource.PaletteFechar)
if err != nil { if err != nil {
log.Print(err) ui.Error(err.Error())
return nil return nil
} }
result.width, result.height, err = checkboxSprite.GetFrameSize(0) result.width, result.height, err = checkboxSprite.GetFrameSize(0)
if err != nil { if err != nil {
log.Print(err) ui.Error(err.Error())
return nil return nil
} }

View File

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

View File

@ -1,8 +1,6 @@
package d2ui package d2ui
import ( import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
@ -69,6 +67,8 @@ func NewUIFrame(
} }
frame.Load() frame.Load()
frame.asset.Logger.SetPrefix(logPrefix) // workaround
return frame return frame
} }
@ -76,7 +76,7 @@ func NewUIFrame(
func (u *UIFrame) Load() { func (u *UIFrame) Load() {
sprite, err := u.manager.NewSprite(d2resource.Frame, d2resource.PaletteSky) sprite, err := u.manager.NewSprite(d2resource.Frame, d2resource.PaletteSky)
if err != nil { if err != nil {
log.Print(err) u.asset.Logger.Error(err.Error())
} }
u.frame = sprite u.frame = sprite
@ -111,7 +111,7 @@ func (u *UIFrame) calculateSize() {
for i := range framesWidth { for i := range framesWidth {
w, _, err := u.frame.GetFrameSize(framesWidth[i]) w, _, err := u.frame.GetFrameSize(framesWidth[i])
if err != nil { if err != nil {
log.Print(err) u.asset.Logger.Error(err.Error())
} }
u.width += w u.width += w
@ -120,7 +120,7 @@ func (u *UIFrame) calculateSize() {
for i := range framesHeight { for i := range framesHeight {
_, h, err := u.frame.GetFrameSize(framesHeight[i]) _, h, err := u.frame.GetFrameSize(framesHeight[i])
if err != nil { if err != nil {
log.Print(err) u.asset.Logger.Error(err.Error())
} }
u.height += h u.height += h
@ -132,11 +132,11 @@ func (u *UIFrame) Render(target d2interface.Surface) {
switch u.frameOrientation { switch u.frameOrientation {
case FrameLeft: case FrameLeft:
if err := u.renderLeft(target); err != nil { if err := u.renderLeft(target); err != nil {
log.Printf("Render error %e", err) u.asset.Logger.Error("Render error" + err.Error())
} }
case FrameRight: case FrameRight:
if err := u.renderRight(target); err != nil { 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 ( import (
"image/color" "image/color"
"log"
"regexp" "regexp"
"strings" "strings"
@ -20,13 +19,15 @@ type Label struct {
font *d2asset.Font font *d2asset.Font
Color map[int]color.Color Color map[int]color.Color
backgroundColor color.Color backgroundColor color.Color
*d2util.Logger
} }
// NewLabel creates a new instance of a UI label // NewLabel creates a new instance of a UI label
func (ui *UIManager) NewLabel(fontPath, palettePath string) *Label { func (ui *UIManager) NewLabel(fontPath, palettePath string) *Label {
font, err := ui.asset.LoadFont(fontPath+".tbl", fontPath+".dc6", palettePath) font, err := ui.asset.LoadFont(fontPath+".tbl", fontPath+".dc6", palettePath)
if err != nil { if err != nil {
log.Print(err) ui.Error(err.Error())
return nil return nil
} }
@ -37,6 +38,7 @@ func (ui *UIManager) NewLabel(fontPath, palettePath string) *Label {
Alignment: HorizontalAlignLeft, Alignment: HorizontalAlignLeft,
Color: map[int]color.Color{0: color.White}, Color: map[int]color.Color{0: color.White},
font: font, font: font,
Logger: ui.Logger,
} }
result.bindManager(ui) result.bindManager(ui)
@ -75,7 +77,7 @@ func (v *Label) Render(target d2interface.Surface) {
err := v.font.RenderText(character, target) err := v.font.RenderText(character, target)
if err != nil { if err != nil {
log.Print(err) v.Error(err.Error())
} }
target.PushTranslation(charWidth, 0) target.PushTranslation(charWidth, 0)
@ -160,7 +162,7 @@ func (v *Label) getAlignOffset(textWidth int) int {
case HorizontalAlignRight: case HorizontalAlignRight:
return -textWidth return -textWidth
default: default:
log.Fatal("Invalid Alignment") v.Fatal("Invalid Alignment")
return 0 return 0
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -72,13 +72,13 @@ func CreateGame(
lastRegionType: d2enum.RegionNone, lastRegionType: d2enum.RegionNone,
ticksSinceLevelCheck: 0, ticksSinceLevelCheck: 0,
mapRenderer: d2maprenderer.CreateMapRenderer(asset, renderer, 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), escapeMenu: d2player.NewEscapeMenu(navigator, renderer, audioProvider, ui, guiManager, asset, l, keyMap),
inputManager: inputManager, inputManager: inputManager,
audioProvider: audioProvider, audioProvider: audioProvider,
renderer: renderer, renderer: renderer,
terminal: term, terminal: term,
soundEngine: d2audio.NewSoundEngine(audioProvider, asset, term), soundEngine: d2audio.NewSoundEngine(audioProvider, asset, l, term),
uiManager: ui, uiManager: ui,
guiManager: guiManager, guiManager: guiManager,
keyMap: keyMap, keyMap: keyMap,

View File

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

View File

@ -77,23 +77,23 @@ func NewKeyBindingMenu(
ret.Box = d2gui.NewBox( ret.Box = d2gui.NewBox(
asset, renderer, ui, ret.mainLayout, asset, renderer, ui, ret.mainLayout,
keyBindingMenuWidth, keyBindingMenuHeight, keyBindingMenuWidth, keyBindingMenuHeight,
keyBindingMenuX, keyBindingMenuY, "", keyBindingMenuX, keyBindingMenuY, l, "",
) )
ret.Box.SetPadding(keyBindingMenuPaddingX, keyBindingSettingPaddingY) ret.Box.SetPadding(keyBindingMenuPaddingX, keyBindingSettingPaddingY)
ret.Box.SetOptions([]*d2gui.LabelButton{ 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 { if err := ret.onCancelClicked(); err != nil {
ret.logger.Error("error while clicking option Cancel: %v" + err.Error()) 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 { if err := ret.onDefaultClicked(); err != nil {
ret.logger.Error("error while clicking option Default: %v" + err.Error()) 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 { if err := ret.onAcceptClicked(); err != nil {
ret.logger.Error("error while clicking option Accept: %v" + err.Error()) ret.logger.Error("error while clicking option Accept: %v" + err.Error())
} }

View File

@ -3,6 +3,7 @@ package d2localclient
import ( import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
@ -22,16 +23,18 @@ type LocalClientConnection struct {
openNetworkServer bool // True if this is a server openNetworkServer bool // True if this is a server
playerState *d2hero.HeroState // Local player state playerState *d2hero.HeroState // Local player state
gameServer *d2server.GameServer // Game Server gameServer *d2server.GameServer // Game Server
logLevel d2util.LogLevel
} }
// GetUniqueID returns LocalClientConnection.uniqueID. // GetUniqueID returns LocalClientConnection.uniqueID.
func (l LocalClientConnection) GetUniqueID() string { func (l *LocalClientConnection) GetUniqueID() string {
return l.uniqueID return l.uniqueID
} }
// GetConnectionType returns an enum representing the connection type. // GetConnectionType returns an enum representing the connection type.
// See: d2clientconnectiontype // See: d2clientconnectiontype
func (l LocalClientConnection) GetConnectionType() d2clientconnectiontype.ClientConnectionType { func (l *LocalClientConnection) GetConnectionType() d2clientconnectiontype.ClientConnectionType {
return d2clientconnectiontype.Local return d2clientconnectiontype.Local
} }
@ -42,7 +45,10 @@ func (l *LocalClientConnection) SendPacketToClient(packet d2netpacket.NetPacket)
// Create constructs a new LocalClientConnection and returns // Create constructs a new LocalClientConnection and returns
// a pointer to it. // 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) heroStateFactory, err := d2hero.NewHeroStateFactory(asset)
if err != nil { if err != nil {
return nil, err return nil, err
@ -53,6 +59,7 @@ func Create(asset *d2asset.AssetManager, openNetworkServer bool) (*LocalClientCo
asset: asset, asset: asset,
uniqueID: uuid.New().String(), uniqueID: uuid.New().String(),
openNetworkServer: openNetworkServer, openNetworkServer: openNetworkServer,
logLevel: l,
} }
return result, nil return result, nil
@ -64,7 +71,7 @@ func (l *LocalClientConnection) Open(_, saveFilePath string) error {
l.SetPlayerState(l.heroState.LoadHeroState(saveFilePath)) 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 { if err != nil {
return err return err
} }

View File

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

View File

@ -2,7 +2,6 @@ package d2client
import ( import (
"fmt" "fmt"
"log"
"os" "os"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
@ -15,6 +14,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector" "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/d2mapengine"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2records" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2records"
@ -26,6 +26,8 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2script" "github.com/OpenDiablo2/OpenDiablo2/d2script"
) )
const logPrefix = "Game Client"
const ( const (
numSubtilesPerTile = 5 numSubtilesPerTile = 5
) )
@ -44,24 +46,32 @@ type GameClient struct {
Players map[string]*d2mapentity.Player // IDs of the other players Players map[string]*d2mapentity.Player // IDs of the other players
Seed int64 // Map seed Seed int64 // Map seed
RegenMap bool // Regenerate tile cache on render (map has changed) RegenMap bool // Regenerate tile cache on render (map has changed)
*d2util.Logger
} }
// Create constructs a new GameClient and returns a pointer to it. // Create constructs a new GameClient and returns a pointer to it.
func Create(connectionType d2clientconnectiontype.ClientConnectionType, 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{ result := &GameClient{
asset: asset, asset: asset,
MapEngine: d2mapengine.CreateMapEngine(asset), MapEngine: d2mapengine.CreateMapEngine(l, asset),
Players: make(map[string]*d2mapentity.Player), Players: make(map[string]*d2mapentity.Player),
connectionType: connectionType, connectionType: connectionType,
scriptEngine: scriptEngine, 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 // for a remote client connection, set loading to true - wait until we process the GenerateMapPacket
// before we start updating map entites // before we start updating map entites
result.MapEngine.IsLoading = connectionType == d2clientconnectiontype.LANClient result.MapEngine.IsLoading = connectionType == d2clientconnectiontype.LANClient
mapGen, err := d2mapgen.NewMapGenerator(asset, result.MapEngine) mapGen, err := d2mapgen.NewMapGenerator(asset, l, result.MapEngine)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -70,11 +80,11 @@ func Create(connectionType d2clientconnectiontype.ClientConnectionType,
switch connectionType { switch connectionType {
case d2clientconnectiontype.LANClient: case d2clientconnectiontype.LANClient:
result.clientConnection, err = d2remoteclient.Create(asset) result.clientConnection, err = d2remoteclient.Create(l, asset)
case d2clientconnectiontype.LANServer: case d2clientconnectiontype.LANServer:
result.clientConnection, err = d2localclient.Create(asset, true) result.clientConnection, err = d2localclient.Create(asset, l, true)
case d2clientconnectiontype.Local: case d2clientconnectiontype.Local:
result.clientConnection, err = d2localclient.Create(asset, false) result.clientConnection, err = d2localclient.Create(asset, l, false)
default: default:
err = fmt.Errorf("unknown client connection type specified: %d", connectionType) 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: case d2netpackettype.Ping:
if err := g.handlePingPacket(); err != nil { 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: case d2netpackettype.PlayerDisconnectionNotification:
// Not implemented // Not implemented
log.Printf("RemoteClientConnection: received disconnect: %s", packet.PacketData) g.Infof("RemoteClientConnection: received disconnect: %s", packet.PacketData)
case d2netpackettype.ServerClosed: case d2netpackettype.ServerClosed:
// https://github.com/OpenDiablo2/OpenDiablo2/issues/802 // https://github.com/OpenDiablo2/OpenDiablo2/issues/802
log.Print("Server has been closed") g.Infof("Server has been closed")
os.Exit(0) os.Exit(0)
case d2netpackettype.ServerFull: case d2netpackettype.ServerFull:
log.Println("Server is full") g.Infof("Server is full") // need to be verified
os.Exit(0) os.Exit(0)
default: default:
log.Fatalf("Invalid packet type: %d", packet.PacketType) g.Fatalf("Invalid packet type: %d", packet.PacketType)
} }
return nil return nil
@ -196,7 +206,7 @@ func (g *GameClient) handleUpdateServerInfoPacket(packet d2netpacket.NetPacket)
g.MapEngine.SetSeed(serverInfo.Seed) g.MapEngine.SetSeed(serverInfo.Seed)
g.PlayerID = serverInfo.PlayerID g.PlayerID = serverInfo.PlayerID
g.Seed = serverInfo.Seed g.Seed = serverInfo.Seed
log.Printf("Player id set to %s", serverInfo.PlayerID) g.Infof("Player id set to %s", serverInfo.PlayerID)
return nil return nil
} }
@ -259,7 +269,7 @@ func (g *GameClient) handleMovePlayerPacket(packet d2netpacket.NetPacket) error
if err != nil { if err != nil {
fmtStr := "GameClient: error setting animation mode for player %s: %s" 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" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"log"
"net" "net"
"sync" "sync"
"time" "time"
@ -13,6 +12,7 @@ import (
"github.com/robertkrimen/otto" "github.com/robertkrimen/otto"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
@ -23,6 +23,8 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2script" "github.com/OpenDiablo2/OpenDiablo2/d2script"
) )
const logPrefix = "Game Server"
const ( const (
port = "6669" port = "6669"
chunkSize int = 4096 // nolint:deadcode,unused,varcheck // WIP chunkSize int = 4096 // nolint:deadcode,unused,varcheck // WIP
@ -51,6 +53,8 @@ type GameServer struct {
maxConnections int maxConnections int
packetManagerChan chan []byte packetManagerChan chan []byte
heroStateFactory *d2hero.HeroStateFactory heroStateFactory *d2hero.HeroStateFactory
*d2util.Logger
} }
// NewGameServer builds a new GameServer that can be started // NewGameServer builds a new GameServer that can be started
@ -58,7 +62,9 @@ type GameServer struct {
// ctx: required context item // ctx: required context item
// networkServer: true = 0.0.0.0 | false = 127.0.0.1 // networkServer: true = 0.0.0.0 | false = 127.0.0.1
// maxConnections (default: 8): maximum number of TCP connections allowed open // 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, maxConnections ...int) (*GameServer,
error) { error) {
if len(maxConnections) == 0 { if len(maxConnections) == 0 {
@ -86,11 +92,15 @@ func NewGameServer(asset *d2asset.AssetManager, networkServer bool,
heroStateFactory: heroStateFactory, 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.SetSeed(gameServer.seed)
mapEngine.ResetMap(d2enum.RegionAct1Town, 100, 100) mapEngine.ResetMap(d2enum.RegionAct1Town, 100, 100)
mapGen, err := d2mapgen.NewMapGenerator(asset, mapEngine) mapGen, err := d2mapgen.NewMapGenerator(asset, l, mapEngine)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -118,7 +128,7 @@ func (g *GameServer) Start() error {
listenerAddress = "0.0.0.0:" + port 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) l, err := net.Listen("tcp4", listenerAddress)
if err != nil { if err != nil {
@ -133,7 +143,7 @@ func (g *GameServer) Start() error {
for { for {
c, err := g.listener.Accept() c, err := g.listener.Accept()
if err != nil { if err != nil {
log.Printf("Unable to accept connection: %s\n", err) g.Errorf("Unable to accept connection: %s", err)
return return
} }
@ -150,7 +160,7 @@ func (g *GameServer) Stop() {
g.cancel() g.cancel()
if err := g.listener.Close(); err != nil { 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: case d2netpackettype.PlayerConnectionRequest:
player, err := d2netpacket.UnmarshalNetPacket(p) player, err := d2netpacket.UnmarshalNetPacket(p)
if err != nil { if err != nil {
log.Printf("Unable to unmarshal PlayerConnectionRequestPacket: %s\n", err) g.Errorf("Unable to unmarshal PlayerConnectionRequestPacket: %s\n", err)
} }
g.sendPacketToClients(player) g.sendPacketToClients(player)
case d2netpackettype.MovePlayer: case d2netpackettype.MovePlayer:
move, err := d2netpacket.UnmarshalNetPacket(p) move, err := d2netpacket.UnmarshalNetPacket(p)
if err != nil { if err != nil {
log.Println(err) g.Error(err.Error())
continue continue
} }
@ -183,7 +193,7 @@ func (g *GameServer) packetManager() {
case d2netpackettype.CastSkill: case d2netpackettype.CastSkill:
castSkill, err := d2netpacket.UnmarshalNetPacket(p) castSkill, err := d2netpacket.UnmarshalNetPacket(p)
if err != nil { if err != nil {
log.Println(err) g.Error(err.Error())
continue continue
} }
@ -191,7 +201,7 @@ func (g *GameServer) packetManager() {
case d2netpackettype.SpawnItem: case d2netpackettype.SpawnItem:
item, err := d2netpacket.UnmarshalNetPacket(p) item, err := d2netpacket.UnmarshalNetPacket(p)
if err != nil { if err != nil {
log.Println(err) g.Error(err.Error())
continue continue
} }
@ -206,7 +216,7 @@ func (g *GameServer) packetManager() {
func (g *GameServer) sendPacketToClients(packet d2netpacket.NetPacket) { func (g *GameServer) sendPacketToClients(packet d2netpacket.NetPacket) {
for _, c := range g.connections { for _, c := range g.connections {
if err := c.SendPacketToClient(packet); err != nil { 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 var packet d2netpacket.NetPacket
log.Printf("Accepting connection: %s\n", conn.RemoteAddr().String()) g.Infof("Accepting connection: %s\n", conn.RemoteAddr().String())
defer func() { defer func() {
if err := conn.Close(); err != nil { 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 { for {
err := decoder.Decode(&packet) err := decoder.Decode(&packet)
if err != nil { if err != nil {
log.Println(err) g.Error(err.Error())
return // exit this connection as we could not read the first packet return // exit this connection as we could not read the first packet
} }
@ -240,16 +250,16 @@ func (g *GameServer) handleConnection(conn net.Conn) {
// to. // to.
if connected == 0 { if connected == 0 {
if packet.PacketType != d2netpackettype.PlayerConnectionRequest { 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 { if err := g.registerConnection(packet.PacketData, conn); err != nil {
switch err { switch err {
case errServerFull: // Server is currently full and not accepting new connections. case errServerFull: // Server is currently full and not accepting new connections.
_, errServerFullPacket := conn.Write(d2netpacket.MarshalPacket(d2netpacket.CreateServerFullPacket())) _, 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. case errPlayerAlreadyExists: // Player is already registered and did not disconnection correctly.
log.Println(err) g.Error(fmt.Sprintln(err))
} }
return return
@ -283,7 +293,7 @@ func (g *GameServer) registerConnection(b []byte, conn net.Conn) error {
// if it is not full, unmarshal the playerConnectionRequest // if it is not full, unmarshal the playerConnectionRequest
packet, err := d2netpacket.UnmarshalPlayerConnectionRequest(b) packet, err := d2netpacket.UnmarshalPlayerConnectionRequest(b)
if err != nil { 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 // 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 a new TCP Client Connection and add it to the connections map
client := d2tcpclientconnection.CreateTCPClientConnection(conn, packet.ID) client := d2tcpclientconnection.CreateTCPClientConnection(conn, packet.ID)
client.SetPlayerState(packet.PlayerState) 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 g.connections[client.GetUniqueID()] = client
// Temporary position hack -------------------------------------------- // Temporary position hack --------------------------------------------
@ -330,7 +340,7 @@ func (g *GameServer) OnClientConnected(client ClientConnection) {
clientPlayerState.Y = sy 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.connections[client.GetUniqueID()] = client
g.handleClientConnection(client, sx, sy) g.handleClientConnection(client, sx, sy)
@ -339,12 +349,12 @@ func (g *GameServer) OnClientConnected(client ClientConnection) {
func (g *GameServer) handleClientConnection(client ClientConnection, x, y float64) { func (g *GameServer) handleClientConnection(client ClientConnection, x, y float64) {
err := client.SendPacketToClient(d2netpacket.CreateUpdateServerInfoPacket(g.seed, client.GetUniqueID())) err := client.SendPacketToClient(d2netpacket.CreateUpdateServerInfoPacket(g.seed, client.GetUniqueID()))
if err != nil { 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)) err = client.SendPacketToClient(d2netpacket.CreateGenerateMapPacket(d2enum.RegionAct1Town))
if err != nil { 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() playerState := client.GetPlayerState()
@ -371,7 +381,7 @@ func (g *GameServer) handleClientConnection(client ClientConnection, x, y float6
for _, connection := range g.connections { for _, connection := range g.connections {
err := connection.SendPacketToClient(createPlayerPacket) err := connection.SendPacketToClient(createPlayerPacket)
if err != nil { 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() { if connection.GetUniqueID() == client.GetUniqueID() {
@ -397,7 +407,7 @@ func (g *GameServer) handleClientConnection(client ClientConnection, x, y float6
) )
if err != nil { 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 // OnClientDisconnected removes the given client from the list
// of client connections. // of client connections.
func (g *GameServer) OnClientDisconnected(client ClientConnection) { 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()) delete(g.connections, client.GetUniqueID())
} }
@ -443,10 +453,10 @@ func (g *GameServer) OnPacketReceived(client ClientConnection, packet d2netpacke
err = g.heroStateFactory.Save(playerState) err = g.heroStateFactory.Save(playerState)
if err != nil { if err != nil {
log.Printf("GameServer: error saving saving Player: %s", err) g.Errorf("GameServer: error saving saving Player: %s", err)
} }
default: default:
log.Printf("GameServer: received unknown packet %T", packet) g.Warningf("GameServer: received unknown packet %T", packet)
} }
return nil return nil

View File

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