removed d2term singleton (#483)

This commit is contained in:
dk 2020-06-28 18:40:52 -07:00 committed by GitHub
parent 3f575cf1d8
commit 09a28c2822
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 276 additions and 253 deletions

View File

@ -0,0 +1,58 @@
package d2interface
import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
)
type TermCategory int
const (
TermCategoryNone TermCategory = iota
TermCategoryInfo
TermCategoryWarning
TermCategoryError
)
const (
termCharWidth = 6
termCharHeight = 16
termRowCount = 24
termRowCountMax = 32
termColCountMax = 128
termAnimLength = 0.5
)
type termVis int
const (
termVisHidden termVis = iota
termVisShowing
termVisShown
termVisHiding
)
type Terminal interface {
BindLogger()
Advance(elapsed float64) error
OnKeyDown(event d2input.KeyEvent) bool
OnKeyChars(event d2input.KeyCharsEvent) bool
Render(surface d2render.Surface) error
Execute(command string) error
OutputRaw(text string, category TermCategory)
Output(format string, params ...interface{})
OutputInfo(format string, params ...interface{})
OutputWarning(format string, params ...interface{})
OutputError(format string, params ...interface{})
OutputClear()
IsVisible() bool
Hide()
Show()
BindAction(name, description string, action interface{}) error
UnbindAction(name string) error
}
type TerminalLogger interface {
Write(p []byte) (int, error)
}

View File

@ -6,15 +6,15 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dat"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2mpq"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2pl2"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2term"
)
var singleton *assetManager
func Initialize() error {
func Initialize(term d2interface.Terminal) error {
verifyNotInit()
var (
@ -36,11 +36,11 @@ func Initialize() error {
fontManager,
}
d2term.BindAction("assetspam", "display verbose asset manager logs", func(verbose bool) {
term.BindAction("assetspam", "display verbose asset manager logs", func(verbose bool) {
if verbose {
d2term.OutputInfo("asset manager verbose logging enabled")
term.OutputInfo("asset manager verbose logging enabled")
} else {
d2term.OutputInfo("asset manager verbose logging disabled")
term.OutputInfo("asset manager verbose logging disabled")
}
archiveManager.cache.SetVerbose(verbose)
@ -50,16 +50,16 @@ func Initialize() error {
animationManager.cache.SetVerbose(verbose)
})
d2term.BindAction("assetstat", "display asset manager cache statistics", func() {
d2term.OutputInfo("archive cache: %f", float64(archiveManager.cache.GetWeight())/float64(archiveManager.cache.GetBudget())*100.0)
d2term.OutputInfo("file cache: %f", float64(fileManager.cache.GetWeight())/float64(fileManager.cache.GetBudget())*100.0)
d2term.OutputInfo("palette cache: %f", float64(paletteManager.cache.GetWeight())/float64(paletteManager.cache.GetBudget())*100.0)
d2term.OutputInfo("palette transform cache: %f", float64(paletteTransformManager.cache.GetWeight())/float64(paletteTransformManager.cache.GetBudget())*100.0)
d2term.OutputInfo("animation cache: %f", float64(animationManager.cache.GetWeight())/float64(animationManager.cache.GetBudget())*100.0)
d2term.OutputInfo("font cache: %f", float64(fontManager.cache.GetWeight())/float64(fontManager.cache.GetBudget())*100.0)
term.BindAction("assetstat", "display asset manager cache statistics", func() {
term.OutputInfo("archive cache: %f", float64(archiveManager.cache.GetWeight())/float64(archiveManager.cache.GetBudget())*100.0)
term.OutputInfo("file cache: %f", float64(fileManager.cache.GetWeight())/float64(fileManager.cache.GetBudget())*100.0)
term.OutputInfo("palette cache: %f", float64(paletteManager.cache.GetWeight())/float64(paletteManager.cache.GetBudget())*100.0)
term.OutputInfo("palette transform cache: %f", float64(paletteTransformManager.cache.GetWeight())/float64(paletteTransformManager.cache.GetBudget())*100.0)
term.OutputInfo("animation cache: %f", float64(animationManager.cache.GetWeight())/float64(animationManager.cache.GetBudget())*100.0)
term.OutputInfo("font cache: %f", float64(fontManager.cache.GetWeight())/float64(fontManager.cache.GetBudget())*100.0)
})
d2term.BindAction("assetclear", "clear asset manager cache", func() {
term.BindAction("assetclear", "clear asset manager cache", func() {
archiveManager.cache.Clear()
fileManager.cache.Clear()
paletteManager.cache.Clear()

View File

@ -14,8 +14,8 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2term"
)
// The map renderer, used to render the map
@ -30,7 +30,7 @@ type MapRenderer struct {
}
// Creates an instance of the map renderer
func CreateMapRenderer(mapEngine *d2mapengine.MapEngine) *MapRenderer {
func CreateMapRenderer(mapEngine *d2mapengine.MapEngine, term d2interface.Terminal) *MapRenderer {
result := &MapRenderer{
mapEngine: mapEngine,
viewport: NewViewport(0, 0, 800, 600),
@ -38,7 +38,7 @@ func CreateMapRenderer(mapEngine *d2mapengine.MapEngine) *MapRenderer {
result.viewport.SetCamera(&result.camera)
d2term.BindAction("mapdebugvis", "set map debug visualization level", func(level int) {
term.BindAction("mapdebugvis", "set map debug visualization level", func(level int) {
result.debugVisLevel = level
})

View File

@ -1,88 +1,19 @@
package d2term
import (
"errors"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
)
var (
ErrWasInit = errors.New("terminal system is already initialized")
ErrNotInit = errors.New("terminal system is not initialized")
)
func Initialize() (*terminal, error) {
var singleton *terminal
func Initialize() error {
verifyNotInit()
terminal, err := createTerminal()
term, err := createTerminal()
if err != nil {
return err
return nil, err
}
if err := d2input.BindHandlerWithPriority(terminal, d2input.PriorityHigh); err != nil {
return err
if err := d2input.BindHandlerWithPriority(term, d2input.PriorityHigh); err != nil {
return nil, err
}
singleton = terminal
return nil
}
func Advance(elapsed float64) error {
verifyWasInit()
return singleton.advance(elapsed)
}
func Output(format string, params ...interface{}) {
verifyWasInit()
singleton.output(format, params...)
}
func OutputInfo(format string, params ...interface{}) {
verifyWasInit()
singleton.outputInfo(format, params...)
}
func OutputWarning(format string, params ...interface{}) {
verifyWasInit()
singleton.outputWarning(format, params...)
}
func OutputError(format string, params ...interface{}) {
verifyWasInit()
singleton.outputError(format, params...)
}
func BindAction(name, description string, action interface{}) error {
verifyWasInit()
return singleton.bindAction(name, description, action)
}
func UnbindAction(name string) error {
verifyWasInit()
return singleton.unbindAction(name)
}
func Render(surface d2render.Surface) error {
verifyWasInit()
return singleton.render(surface)
}
func BindLogger() {
log.SetOutput(&terminalLogger{writer: log.Writer()})
}
func verifyWasInit() {
if singleton == nil {
panic(ErrNotInit)
}
}
func verifyNotInit() {
if singleton != nil {
panic(ErrWasInit)
}
return term, nil
}

View File

@ -1,12 +1,10 @@
package d2term
import (
"bufio"
"bytes"
"errors"
"fmt"
"image/color"
"io"
"log"
"math"
"reflect"
"sort"
@ -14,10 +12,20 @@ import (
"strings"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
)
type TermCategory d2interface.TermCategory
const (
TermCategoryNone = TermCategory(d2interface.TermCategoryNone)
TermCategoryInfo = TermCategory(d2interface.TermCategoryInfo)
TermCategoryWarning = TermCategory(d2interface.TermCategoryWarning)
TermCategoryError = TermCategory(d2interface.TermCategoryError)
)
const (
termCharWidth = 6
termCharHeight = 16
@ -27,15 +35,6 @@ const (
termAnimLength = 0.5
)
type termCategory int
const (
termCategoryNone termCategory = iota
termCategoryInfo
termCategoryWarning
termCategoryError
)
type termVis int
const (
@ -55,7 +54,7 @@ var (
type termHistroyEntry struct {
text string
category termCategory
category d2interface.TermCategory
}
type termActionEntry struct {
@ -78,37 +77,7 @@ type terminal struct {
actions map[string]termActionEntry
}
func createTerminal() (*terminal, error) {
terminal := &terminal{
lineCount: termRowCount,
actions: make(map[string]termActionEntry),
}
terminal.outputInfo("::: OpenDiablo2 Terminal :::")
terminal.outputInfo("type \"ls\" for a list of actions")
terminal.bindAction("ls", "list available actions", func() {
var names []string
for name := range terminal.actions {
names = append(names, name)
}
sort.Strings(names)
terminal.outputInfo("available actions (%d):", len(names))
for _, name := range names {
entry := terminal.actions[name]
terminal.outputInfo("%s: %s; %s", name, entry.description, reflect.TypeOf(entry.action).String())
}
})
terminal.bindAction("clear", "clear terminal", func() {
terminal.outputClear()
})
return terminal, nil
}
func (t *terminal) advance(elapsed float64) error {
func (t *terminal) Advance(elapsed float64) error {
switch t.visState {
case termVisShowing:
t.visAnim = math.Min(1.0, t.visAnim+elapsed/termAnimLength)
@ -122,7 +91,7 @@ func (t *terminal) advance(elapsed float64) error {
}
}
if !t.isVisible() {
if !t.IsVisible() {
return nil
}
@ -131,16 +100,16 @@ func (t *terminal) advance(elapsed float64) error {
func (t *terminal) OnKeyDown(event d2input.KeyEvent) bool {
if t.visState == termVisHiding || t.visState == termVisHidden && event.Key == d2input.KeyGraveAccent {
t.show()
t.Show()
return true
}
if !t.isVisible() {
if !t.IsVisible() {
return false
}
if event.Key == d2input.KeyGraveAccent {
t.hide()
t.Hide()
return true
}
@ -149,10 +118,10 @@ func (t *terminal) OnKeyDown(event d2input.KeyEvent) bool {
return true
}
maxOutputIndex := d2common.MaxInt(0, len(t.outputHistory)-t.lineCount)
maxoutputIndex := d2common.MaxInt(0, len(t.outputHistory)-t.lineCount)
if event.Key == d2input.KeyHome {
t.outputIndex = maxOutputIndex
t.outputIndex = maxoutputIndex
return true
}
@ -162,8 +131,8 @@ func (t *terminal) OnKeyDown(event d2input.KeyEvent) bool {
}
if event.Key == d2input.KeyPageUp {
if t.outputIndex += t.lineCount; t.outputIndex >= maxOutputIndex {
t.outputIndex = maxOutputIndex
if t.outputIndex += t.lineCount; t.outputIndex >= maxoutputIndex {
t.outputIndex = maxoutputIndex
}
return true
@ -207,9 +176,9 @@ func (t *terminal) OnKeyDown(event d2input.KeyEvent) bool {
t.commandHistory = append(commandHistory, t.command)
t.output(t.command)
if err := t.execute(t.command); err != nil {
t.outputError(err.Error())
t.Output(t.command)
if err := t.Execute(t.command); err != nil {
t.OutputError(err.Error())
}
t.commandIndex = len(t.commandHistory) - 1
@ -227,7 +196,7 @@ func (t *terminal) OnKeyDown(event d2input.KeyEvent) bool {
}
func (t *terminal) OnKeyChars(event d2input.KeyCharsEvent) bool {
if !t.isVisible() {
if !t.IsVisible() {
return false
}
@ -242,8 +211,8 @@ func (t *terminal) OnKeyChars(event d2input.KeyCharsEvent) bool {
return handled
}
func (t *terminal) render(surface d2render.Surface) error {
if !t.isVisible() {
func (t *terminal) Render(surface d2render.Surface) error {
if !t.IsVisible() {
return nil
}
@ -267,11 +236,11 @@ func (t *terminal) render(surface d2render.Surface) error {
surface.DrawText(historyEntry.text)
surface.PushTranslation(-termCharWidth*2, 0)
switch historyEntry.category {
case termCategoryInfo:
case d2interface.TermCategoryInfo:
surface.DrawRect(termCharWidth, termCharHeight, termInfoColor)
case termCategoryWarning:
case d2interface.TermCategoryWarning:
surface.DrawRect(termCharWidth, termCharHeight, termWarningColor)
case termCategoryError:
case d2interface.TermCategoryError:
surface.DrawRect(termCharWidth, termCharHeight, termErrorColor)
}
surface.Pop()
@ -288,7 +257,7 @@ func (t *terminal) render(surface d2render.Surface) error {
return nil
}
func (t *terminal) execute(command string) error {
func (t *terminal) Execute(command string) error {
params := parseCommand(command)
if len(params) == 0 {
return errors.New("invalid command")
@ -349,16 +318,16 @@ func (t *terminal) execute(command string) error {
actionReturnValues := actionValue.Call(paramValues)
if actionReturnValueCount := len(actionReturnValues); actionReturnValueCount > 0 {
t.outputInfo("function returned %d values:", actionReturnValueCount)
t.OutputInfo("function returned %d values:", actionReturnValueCount)
for _, actionReturnValue := range actionReturnValues {
t.outputInfo("%v: %s", actionReturnValue.Interface(), actionReturnValue.String())
t.OutputInfo("%v: %s", actionReturnValue.Interface(), actionReturnValue.String())
}
}
return nil
}
func (t *terminal) outputRaw(text string, category termCategory) {
func (t *terminal) OutputRaw(text string, category d2interface.TermCategory) {
var line string
for _, word := range strings.Split(text, " ") {
if len(line) > 0 {
@ -379,44 +348,44 @@ func (t *terminal) outputRaw(text string, category termCategory) {
t.outputHistory = append(t.outputHistory, termHistroyEntry{line, category})
}
func (t *terminal) output(format string, params ...interface{}) {
t.outputRaw(fmt.Sprintf(format, params...), termCategoryNone)
func (t *terminal) Output(format string, params ...interface{}) {
t.OutputRaw(fmt.Sprintf(format, params...), d2interface.TermCategoryNone)
}
func (t *terminal) outputInfo(format string, params ...interface{}) {
t.outputRaw(fmt.Sprintf(format, params...), termCategoryInfo)
func (t *terminal) OutputInfo(format string, params ...interface{}) {
t.OutputRaw(fmt.Sprintf(format, params...), d2interface.TermCategoryInfo)
}
func (t *terminal) outputWarning(format string, params ...interface{}) {
t.outputRaw(fmt.Sprintf(format, params...), termCategoryWarning)
func (t *terminal) OutputWarning(format string, params ...interface{}) {
t.OutputRaw(fmt.Sprintf(format, params...), d2interface.TermCategoryWarning)
}
func (t *terminal) outputError(format string, params ...interface{}) {
t.outputRaw(fmt.Sprintf(format, params...), termCategoryError)
func (t *terminal) OutputError(format string, params ...interface{}) {
t.OutputRaw(fmt.Sprintf(format, params...), d2interface.TermCategoryError)
}
func (t *terminal) outputClear() {
func (t *terminal) OutputClear() {
t.outputHistory = nil
t.outputIndex = 0
}
func (t *terminal) isVisible() bool {
func (t *terminal) IsVisible() bool {
return t.visState != termVisHidden
}
func (t *terminal) hide() {
func (t *terminal) Hide() {
if t.visState != termVisHidden {
t.visState = termVisHiding
}
}
func (t *terminal) show() {
func (t *terminal) Show() {
if t.visState != termVisShown {
t.visState = termVisShowing
}
}
func (t *terminal) bindAction(name, description string, action interface{}) error {
func (t *terminal) BindAction(name, description string, action interface{}) error {
actionType := reflect.TypeOf(action)
if actionType.Kind() != reflect.Func {
return errors.New("action is not a function")
@ -438,42 +407,15 @@ func (t *terminal) bindAction(name, description string, action interface{}) erro
return nil
}
func (t *terminal) unbindAction(name string) error {
func (t *terminal) BindLogger() {
log.SetOutput(&terminalLogger{writer: log.Writer(), terminal: t})
}
func (t *terminal) UnbindAction(name string) error {
delete(t.actions, name)
return nil
}
type terminalLogger struct {
buffer bytes.Buffer
writer io.Writer
}
func (t *terminalLogger) Write(p []byte) (int, error) {
n, err := t.buffer.Write(p)
if err != nil {
return n, err
}
reader := bufio.NewReader(&t.buffer)
termBytes, _, err := reader.ReadLine()
if err != nil {
return n, err
}
line := string(termBytes[:])
lineLower := strings.ToLower(line)
if strings.Index(lineLower, "error") > 0 {
OutputError(line)
} else if strings.Index(lineLower, "warning") > 0 {
OutputWarning(line)
} else {
Output(line)
}
return t.writer.Write(p)
}
func easeInOut(t float64) float64 {
t *= 2
if t < 1 {
@ -526,3 +468,33 @@ func parseCommand(command string) []string {
return params
}
func createTerminal() (*terminal, error) {
terminal := &terminal{
lineCount: termRowCount,
actions: make(map[string]termActionEntry),
}
terminal.OutputInfo("::: OpenDiablo2 Terminal :::")
terminal.OutputInfo("type \"ls\" for a list of actions")
terminal.BindAction("ls", "list available actions", func() {
var names []string
for name := range terminal.actions {
names = append(names, name)
}
sort.Strings(names)
terminal.OutputInfo("available actions (%d):", len(names))
for _, name := range names {
entry := terminal.actions[name]
terminal.OutputInfo("%s: %s; %s", name, entry.description, reflect.TypeOf(entry.action).String())
}
})
terminal.BindAction("clear", "clear terminal", func() {
terminal.OutputClear()
})
return terminal, nil
}

View File

@ -0,0 +1,44 @@
package d2term
import (
"bufio"
"bytes"
"io"
"strings"
)
type terminalLogger struct {
terminal *terminal
buffer bytes.Buffer
writer io.Writer
}
func (tl *terminalLogger) Write(p []byte) (int, error) {
n, err := tl.buffer.Write(p)
if err != nil {
return n, err
}
reader := bufio.NewReader(&tl.buffer)
termBytes, _, err := reader.ReadLine()
if err != nil {
return n, err
}
line := string(termBytes[:])
lineLower := strings.ToLower(line)
if strings.Index(lineLower, "error") > 0 {
tl.terminal.OutputError(line)
} else if strings.Index(lineLower, "warning") > 0 {
tl.terminal.OutputWarning(line)
} else {
tl.terminal.Output(line)
}
return tl.writer.Write(p)
}
func (tl *terminalLogger) BindToTerminal(t *terminal) {
tl.terminal = t
}

View File

@ -47,15 +47,17 @@ type CharacterSelect struct {
connectionType d2clientconnectiontype.ClientConnectionType
connectionHost string
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
}
func CreateCharacterSelect(audioProvider d2interface.AudioProvider,
connectionType d2clientconnectiontype.ClientConnectionType, connectionHost string) *CharacterSelect {
connectionType d2clientconnectiontype.ClientConnectionType, connectionHost string, term d2interface.Terminal) *CharacterSelect {
return &CharacterSelect{
selectedCharacter: -1,
connectionType: connectionType,
connectionHost: connectionHost,
audioProvider: audioProvider,
terminal: term,
}
}
@ -180,7 +182,7 @@ func (v *CharacterSelect) onNewCharButtonClicked() {
}
func (v *CharacterSelect) onExitButtonClicked() {
mainMenu := CreateMainMenu(v.audioProvider)
mainMenu := CreateMainMenu(v.audioProvider, v.terminal)
mainMenu.SetScreenMode(ScreenModeMainMenu)
d2screen.SetNextScreen(mainMenu)
}
@ -311,5 +313,5 @@ func (v *CharacterSelect) onOkButtonClicked() {
gameClient.Open("", v.gameStates[v.selectedCharacter].FilePath)
}
d2screen.SetNextScreen(CreateGame(v.audioProvider, gameClient))
d2screen.SetNextScreen(CreateGame(v.audioProvider, gameClient, v.terminal))
}

View File

@ -35,6 +35,7 @@ type Credits struct {
cyclesTillNextLine int
doneWithCredits bool
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
}
// CreateCredits creates an instance of the credits screen
@ -138,7 +139,7 @@ func (v *Credits) Advance(tickTime float64) error {
}
func (v *Credits) onExitButtonClicked() {
mainMenu := CreateMainMenu(v.audioProvider)
mainMenu := CreateMainMenu(v.audioProvider, v.terminal)
mainMenu.SetScreenMode(ScreenModeMainMenu)
d2screen.SetNextScreen(mainMenu)
}

View File

@ -65,6 +65,7 @@ type EscapeMenu struct {
rightPent *d2gui.AnimatedSprite
layouts []*layout
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
}
type layout struct {
@ -112,9 +113,10 @@ type actionableElement interface {
Trigger()
}
func NewEscapeMenu(audioProvider d2interface.AudioProvider) *EscapeMenu {
func NewEscapeMenu(audioProvider d2interface.AudioProvider, term d2interface.Terminal) *EscapeMenu {
m := &EscapeMenu{
audioProvider: audioProvider,
terminal: term,
}
m.layouts = []*layout{
@ -339,7 +341,7 @@ func (m *EscapeMenu) showLayout(id layoutID) {
}
if id == saveLayoutID {
mainMenu := CreateMainMenu(m.audioProvider)
mainMenu := CreateMainMenu(m.audioProvider, m.terminal)
mainMenu.SetScreenMode(ScreenModeMainMenu)
d2screen.SetNextScreen(mainMenu)
return

View File

@ -27,20 +27,22 @@ type Game struct {
localPlayer *d2mapentity.Player
lastRegionType d2enum.RegionIdType
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
ticksSinceLevelCheck float64
escapeMenu *EscapeMenu
}
func CreateGame(audioProvider d2interface.AudioProvider, gameClient *d2client.GameClient) *Game {
func CreateGame(audioProvider d2interface.AudioProvider, gameClient *d2client.GameClient, term d2interface.Terminal) *Game {
result := &Game{
gameClient: gameClient,
gameControls: nil,
localPlayer: nil,
lastRegionType: d2enum.RegionNone,
ticksSinceLevelCheck: 0,
mapRenderer: d2maprenderer.CreateMapRenderer(gameClient.MapEngine),
escapeMenu: NewEscapeMenu(audioProvider),
mapRenderer: d2maprenderer.CreateMapRenderer(gameClient.MapEngine, term),
escapeMenu: NewEscapeMenu(audioProvider, term),
audioProvider: audioProvider,
terminal: term,
}
result.escapeMenu.OnLoad()
d2input.BindHandler(result.escapeMenu)
@ -112,7 +114,7 @@ func (v *Game) Advance(tickTime float64) error {
continue
}
v.localPlayer = player
v.gameControls = d2player.NewGameControls(player, v.gameClient.MapEngine, v.mapRenderer, v)
v.gameControls = d2player.NewGameControls(player, v.gameClient.MapEngine, v.mapRenderer, v, v.terminal)
v.gameControls.Load()
d2input.BindHandler(v.gameControls)

View File

@ -71,14 +71,16 @@ type MainMenu struct {
screenMode MainMenuScreenMode
leftButtonHeld bool
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
}
// CreateMainMenu creates an instance of MainMenu
func CreateMainMenu(audioProvider d2interface.AudioProvider) *MainMenu {
func CreateMainMenu(audioProvider d2interface.AudioProvider, term d2interface.Terminal) *MainMenu {
return &MainMenu{
screenMode: ScreenModeUnknown,
leftButtonHeld: true,
audioProvider: audioProvider,
terminal: term,
}
}
@ -255,7 +257,7 @@ func (v *MainMenu) OnLoad(loading d2screen.LoadingState) {
}
func (v *MainMenu) onMapTestClicked() {
d2screen.SetNextScreen(CreateMapEngineTest(0, 1))
d2screen.SetNextScreen(CreateMapEngineTest(0, 1, v.terminal))
}
func openbrowser(url string) {
@ -280,7 +282,7 @@ func openbrowser(url string) {
func (v *MainMenu) onSinglePlayerClicked() {
// Go here only if existing characters are available to select
if d2player.HasGameStates() {
d2screen.SetNextScreen(CreateCharacterSelect(v.audioProvider, d2clientconnectiontype.Local, v.tcpJoinGameEntry.GetText()))
d2screen.SetNextScreen(CreateCharacterSelect(v.audioProvider, d2clientconnectiontype.Local, v.tcpJoinGameEntry.GetText(), v.terminal))
return
}
d2screen.SetNextScreen(CreateSelectHeroClass(v.audioProvider, d2clientconnectiontype.Local, v.tcpJoinGameEntry.GetText()))
@ -410,7 +412,7 @@ func (v *MainMenu) onTcpIpCancelClicked() {
}
func (v *MainMenu) onTcpIpHostGameClicked() {
d2screen.SetNextScreen(CreateCharacterSelect(v.audioProvider, d2clientconnectiontype.LANServer, ""))
d2screen.SetNextScreen(CreateCharacterSelect(v.audioProvider, d2clientconnectiontype.LANServer, "", v.terminal))
}
func (v *MainMenu) onTcpIpJoinGameClicked() {
@ -422,5 +424,5 @@ func (v *MainMenu) onBtnTcpIpCancelClicked() {
}
func (v *MainMenu) onBtnTcpIpOkClicked() {
d2screen.SetNextScreen(CreateCharacterSelect(v.audioProvider, d2clientconnectiontype.LANClient, v.tcpJoinGameEntry.GetText()))
d2screen.SetNextScreen(CreateCharacterSelect(v.audioProvider, d2clientconnectiontype.LANClient, v.tcpJoinGameEntry.GetText(), v.terminal))
}

View File

@ -11,6 +11,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2maprenderer"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
@ -82,6 +83,7 @@ type MapEngineTest struct {
gameState *d2player.PlayerState
mapEngine *d2mapengine.MapEngine
mapRenderer *d2maprenderer.MapRenderer
terminal d2interface.Terminal
//TODO: this is region specific properties, should be refactored for multi-region rendering
currentRegion int
@ -92,13 +94,14 @@ type MapEngineTest struct {
debugVisLevel int
}
func CreateMapEngineTest(currentRegion int, levelPreset int) *MapEngineTest {
func CreateMapEngineTest(currentRegion int, levelPreset int, term d2interface.Terminal) *MapEngineTest {
result := &MapEngineTest{
currentRegion: currentRegion,
levelPreset: levelPreset,
fileIndex: 0,
regionSpec: RegionSpec{},
filesCount: 0,
terminal: term,
}
result.gameState = d2player.CreateTestGameState()
return result
@ -148,7 +151,7 @@ func (met *MapEngineTest) OnLoad(loading d2screen.LoadingState) {
loading.Progress(0.2)
met.mapEngine = d2mapengine.CreateMapEngine()
loading.Progress(0.5)
met.mapRenderer = d2maprenderer.CreateMapRenderer(met.mapEngine)
met.mapRenderer = d2maprenderer.CreateMapRenderer(met.mapEngine, met.terminal)
loading.Progress(0.7)
met.LoadRegionByIndex(met.currentRegion, met.levelPreset, met.fileIndex)
}

View File

@ -69,6 +69,7 @@ type SelectHeroClass struct {
connectionType d2clientconnectiontype.ClientConnectionType
connectionHost string
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
}
func CreateSelectHeroClass(audioProvider d2interface.AudioProvider,
@ -434,14 +435,14 @@ func (v *SelectHeroClass) OnUnload() error {
}
func (v *SelectHeroClass) onExitButtonClicked() {
d2screen.SetNextScreen(CreateCharacterSelect(v.audioProvider, v.connectionType, v.connectionHost))
d2screen.SetNextScreen(CreateCharacterSelect(v.audioProvider, v.connectionType, v.connectionHost, v.terminal))
}
func (v *SelectHeroClass) onOkButtonClicked() {
gameState := d2player.CreatePlayerState(v.heroNameTextbox.GetText(), v.selectedHero, *d2datadict.CharStats[v.selectedHero], v.hardcoreCheckbox.GetCheckState())
gameClient, _ := d2client.Create(d2clientconnectiontype.Local)
gameClient.Open(v.connectionHost, gameState.FilePath)
d2screen.SetNextScreen(CreateGame(v.audioProvider, gameClient))
d2screen.SetNextScreen(CreateGame(v.audioProvider, gameClient, v.terminal))
}
func (v *SelectHeroClass) Render(screen d2render.Surface) error {

View File

@ -7,6 +7,7 @@ import (
"time"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
@ -14,7 +15,6 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2maprenderer"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2term"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
@ -82,8 +82,8 @@ const (
rightSkill = ActionableType(iota)
)
func NewGameControls(hero *d2mapentity.Player, mapEngine *d2mapengine.MapEngine, mapRenderer *d2maprenderer.MapRenderer, inputListener InputCallbackListener) *GameControls {
d2term.BindAction("setmissile", "set missile id to summon on right click", func(id int) {
func NewGameControls(hero *d2mapentity.Player, mapEngine *d2mapengine.MapEngine, mapRenderer *d2maprenderer.MapRenderer, inputListener InputCallbackListener, term d2interface.Terminal) *GameControls {
term.BindAction("setmissile", "set missile id to summon on right click", func(id int) {
missileID = id
})
@ -117,7 +117,7 @@ func NewGameControls(hero *d2mapentity.Player, mapEngine *d2mapengine.MapEngine,
},
}
d2term.BindAction("freecam", "toggle free camera movement", func() {
term.BindAction("freecam", "toggle free camera movement", func() {
gc.FreeCam = !gc.FreeCam
})

63
main.go
View File

@ -4,6 +4,7 @@ import (
"bytes"
"errors"
"fmt"
ebiten_input "github.com/OpenDiablo2/OpenDiablo2/d2core/d2input/ebiten"
"image"
"image/gif"
"image/png"
@ -27,7 +28,6 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
ebiten_input "github.com/OpenDiablo2/OpenDiablo2/d2core/d2input/ebiten"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2inventory"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render/ebiten"
@ -65,6 +65,8 @@ var singleton struct {
captureFrames []*image.RGBA
}
var terminal_hack d2interface.Terminal // we need to make this available inside of advance/update/render
func main() {
region := kingpin.Arg("region", "Region type id").Int()
preset := kingpin.Arg("preset", "Level preset").Int()
@ -81,7 +83,15 @@ func main() {
panic(err)
}
if err := initialize(audioProvider); err != nil {
d2input.Initialize(ebiten_input.InputService{}) // TODO d2input singleton must be init before d2term
term, err := d2term.Initialize()
terminal_hack = term // needs to be used in advance, no easy way for that right now
if err != nil {
log.Fatal(err)
}
if err := initialize(audioProvider, term); err != nil {
if os.IsNotExist(err) {
run(updateInitError)
}
@ -96,15 +106,15 @@ func main() {
}
if *region == 0 {
d2screen.SetNextScreen(d2gamescreen.CreateMainMenu(audioProvider))
d2screen.SetNextScreen(d2gamescreen.CreateMainMenu(audioProvider, term))
} else {
d2screen.SetNextScreen(d2gamescreen.CreateMapEngineTest(*region, *preset))
d2screen.SetNextScreen(d2gamescreen.CreateMapEngineTest(*region, *preset, term))
}
run(update)
}
func initialize(audioProvider d2interface.AudioProvider) error {
func initialize(audioProvider d2interface.AudioProvider, term d2interface.Terminal) error {
singleton.timeScale = 1.0
singleton.lastTime = d2common.Now()
singleton.lastScreenAdvance = singleton.lastTime
@ -116,8 +126,6 @@ func initialize(audioProvider d2interface.AudioProvider) error {
config := d2config.Get()
d2resource.LanguageCode = config.Language
d2input.Initialize(ebiten_input.InputService{})
renderer, err := ebiten.CreateRenderer()
if err != nil {
return err
@ -128,60 +136,57 @@ func initialize(audioProvider d2interface.AudioProvider) error {
}
d2render.SetWindowIcon("d2logo.png")
if err := d2term.Initialize(); err != nil {
return err
}
d2term.BindLogger()
d2term.BindAction("dumpheap", "dumps the heap to pprof/heap.pprof", func() {
term.BindLogger()
term.BindAction("dumpheap", "dumps the heap to pprof/heap.pprof", func() {
os.Mkdir("./pprof/", 0755)
fileOut, _ := os.Create("./pprof/heap.pprof")
pprof.WriteHeapProfile(fileOut)
fileOut.Close()
})
d2term.BindAction("fullscreen", "toggles fullscreen", func() {
term.BindAction("fullscreen", "toggles fullscreen", func() {
fullscreen := !d2render.IsFullScreen()
d2render.SetFullScreen(fullscreen)
d2term.OutputInfo("fullscreen is now: %v", fullscreen)
term.OutputInfo("fullscreen is now: %v", fullscreen)
})
d2term.BindAction("capframe", "captures a still frame", func(path string) {
term.BindAction("capframe", "captures a still frame", func(path string) {
singleton.captureState = captureStateFrame
singleton.capturePath = path
singleton.captureFrames = nil
})
d2term.BindAction("capgifstart", "captures an animation (start)", func(path string) {
term.BindAction("capgifstart", "captures an animation (start)", func(path string) {
singleton.captureState = captureStateGif
singleton.capturePath = path
singleton.captureFrames = nil
})
d2term.BindAction("capgifstop", "captures an animation (stop)", func() {
term.BindAction("capgifstop", "captures an animation (stop)", func() {
singleton.captureState = captureStateNone
})
d2term.BindAction("vsync", "toggles vsync", func() {
term.BindAction("vsync", "toggles vsync", func() {
vsync := !d2render.GetVSyncEnabled()
d2render.SetVSyncEnabled(vsync)
d2term.OutputInfo("vsync is now: %v", vsync)
term.OutputInfo("vsync is now: %v", vsync)
})
d2term.BindAction("fps", "toggle fps counter", func() {
term.BindAction("fps", "toggle fps counter", func() {
singleton.showFPS = !singleton.showFPS
d2term.OutputInfo("fps counter is now: %v", singleton.showFPS)
term.OutputInfo("fps counter is now: %v", singleton.showFPS)
})
d2term.BindAction("timescale", "set scalar for elapsed time", func(timeScale float64) {
term.BindAction("timescale", "set scalar for elapsed time", func(timeScale float64) {
if timeScale <= 0 {
d2term.OutputError("invalid time scale value")
term.OutputError("invalid time scale value")
} else {
d2term.OutputInfo("timescale changed from %f to %f", singleton.timeScale, timeScale)
term.OutputInfo("timescale changed from %f to %f", singleton.timeScale, timeScale)
singleton.timeScale = timeScale
}
})
d2term.BindAction("quit", "exits the game", func() {
term.BindAction("quit", "exits the game", func() {
os.Exit(0)
})
d2term.BindAction("screen-gui", "enters the gui playground screen", func() {
term.BindAction("screen-gui", "enters the gui playground screen", func() {
d2screen.SetNextScreen(d2gamescreen.CreateGuiTestMain())
})
if err := d2asset.Initialize(); err != nil {
if err := d2asset.Initialize(term); err != nil {
return err
}
@ -268,7 +273,7 @@ func advance(elapsed, current float64) error {
return err
}
if err := d2term.Advance(elapsed); err != nil {
if err := terminal_hack.Advance(elapsed); err != nil {
return err
}
@ -294,7 +299,7 @@ func render(target d2render.Surface) error {
return err
}
if err := d2term.Render(target); err != nil {
if err := terminal_hack.Render(target); err != nil {
return err
}